Content-Type: multipart/mixed; boundary="Apple-Mail=_3E0AF434-0607-4C09-B25B-E98987DEC244" --Apple-Mail=_3E0AF434-0607-4C09-B25B-E98987DEC244 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=windows-1252 Hi = all,

I wrote a custom depiction generator last year = that will plug into the current (since 1.5.4) renderer and give what I = (subjectively) consider nicer depictions. I did send round some = preliminary depictions to do with bounding boxes. Still working on = cleaning this up for the main code base but as I=92ve sent the code to a = couple of people already I thought I should share with the cdk-devel = list.

Here are some large (~10Mb) examples of = the SVG generated with it. You can zoom in/out with mouse scroll when = viewed in the browser.

http://www.ebi.ac.uk/steinbeck-srv/cdk/chebi-release/chebi= -release-108-color.svg
http://www.ebi.ac.uk/steinbeck-srv/cdk/chebi-release/chebi-relea= se-108.svg

It=92s prototyping code so a = complete hairball but I=92ve been using it for around two months and is = working well. To use it just put it in the generator list and remove any = other generators that draw atoms or = bonds.

Cheers,
J

= --Apple-Mail=_3E0AF434-0607-4C09-B25B-E98987DEC244 Content-Disposition: attachment; filename=SmoothGenerator.java Content-Type: application/octet-stream; name="SmoothGenerator.java" Content-Transfer-Encoding: quoted-printable /*=0A=20*=20Copyright=20(c)=202013.=20EMBL,=20European=20Bioinformatics=20= Institute=0A=20*=0A=20*=20This=20program=20is=20free=20software:=20you=20= can=20redistribute=20it=20and/or=20modify=0A=20*=20it=20under=20the=20= terms=20of=20the=20GNU=20Lesser=20General=20Public=20License=20as=20= published=20by=0A=20*=20the=20Free=20Software=20Foundation,=20either=20= version=203=20of=20the=20License,=20or=0A=20*=20(at=20your=20option)=20= any=20later=20version.=0A=20*=0A=20*=20This=20program=20is=20distributed=20= in=20the=20hope=20that=20it=20will=20be=20useful,=0A=20*=20but=20WITHOUT=20= ANY=20WARRANTY;=20without=20even=20the=20implied=20warranty=20of=0A=20*=20= MERCHANTABILITY=20or=20FITNESS=20FOR=20A=20PARTICULAR=20PURPOSE.=20=20= See=20the=0A=20*=20GNU=20Lesser=20General=20Public=20License=20for=20= more=20details.=0A=20*=0A=20*=20You=20should=20have=20received=20a=20= copy=20of=20the=20GNU=20Lesser=20General=20Public=20License=0A=20*=20= along=20with=20this=20program.=20=20If=20not,=20see=20= .=0A=20*/=0A=0Apackage=20= uk.ac.ebi.mdk.ui.render.molecule;=0A=0Aimport=20= com.google.common.primitives.Doubles;=0Aimport=20= org.openscience.cdk.config.Isotopes;=0Aimport=20= org.openscience.cdk.geometry.GeometryTools;=0Aimport=20= org.openscience.cdk.graph.Cycles;=0Aimport=20= org.openscience.cdk.interfaces.IAtom;=0Aimport=20= org.openscience.cdk.interfaces.IAtomContainer;=0Aimport=20= org.openscience.cdk.interfaces.IBond;=0Aimport=20= org.openscience.cdk.interfaces.IRingSet;=0Aimport=20= org.openscience.cdk.renderer.RendererModel;=0Aimport=20= org.openscience.cdk.renderer.elements.Bounds;=0Aimport=20= org.openscience.cdk.renderer.elements.ElementGroup;=0Aimport=20= org.openscience.cdk.renderer.elements.GeneralPath;=0Aimport=20= org.openscience.cdk.renderer.elements.IRenderingElement;=0Aimport=20= org.openscience.cdk.renderer.elements.LineElement;=0Aimport=20= org.openscience.cdk.renderer.generators.BasicSceneGenerator;=0Aimport=20= org.openscience.cdk.renderer.generators.IGenerator;=0Aimport=20= org.openscience.cdk.renderer.generators.IGeneratorParameter;=0Aimport=20= org.openscience.cdk.ringsearch.RingSearch;=0A=0Aimport=20= javax.vecmath.Point2d;=0Aimport=20javax.vecmath.Vector2d;=0Aimport=20= java.awt.Color;=0Aimport=20java.awt.Font;=0Aimport=20java.awt.Shape;=0A= import=20java.awt.font.FontRenderContext;=0Aimport=20= java.awt.geom.AffineTransform;=0Aimport=20java.awt.geom.Area;=0Aimport=20= java.awt.geom.Line2D;=0Aimport=20java.awt.geom.Path2D;=0Aimport=20= java.awt.geom.PathIterator;=0Aimport=20java.awt.geom.Point2D;=0Aimport=20= java.awt.geom.Rectangle2D;=0Aimport=20java.io.IOException;=0Aimport=20= java.util.Arrays;=0Aimport=20java.util.Collections;=0Aimport=20= java.util.Comparator;=0Aimport=20java.util.HashMap;=0Aimport=20= java.util.LinkedList;=0Aimport=20java.util.List;=0Aimport=20= java.util.Map;=0Aimport=20java.util.Set;=0A=0A/**=20@author=20John=20May=20= */=0Apublic=20class=20SmoothGenerator=20implements=20= IGenerator=20{=0A=0A=20=20=20=20private=20final=20static=20= boolean=20DISPLAY_TERMINAL_CARBONS=20=3D=20true;=0A=0A=20=20=20=20= private=20final=20static=20Font=20font=20=3D=20new=20Font("Verdana",=20= Font.PLAIN,=2018);=0A=0A=20=20=20=20private=20static=20final=20= FontRenderContext=20FONT_RENDER_CONTEXT=20=3D=20new=20= FontRenderContext(new=20AffineTransform(),=20true,=20false);=0A=0A=20=20=20= =20private=20static=20final=20Color=20fg=20=20=20=20=3D=20new=20= Color(0x444444);=0A=20=20=20=20private=20static=20final=20Color=20debug=20= =3D=20new=20Color(0xFF6666);=0A=0A=20=20=20=20private=20boolean=20= coloured;=0A=0A=20=20=20=20public=20SmoothGenerator(boolean=20coloured)=20= {=0A=20=20=20=20=20=20=20=20this.coloured=20=3D=20coloured;=0A=20=20=20=20= =20=20=20=20String[]=20symbols=20=3D=20"Se,=20F,=20C,=20As,=20N,=20O,=20= H,=20I,=20K,=20=E2=80=93,=20Cl,=20P,=20Co,=202+,=20S,=20R,=20Hg,=20=E2=80=A2= ,=20Br,=20+,=203=E2=80=93,=20.,=202,=20Mg,=204=E2=80=93".split(",=20");=0A= =20=20=20=20=20=20=20=20for=20(String=20text=20:=20symbols)=0A=20=20=20=20= =20=20=20=20=20=20=20=20obtainGlyph(text);=0A=20=20=20=20}=0A=0A=20=20=20= =20public=20SmoothGenerator()=20{=0A=20=20=20=20=20=20=20=20this(false);=0A= =20=20=20=20}=0A=0A=20=20=20=20Color=20getColor(IAtom=20atom)=20{=0A=20=20= =20=20=20=20=20=20if=20(!coloured)=0A=20=20=20=20=20=20=20=20=20=20=20=20= return=20fg;=0A=20=20=20=20=20=20=20=20switch=20(atom.getAtomicNumber())=20= {=0A=20=20=20=20=20=20=20=20=20=20=20=20case=207:=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20return=20new=20Color(0x4F4BFF);=0A=20=20=20=20= =20=20=20=20=20=20=20=20case=208:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20return=20new=20Color(0xFF464F);=0A=20=20=20=20=20=20=20=20=20=20= =20=20case=209:=20=20//=20F=0A=20=20=20=20=20=20=20=20=20=20=20=20case=20= 17:=20//=20Cl=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20= new=20Color(0x76FF5A);=0A=20=20=20=20=20=20=20=20=20=20=20=20case=2035:=20= //=20Br=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20new=20= Color(0x972D1D);=0A=20=20=20=20=20=20=20=20=20=20=20=20case=2053:=20//=20= I=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20new=20= Color(0x68307F);=0A=20=20=20=20=20=20=20=20=20=20=20=20case=2015:=20//=20= P=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20new=20= Color(0xFF8443);=0A=20=20=20=20=20=20=20=20=20=20=20=20case=2016:=20//=20= S=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20new=20= Color(0xEFD657);=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= return=20fg;=0A=20=20=20=20}=0A=0A=20=20=20=20Set=20= cachedGlyphs()=20{=0A=20=20=20=20=20=20=20=20return=20glyphs.keySet();=0A= =20=20=20=20}=0A=0A=20=20=20=20@Override=20public=20= List>=20getParameters()=20{=0A=20=20=20=20=20=20=20= =20return=20Collections.emptyList();=0A=20=20=20=20}=0A=0A=20=20=20=20= @Override=20public=20IRenderingElement=20generate(IAtomContainer=20= container,=20RendererModel=20model)=20{=0A=20=20=20=20=20=20=20=20= ElementGroup=20group=20=3D=20new=20ElementGroup();=0A=0A=20=20=20=20=20=20= =20=20double=20scale=20=3D=20model.get(BasicSceneGenerator.Scale.class);=0A= =0A=20=20=20=20=20=20=20=20Area[]=20filled=20=3D=20new=20= Area[container.getAtomCount()];=0A=20=20=20=20=20=20=20=20Path2D[]=20= symbols=20=3D=20new=20Path2D[container.getAtomCount()];=0A=0A=20=20=20=20= =20=20=20=20for=20(IAtom=20atom=20:=20container.atoms())=20{=0A=0A=20=20=20= =20=20=20=20=20=20=20=20=20int=20atNum=20=3D=20= container.getAtomNumber(atom);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= if=20(!displaySymbol(container,=20atom))=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20continue;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= Shape=20shape=20=3D=20obtainGlyph(atom.getSymbol());=0A=0A=20=20=20=20=20= =20=20=20=20=20=20=20double=20x=20=3D=20atom.getPoint2d().x;=0A=20=20=20=20= =20=20=20=20=20=20=20=20double=20y=20=3D=20atom.getPoint2d().y;=0A=20=20=20= =20=20=20=20=20=20=20=20=20Rectangle2D=20bounds=20=3D=20= shape.getBounds2D();=0A=20=20=20=20=20=20=20=20=20=20=20=20= AffineTransform=20at=20=3D=20AffineTransform.getTranslateInstance(x=20-=20= (bounds.getX()=20/=20scale)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20-=20((bounds.getWidth()=20/=20= scale)=20/=202),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20y=20+=20((bounds.getY()=20+=20bounds.getHeight())=20/=20scale)=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20-=20((bounds.getHeight()=20/=20scale)=20/=202));=0A=20=20=20=20=20=20= =20=20=20=20=20=20at.scale(1=20/=20scale,=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=201=20/=20-scale);=0A=0A=20=20=20=20=20=20= =20=20=20=20=20=20Shape=20symbol=20=3D=20= at.createTransformedShape(shape);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= filled[atNum]=20=3D=20new=20Area(getConvexHullPath2D(symbol));=0A=0A=20=20= =20=20=20=20=20=20=20=20=20=20= //group.add(GeneralPath.filledPathOf(cvxhul,=20debug));=20//=20optional=0A= =20=20=20=20=20=20=20=20=20=20=20=20symbols[atNum]=20=3D=20new=20= Path2D.Double();=0A=20=20=20=20=20=20=20=20=20=20=20=20= symbols[atNum].append(symbol.getPathIterator(new=20AffineTransform()),=20= false);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20//=20place=20hydrogens=0A= =20=20=20=20=20=20=20=20=20=20=20=20int=20hPlacement=20=3D=20= hPlacement(container,=20x,=20y,=20atom,=20group);=0A=0A=20=20=20=20=20=20= =20=20=20=20=20=20Shape=20hydrogenLabel=20=3D=20new=20Area(toShape("H",=20= x,=20y,=20scale));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20double=20wS=20= =3D=20symbol.getBounds2D().getWidth();=0A=20=20=20=20=20=20=20=20=20=20=20= =20double=20hS=20=3D=20symbol.getBounds2D().getHeight();=0A=20=20=20=20=20= =20=20=20=20=20=20=20double=20wH=20=3D=20= hydrogenLabel.getBounds2D().getWidth();=0A=20=20=20=20=20=20=20=20=20=20=20= =20double=20wH2=20=3D=20hydrogenLabel.getBounds2D().getWidth();=0A=20=20=20= =20=20=20=20=20=20=20=20=20double=20hH=20=3D=20= hydrogenLabel.getBounds2D().getHeight();=0A=0A=20=20=20=20=20=20=20=20=20= =20=20=20hydrogenLabel=20=3D=20= AffineTransform.getTranslateInstance(-((symbol.getBounds2D().getWidth()=20= /=202)=20-=20(wH=20/=202)),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= 0)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(hydrogenLabel);=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20if=20(atom.getImplicitHydrogenCount()=20!=3D=20null=20&&=20= atom.getImplicitHydrogenCount()=20>=201)=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20Shape=20hCount=20=3D=20= toShape(Integer.toString(atom.getImplicitHydrogenCount()),=20x,=20y,=20= scale);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20hCount=20=3D=20= AffineTransform.getScaleInstance(0.6,=200.6)=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20.createTransformedShape(hCount);=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20Rectangle2D=20hCountBounds=20=3D=20= hCount.getBounds2D();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= hCount=20=3D=20AffineTransform.getTranslateInstance(x=20-=20= hCountBounds.getX()=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20+=20((wH=20/=202)=20+=20(wH=20*=200.2)),=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20y=20-=20hCountBounds.getY()=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20-=20((hCountBounds.getHeight())=20/=202)=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20-=20(hH=20/=20= 2))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(hCount);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Area=20hArea=20=3D=20new=20Area(hydrogenLabel);=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20hArea.add(new=20Area(hCount));=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20hydrogenLabel=20=3D=20hArea;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20wH2=20=3D=20= hydrogenLabel.getBounds2D().getWidth();=20//=20adjust=20width=20to=20do=0A= =20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20double=20spacing=20=3D=20hS=20*=200.2;=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20switch=20(hPlacement)=20{=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20case=20NORTH:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20hydrogenLabel=20=3D=20= AffineTransform.getTranslateInstance(0,=20hS=20+=20(spacing))=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(hydrogenLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20case=20NORTH_EAST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20case=20EAST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20case=20= SOUTH_EAST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= hydrogenLabel=20=3D=20AffineTransform.getTranslateInstance(wS=20+=20= (spacing),=200)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20.createTransformedShape(hydrogenLabel);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20case=20SOUTH:=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20hydrogenLabel=20=3D=20= AffineTransform.getTranslateInstance(0,=20-(hH=20+=20(spacing)))=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(hydrogenLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20case=20NORTH_WEST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20case=20WEST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20case=20= SOUTH_WEST:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= hydrogenLabel=20=3D=20AffineTransform.getTranslateInstance(-(wH2=20+=20= (spacing)),=200)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20.createTransformedShape(hydrogenLabel);=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20default:=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20hydrogenLabel=20=3D=20null;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20int=20q=20=3D=20= atom.getFormalCharge();=0A=20=20=20=20=20=20=20=20=20=20=20=20int=20nRad=20= =3D=200;=0A=20=20=20=20=20=20=20=20=20=20=20=20Shape=20radicalLabel=20=3D=20= null;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20//=20render=20radical=20= (only=20single=20supported=20for=20now)=0A=20=20=20=20=20=20=20=20=20=20=20= =20if=20((nRad=20=3D=20container.getConnectedSingleElectronsCount(atom))=20= >=200)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20String=20= text=20=3D=20nRad=20>=201=20?=20q=20!=3D=200=20?=20"("=20+=20nRad=20+=20= "\u2022"=20+=20")"=20:=20nRad=20+=20"\u2022"=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20:=20"\u2022";=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20radicalLabel=20=3D=20toShape(text,=20x,=20y,=20scale);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20radicalLabel=20=3D=20= AffineTransform.getScaleInstance(0.6,=200.6)=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(radicalLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20Rectangle2D=20radicalBounds=20=3D=20= radicalLabel.getBounds2D();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20radicalLabel=20=3D=20AffineTransform.getTranslateInstance(x=20-=20= radicalBounds.getX()=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20+=20((wS=20/=202)=20+=20(spacing)),=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20y=20-=20= radicalBounds.getY()=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20-=20((radicalBounds.getHeight())=20/=202)=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= +=20(hS=20/=202))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20.createTransformedShape(radicalLabel);=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20if=20(hPlacement=20=3D=3D=20EAST)=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20radicalLabel=20=3D=20= AffineTransform.getTranslateInstance(wH=20+=20(spacing),=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=200)=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(radicalLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20= if=20(hPlacement=20=3D=3D=20NORTH=20&&=20atom.getImplicitHydrogenCount()=20= >=201)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.err.println("H=20subscript=20collides=20with=20radical!");=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20filled[container.getAtomNumber(atom)].add(new=20= Area(getConvexHullPath2D(radicalLabel)));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20symbols[atNum].append(radicalLabel.getPathIterator(new=20= AffineTransform()),=20false);=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A= =20=20=20=20=20=20=20=20=20=20=20=20//=20render=20charge=0A=0A=20=20=20=20= =20=20=20=20=20=20=20=20if=20(q=20!=3D=200)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20String=20text=20=3D=20q=20>=200=20?=20"+"=20:=20= "\u2013";=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (Math.abs(q)=20>=201)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20text=20=3D=20Math.abs(q)=20+=20text;=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20Shape=20chargeLabel=20=3D=20toShape(text,=20x,=20= y,=20scale);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= chargeLabel=20=3D=20AffineTransform.getScaleInstance(0.6,=200.6)=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(chargeLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20Rectangle2D=20chareBounds=20=3D=20= chargeLabel.getBounds2D();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20chargeLabel=20=3D=20AffineTransform.getTranslateInstance(x=20-=20= chareBounds.getX()=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20+=20((wS=20/=202)=20+=20(spacing)),=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20y=20-=20chareBounds.getY()=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20-=20= ((chareBounds.getHeight())=20/=202)=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20+=20(hS=20/=202))=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(chargeLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20//=20move=20charge=20over=20to=20the=20side=20of=20the=20= H=20/=20radical=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (hPlacement=20=3D=3D=20EAST)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20chargeLabel=20=3D=20= AffineTransform.getTranslateInstance(wH=20+=20(spacing),=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=200)=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(chargeLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20= if=20(hPlacement=20=3D=3D=20NORTH=20&&=20atom.getImplicitHydrogenCount()=20= >=201)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.err.println("H=20subscript=20collides=20with=20charge!");=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20if=20(radicalLabel=20!=3D=20null)=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20chargeLabel=20=3D=20= AffineTransform.getTranslateInstance(radicalLabel.getBounds2D().getWidth()= =20+=20(spacing),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=200)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20.createTransformedShape(chargeLabel);=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20filled[atNum].add(new=20= Area(getConvexHullPath2D(chargeLabel)));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20symbols[atNum].append(chargeLabel.getPathIterator(new=20= AffineTransform()),=20false);=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A= =20=20=20=20=20=20=20=20=20=20=20=20Integer=20mass=20=3D=20= atom.getMassNumber();=0A=20=20=20=20=20=20=20=20=20=20=20=20if=20= (renderMass(mass,=20atom.getAtomicNumber()))=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20String=20text=20=3D=20mass.toString();=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20Shape=20massLabel=20=3D=20= toShape(text,=20x,=20y,=20scale);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20massLabel=20=3D=20AffineTransform.getScaleInstance(0.6,=200.6)=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(massLabel);=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20Rectangle2D=20massBounds=20=3D=20massLabel.getBounds2D();=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20massLabel=20=3D=20= AffineTransform.getTranslateInstance(x=20-=20massBounds.getX()=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20-=20((wS=20/=20= 2)=20+=20(spacing))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20-=20massBounds.getWidth(),=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20y=20-=20massBounds.getY()=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20-=20((massBounds.getHeight())=20= /=202)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20+=20(hS=20/=202))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20.createTransformedShape(massLabel);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20//=20move=20H=20label=20placement=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20if=20(hPlacement=20=3D=3D=20WEST)=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20hydrogenLabel=20=3D=20= AffineTransform.getTranslateInstance(-(massBounds.getWidth()=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= -=20(wH2=20-=20wH)=20//=20adjust=20for=20subscript=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20+=20= spacing=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20),=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=200)=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20.createTransformedShape(hydrogenLabel);=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= filled[container.getAtomNumber(atom)].add(new=20= Area(getConvexHullPath2D(massLabel)));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20symbols[atNum].append(massLabel.getPathIterator(new=20= AffineTransform()),=20false);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20if=20(hydrogenLabel=20!=3D=20= null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= filled[container.getAtomNumber(atom)].add(new=20= Area(getConvexHullPath2D(hydrogenLabel)));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20= symbols[atNum].append(hydrogenLabel.getPathIterator(new=20= AffineTransform()),=20false);=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A= =20=20=20=20=20=20=20=20=20=20=20=20//=20= group.add(GeneralPath.filledPathOf(filled[container.getAtomNumber(atom)],=20= debug));=0A=0A=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20= double=20bondWidthRatio=20=3D=201;=0A=20=20=20=20=20=20=20=20double=20= bondWidth=20=3D=20bondWidthRatio=20*=20toShape("i",=205,=205,=20= scale).getBounds2D().getWidth();=0A=20=20=20=20=20=20=20=20double=20= bondSeparation=20=3D=204;=0A=0A=20=20=20=20=20=20=20=20RingSearch=20= ringSearch=20=3D=20new=20RingSearch(container);=0A=20=20=20=20=20=20=20=20= IRingSet=20ringSet=20=3D=20Cycles.mcb(container).toRingSet();=0A=0A=20=20= =20=20=20=20=20=20ringSet.sortAtomContainers(new=20= Comparator()=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= @Override=20public=20int=20compare(IAtomContainer=20a,=20IAtomContainer=20= b)=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20int=20aSize=20= =3D=20a.getAtomCount();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= int=20bSize=20=3D=20b.getAtomCount();=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20//=20IUPAC=20say=206=20member=20rings=20take=20= precedence=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(aSize=20= =3D=3D=206)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= aSize=20=3D=202;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (bSize=20=3D=3D=206)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20bSize=20=3D=202;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(aSize=20>=20bSize)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20return=20+1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(aSize=20<=20bSize)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20return=20-1;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Point2d=20p1=20=3D=20GeometryTools.get2DCenter(a);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20Point2d=20p2=20=3D=20= GeometryTools.get2DCenter(b);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20if=20(p1.x=20>=20p2.x)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20return=20+1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20if=20(p1.x=20<=20p2.x)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20return=20-1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20if=20(p1.y=20>=20p2.y)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20return=20+1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20if=20(p1.y=20<=20p2.y)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20return=20-1;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20return=200;=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20= =20=20=20=20=20});=0A=0A=20=20=20=20=20=20=20=20for=20(IBond=20bond=20:=20= container.bonds())=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20= a1=20=3D=20bond.getAtom(0);=0A=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20= a2=20=3D=20bond.getAtom(1);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= final=20int=20u=20=3D=20container.getAtomNumber(a1);=0A=20=20=20=20=20=20= =20=20=20=20=20=20final=20int=20v=20=3D=20container.getAtomNumber(a2);=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20Point2d=20p1=20=3D=20= a1.getPoint2d();=0A=20=20=20=20=20=20=20=20=20=20=20=20Point2d=20p2=20=3D=20= a2.getPoint2d();=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20double=20x1=20= =3D=20a1.getPoint2d().x;=0A=20=20=20=20=20=20=20=20=20=20=20=20double=20= x2=20=3D=20a2.getPoint2d().x;=0A=20=20=20=20=20=20=20=20=20=20=20=20= double=20y1=20=3D=20a1.getPoint2d().y;=0A=20=20=20=20=20=20=20=20=20=20=20= =20double=20y2=20=3D=20a2.getPoint2d().y;=0A=0A=20=20=20=20=20=20=20=20=20= =20=20=20double=20dx=20=3D=20x2=20-=20x1;=0A=20=20=20=20=20=20=20=20=20=20= =20=20double=20dy=20=3D=20y2=20-=20y1;=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20double=20mag=20=3D=20Math.sqrt((dx=20*=20dx)=20+=20(dy=20*=20dy));=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20dx=20/=3D=20mag;=0A=20=20=20=20=20= =20=20=20=20=20=20=20dy=20/=3D=20mag;=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20double=20pad=20=3D=201.5=20*=20bondWidth;=0A=0A=20=20=20=20=20=20=20= =20=20=20=20=20if=20(filled[u]=20!=3D=20null)=20{=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20Point2D=20p=20=3D=20= getMinIntersection(filled[u],=20new=20Line2D.Double(x1,=20y1,=20x2,=20= y2));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(p=20!=3D=20= null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= x1=20=3D=20p.getX();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20y1=20=3D=20p.getY();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20x1=20+=3D=20dx=20*=20pad;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20y1=20+=3D=20dy=20*=20pad;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20= =20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20if=20(filled[v]=20!=3D=20= null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20p=20= =3D=20getMinIntersection(filled[v],=20new=20Line2D.Double(x1,=20y1,=20= x2,=20y2));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(p=20= !=3D=20null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20x2=20=3D=20p.getX();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20y2=20=3D=20p.getY();=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20x2=20-=3D=20dx=20*=20pad;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20y2=20-=3D=20dy=20*=20pad;=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20= =20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20double=20bondSep=20=3D= =20(bondSeparation=20/=20scale);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= int=20a1count=20=3D=20container.getConnectedAtomsCount(a1);=0A=20=20=20=20= =20=20=20=20=20=20=20=20int=20a2count=20=3D=20= container.getConnectedAtomsCount(a2);=0A=0A=0A=20=20=20=20=20=20=20=20=20= =20=20=20switch=20(bond.getOrder())=20{=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20case=20SINGLE:=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20//=20orthogonal=20unit=20vector=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20dox=20=3D=20(x1=20+=20= dy)=20-=20x1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20double=20doy=20=3D=20(y1=20-=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20omag=20=3D=20Math.sqrt((dox=20= *=20dox)=20+=20(doy=20*=20doy));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20dox=20/=3D=20omag;=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20doy=20/=3D=20omag;=0A=0A=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20thinEnd=20=3D=200.25=20= *=20bondSep;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= double=20fatEnd=20=3D=201.5=20*=20bondSep;=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20double=20step=20=3D=20mag=20/=2012;=0A=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20end=20= =3D=20magnitude(p1.x,=20p1.y,=20x2,=20y2);=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20double=20start=20=3D=20magnitude(p1.x,=20= p1.y,=20x1,=20y1);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20double=20x3=20=3D=20p2.x=20-=20dox=20*=20fatEnd;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20y3=20=3D=20p2.y=20= -=20doy=20*=20fatEnd;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20double=20x4=20=3D=20p2.x=20+=20dox=20*=20fatEnd;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20y4=20=3D=20p2.y=20= +=20doy=20*=20fatEnd;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20double=20dx3=20=3D=20x3=20-=20p1.x;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20dy3=20=3D=20y3=20-=20p1.y;=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20dx4=20= =3D=20x4=20-=20p1.x;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20double=20dy4=20=3D=20y4=20-=20p1.y;=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20mag3=20=3D=20Math.sqrt((dx3=20= *=20dx3)=20+=20(dy3=20*=20dy3));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20double=20mag4=20=3D=20Math.sqrt((dx4=20*=20dx4)=20+=20= (dy4=20*=20dy4));=0A=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20//=20wedge=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20if=20(bond.getStereo()=20=3D=3D=20IBond.Stereo.UP)=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Path2D=20= path=20=3D=20new=20Path2D.Double();=0A=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20double=20theta=20=3D=20= Math.acos(mag=20/=20mag3);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20double=20fact=20=3D=20Math.tan(theta);=0A=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2D=20p3=20=3D=20new=20Point2D.Double(p1.x=20+=20dx=20*=20end=20-=20= dox=20*=20(end=20*=20fact),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20end=20= -=20doy=20*=20(end=20*=20fact));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20p4=20=3D=20new=20= Point2D.Double(p1.x=20+=20dx=20*=20end=20+=20dox=20*=20(end=20*=20fact),=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20p1.y=20+=20dy=20*=20end=20+=20doy=20*=20(end=20*=20= fact));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Point2D=20p5=20=3D=20p3;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20p6=20=3D=20p4;=0A=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= magPlus=20=3D=202=20*=20mag;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Line2D.Double=20l1=20=3D=20new=20= Line2D.Double(p1.x,=20p1.y,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.x=20+=20= dx=20*=20magPlus=20-=20dox=20*=20magPlus=20*=20fact,=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20p1.y=20+=20dy=20*=20magPlus=20-=20doy=20*=20magPlus=20*=20= fact);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20Line2D.Double=20l2=20=3D=20new=20Line2D.Double(p1.x,=20p1.y,=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20p1.x=20+=20dx=20*=20magPlus=20+=20dox=20*=20= magPlus=20*=20fact,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20= *=20magPlus=20+=20doy=20*=20magPlus=20*=20fact);=0A=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(filled[v]=20=3D=3D= =20null=20&&=20a2count=20>=201=20&&=20!ringSearch.cyclic(u,=20v))=20{=0A=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20//=20debug=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20//group.add(new=20LineElement(l1.x1,=20= l1.y1,=20l1.x2,=20l1.y2,=20bondWidth,=20debug));=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= //group.add(new=20LineElement(l2.x1,=20l2.y1,=20l2.x2,=20l2.y2,=20= bondWidth,=20debug));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20for=20(IBond=20b2=20:=20= container.getConnectedBondsList(a2))=20{=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (b2=20=3D=3D=20bond=20||=20b2.getOrder()=20!=3D=20IBond.Order.SINGLE)=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20continue;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Line2D.Double=20line=20=3D=20toLine(b2);=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (l1.intersectsLine(line))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2D=20intersect=20=3D=20getIntersection(l1,=20line);=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20if=20(p5=20=3D=3D=20p3=20||=20magnitude(p1.x,=20p1.y,=20= intersect.getX(),=20intersect.getY())=20<=20magnitude(p1.x,=20p1.y,=20= p5.getX(),=20p5.getY()))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p5=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= else=20if=20(l2.intersectsLine(line))=20{=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20Point2D=20intersect=20=3D=20getIntersection(l2,=20line);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20if=20(p6=20=3D=3D=20p4=20||=20magnitude(p1.x,=20= p1.y,=20intersect.getX(),=20intersect.getY())=20<=20magnitude(p1.x,=20= p1.y,=20p6.getX(),=20p6.getY()))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20p6=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= boolean=20bifurcated=20=3D=20false;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20if=20(p5=20!=3D=20p3=20&&=20p6=20!=3D=20= p4)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20bifurcated=20=3D=20true;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20(p5=20!=3D=20= p3)=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20double=20slantDx=20=3D=20p5.getX()=20-=20x2;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20double=20slantDy=20=3D=20p5.getY()=20-=20y2;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= slantMag=20=3D=20Math.sqrt((slantDx=20*=20slantDx)=20+=20(slantDy=20*=20= slantDy));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20slantDx=20/=3D=20slantMag;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20slantDy=20= /=3D=20slantMag;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20intersect=20=3D=20= getIntersection(l2,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20new=20= Line2D.Double(p5.getX(),=20p5.getY(),=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p5.getX()=20= +=20slantDx=20*=202=20*=20slantMag,=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p5.getY()=20= +=20slantDy=20*=202=20*=20slantMag));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p5=20=3D=20= adjustP2(new=20Point2D.Double(p1.x,=20p1.y),=20p5,=200.6=20*=20= bondWidth);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20p6=20=3D=20adjustP2(new=20Point2D.Double(p1.x,=20= p1.y),=20intersect,=200.6=20*=20bondWidth);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20(p6=20!=3D=20= p4)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20double=20slantDx=20=3D=20p6.getX()=20-=20x2;=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20double=20slantDy=20=3D=20p6.getY()=20-=20y2;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= slantMag=20=3D=20Math.sqrt((slantDx=20*=20slantDx)=20+=20(slantDy=20*=20= slantDy));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20slantDx=20/=3D=20slantMag;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20slantDy=20= /=3D=20slantMag;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20intersect=20=3D=20= getIntersection(l1,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20new=20= Line2D.Double(p6.getX(),=20p6.getY(),=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p6.getX()=20= +=20slantDx=20*=202=20*=20slantMag,=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p6.getY()=20= +=20slantDy=20*=202=20*=20slantMag));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p5=20=3D=20= adjustP2(new=20Point2D.Double(p1.x,=20p1.y),=20intersect,=200.6=20*=20= bondWidth);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20p6=20=3D=20adjustP2(new=20Point2D.Double(p1.x,=20= p1.y),=20p6,=200.6=20*=20bondWidth);=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20path.moveTo(x1=20+=20dox=20*=20= (start=20*=20fact),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20y1=20+=20doy=20= *=20(start=20*=20fact));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20path.lineTo(x1=20-=20dox=20*=20(start=20*=20= fact),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20y1=20-=20doy=20*=20(start=20*=20= fact));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20path.lineTo(p5.getX(),=20p5.getY());=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(bifurcated)=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.lineTo(x2,=20y2);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20path.lineTo(p6.getX(),=20p6.getY());=0A=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.closePath();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20group.add(GeneralPath.shapeOf(path,=20fg));=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20(bond.getStereo()=20= =3D=3D=20IBond.Stereo.DOWN)=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20theta=20=3D=20Math.acos(mag=20= /=20mag3);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20double=20fact=20=3D=20Math.tan(theta);=0A=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20p3=20=3D=20= new=20Point2D.Double(p1.x=20+=20dx=20*=20end=20-=20dox=20*=20(end=20*=20= fact),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20end=20-=20doy=20*=20(end=20= *=20fact));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20Point2D=20p4=20=3D=20new=20Point2D.Double(p1.x=20+=20dx=20*=20= end=20+=20dox=20*=20(end=20*=20fact),=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20= dy=20*=20end=20+=20doy=20*=20(end=20*=20fact));=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20p5=20=3D=20p3;=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2D=20p6=20=3D=20p4;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20double=20magPlus=20=3D=202=20*=20mag;=0A=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Line2D.Double=20l1=20=3D=20new=20Line2D.Double(p1.x,=20p1.y,=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20p1.x=20+=20dx=20*=20magPlus=20-=20dox=20*=20magPlus=20= *=20fact,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20magPlus=20= -=20doy=20*=20magPlus=20*=20fact);=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20Line2D.Double=20l2=20=3D=20new=20= Line2D.Double(p1.x,=20p1.y,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.x=20+=20= dx=20*=20magPlus=20+=20dox=20*=20magPlus=20*=20fact,=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20p1.y=20+=20dy=20*=20magPlus=20+=20doy=20*=20magPlus=20*=20= fact);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20if=20(filled[v]=20=3D=3D=20null=20&&=20a2count=20=3D=3D=202)=20= {=0A=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20//=20debug=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//group.add(new=20= LineElement(l1.x1,=20l1.y1,=20l1.x2,=20l1.y2,=20bondWidth,=20debug));=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20//group.add(new=20LineElement(l2.x1,=20l2.y1,=20l2.x2,=20l2.y2,=20= bondWidth,=20debug));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20for=20(IBond=20b2=20:=20= container.getConnectedBondsList(a2))=20{=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (b2=20=3D=3D=20bond=20||=20b2.getOrder()=20!=3D=20IBond.Order.SINGLE)=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20continue;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Line2D.Double=20line=20=3D=20toLine(b2);=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (l1.intersectsLine(line))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2D=20intersect=20=3D=20getIntersection(l1,=20line);=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20if=20(p5=20=3D=3D=20p3=20||=20magnitude(p1.x,=20p1.y,=20= intersect.getX(),=20intersect.getY())=20<=20magnitude(p1.x,=20p1.y,=20= p5.getX(),=20p5.getY()))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p5=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= else=20if=20(l2.intersectsLine(line))=20{=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20Point2D=20intersect=20=3D=20getIntersection(l2,=20line);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20if=20(p6=20=3D=3D=20p4=20||=20magnitude(p1.x,=20= p1.y,=20intersect.getX(),=20intersect.getY())=20<=20magnitude(p1.x,=20= p1.y,=20p6.getX(),=20p6.getY()))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20p6=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(p5=20!=3D=20p3=20&&=20p6=20!=3D=20p4)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p5=20=3D=20= p3;=20//=20bifurcated=20->=20reset=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p6=20=3D=20p4;=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20= if=20(p5=20!=3D=20p3)=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20slantDx=20=3D=20= p5.getX()=20-=20x2;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20double=20slantDy=20=3D=20p5.getY()=20-=20= y2;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20double=20slantMag=20=3D=20Math.sqrt((slantDx=20*=20= slantDx)=20+=20(slantDy=20*=20slantDy));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20slantDx=20/=3D=20= slantMag;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20slantDy=20/=3D=20slantMag;=0A=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20= intersect=20=3D=20getIntersection(l2,=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20new=20Line2D.Double(p5.getX(),=20p5.getY(),=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p5.getX()=20+=20slantDx=20*=202=20*=20slantMag,=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p5.getY()=20+=20slantDy=20*=202=20*=20slantMag));=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p6=20=3D=20= intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20else=20if=20(p6=20!=3D=20p4)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= slantDx=20=3D=20p6.getX()=20-=20x2;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20slantDy=20=3D=20= p6.getY()=20-=20y2;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20double=20slantMag=20=3D=20= Math.sqrt((slantDx=20*=20slantDx)=20+=20(slantDy=20*=20slantDy));=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20slantDx=20/=3D=20slantMag;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20slantDy=20/=3D=20slantMag;=0A=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Point2D=20intersect=20=3D=20getIntersection(l1,=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20new=20Line2D.Double(p6.getX(),=20p6.getY(),=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20p6.getX()=20+=20slantDx=20*=202=20*=20slantMag,=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20p6.getY()=20+=20slantDy=20*=202=20*=20slantMag));=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20p5=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20int=20nHatchSection=20=3D=20(int)=20= (mag=20/=20bondWidth);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20if=20(nHatchSection=20%=203=20!=3D=200)=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20nHatchSection=20-=3D=20nHatchSection=20%=203;=0A=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Path2D=20path=20=3D=20= new=20Path2D.Double();=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20mag3=20=3D=20magnitude(p1.x,=20p1.y,=20= p5.getX(),=20p5.getY());=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20mag4=20=3D=20magnitude(p1.x,=20p1.y,=20= p6.getX(),=20p6.getY());=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20dx3=20=3D=20(p5.getX()=20-=20p1.x)=20/=20= mag3;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20dy3=20=3D=20(p5.getY()=20-=20p1.y)=20/=20mag3;=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dx4=20=3D=20= (p6.getX()=20-=20p1.x)=20/=20mag4;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20dy4=20=3D=20(p6.getY()=20-=20p1.y)=20= /=20mag4;=0A=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20group.add(new=20OvalElement(p5.getX(),=20p5.getY(),=20= 0.03,=20Color.blue));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20group.add(new=20OvalElement(p6.getX(),=20= p6.getY(),=200.03,=20Color.blue));=0A//=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20LineElement(p1.x,=20= p1.y,=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20p1.x=20+=20dx3=20*=20mag3,=0A//=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy3=20*=20mag3,=20= bondWidth,=20debug));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20group.add(new=20LineElement(p1.x,=20p1.y,=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p1.x=20+=20dx4=20*=20mag4,=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy4=20*=20mag4,=20bondWidth,=20= debug));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20mag=20/=3D=20nHatchSection;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20mag3=20/=3D=20nHatchSection;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= mag4=20/=3D=20nHatchSection;=0A=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20group.add(new=20LineElement(p1.x,=20= p1.y,=20p1.x=20+=20dx=20*=20end,=20p1.y=20+=20dy=20*=20end,=20bondWidth,=20= debug));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20for=20(int=20i=20=3D=202;=20i=20<=3D=20nHatchSection;=20i=20= +=3D=203)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20if=20((i=20-=201)=20*=20mag=20>=20start)=20{=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20path.moveTo(p1.x=20+=20dx3=20*=20(i=20+=201)=20*=20= mag3,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20= +=20dy3=20*=20(i=20+=201)=20*=20mag3);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.lineTo(p1.x=20+=20dx4=20*=20(i=20+=201)=20*=20mag4,=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy4=20*=20(i=20+=20= 1)=20*=20mag4);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20}=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20((i=20+=201)=20*=20= mag=20>=3D=20start=20&&=20(i=20+=201)=20*=20mag=20<=3D=20end)=20{=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20path.moveTo(p1.x=20+=20dox=20*=20start=20*=20fact=20+=20= dx=20*=20start,=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p1.y=20+=20doy=20*=20start=20*=20fact=20+=20dy=20*=20start);=0A//=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20path.lineTo(p1.x=20-=20dox=20*=20start=20*=20fact=20+=20= dx=20*=20start,=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p1.y=20-=20doy=20*=20start=20*=20fact=20+=20dy=20*=20start);=0A//=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20path.lineTo(p1.x=20-=20dox=20*=20(i=20+=201)=20*=20mag=20= *=20fact=20+=20dx=20*=20((i=20+=201)=20*=20mag),=0A//=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20p1.y=20-=20doy=20*=20(i=20+=201)=20*=20= mag=20*=20fact=20+=20dy=20*=20((i=20+=201)=20*=20mag));=0A//=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20path.lineTo(p1.x=20+=20dox=20*=20(i=20+=201)=20*=20mag=20*=20fact=20= +=20dx=20*=20((i=20+=201)=20*=20mag),=0A//=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20p1.y=20+=20doy=20*=20(i=20+=201)=20*=20mag=20*=20= fact=20+=20dy=20*=20((i=20+=201)=20*=20mag));=0A//=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.closePath();=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20}=0A//=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20(i=20*=20mag=20= >=3D=20start=20&&=20i=20*=20mag=20<=3D=20end)=20{=0A//=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.moveTo(p1.x=20+=20dox=20*=20(i=20*=20mag)=20*=20fact=20+=20dx=20*=20= (i=20*=20mag),=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p1.y=20+=20doy=20*=20(i=20*=20mag)=20*=20fact=20+=20dy=20*=20(i=20*=20= mag));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20path.lineTo(p1.x=20-=20dox=20*=20(i=20*=20= mag)=20*=20fact=20+=20dx=20*=20(i=20*=20mag),=0A//=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20p1.y=20-=20doy=20*=20(i=20*=20mag)=20*=20= fact=20+=20dy=20*=20(i=20*=20mag));=0A//=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.lineTo(p1.x=20-=20dox=20*=20end=20*=20fact=20+=20dx=20*=20end,=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20-=20doy=20*=20= end=20*=20fact=20+=20dy=20*=20end);=0A//=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.lineTo(p1.x=20+=20dox=20*=20end=20*=20fact=20+=20dx=20*=20end,=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20doy=20*=20= end=20*=20fact=20+=20dy=20*=20end);=0A//=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.closePath();=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20= group.add(GeneralPath.outlineOf(path,=20bondWidth,=20fg));=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20(bond.getStereo()=20= =3D=3D=20IBond.Stereo.UP_OR_DOWN)=20{=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20ElementGroup=20subgroup=20=3D=20= new=20ElementGroup();=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20Path2D=20path=20=3D=20new=20Path2D.Double();=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.moveTo(p1.x,=20p1.y);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20double=20xPeak=20=3D=20dox=20*=20bondSep;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= double=20yPeak=20=3D=20doy=20*=20bondSep;=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20boolean=20started=20=3D=20= false;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20for=20(int=20i=20=3D=200;=20i=20<=2024;=20i=20+=3D=202)=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20double=20stepMag=20=3D=20((2=20+=20i)=20/=202)=20*=20step;=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(i=20%=204=20=3D=3D=200)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20xPeak=20*=3D=20= -1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20yPeak=20*=3D=20-1;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(stepMag=20<=20start=20||=20stepMag=20>=20end)=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= continue;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20if=20(i=20%=204=20=3D=3D=200)=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20if=20(!started)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.moveTo(p1.x=20+=20dx=20*=20(i=20/=202)=20*=20step,=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20= (i=20/=202)=20*=20step);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20started=20=3D=20= true;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.curveTo(p1.x=20+=20dx=20*=20((i=20/=202))=20*=20step=20+=20xPeak=20= /=202,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p1.y=20+=20dy=20*=20((i=20/=202))=20*=20step=20+=20yPeak=20/=202,=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.x=20+=20dx=20*=20= ((1=20+=20i)=20/=202d)=20*=20step=20+=20xPeak,=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20((1=20+=20i)=20/=20= 2d)=20*=20step=20+=20yPeak,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20p1.x=20+=20dx=20*=20stepMag=20+=20xPeak,=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20stepMag=20= +=20yPeak);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(!started)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= path.moveTo(p1.x=20+=20dx=20*=20(i=20/=202)=20*=20step=20+=20xPeak,=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.y=20= +=20dy=20*=20(i=20/=202)=20*=20step=20+=20yPeak);=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20started=20=3D=20true;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20path.curveTo(p1.x=20+=20dx=20*=20((1=20+=20i)=20/=202d)=20*=20= step=20+=20xPeak,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20p1.y=20+=20dy=20*=20((1=20+=20i)=20/=202d)=20*=20step=20+=20yPeak,=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.x=20+=20= dx=20*=20stepMag=20+=20(xPeak=20/=202),=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20stepMag=20+=20(yPeak=20/=20= 2),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p1.x=20= +=20dx=20*=20stepMag,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20p1.y=20+=20dy=20*=20stepMag);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= group.add(GeneralPath.outlineOf(path,=20bondWidth,=20fg));=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= group.add(subgroup);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= else=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20group.add(new=20LineElement(x1,=20y1,=20x2,=20y2,=20bondWidth,=20= fg));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20case=20DOUBLE:=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20if=20(ringSearch.cyclic(u,=20v))=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= group.add(new=20LineElement(x1,=20y1,=20x2,=20y2,=20bondWidth,=20fg));=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= IAtomContainer=20ring=20=3D=20= ringSet.getRings(bond).getAtomContainer(0);=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2d=20centre=20=3D=20= GeometryTools.get2DCenter(ring);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20dcx,=20dcy;=0A=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//=20set=20= the=20side=20to=20draw=20the=20bond=20on=20(the=20pointing=20into=20the=20= ring)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(dot(x1,=20y1,=20x1=20+=20dy,=20y1=20-=20dx,=20centre.x,=20= centre.y)=20>=200)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20dcx=20=3D=20(x1=20+=20dy)=20-=20x1;=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20dcy=20=3D=20(y1=20-=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcx=20= =3D=20(x1=20-=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20=3D=20(y1=20+=20dx)=20-=20= y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20double=20cmag=20=3D=20Math.sqrt((dcx=20*=20dcx)=20+=20(dcy=20*=20= dcy));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20dcx=20/=3D=20cmag;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20dcy=20/=3D=20cmag;=0A=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//group.add(new=20= LineElement(x1,=20y1,=20y1,=20-x1,=20bondWidth,=20debug));=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= //group.add(new=20LineElement(x1,=20y1,=20-y1,=20x1,=20bondWidth,=20= debug));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20double=20cx=20=3D=20(p1.x=20+=20p2.x)=20/=202;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20cy=20= =3D=20(p1.y=20+=20p2.y)=20/=202;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20//=20debug=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//group.add(new=20= OvalElement(centre.x,=20centre.y,=200.2,=20=20debug));=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//group.add(new=20= LineElement(cx,=20cy,=20cx=20+=20dcx,=20cy=20+=20dcy,=20bondWidth,=20= debug));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20dcx=20/=3D=20cmag;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20dcy=20/=3D=20cmag;=0A=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2d=20p3=20=3D=20= new=20Point2d();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20Point2d=20p4=20=3D=20new=20Point2d();=0A=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(x1=20= !=3D=20p1.x=20||=20y1=20!=3D=20p1.y)=20{=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p3.x=20=3D=20x1=20= +=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p3.y=20= =3D=20y1=20+=20dcy=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= else=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20IAtom=20other=20=3D=20getOtherConnectedBond(ring,=20= a1,=20bond).getConnectedAtom(a1);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20theta=20=3D=20= theta(p1.x,=20p1.y,=20p2.x,=20p2.y,=20other.getPoint2d().x,=20= other.getPoint2d().y);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20double=20opp=20=3D=20(2=20*=20= (bondSeparation=20/=20scale))=20/=20Math.tan(theta=20/=202);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= opp=20+=3D=20(bondSeparation=20/=20scale)=20/=202;=20//=20improved=20= aesthetics=20due=20to=20rounded=20caps=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p3.x=20=3D=20p1.x=20+=20= dx=20*=20opp;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20p3.y=20=3D=20p1.y=20+=20dy=20*=20opp;=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p3.x=20+=3D=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p3.y=20+=3D=20dcy=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20group.add(new=20OvalElement(p1.x=20+=20dx=20*=20opp,=0A= //=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20p1.y=20+=20dy=20*=20opp,=0A//=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=200.01,=20debug));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20deg=20=20=20=3D=20= Math.toDegrees(theta);=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20= TextElement(p1.x,=20p1.y,=20String.format("%.2f",=20deg),=20debug));=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(x2=20!=3D=20p2.x=20||=20y2=20!=3D=20p2.y)=20{=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.x=20=3D=20= x2=20+=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p4.y=20=3D=20y2=20+=20dcy=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20else=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20IAtom=20other=20=3D=20= getOtherConnectedBond(ring,=20a2,=20bond).getConnectedAtom(a2);=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= double=20theta=20=3D=20theta(p2.x,=20p2.y,=20p1.x,=20p1.y,=20= other.getPoint2d().x,=20other.getPoint2d().y);=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20opp=20= =3D=20(2=20*=20(bondSeparation=20/=20scale))=20/=20Math.tan(theta=20/=20= 2);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20opp=20+=3D=20(bondSeparation=20/=20scale)=20/=202;=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20p4.x=20=3D=20p2.x=20-=20dx=20*=20opp;=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.y=20=3D=20p2.y=20= -=20dy=20*=20opp;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20p4.x=20+=3D=20dcx=20*=20(2=20*=20= (bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.y=20+=3D=20dcy=20*=20(2=20*=20= (bondSeparation=20/=20scale));=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20= OvalElement(p2.x=20-=20dx=20*=20opp,=0A//=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p2.y=20= -=20dy=20*=20opp,=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=200.01,=20debug));=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= group.add(new=20LineElement(p3.x,=20p3.y,=20p4.x,=20p4.y,=20bondWidth,=20= fg));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= double=20dcx,=20dcy;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20//=20set=20the=20side=20to=20draw=20the=20bond=20= on=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20if=20(a1count=20=3D=3D=202)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20other=20=3D=20= getOtherConnectedBond(container,=20a1,=20bond).getConnectedAtom(a1);=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(dot(x1,=20y1,=20x1=20+=20dy,=20y1=20-=20dx,=20= other.getPoint2d().x,=20other.getPoint2d().y)=20>=200)=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20dcx=20=3D=20(x1=20+=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20= =3D=20(y1=20-=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20dcx=20=3D=20(x1=20-=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= dcy=20=3D=20(y1=20+=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20= (a2count=20=3D=3D=202)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20other=20=3D=20= getOtherConnectedBond(container,=20a2,=20bond).getConnectedAtom(a2);=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(dot(x1,=20y1,=20x1=20+=20dy,=20y1=20-=20dx,=20= other.getPoint2d().x,=20other.getPoint2d().y)=20>=200)=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20dcx=20=3D=20(x1=20+=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20= =3D=20(y1=20-=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20dcx=20=3D=20(x1=20-=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= dcy=20=3D=20(y1=20+=20dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= dcx=20=3D=20(x1=20-=20dy)=20-=20x1;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20=3D=20(y1=20+=20= dx)=20-=20y1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20double=20cmag=20=3D=20Math.sqrt((dcx=20*=20dcx)=20+=20= (dcy=20*=20dcy));=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20dcx=20/=3D=20cmag;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20/=3D=20cmag;=0A=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (a1count=20=3D=3D=202=20||=20a2count=20=3D=3D=202)=20{=0A=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//=20= cis/trans=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20Point2d=20p3=20=3D=20new=20Point2d();=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2d=20p4=20=3D=20new=20Point2d();=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20other=20=3D=20= a1count=20>=201=20?=20getOtherConnectedBond(container,=20a1,=20= bond).getConnectedAtom(a1)=20:=20null;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20IAtom=20other2=20=3D=20= a2count=20>=201=20?=20getOtherConnectedBond(container,=20a2,=20= bond).getConnectedAtom(a2)=20:=20null;=0A=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20boolean=20= straighten=20=3D=20false;=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(x1=20!=3D=20p1.x=20||=20= y1=20!=3D=20p1.y)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(other=20=3D=3D=20null=20= &&=20filled[v]=20=3D=3D=20null)=20{=20//=20terminal?=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20p3.x=20=3D=20x1=20+=20dcx=20*=20(2=20*=20(bondSeparation=20= /=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p3.y=20=3D=20y1=20+=20= dcy=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20//=20shift=20symbol=20to=20be=20centred=20on=20double=20bond=20= gap=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20if=20(symbols[u]=20!=3D=20null)=20= {=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20symbols[u]=20=3D=20= new=20Path2D.Double(AffineTransform.getTranslateInstance(dcx=20*=20= (bondSeparation=20/=20scale),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20*=20= (bondSeparation=20/=20scale))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(symbols[u]));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20straighten=20=3D=20true;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20else=20if=20(other=20!=3D=20null)=20{=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20double=20theta=20=3D=20theta(p1.x,=20p1.y,=20p2.x,=20= p2.y,=20other.getPoint2d().x,=20other.getPoint2d().y);=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20double=20opp=20=3D=20(2=20*=20(bondSeparation=20/=20scale))=20/=20= Math.tan(theta=20/=202);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20opp=20+=3D=20= (bondSeparation=20/=20scale)=20/=202;=20//=20improved=20aesthetics=20due=20= to=20rounded=20caps=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//=20shallow=20angle=20->=20= draw=20as=20symetric=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20straighten=20=3D=20= straighten=20||=20Math.abs(Math.toDegrees(theta)=20-=20180)=20<=205;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20p3.x=20=3D=20p1.x=20+=20dx=20*=20opp;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20p3.y=20=3D=20p1.y=20+=20dy=20*=20opp;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p3.x=20+=3D=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20p3.y=20+=3D=20dcy=20*=20(2=20*=20(bondSeparation=20/=20= scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= p3.x=20=3D=20p1.x;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20p3.y=20=3D=20p1.y;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20p3.x=20+=3D=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20p3.y=20+=3D=20dcy=20*=20(2=20*=20(bondSeparation=20= /=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(x2=20!=3D=20p2.x=20||=20= y2=20!=3D=20p2.y)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(other2=20=3D=3D=20= null)=20{=20//=20terminal?=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.x=20=3D=20= x2=20+=20dcx=20*=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20p4.y=20=3D=20y2=20+=20dcy=20*=20(2=20*=20= (bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//=20= shift=20symbol=20to=20be=20centred=20on=20double=20bond=20gap=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20if=20(symbols[v]=20!=3D=20null=20&&=20filled[u]=20= =3D=3D=20null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= symbols[v]=20=3D=20new=20= Path2D.Double(AffineTransform.getTranslateInstance(dcx=20*=20= (bondSeparation=20/=20scale),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20dcy=20*=20= (bondSeparation=20/=20scale))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(symbols[v]));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20straighten=20=3D=20true;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20else=20if=20(other2=20!=3D=20null)=20{=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20double=20theta=20=3D=20theta(p2.x,=20p2.y,=20p1.x,=20= p1.y,=20other2.getPoint2d().x,=20other2.getPoint2d().y);=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20double=20opp=20=3D=20(2=20*=20(bondSeparation=20/=20scale))=20/=20= Math.tan(theta=20/=202);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20opp=20+=3D=20= (bondSeparation=20/=20scale)=20/=202;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20//=20= shallow=20angle=20->=20draw=20as=20symetric=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= straighten=20=3D=20straighten=20||=20Math.abs(Math.toDegrees(theta)=20-=20= 180)=20<=205;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20p4.x=20=3D=20p2.x=20-=20dx=20*=20= opp;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20p4.y=20=3D=20p2.y=20-=20dy=20*=20opp;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20p4.x=20+=3D=20dcx=20*=20(2=20*=20(bondSeparation=20/=20= scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20p4.y=20+=3D=20dcy=20*=20(2=20*=20= (bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20p4.x=20=3D=20p2.x;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.y=20=3D=20= p2.y;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20p4.x=20+=3D=20dcx=20*=20(2=20*=20= (bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20p4.y=20+=3D=20dcy=20= *=20(2=20*=20(bondSeparation=20/=20scale));=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= if=20(straighten)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20createLines(new=20= Point2d(x1,=20y1),=20new=20Point2d(x2,=20y2),=20bondWidth,=20= bondSeparation=20/=20scale,=20fg,=20group);=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= else=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20group.add(new=20LineElement(x1,=20y1,=20= x2,=20y2,=20bondWidth,=20fg));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20= LineElement(p3.x,=20p3.y,=20p4.x,=20p4.y,=20bondWidth,=20fg));=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20else=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20double[]=20out=20=3D=20= generateDistanceData(new=20Point2d(x1,=20y1),=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20new=20Point2d(x2,=20y2),=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20bondSep);=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20if=20(a1count=20=3D=3D=203=20&&=20(x1=20= =3D=3D=20p1.x=20&&=20y1=20=3D=3D=20p1.y))=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20for=20= (IBond=20b=20:=20container.getConnectedBondsList(a1))=20{=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20Line2D.Double=20bLine=20=3D=20toLine(b);=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20if=20(bLine.intersectsLine(out[0]=20-=20dx=20*=20= mag,=20out[1]=20-=20dy=20*=20mag,=20out[4],=20out[5]))=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20p=20=3D=20= getIntersection(bLine,=20new=20Line2D.Double(out[0]=20-=20dx=20*=20mag,=20= out[1]=20-=20dy=20*=20mag,=20out[4],=20out[5]));=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20out[0]=20=3D=20p.getX()=20+=20dx=20*=200.5=20*=20= bondWidth;=20//=20we=20back=20off=20a=20bit=20so=20the=20stroke=20= doesn't=20protrude=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20out[1]=20= =3D=20p.getY()=20+=20dy=20*=200.5=20*=20bondWidth;=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20else=20if=20= (bLine.intersectsLine(out[2]=20-=20dx=20*=20mag,=20out[3]=20-=20dy=20*=20= mag,=20out[6],=20out[7]))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20Point2D=20p=20=3D=20getIntersection(bLine,=20new=20= Line2D.Double(out[2]=20-=20dx=20*=20mag,=20out[3]=20-=20dy=20*=20mag,=20= out[6],=20out[7]));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[2]=20=3D=20p.getX()=20+=20dx=20*=200.5=20*=20bondWidth;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20out[3]=20=3D=20p.getY()=20+=20dy=20*=20= 0.5=20*=20bondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20}=20else=20if=20(x1=20!=3D=20p1.x=20||=20y1=20!=3D= =20p1.y)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20Point2D=20intersect1=20=3D=20= getMinIntersection(filled[u],=20new=20Line2D.Double(out[0]=20-=20dx=20*=20= pad,=20out[1]=20-=20dy=20*=20pad,=20out[4],=20out[5]));=20=20=20=20=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20Point2D=20intersect2=20=3D=20= getMinIntersection(filled[u],=20new=20Line2D.Double(out[2]=20-=20dx=20*=20= pad,=20out[3]=20-=20dy=20*=20pad,=20out[6],=20out[7]));=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20//=20if=20(intersect2=20!=3D=20null)=20group.add(new=20= OvalElement(intersect2.getX(),=20intersect2.getY(),=200.2,=20debug));=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20if=20(intersect1=20!=3D=20null=20&&=20intersect2=20!=3D=20= null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.err.println("handle");=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=20else=20if=20= (intersect1=20!=3D=20null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= magAdjust=20=3D=20pad=20+=20magnitude(out[0],=20out[1],=20= intersect1.getX(),=20intersect1.getY());=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20out[0]=20+=3D=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[1]=20+=3D=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[2]=20+=3D=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[3]=20+=3D=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=20else=20= if=20(intersect2=20!=3D=20null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= double=20magAdjust=20=3D=20pad=20+=20magnitude(out[2],=20out[3],=20= intersect2.getX(),=20intersect2.getY());=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20out[0]=20+=3D=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[1]=20+=3D=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[2]=20+=3D=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[3]=20+=3D=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20if=20(a2count=20=3D=3D=203=20&&=20(x2=20=3D=3D=20= p2.x=20||=20y2=20=3D=3D=20p2.y))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20for=20(IBond=20= b=20:=20container.getConnectedBondsList(a2))=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Line2D.Double=20bLine=20=3D=20toLine(b);=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20if=20(bLine.intersectsLine(out[0],=20out[1],=20out[4]=20+=20= dx=20*=20mag,=20out[5]=20+=20dy=20*=20mag))=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20Point2D=20p=20=3D=20getIntersection(bLine,=20new=20= Line2D.Double(out[0],=20out[1],=20out[4]=20+=20dx=20*=20mag,=20out[5]=20= +=20dy=20*=20mag));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[4]=20=3D=20p.getX()=20-=20dx=20*=200.5=20*=20bondWidth;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20out[5]=20=3D=20p.getY()=20-=20dy=20*=20= 0.5=20*=20bondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20else=20if=20(bLine.intersectsLine(out[2],=20out[3],=20= out[6]=20+=20dx=20*=20mag,=20out[7]=20+=20dy=20*=20mag))=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20Point2D=20p=20=3D=20= getIntersection(bLine,=20new=20Line2D.Double(out[2],=20out[3],=20out[6]=20= +=20dx=20*=20mag,=20out[7]=20+=20dy=20*=20mag));=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20out[6]=20=3D=20p.getX()=20-=20dx=20*=200.5=20*=20= bondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20out[7]=20=3D=20= p.getY()=20-=20dy=20*=200.5=20*=20bondWidth;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=20else=20if=20(x2=20!=3D= =20p2.x=20||=20y2=20!=3D=20p2.y)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20= intersect1=20=3D=20getMinIntersection(filled[v],=20new=20= Line2D.Double(out[0],=20out[1],=20out[4]=20+=20dx=20*=20pad,=20out[5]=20= +=20dy=20*=20pad=20));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20intersect2=20=3D= =20getMinIntersection(filled[v],=20new=20Line2D.Double(out[2],=20out[3],=20= out[6]=20+=20dx=20*=20pad,=20out[7]=20+=20dy=20*=20pad));=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20//=20if=20(intersect2=20!=3D=20null)=20group.add(new=20= OvalElement(intersect2.getX(),=20intersect2.getY(),=200.2,=20debug));=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20if=20(intersect1=20!=3D=20null=20&&=20intersect2=20!=3D=20= null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.err.println("handle");=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=20else=20if=20= (intersect1=20!=3D=20null)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20double=20= magAdjust=20=3D=20magnitude(out[0],=20out[1],=20intersect1.getX(),=20= intersect1.getY())=20-=20pad;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20out[4]=20= =3D=20out[0]=20+=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= out[5]=20=3D=20out[1]=20+=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20out[6]=20=3D=20out[2]=20+=20dx=20*=20magAdjust;=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20out[7]=20=3D=20out[3]=20+=20dy=20*=20magAdjust;=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20}=20else=20if=20(intersect2=20!=3D=20null)=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20double=20magAdjust=20=3D=20magnitude(out[2],=20= out[3],=20intersect2.getX(),=20intersect2.getY())=20-=20pad;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20out[4]=20=3D=20out[0]=20+=20dx=20*=20magAdjust;=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20out[5]=20=3D=20out[1]=20+=20dy=20*=20= magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20out[6]=20=3D=20out[2]=20= +=20dx=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20out[7]=20=3D=20= out[3]=20+=20dy=20*=20magAdjust;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=20=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20group.add(new=20LineElement(out[0],=20out[1],=20= out[4],=20out[5],=20bondWidth,=20fg));=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20= LineElement(out[2],=20out[3],=20out[6],=20out[7],=20bondWidth,=20fg));=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20case=20TRIPLE:=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20group.add(new=20LineElement(x1,=20= y1,=20x2,=20y2,=20bondWidth,=20fg));=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20createLines(new=20Point2d(x1,=20y1),=20new=20= Point2d(x2,=20y2),=20bondWidth,=201.5=20*=20bondSeparation=20/=20scale,=20= fg,=20group);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20default:=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.err.println("unsupported=20bond=20type:=20"=20+=20= bond.getOrder());=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20= =20=20=20}=0A=0A=20=20=20=20=20=20=20=20//=20compute=20depiction=20= bounds=0A=20=20=20=20=20=20=20=20double=20minX=20=3D=20= Integer.MAX_VALUE,=20minY=20=3D=20Integer.MAX_VALUE;=0A=20=20=20=20=20=20= =20=20double=20maxX=20=3D=20Integer.MIN_VALUE,=20maxY=20=3D=20= Integer.MIN_VALUE;=0A=0A=20=20=20=20=20=20=20=20double=20halfBondWidth=20= =3D=20bondWidth=20/=202;=0A=0A=20=20=20=20=20=20=20=20for=20(int=20v=20=3D= =200;=20v=20<=20container.getAtomCount();=20v++)=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20if=20(symbols[v]=20!=3D=20null)=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20group.add(GeneralPath.shapeOf(symbols[v],=20= getColor(container.getAtom(v))));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Rectangle2D=20rect=20=3D=20filled[v].getBounds2D();=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20if=20(rect.getMaxX()=20>=20maxX)=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20maxX=20=3D=20= rect.getMaxX();=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (rect.getMinX()=20<=20minX)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20minX=20=3D=20rect.getX();=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20if=20(rect.getMaxY()=20>=20maxY)=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20maxY=20=3D=20rect.getMaxY();=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(rect.getMinY()=20<=20= minY)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20minY=20= =3D=20rect.getY();=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20= =20=20=20=20=20=20=20=20else=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20Point2d=20p=20=3D=20container.getAtom(v).getPoint2d();=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20if=20(p.y=20-=20halfBondWidth=20<=20= minY)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20minY=20= =3D=20p.y=20-=20halfBondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20if=20(p.x=20-=20halfBondWidth=20<=20minX)=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20minX=20=3D=20p.x=20-=20= halfBondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (p.x=20+=20halfBondWidth=20>=20maxX)=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20maxX=20=3D=20p.x=20+=20halfBondWidth;=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20if=20(p.y=20+=20halfBondWidth=20>=20= maxY)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20maxY=20= =3D=20p.y=20+=20halfBondWidth;=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20=20=20//=20debug:=20= show=20bounding=20box=0A=20=20=20=20=20=20=20=20//=20group.add(new=20= RectangleElement(minX,=20minY,=20maxX=20-=20minX,=20maxY=20-=20minY,=20= false,=20debug));=0A=20=20=20=20=20=20=20=20group.add(new=20Bounds(minX,=20= minY,=20maxX,=20maxY));=0A=20=20=20=20=20=20=20=20=0A//=20=20=20=20=20=20= =20=20String=20id=20=3D=20container.getProperty("ChEBI=20ID");=0A//=20=20= =20=20=20=20=20=20=0A//=20=20=20=20=20=20=20=20if=20(id=20=3D=3D=20null)=0A= //=20=20=20=20=20=20=20=20=20=20=20=20id=20=3D=20"n/a";=0A//=20=20=20=20=20= =20=20=20=0A//=20=20=20=20=20=20=20=20Shape=20idLabel=20=20=3D=20= toShape(id,=20minX,=20minY,=20scale);=0A//=20=20=20=20=20=20=20=20= Rectangle2D=20idBounds=20=3D=20idLabel.getBounds2D();=0A//=20=20=20=20=20= =20=20=20idLabel=20=3D=20= AffineTransform.getTranslateInstance(idBounds.getWidth()=20/=202,=0A//=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20idBounds.getHeight()=20/=202)=0A//=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= .createTransformedShape(idLabel);=0A//=20=20=20=20=20=20=20=20=0A//=20=20= =20=20=20=20=20=20//group.add(new=20OvalElement(minX,=20minY,=200.05,=20= debug));=0A//=20=20=20=20=20=20=20=20//group.add(new=20OvalElement(minX,=20= maxY,=200.05,=20Color.BLUE));=0A//=20=20=20=20=20=20=20=20=0A//=20=20=20=20= =20=20=20=20group.add(GeneralPath.shapeOf(idLabel.getBounds2D(),=20new=20= Color(0x44FFFFFF,=20true)));=0A//=20=20=20=20=20=20=20=20= group.add(GeneralPath.shapeOf(idLabel,=20fg));=0A=20=20=20=20=20=20=20=20= =0A=20=20=20=20=20=20=20=20return=20group;=0A=20=20=20=20}=0A=0A=20=20=20= =20static=20Line2D.Double=20toLine(IBond=20bond)=20{=0A=20=20=20=20=20=20= =20=20return=20new=20Line2D.Double(bond.getAtom(0).getPoint2d().x,=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20bond.getAtom(0).getPoint2d().y,=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20bond.getAtom(1).getPoint2d().x,=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= bond.getAtom(1).getPoint2d().y);=0A=20=20=20=20}=0A=0A=20=20=20=20= private=20IBond=20getOtherConnectedBond(IAtomContainer=20container,=20= IAtom=20atom,=20IBond=20bond)=20{=0A=20=20=20=20=20=20=20=20List=20= bonds=20=3D=20container.getConnectedBondsList(atom);=0A=20=20=20=20=20=20= =20=20for=20(IBond=20other=20:=20bonds)=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20if=20(other=20!=3D=20bond)=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20return=20other;=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20= =20=20=20return=20null;=0A=20=20=20=20}=0A=0A=20=20=20=20private=20= double=20theta(double=20x1,=20double=20y1,=20double=20x2,=20double=20y2,=20= double=20x3,=20double=20y3)=20{=0A=20=20=20=20=20=20=20=20return=20= Math.acos(dot(x1,=20y1,=20x2,=20y2,=20x3,=20y3)=20/=20(magnitude(x1,=20= y1,=20x2,=20y2)=20*=20magnitude(x1,=20y1,=20x3,=20y3)));=0A=20=20=20=20}=0A= =0A=20=20=20=20private=20double=20dot(double=20x1,=20double=20y1,=20= double=20x2,=20double=20y2,=20double=20x3,=20double=20y3)=20{=0A=20=20=20= =20=20=20=20=20return=20((x2=20-=20x1)=20*=20(x3=20-=20x1))=20+=20((y2=20= -=20y1)=20*=20(y3=20-=20y1));=0A=20=20=20=20}=0A=0A=20=20=20=20private=20= double=20magnitude(double=20x1,=20double=20y1,=20double=20x2,=20double=20= y2)=20{=0A=20=20=20=20=20=20=20=20double=20dx=20=3D=20x2=20-=20x1;=0A=20=20= =20=20=20=20=20=20double=20dy=20=3D=20y2=20-=20y1;=0A=20=20=20=20=20=20=20= =20return=20Math.sqrt((dx=20*=20dx)=20+=20(dy=20*=20dy));=0A=20=20=20=20= }=0A=0A=20=20=20=20private=20void=20createLines(Point2d=20point1,=20= Point2d=20point2,=20double=20width,=20double=20dist,=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Color=20color,=20ElementGroup=20group)=20{=0A=20=20=20=20=20=20=20=20= double[]=20out=20=3D=20generateDistanceData(point1,=20point2,=20dist);=0A= =20=20=20=20=20=20=20=20LineElement=20l1=20=3D=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20new=20LineElement(out[0],=20out[1],=20out[4],=20= out[5],=20width,=20color);=0A=20=20=20=20=20=20=20=20LineElement=20l2=20= =3D=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20new=20= LineElement(out[2],=20out[3],=20out[6],=20out[7],=20width,=20color);=0A=20= =20=20=20=20=20=20=20group.add(l1);=0A=20=20=20=20=20=20=20=20= group.add(l2);=0A=20=20=20=20}=0A=0A=20=20=20=20private=20double[]=20= generateDistanceData(Point2d=20point1,=20Point2d=20point2,=20double=20= dist)=20{=0A=20=20=20=20=20=20=20=20Vector2d=20normal=20=3D=20new=20= Vector2d();=0A=20=20=20=20=20=20=20=20normal.sub(point2,=20point1);=0A=20= =20=20=20=20=20=20=20normal=20=3D=20new=20Vector2d(-normal.y,=20= normal.x);=0A=20=20=20=20=20=20=20=20normal.normalize();=0A=20=20=20=20=20= =20=20=20normal.scale(dist);=0A=0A=20=20=20=20=20=20=20=20Point2d=20= line1p1=20=3D=20new=20Point2d();=0A=20=20=20=20=20=20=20=20Point2d=20= line1p2=20=3D=20new=20Point2d();=0A=20=20=20=20=20=20=20=20= line1p1.add(point1,=20normal);=0A=20=20=20=20=20=20=20=20= line1p2.add(point2,=20normal);=0A=0A=20=20=20=20=20=20=20=20= normal.negate();=0A=20=20=20=20=20=20=20=20Point2d=20line2p1=20=3D=20new=20= Point2d();=0A=20=20=20=20=20=20=20=20Point2d=20line2p2=20=3D=20new=20= Point2d();=0A=20=20=20=20=20=20=20=20line2p1.add(point1,=20normal);=0A=20= =20=20=20=20=20=20=20line2p2.add(point2,=20normal);=0A=0A=20=20=20=20=20=20= =20=20return=20new=20double[]{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20line1p1.x,=20line1p1.y,=20line2p1.x,=20line2p1.y,=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20line1p2.x,=20line1p2.y,=20line2p2.x,=20= line2p2.y};=0A=20=20=20=20}=0A=0A=20=20=20=20boolean=20= renderMass(Integer=20massNumber,=20int=20elem)=20{=0A=20=20=20=20=20=20=20= =20try=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20return=20massNumber=20= !=3D=20null=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= &&=20massNumber=20!=3D=20= Isotopes.getInstance().getMajorIsotope(elem).getMassNumber();=0A=20=20=20= =20=20=20=20=20}=20catch=20(IOException=20e)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20return=20false;=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20}=0A= =0A=20=20=20=20public=20Point2D=20getMinIntersection(final=20Shape=20= poly,=20final=20Line2D.Double=20line)=20{=0A=0A=20=20=20=20=20=20=20=20= double=20midX=20=3D=20line.x2=20-=20line.x1;=0A=20=20=20=20=20=20=20=20= double=20midY=20=3D=20line.y2=20-=20line.y1;=0A=0A=20=20=20=20=20=20=20=20= final=20PathIterator=20pathIterator=20=3D=20poly.getPathIterator(null);=20= //Getting=20an=20iterator=20along=20the=20polygon=20path=0A=20=20=20=20=20= =20=20=20final=20double[]=20curr=20=3D=20new=20double[6];=20//Double=20= array=20with=20length=206=20needed=20by=20iterator=0A=20=20=20=20=20=20=20= =20final=20double[]=20first=20=3D=20new=20double[2];=20//First=20point=20= (needed=20for=20closing=20polygon=20path)=0A=20=20=20=20=20=20=20=20= final=20double[]=20prev=20=3D=20new=20double[2];=20//Previously=20= visited=20point=0A=20=20=20=20=20=20=20=20Point2D=20min=20=3D=20null;=0A=20= =20=20=20=20=20=20=20double=20minMag=20=3D=20Integer.MAX_VALUE;=0A=20=20=20= =20=20=20=20=20while=20(!pathIterator.isDone())=20{=0A=20=20=20=20=20=20=20= =20=20=20=20=20switch=20(pathIterator.currentSegment(curr))=20{=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20case=20PathIterator.SEG_LINETO:=20= {=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20final=20= Line2D.Double=20currentLine=20=3D=20new=20Line2D.Double(prev[0],=20= prev[1],=20curr[0],=20curr[1]);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20if=20(currentLine.intersectsLine(line))=20{=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= Point2D=20intersect=20=3D=20getIntersection(currentLine,=20line);=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (magnitude(midX,=20midY,=20intersect.getX(),=20intersect.getY())=20<=20= minMag)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20min=20=3D=20intersect;=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20prev[0]=20=3D=20curr[0];=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20prev[1]=20=3D=20curr[1];=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20case=20PathIterator.SEG_CLOSE:=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20final=20Line2D.Double=20currentLine=20=3D= =20new=20Line2D.Double(curr[0],=20curr[1],=20first[0],=20first[1]);=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20= (currentLine.intersectsLine(line))=20{=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20Point2D=20intersect=20=3D=20= getIntersection(currentLine,=20line);=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20if=20(magnitude(midX,=20midY,=20= intersect.getX(),=20intersect.getY())=20<=20minMag)=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20min=20=3D=20= intersect;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20break;=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20case=20PathIterator.SEG_MOVETO:=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20first[0]=20=3D=20prev[0]=20= =3D=20curr[0];=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20first[1]=20=3D=20prev[1]=20=3D=20curr[1];=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20default:=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20throw=20new=20IllegalArgumentException("Unsupported=20= PathIterator=20segment=20type.");=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20}=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20= =20=20=20=20=20pathIterator.next();=0A=20=20=20=20=20=20=20=20}=0A=20=20=20= =20=20=20=20=20return=20min;=0A=0A=20=20=20=20}=0A=0A=20=20=20=20public=20= static=20Point2D=20getIntersection(final=20Line2D.Double=20line1,=20= final=20Line2D.Double=20line2)=20{=0A=0A=20=20=20=20=20=20=20=20final=20= double=20x1,=20y1,=20x2,=20y2,=20x3,=20y3,=20x4,=20y4;=0A=20=20=20=20=20=20= =20=20x1=20=3D=20line1.x1;=0A=20=20=20=20=20=20=20=20y1=20=3D=20= line1.y1;=0A=20=20=20=20=20=20=20=20x2=20=3D=20line1.x2;=0A=20=20=20=20=20= =20=20=20y2=20=3D=20line1.y2;=0A=20=20=20=20=20=20=20=20x3=20=3D=20= line2.x1;=0A=20=20=20=20=20=20=20=20y3=20=3D=20line2.y1;=0A=20=20=20=20=20= =20=20=20x4=20=3D=20line2.x2;=0A=20=20=20=20=20=20=20=20y4=20=3D=20= line2.y2;=0A=20=20=20=20=20=20=20=20final=20double=20x=20=3D=20(=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20(x2=20-=20x1)=20*=20(x3=20*=20= y4=20-=20x4=20*=20y3)=20-=20(x4=20-=20x3)=20*=20(x1=20*=20y2=20-=20x2=20= *=20y1)=0A=20=20=20=20=20=20=20=20)=20/=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(x1=20-=20x2)=20*=20(y3=20-=20y4)=20-=20(y1=20-=20y2)=20= *=20(x3=20-=20x4)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20);=0A= =20=20=20=20=20=20=20=20final=20double=20y=20=3D=20(=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(y3=20-=20y4)=20*=20(x1=20*=20y2=20-=20x2=20= *=20y1)=20-=20(y1=20-=20y2)=20*=20(x3=20*=20y4=20-=20x4=20*=20y3)=0A=20=20= =20=20=20=20=20=20)=20/=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(x1=20-=20x2)=20*=20(y3=20-=20y4)=20-=20(y1=20-=20y2)=20*=20(x3=20-=20= x4)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20);=0A=0A=20=20=20=20= =20=20=20=20return=20new=20Point2D.Double(x,=20y);=0A=0A=20=20=20=20}=0A=0A= =20=20=20=20public=20static=20Point2D=20getIntersection(double=20x1,=20= double=20y1,=20double=20x2,=20double=20y2,=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20double=20x3,=20double=20y3,=20double=20x4,=20double=20= y4)=20{=0A=0A=20=20=20=20=20=20=20=20Line2D.Double=20line1=20=3D=20new=20= Line2D.Double(x1,=20y1,=20x2,=20y2);=0A=20=20=20=20=20=20=20=20= Line2D.Double=20line2=20=3D=20new=20Line2D.Double(x3,=20y3,=20x4,=20y4);=0A= =20=20=20=20=20=20=20=20if=20(line1.intersects(x3,=20y3,=20x4,=20y4))=0A=20= =20=20=20=20=20=20=20=20=20=20=20return=20getIntersection(line1,=20= line2);=0A=20=20=20=20=20=20=20=20return=20null;=0A=20=20=20=20}=0A=0A=20= =20=20=20static=20final=20int=20NONE=20=20=20=20=20=20=20=3D=200;=0A=20=20= =20=20static=20final=20int=20NORTH=20=20=20=20=20=20=3D=203;=0A=20=20=20=20= static=20final=20int=20NORTH_EAST=20=3D=202;=0A=20=20=20=20static=20= final=20int=20EAST=20=20=20=20=20=20=20=3D=201;=0A=20=20=20=20static=20= final=20int=20SOUTH_EAST=20=3D=208;=0A=20=20=20=20static=20final=20int=20= SOUTH=20=20=20=20=20=20=3D=207;=0A=20=20=20=20static=20final=20int=20= SOUTH_WEST=20=3D=206;=0A=20=20=20=20static=20final=20int=20WEST=20=20=20=20= =20=20=20=3D=205;=0A=20=20=20=20static=20final=20int=20NORTH_WEST=20=3D=20= 4;=0A=0A=20=20=20=20static=20int=20hPlacement(IAtomContainer=20= container,=20double=20x,=20double=20y,=20IAtom=20atom,=20ElementGroup=20= group)=20{=0A=20=20=20=20=20=20=20=20if=20= (atom.getImplicitHydrogenCount()=20=3D=3D=20null=20||=20= atom.getImplicitHydrogenCount()=20=3D=3D=200)=0A=20=20=20=20=20=20=20=20=20= =20=20=20return=20NONE;=0A=20=20=20=20=20=20=20=20List=20= neighbors=20=3D=20container.getConnectedAtomsList(atom);=0A=20=20=20=20=20= =20=20=20double=20ux=20=3D=200;=0A=20=20=20=20=20=20=20=20double=20uy=20= =3D=200;=0A=20=20=20=20=20=20=20=20for=20(int=20i=20=3D=200;=20i=20<=20= neighbors.size();=20i++)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= Point2d=20p=20=3D=20neighbors.get(i).getPoint2d();=0A=20=20=20=20=20=20=20= =20=20=20=20=20double=20dx=20=3D=20p.x=20-=20x;=0A=20=20=20=20=20=20=20=20= =20=20=20=20double=20dy=20=3D=20p.y=20-=20y;=0A=20=20=20=20=20=20=20=20=20= =20=20=20double=20mag=20=3D=20Math.sqrt((dx=20*=20dx)=20+=20(dy=20*=20= dy));=0A=20=20=20=20=20=20=20=20=20=20=20=20dx=20/=3D=20mag;=0A=20=20=20=20= =20=20=20=20=20=20=20=20dy=20/=3D=20mag;=0A=20=20=20=20=20=20=20=20=20=20= =20=20ux=20+=3D=20dx;=0A=20=20=20=20=20=20=20=20=20=20=20=20uy=20+=3D=20= dy;=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20ux=20/=3D=20= neighbors.size();=0A=20=20=20=20=20=20=20=20uy=20/=3D=20= neighbors.size();=0A=20=20=20=20=20=20=20=20if=20(neighbors.size()=20>=20= 1)=20{=0A//=20=20=20=20=20=20=20=20=20=20=20=20if=20(ux=20<=200.1=20&&=20= uy=20<=200.1)=20{=0A//=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= System.out.println(ux=20+=20",=20"=20+=20uy);=0A//=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20return=201;=0A//=20=20=20=20=20=20=20=20=20=20=20= =20}=0A//=20=20=20=20=20=20=20=20=20=20=20=20else=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20//=20debug=0A=20=20=20=20=20=20=20=20=20=20=20=20//=20= group.add(new=20LineElement(x,=20y,=20x=20-=20ux,=20y=20-=20uy,=200.001,=20= debug));=0A=20=20=20=20=20=20=20=20=20=20=20=20//=20group.add(new=20= TextElement(x,=20y,=20"=20=20=20=20"=20+=20Integer.toString(((((int)=20= Math.round(Math.atan2(-uy,=20-ux)=20/=20(2=20*=20Math.PI=20/=208)))=20+=20= 8)=20%=208)),=20debug));=0A=20=20=20=20=20=20=20=20=20=20=20=20return=20= 1=20+=20(((int)=20Math.round(Math.atan2(-uy,=20-ux)=20/=20(2=20*=20= Math.PI=20/=208)))=20+=208)=20%=208;=0A//=20=20=20=20=20=20=20=20=20=20=20= =20}=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20else=20if=20= (neighbors.size()=20=3D=3D=201)=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20= if=20(Math.abs(ux)=20<=200.1=20||=20ux=20<=200)=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20return=20EAST;=0A=20=20=20=20=20=20=20=20=20=20=20= =20return=20WEST;=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20= else=20if=20(neighbors.size()=20=3D=3D=200)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20//=20special=20case,=20it's=20H20=20not=20OH2=0A=20=20=20=20=20= =20=20=20=20=20=20=20switch=20(atom.getAtomicNumber())=20{=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20case=208:=20=20//=20O=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20case=2016:=20//=20S=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20case=2034:=20//=20Se=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20case=2052:=20//=20Te=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20case=209:=20=20//=20F=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20case=2017:=20//=20Cl=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20case=2035:=20//=20Br=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20case=2053:=20//=20I=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20return=20WEST;=0A=20=20=20=20=20=20=20=20=20=20=20= =20}=0A=20=20=20=20=20=20=20=20=20=20=20=20return=20EAST;=0A=20=20=20=20=20= =20=20=20}=0A=0A=20=20=20=20=20=20=20=20throw=20new=20= InternalError("unplaced=20hydrogen=20label");=0A=20=20=20=20}=0A=0A=0A=20= =20=20=20static=20boolean=20displaySymbol(IAtomContainer=20container,=20= IAtom=20atom)=20{=0A=0A=20=20=20=20=20=20=20=20//=20non-carbon?=0A=20=20=20= =20=20=20=20=20if=20(atom.getAtomicNumber()=20!=3D=206)=0A=20=20=20=20=20= =20=20=20=20=20=20=20return=20true;=0A=0A=20=20=20=20=20=20=20=20//=20= charged=0A=20=20=20=20=20=20=20=20if=20(atom.getFormalCharge()=20!=3D=20= 0)=0A=20=20=20=20=20=20=20=20=20=20=20=20return=20true;=0A=0A=20=20=20=20= =20=20=20=20//=20radical=0A=20=20=20=20=20=20=20=20if=20= (container.getConnectedSingleElectronsCount(atom)=20>=200)=0A=20=20=20=20= =20=20=20=20=20=20=20=20return=20true;=0A=0A=20=20=20=20=20=20=20=20int=20= db=20=3D=200,=20deg=20=3D=200;=0A=20=20=20=20=20=20=20=20for=20(IBond=20= bond=20:=20container.getConnectedBondsList(atom))=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20if=20(bond.getOrder()=20=3D=3D=20IBond.Order.DOUBLE)=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20db++;=0A=20=20=20=20=20=20= =20=20=20=20=20=20deg++;=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20= =20=20=0A=20=20=20=20=20=20=20=20if=20(deg=20=3D=3D=200)=0A=20=20=20=20=20= =20=20=20=20=20=20=20return=20true;=0A=0A=20=20=20=20=20=20=20=20if=20= (DISPLAY_TERMINAL_CARBONS=20&&=20deg=20=3D=3D=201)=0A=20=20=20=20=20=20=20= =20=20=20=20=20return=20true;=0A=0A=20=20=20=20=20=20=20=20if=20(deg=20= =3D=3D=202=20&&=20db=20=3D=3D=202)=20//=20allene/cumulene=0A=20=20=20=20=20= =20=20=20=20=20=20=20return=20true;=0A=0A=20=20=20=20=20=20=20=20return=20= false;=0A=20=20=20=20}=0A=0A=20=20=20=20Shape=20toShape(String=20text,=20= double=20x,=20double=20y,=20double=20scale)=20{=0A=20=20=20=20=20=20=20=20= Shape=20shape=20=3D=20obtainGlyph(text);=0A=20=20=20=20=20=20=20=20= Rectangle2D=20bounds=20=3D=20shape.getBounds2D();=0A=20=20=20=20=20=20=20= =20AffineTransform=20at=20=3D=20AffineTransform.getTranslateInstance(x=20= -=20(bounds.getX()=20/=20scale)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20-=20((bounds.getWidth()=20/=20scale)=20= /=202),=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20y=20+=20= ((bounds.getY()=20+=20bounds.getHeight())=20/=20scale)=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20-=20= ((bounds.getHeight()=20/=20scale)=20/=202));=0A=20=20=20=20=20=20=20=20= at.scale(1=20/=20scale,=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =201=20/=20-scale);=0A=0A=20=20=20=20=20=20=20=20return=20= at.createTransformedShape(shape);=0A=20=20=20=20}=0A=0A=20=20=20=20= private=20final=20Map=20glyphs=20=3D=20new=20= HashMap();=0A=0A=20=20=20=20private=20Shape=20= obtainGlyph(String=20text)=20{=0A=20=20=20=20=20=20=20=20Shape=20shape=20= =3D=20glyphs.get(text);=0A=20=20=20=20=20=20=20=20if=20(shape=20=3D=3D=20= null)=0A=20=20=20=20=20=20=20=20=20=20=20=20glyphs.put(text,=20shape=20=3D= =20createGlyph(text));=0A=20=20=20=20=20=20=20=20return=20shape;=0A=20=20= =20=20}=0A=0A=20=20=20=20private=20Shape=20createGlyph(String=20text)=20= {=0A=20=20=20=20=20=20=20=20return=20= font.createGlyphVector(FONT_RENDER_CONTEXT,=20text)=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20.getOutline();=0A=20=20=20=20}=0A=0A=20= =20=20=20public=20static=20Shape=20getConvexHullPath2D(Shape=20shape)=20= {=0A=20=20=20=20=20=20=20=20List=20points=20=3D=20new=20= LinkedList();=0A=20=20=20=20=20=20=20=20double[]=20= coords=20=3D=20new=20double[6];=0A=20=20=20=20=20=20=20=20for=20= (PathIterator=20i=20=3D=20shape.getPathIterator(null);=20!i.isDone();=20= i.next())=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20switch=20= (i.currentSegment(coords))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20case=20PathIterator.SEG_CLOSE:=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20case=20PathIterator.SEG_MOVETO:=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20case=20PathIterator.SEG_LINETO:=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20points.add(new=20= Point2D.Double(coords[0],=20coords[1]));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20case=20PathIterator.SEG_QUADTO:=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20points.add(new=20= Point2D.Double(coords[0],=20coords[1]));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20points.add(new=20Point2D.Double(coords[2],=20= coords[3]));=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= break;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20case=20= PathIterator.SEG_CUBICTO:=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20points.add(new=20Point2D.Double(coords[0],=20coords[1]));=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= points.add(new=20Point2D.Double(coords[2],=20coords[3]));=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20points.add(new=20= Point2D.Double(coords[4],=20coords[5]));=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20break;=0A=20=20=20=20=20=20=20=20=20=20=20=20= }=0A=0A=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20Path2D.Double=20= path2d=20=3D=20new=20Path2D.Double();=0A=20=20=20=20=20=20=20=20= Point2D.Double[]=20chPoints=20=3D=20getConvexHull(points.toArray(new=20= Point2D.Double[0]));=0A=20=20=20=20=20=20=20=20if=20(!points.isEmpty())=20= {=0A=20=20=20=20=20=20=20=20=20=20=20=20path2d.moveTo(chPoints[0].x,=20= chPoints[0].y);=0A=20=20=20=20=20=20=20=20=20=20=20=20for=20(int=20i=20=3D= =201;=20i=20<=20chPoints.length;=20i++)=20{=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20path2d.lineTo(chPoints[i].x,=20chPoints[i].y);=0A=20= =20=20=20=20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20}=0A=20=20=20= =20=20=20=20=20return=20path2d;=0A=20=20=20=20}=0A=0A=20=20=20=20static=20= Point2D=20unit(Point2D=20p1,=20Point2D=20p2)=20{=0A=20=20=20=20=20=20=20=20= double=20dx=20=3D=20p2.getX()=20-=20p1.getX();=0A=20=20=20=20=20=20=20=20= double=20dy=20=3D=20p2.getY()=20-=20p1.getY();=0A=20=20=20=20=20=20=20=20= double=20mag=20=3D=20Math.sqrt((dx=20*=20dx)=20+=20(dy=20*=20dy));=0A=20=20= =20=20=20=20=20=20dx=20/=3D=20mag;=0A=20=20=20=20=20=20=20=20dy=20/=3D=20= mag;=0A=20=20=20=20=20=20=20=20return=20new=20Point2D.Double(dx,=20dy);=0A= =20=20=20=20}=0A=0A=20=20=20=20static=20Point2D=20adjustP2(Point2D=20p1,=20= Point2D=20p2,=20double=20fact)=20{=0A=20=20=20=20=20=20=20=20Point2D=20= unit=20=3D=20unit(p1,=20p2);=0A=20=20=20=20=20=20=20=20return=20new=20= Point2D.Double(p2.getX()=20+=20unit.getX()=20*=20fact,=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20p2.getY()=20+=20unit.getY()=20*=20fact);=0A=20=20=20=20}=0A=0A=20= =20=20=20//=20from=20JHotDraw=20LGPL=0A=20=20=20=20public=20static=20= Point2D.Double[]=20getConvexHull(Point2D.Double[]=20points)=20{=0A=20=20=20= =20=20=20=20=20//=20Quickly=20return=20if=20no=20work=20is=20needed=0A=20= =20=20=20=20=20=20=20if=20(points.length=20<=203)=20{=0A=20=20=20=20=20=20= =20=20=20=20=20=20return=20points.clone();=0A=20=20=20=20=20=20=20=20}=0A= =0A=20=20=20=20=20=20=20=20//=20Sort=20points=20from=20left=20to=20right=20= O(n=20log=20n)=0A=20=20=20=20=20=20=20=20Point2D.Double[]=20sorted=20=3D=20= points.clone();=0A=20=20=20=20=20=20=20=20Arrays.sort(sorted,=20new=20= Comparator()=20{=0A=0A=20=20=20=20=20=20=20=20=20=20=20=20= @Override=0A=20=20=20=20=20=20=20=20=20=20=20=20public=20int=20= compare(Point2D.Double=20o1,=20Point2D.Double=20o2)=20{=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20int=20c1=20=3D=20Doubles.compare(o1.x,=20= o2.x);=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20if=20(c1=20!=3D=20= 0)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20= c1;=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20return=20= Doubles.compare(o1.y,=20o2.y);=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =20=20=20=20=20=20=20=20});=0A=0A=20=20=20=20=20=20=20=20= Point2D.Double[]=20hull=20=3D=20new=20Point2D.Double[sorted.length=20+=20= 2];=0A=0A=20=20=20=20=20=20=20=20//=20Process=20upper=20part=20of=20= convex=20hull=20O(n)=0A=20=20=20=20=20=20=20=20int=20upper=20=3D=200;=20= //=20Number=20of=20points=20in=20upper=20part=20of=20convex=20hull=0A=20=20= =20=20=20=20=20=20hull[upper++]=20=3D=20sorted[0];=0A=20=20=20=20=20=20=20= =20hull[upper++]=20=3D=20sorted[1];=0A=20=20=20=20=20=20=20=20for=20(int=20= i=20=3D=202;=20i=20<=20sorted.length;=20i++)=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20hull[upper++]=20=3D=20sorted[i];=0A=20=20=20=20=20=20=20=20=20= =20=20=20while=20(upper=20>=202=20&&=20!isRightTurn(hull[upper=20-=203],=20= hull[upper=20-=202],=20hull[upper=20-=201]))=20{=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20hull[upper=20-=202]=20=3D=20hull[upper=20-=201];=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20upper--;=0A=20=20=20=20=20= =20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20}=0A=0A=20=20=20=20=20=20= =20=20//=20Process=20lower=20part=20of=20convex=20hull=20O(n)=0A=20=20=20= =20=20=20=20=20int=20lower=20=3D=20upper;=20//=20(lower=20-=20number=20+=20= 1)=20=3D=20number=20of=20points=20in=20the=20lower=20part=20of=20the=20= convex=20hull=0A=20=20=20=20=20=20=20=20hull[lower++]=20=3D=20= sorted[sorted.length=20-=202];=0A=20=20=20=20=20=20=20=20for=20(int=20i=20= =3D=20sorted.length=20-=203;=20i=20>=3D=200;=20i--)=20{=0A=20=20=20=20=20= =20=20=20=20=20=20=20hull[lower++]=20=3D=20sorted[i];=0A=20=20=20=20=20=20= =20=20=20=20=20=20while=20(lower=20-=20upper=20>=201=20&&=20= !isRightTurn(hull[lower=20-=203],=20hull[lower=20-=202],=20hull[lower=20= -=201]))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= hull[lower=20-=202]=20=3D=20hull[lower=20-=201];=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20lower--;=0A=20=20=20=20=20=20=20=20=20=20=20=20}=0A= =20=20=20=20=20=20=20=20}=0A=20=20=20=20=20=20=20=20lower=20-=3D=201;=0A=0A= =20=20=20=20=20=20=20=20//=20Reduce=20array=0A=20=20=20=20=20=20=20=20= Point2D.Double[]=20convexHull=20=3D=20new=20Point2D.Double[lower];=0A=20=20= =20=20=20=20=20=20System.arraycopy(hull,=200,=20convexHull,=200,=20= lower);=0A=20=20=20=20=20=20=20=20return=20convexHull;=0A=20=20=20=20}=0A= =0A=20=20=20=20//=20from=20JHotDraw=20LGPL=0A=20=20=20=20public=20static=20= boolean=20isRightTurn(Point2D.Double=20p1,=20Point2D.Double=20p2,=20= Point2D.Double=20p3)=20{=0A=20=20=20=20=20=20=20=20if=20(p1.equals(p2)=20= ||=20p2.equals(p3))=20{=0A=20=20=20=20=20=20=20=20=20=20=20=20//=20no=20= right=20turn=20if=20points=20are=20at=20same=20location=0A=20=20=20=20=20= =20=20=20=20=20=20=20return=20false;=0A=20=20=20=20=20=20=20=20}=0A=20=20= =20=20=20=20=20=20double=20val=20=3D=20(p2.x=20*=20p3.y=20+=20p1.x=20*=20= p2.y=20+=20p3.x=20*=20p1.y)=20-=20(p2.x=20*=20p1.y=20+=20p3.x=20*=20p2.y=20= +=20p1.x=20*=20p3.y);=0A=20=20=20=20=20=20=20=20return=20val=20>=200;=0A=20= =20=20=20}=0A}=0A= --Apple-Mail=_3E0AF434-0607-4C09-B25B-E98987DEC244 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_3E0AF434-0607-4C09-B25B-E98987DEC244--