/* Copyright 2006 Rene Grothmann, modified by Eric Hakenholz This file is part of C.a.R. software. C.a.R. is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. C.a.R. is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package rene.zirkel.objects; // file: TrackObject.java import java.util.Enumeration; import java.util.Vector; import rene.gui.Global; import rene.util.xml.XmlWriter; import rene.zirkel.ZirkelCanvas; import rene.zirkel.construction.Construction; import rene.zirkel.construction.ConstructionException; import rene.zirkel.construction.Count; import rene.zirkel.expression.ExpressionColor; import rene.zirkel.graphics.MainGraphics; import rene.zirkel.graphics.MyGraphics; import rene.zirkel.graphics.PolygonDrawer; import rene.zirkel.graphics.PolygonFiller; import rene.zirkel.structures.Coordinates; /** * This object contains an automatic track. It is saved in the construction like * any other ConstructionObject. Validation is time consuming and is done only * on repaints from ZirkelCanvas. */ public class TrackObject extends ConstructionObject implements PointonObject { static Count N = new Count(); public PointObject PM; public ConstructionObject O, P; public int PMax = 16, PN; public ConstructionObject PO[] = new ConstructionObject[PMax]; public boolean Filled = false; public boolean Discrete = false; public int Type = 0; @Override public void setFilled(final boolean flag) { Filled = flag; } @Override public boolean isFilled() { return Filled; } public TrackObject(final Construction c) { super(c); } public TrackObject(final Construction c, final ConstructionObject p, final ConstructionObject po[], final int pn, final ConstructionObject o, final PointObject pm) { super(c); P = p; PN = pn; for (int i = 0; i < PN; i++) { PO[i] = po[i]; } O = o; PM = pm; validate(); updateText(); } @Override public void setDefaults() { setShowName(Global.getParameter("options.locus.shownames", false)); setShowValue(Global.getParameter("options.locus.showvalues", false)); setColor(Global.getParameter("options.locus.color", 0), Global .getParameter("options.locus.pcolor", (ExpressionColor) null, this)); setColorType(Global.getParameter("options.locus.colortype", 0)); setFilled(Global.getParameter("options.locus.filled", false)); setHidden(Cn.Hidden); setObtuse(Cn.Obtuse); setSolid(Cn.Solid); setLarge(Cn.LargeFont); setBold(Cn.BoldFont); } @Override public void setTargetDefaults() { setShowName(Global.getParameter("options.locus.shownames", false)); setShowValue(Global.getParameter("options.locus.showvalues", false)); setColor(Global.getParameter("options.locus.color", 0), Global .getParameter("options.locus.pcolor", (ExpressionColor) null, this)); setColorType(Global.getParameter("options.locus.colortype", 0)); setFilled(Global.getParameter("options.locus.filled", false)); } @Override public String getTag() { return "Track"; } @Override public int getN() { return N.next(); } @Override public void updateText() { if (PM != null) { setText(text3(Global.name("text.track"), P.getName(), PM.getName(), O.getName())); } else { setText(text2(Global.name("text.trackof"), P.getName(), O.getName())); } } // Update only from ZirkelCanvas, when needed. @Override public void validate() { } public PolygonFiller PF = null; // Paint the track @Override public void paint(final MyGraphics g, final ZirkelCanvas zc) { if (!Valid || mustHide(zc)) { return; } Coordinates C; Enumeration e = V.elements(); double c0, r0, c, r; if (!Discrete && isStrongSelected() && g instanceof MainGraphics) { final PolygonDrawer pm = new PolygonDrawer(false,g, this); pm.useAsMarker(); if (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c0 = zc.col(C.X); r0 = zc.row(C.Y); pm.drawTo(c0, r0); while (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c = zc.col(C.X); r = zc.row(C.Y); if (Math.abs(c0 - c) < 100 && Math.abs(r0 - r) < 100) { pm.drawTo(c, r); } else { if (isFilled()) { PF.finishPolygon(); } pm.finishPolygon(); } c0 = c; r0 = r; } pm.finishPolygon(); } } e = V.elements(); if (indicated()) { final boolean sel = P.indicated(); P.setIndicated(true); g.setColor(P); P.setIndicated(sel); } else { g.setColor(this); } if (Discrete) { final int col = getColorIndex(); final int th = getColorType(); if (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c0 = zc.col(C.X); r0 = zc.row(C.Y); PF.drawTo(c0, r0); while (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c = zc.col(C.X); r = zc.row(C.Y); if (Math.abs(c0 - c) < 100 && Math.abs(r0 - r) < 100) { if (isFilled()) { PF.drawTo(c, r); } } else { if (isFilled()) { PF.finishPolygon(); } } if (C.Color >= 0) { setColor(C.Color); } if (C.Thickness >= 0) { setColorType(C.Thickness); } PointObject.drawPoint(g, zc, this, C.X, C.Y, Type); setColor(col); setColorType(th); c0 = c; r0 = r; } if (isFilled()) { PF.finishPolygon(); } } for (int i = 0; i < PN; i++) { e = VO[i].elements(); g.setColor(PO[i]); if (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); while (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); if (C.Color >= 0) { setColor(C.Color); } if (C.Thickness >= 0) { setColorType(C.Thickness); } PointObject.drawPoint(g, zc, this, C.X, C.Y, Type); setColor(col); setColorType(th); } } } } else { PolygonDrawer pd = new PolygonDrawer(false,g, this); if (isFilled()) { if (PF == null) { PF = new PolygonFiller(g, this); } PF.start(); PF.setGraphics(g); } if (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c0 = zc.col(C.X); r0 = zc.row(C.Y); pd.drawTo(c0, r0); while (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c = zc.col(C.X); r = zc.row(C.Y); if (Math.abs(c0 - c) < 100 && Math.abs(r0 - r) < 100) { if (isFilled()) { PF.drawTo(c, r); } pd.drawTo(c, r); } else { if (isFilled()) { PF.finishPolygon(); } pd.finishPolygon(); } c0 = c; r0 = r; } if (isFilled()) { PF.finishPolygon(); } pd.finishPolygon(); } for (int i = 0; i < PN; i++) { e = VO[i].elements(); g.setColor(PO[i]); pd = new PolygonDrawer(false,g, PO[i]); if (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c0 = zc.col(C.X); r0 = zc.row(C.Y); while (e.hasMoreElements()) { C = (Coordinates) e.nextElement(); c = zc.col(C.X); r = zc.row(C.Y); if (Math.abs(c0 - c) < 100 && Math.abs(r0 - r) < 100) { pd.drawTo(c, r); } else { pd.finishPolygon(); } c0 = c; r0 = r; } } pd.finishPolygon(); } } } public double getSum(final double x, final double y) throws ConstructionException { if (!Valid) { throw new ConstructionException(""); } double sum = 0; boolean started = false; double x0 = 0, y0 = 0; final Enumeration e = V.elements(); while (e.hasMoreElements()) { final Coordinates C = (Coordinates) e.nextElement(); if (started) { sum += (-(C.X - x) * (y0 - y) + (C.Y - y) * (x0 - x)) / 2; } x0 = C.X; y0 = C.Y; started = true; } return sum; } public double getSum() throws ConstructionException { if (!Valid) { throw new ConstructionException(""); } double sum = 0; boolean started = false; double x0 = 0, y0 = 0, x = 0, y = 0; final Enumeration e = V.elements(); while (e.hasMoreElements()) { final Coordinates C = (Coordinates) e.nextElement(); if (started) { sum += (-(C.X - x) * (y0 - y) + (C.Y - y) * (x0 - x)) / 2; } else { x = C.X; y = C.Y; } x0 = C.X; y0 = C.Y; started = true; } return sum; } public double getLength() throws ConstructionException { if (!Valid) { throw new ConstructionException(""); } double sum = 0; boolean started = false; double x0 = 0, y0 = 0; final Enumeration e = V.elements(); while (e.hasMoreElements()) { final Coordinates C = (Coordinates) e.nextElement(); if (started) { sum += Math.sqrt((C.X - x0) * (C.X - x0) + (C.Y - y0) * (C.Y - y0)); } x0 = C.X; y0 = C.Y; started = true; } return sum; } @Override public void printArgs(final XmlWriter xml) { super.printArgs(xml); if (PM != null) { xml.printArg("point", PM.getName()); } xml.printArg("on", O.getName()); xml.printArg("track", P.getName()); xml.printArg("dmin", "" + DMin); for (int i = 0; i < PN; i++) { xml.printArg("track" + i, PO[i].getName()); } if (Filled) { xml.printArg("filled", "true"); } if (Fixed) { xml.printArg("fixed", "true"); } if (Discrete) { xml.printArg("discrete", "true"); } printType(xml); } public void printType(final XmlWriter xml) { if (Type != 0) { switch (Type) { case PointObject.DIAMOND: xml.printArg("shape", "diamond"); break; case PointObject.CIRCLE: xml.printArg("shape", "circle"); break; case PointObject.DOT: xml.printArg("shape", "dot"); break; case PointObject.CROSS: xml.printArg("shape", "cross"); break; case PointObject.DCROSS: xml.printArg("shape", "dcross"); break; } } } @Override public Enumeration depending() { super.depending(); if (PM != null) { DL.add(PM); } DL.add(O); DL.add(P); for (int i = 0; i < PN; i++) { DL.add(PO[i]); } return DL.elements(); } @Override public boolean equals(final ConstructionObject o) { return false; } @Override public void translate() { if (PM != null) { PM = (PointObject) PM.getTranslation(); } O = O.getTranslation(); P = P.getTranslation(); } @Override public boolean maybeTransparent() { return false; } public Vector V = new Vector(); public Vector VO[] = new Vector[PMax]; // Mainly to select the track for delete @Override public boolean nearto(final int x, final int y, final ZirkelCanvas zc) { if (!displays(zc)) { return false; } final int size = (int) zc.selectionSize(); final Enumeration e = V.elements(); while (e.hasMoreElements()) { final Coordinates c = (Coordinates) e.nextElement(); final double col = zc.col(c.X), row = zc.row(c.Y); if (Math.max(Math.abs(col - x), Math.abs(row - y)) < size) { return true; } } return false; } @Override public boolean onlynearto(final int c, final int r, final ZirkelCanvas zc) { return false; } public double da = 0; double oldx, oldy; public double X, Y, DX, DY; double XO[] = new double[PMax], YO[] = new double[PMax], DXO[] = new double[PMax], DYO[] = new double[PMax]; int Omit = 1; public double mod(final double x) { if (x >= Math.PI) { return x - 2 * Math.PI; } if (x < -Math.PI) { return x + 2 * Math.PI; } return x; } public boolean DontProject = false; public double DMin = 0.005; /** * Complicated procedure to recompute the automatic track. In principle, a * moving point moves on some object, the coordinates of the tracked points * or the intersections of the tracked lines are stored, as well as the * positions of the moved point. * * But if the tracked point gets invalid, the movement reverses and the * interesections change. * * Moreover, there is a list of secondary tracked objects. * * @param zc */ public synchronized void docompute(final ZirkelCanvas zc) { V = new Vector(); for (int i = 0; i < PN; i++) { VO[i] = new Vector(); } // Running on a circle: if (O instanceof PrimitiveCircleObject) { zc.getConstruction().shouldSwitch(false); final PrimitiveCircleObject c = (PrimitiveCircleObject) O; final double x = c.getX(), y = c.getY(), r = c.getR(); PM.project(c); double amin = 0, amax = 0, astart = 0, anull = 0; final double dmax = 0.5; boolean range = false; if (c.hasRange()) { range = true; final double a1 = c.getA1(); final double a2 = c.getA2(); double d = a2 - a1; while (d < 0) { d += 2 * Math.PI; } while (d >= 2 * Math.PI) { d -= 2 * Math.PI; } amin = astart = -d / 2; amax = d / 2; anull = (a1 + a2) / 2; } else { amin = astart = -Math.PI * 0.9999; amax = Math.PI * 0.9999; } double a = astart; PM.move(x + r * Math.cos(anull + a), y + r * Math.sin(anull + a)); PM.project(c); zc.getConstruction().validate(this, PM); zc.resetSum(); double x1 = 0, y1 = 0; boolean started = false; if (P.valid()) { zc.getConstruction().shouldSwitch(true); if (P instanceof PointObject) { final PointObject p = (PointObject) P; x1 = p.getX(); y1 = p.getY(); addCoordinates(V, P, x1, y1); started = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); started = true; } } final boolean startedO[] = new boolean[PMax]; for (int i = 0; i < PN; i++) { startedO[i] = false; } final long time = System.currentTimeMillis(); addSecondary(startedO); final double dmin = DMin; if (da < 1e-10 || da > zc.dx(1)) { da = zc.dx(1) / 10; } double aold = a; while (true) { a = a + da; boolean Break = false; if ((!started || range) && a >= amax) { a = amax; Break = true; } else if ((!started || range) && a <= amin) { a = amin; Break = true; } else if (started && da > 0) { if ((mod(aold - astart) < 0 && mod(a - astart) >= 0) && !zc.getConstruction().haveSwitched()) { Break = true; a = astart; } } aold = a; PM.move(x + r * Math.cos(anull + a), y + r * Math.sin(anull + a)); PM.project(c); zc.getConstruction().validate(this, PM); if (P.valid()) { if (!started) { zc.getConstruction().shouldSwitch(true); astart = a; } double x2 = 0, y2 = 0; boolean valid = false; if (P instanceof PointObject) { final PointObject p = (PointObject) P; x2 = p.getX(); y2 = p.getY(); valid = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; if (!started) { X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); } else { double xx, yy, dx, dy; xx = L.getX(); yy = L.getY(); dx = L.getDX(); dy = L.getDY(); final double det = dx * DY - dy * DX; if (Math.sqrt(Math.abs(det)) > 1e-9) { final double h = (-(X - xx) * DY + DX * (Y - yy)) / (-det); x2 = xx + h * dx; y2 = yy + h * dy; valid = true; } X = xx; Y = yy; DX = dx; DY = dy; } } final double dist = zc.dCenter(x2, y2); final boolean different = ((int) zc.col(x1) != (int) zc .col(x2) || (int) zc.row(y1) != (int) zc.row(y2)); if (valid && different) { addCoordinates(V, P, x2, y2); } final double dp = Math.abs(x2 - x1) + Math.abs(y2 - y1); da = updateDA(da, valid, dist, dp, dmin, dmax, zc); x1 = x2; y1 = y2; started = true; } else if (started) { da = -da; } addSecondary(startedO); if (Break || System.currentTimeMillis() - time > 1000) { break; } } // System.out.println("Points "+V.size()+" Time "+(System.currentTimeMillis()-time)); } // Running on a line: else if (O instanceof PrimitiveLineObject) { zc.getConstruction().shouldSwitch(false); final PrimitiveLineObject l = (PrimitiveLineObject) O; PM.project(l); final double lx = l.getX(), ly = l.getY(), ldx = l.getDX(), ldy = l .getDY(); double amin = 0, amax = 0, astart = 0; double dmax = 0.5; boolean range = false; if (l instanceof RayObject) { amin = astart = 0; amax = Math.PI * 0.9999; range = true; } else if (l instanceof SegmentObject) { amin = astart = 0; final double r = ((SegmentObject) l).getLength(); dmax = r / 20; amax = Math.atan(r) * 2; range = true; } else { amin = astart = -Math.PI * 0.99999; amax = Math.PI * 0.9999; } double a = astart; double hd = Math.tan(mod(a) / 2); PM.move(lx + hd * ldx, ly + hd * ldy); PM.project(l); zc.getConstruction().validate(this, PM); zc.resetSum(); double x1 = 0, y1 = 0; boolean started = false; if (P.valid()) { zc.getConstruction().shouldSwitch(true); if (P instanceof PointObject) { final PointObject p = (PointObject) P; x1 = p.getX(); y1 = p.getY(); addCoordinates(V, P, x1, y1); started = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); started = true; } } final boolean startedO[] = new boolean[PMax]; for (int i = 0; i < PN; i++) { startedO[i] = false; } final long time = System.currentTimeMillis(); addSecondary(startedO); final double dmin = DMin; if (da < 1e-10 || da > zc.dx(1)) { da = zc.dx(1) / 10; } double aold = a; while (true) { a = a + da; boolean Break = false; if ((!started || range) && a >= amax) { a = amax; Break = true; } else if ((!started || range) && a <= amin) { a = amin; Break = true; } else if (started && da > 0) { if ((mod(aold - astart) < 0 && mod(a - astart) >= 0) && !zc.getConstruction().haveSwitched()) { Break = true; a = astart; } } aold = a; hd = Math.tan(mod(a) / 2); PM.move(lx + hd * ldx, ly + hd * ldy); PM.project(l); zc.getConstruction().validate(this, PM); if (P.valid()) { if (!started) { zc.getConstruction().shouldSwitch(true); astart = a; } double x2 = 0, y2 = 0; boolean valid = false; if (P instanceof PointObject) { final PointObject p = (PointObject) P; x2 = p.getX(); y2 = p.getY(); valid = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; if (!started) { X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); } else { double xx, yy, dx, dy; xx = L.getX(); yy = L.getY(); dx = L.getDX(); dy = L.getDY(); final double det = dx * DY - dy * DX; if (Math.sqrt(Math.abs(det)) > 1e-9) { final double h = (-(X - xx) * DY + DX * (Y - yy)) / (-det); x2 = xx + h * dx; y2 = yy + h * dy; valid = true; } X = xx; Y = yy; DX = dx; DY = dy; } } final double dist = zc.dCenter(x2, y2); final boolean different = ((int) zc.col(x1) != (int) zc .col(x2) || (int) zc.row(y1) != (int) zc.row(y2)); if (valid && different) { addCoordinates(V, P, x2, y2); } final double dp = Math.abs(x2 - x1) + Math.abs(y2 - y1); da = updateDA(da, valid, dist, dp, dmin, dmax, zc); x1 = x2; y1 = y2; started = true; } else if (started) { da = -da; } addSecondary(startedO); if (Break || System.currentTimeMillis() - time > 1000) { break; } } } // Running an expression slider: else if (O instanceof ExpressionObject) { zc.getConstruction().shouldSwitch(false); final ExpressionObject eo = (ExpressionObject) O; if (!eo.isSlider()) { return; } double amin = 0, amax = 0, astart = 0; double dmax = 0.5; boolean range = false; amin = astart = 0; final double r = 1; dmax = r / 20; amax = r; range = true; double a = astart; double hd = a; eo.setSliderPosition(0); zc.getConstruction().validate(P, null); zc.resetSum(); double x1 = 0, y1 = 0; boolean started = false; if (P.valid()) { zc.getConstruction().shouldSwitch(true); if (P instanceof PointObject) { final PointObject p = (PointObject) P; x1 = p.getX(); y1 = p.getY(); addCoordinates(V, P, x1, y1); started = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); started = true; } } final boolean startedO[] = new boolean[PMax]; for (int i = 0; i < PN; i++) { startedO[i] = false; } final long time = System.currentTimeMillis(); addSecondary(startedO); final double dmin = DMin; if (da < 1e-10 || da > zc.dx(1)) { da = zc.dx(1) / 10; } double aold = a; double x2 = 0, y2 = 0; while (true) { a = a + da; boolean Break = false; if ((!started || range) && a >= amax) { a = amax; Break = true; } else if ((!started || range) && a <= amin) { a = amin; Break = true; } else if (started && da > 0) { if ((mod(aold - astart) < 0 && mod(a - astart) >= 0) && !zc.getConstruction().haveSwitched()) { Break = true; a = astart; } } aold = a; hd = a; eo.setSliderPosition(hd); zc.getConstruction().validate(P, null); if (P.valid()) { if (!started) { zc.getConstruction().shouldSwitch(true); astart = a; } boolean valid = false; if (P instanceof PointObject) { final PointObject p = (PointObject) P; x2 = p.getX(); y2 = p.getY(); valid = true; } else if (P instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) P; if (!started) { X = L.getX(); Y = L.getY(); DX = L.getDX(); DY = L.getDY(); } else { double xx, yy, dx, dy; xx = L.getX(); yy = L.getY(); dx = L.getDX(); dy = L.getDY(); final double det = dx * DY - dy * DX; if (Math.sqrt(Math.abs(det)) > 1e-9) { final double h = (-(X - xx) * DY + DX * (Y - yy)) / (-det); x2 = xx + h * dx; y2 = yy + h * dy; valid = true; } X = xx; Y = yy; DX = dx; DY = dy; } } final double dist = zc.dCenter(x2, y2); final boolean different = ((int) zc.col(x1) != (int) zc .col(x2) || (int) zc.row(y1) != (int) zc.row(y2)); if (valid && different) { addCoordinates(V, P, x2, y2); } final double dp = Math.abs(x2 - x1) + Math.abs(y2 - y1); da = updateDA(da, valid, dist, dp, dmin, dmax, zc); x1 = x2; y1 = y2; started = true; } else if (started) { addCoordinates(V, P, x2, y2); da = -da; } addSecondary(startedO); if (Break || System.currentTimeMillis() - time > 1000) { break; } } } } // This is the update function. It is a time consuming moving of // the point P on the object O. The function is a copy from the // same function in ObjectTracker. public synchronized void compute(final ZirkelCanvas zc) { if (Fixed && !StartFix) { return; } StartFix = false; double x = 0, y = 0; if (PM != null) { x = PM.getX(); y = PM.getY(); } else if (O instanceof ExpressionObject && ((ExpressionObject) O).isSlider()) { x = ((ExpressionObject) O).getSliderPosition(); } zc.getConstruction().clearSwitches(); zc.getConstruction().shouldSwitch(true); DontProject = true; docompute(zc); DontProject = false; zc.getConstruction().shouldSwitch(false); zc.getConstruction().clearSwitches(); if (PM != null) { PM.move(x, y); } else if (O instanceof ExpressionObject && ((ExpressionObject) O).isSlider()) { ((ExpressionObject) O).setSliderPosition(x); } final Enumeration e = V.elements(); if (e.hasMoreElements()) { Coordinates c = (Coordinates) e.nextElement(); x = c.X; y = c.Y; double col1 = zc.col(c.X); double row1 = zc.row(c.Y); while (e.hasMoreElements()) { c = (Coordinates) e.nextElement(); final double col2 = zc.col(c.X); final double row2 = zc.row(c.Y); c.flag = Math.abs(col2 - col1) < 100 && Math.abs(row2 - row1) < 100; row1 = row2; col1 = col2; } } zc.dovalidate(); } public void addSecondary(final boolean startedO[]) { for (int i = 0; i < PN; i++) { if (!PO[i].valid()) { continue; } if (PO[i] instanceof PointObject) { final PointObject p = (PointObject) PO[i]; addCoordinates(VO[i], p, p.getX(), p.getY()); VO[i].addElement(new Coordinates(p.getX(), p.getY())); } else if (PO[i] instanceof PrimitiveLineObject) { final PrimitiveLineObject L = (PrimitiveLineObject) PO[i]; if (!startedO[i]) { XO[i] = L.getX(); YO[i] = L.getY(); DXO[i] = L.getDX(); DYO[i] = L.getDY(); startedO[i] = true; } else { double xx, yy, dx, dy; xx = L.getX(); yy = L.getY(); dx = L.getDX(); dy = L.getDY(); final double det = dx * DYO[i] - dy * DXO[i]; if (Math.sqrt(Math.abs(det)) > 1e-9) { final double h = (-(XO[i] - xx) * DYO[i] + DXO[i] * (YO[i] - yy)) / (-det); XO[i] = xx; YO[i] = yy; DXO[i] = dx; DYO[i] = dy; addCoordinates(VO[i], PO[i], xx + h * dx, yy + h * dy); } } } } } public void addCoordinates(final Vector v, final ConstructionObject p, final double x, final double y) { final Coordinates C = new Coordinates(x, y); if (Discrete && p instanceof PointObject) { C.Color = p.getColorIndex(); C.Thickness = p.getColorType(); } v.addElement(C); } public void addCoordinates(final Vector v, final ConstructionObject p) { v.addElement(new Coordinates(p.getX(), p.getY())); } public void addCoordinates(final Vector v, final double x, final double y) { v.addElement(new Coordinates(x, y)); } public double StepSize = 5; public double updateDA(double da, final boolean valid, final double dist, final double dp, final double dmin, final double dmax, final ZirkelCanvas zc) { if (V.size() > 0 && valid) { if (dist < 1.2) { if (dp > zc.dx(StepSize)) { da /= 2; } else if (dp < zc.dx(StepSize / 2)) { da *= 2; } if (da > 0 && da < dmin) { da = dmin; } else if (da < 0 && da > -dmin) { da = -dmin; } if (da > dmax) { da = dmax; } else if (da < -dmax) { da = -dmax; } } else { if (dp > zc.dx(StepSize * 10)) { da /= 2; } else if (dp < zc.dx(StepSize * 5)) { da *= 2; } if (da > 0 && da < dmin) { da = dmin; } else if (da < 0 && da > -dmin) { da = -dmin; } if (da > dmax) { da = dmax; } else if (da < -dmax) { da = -dmax; } } } return da; } @Override public boolean hasUnit() { return false; } /** * Project a point to this object. */ public synchronized void project(final PointObject P) { if (DontProject) { return; } final Enumeration e = V.elements(); double x = 0, y = 0, x0 = 0, y0 = 0, dmin = 0; boolean started = false; while (e.hasMoreElements()) { final Coordinates c = (Coordinates) e.nextElement(); final double x1 = c.X; final double y1 = c.Y; if (!started) { dmin = Math.sqrt((P.getX() - x1) * (P.getX() - x1) + (P.getY() - y1) * (P.getY() - y1)); x0 = x = x1; y0 = y = y1; started = true; } else { if (c.flag) { double h = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); if (h < 1e-10) { h = 1e-10; } double g = (P.getX() - x0) * (x1 - x0) + (P.getY() - y0) * (y1 - y0); if (g < 0) { g = 0; } if (g > h) { g = h; } final double x2 = x0 + g / h * (x1 - x0), y2 = y0 + g / h * (y1 - y0); final double d = Math.sqrt((P.getX() - x2) * (P.getX() - x2) + (P.getY() - y2) * (P.getY() - y2)); if (d < dmin) { dmin = d; x = x2; y = y2; } } x0 = x1; y0 = y1; } } if (started) { P.setXY(x, y); P.Valid = true; } else { P.Valid = false; } } public synchronized int getDistance(final PointObject P) { final Enumeration e = V.elements(); double x = 0, y = 0, x0 = 0, y0 = 0, dmin = 0; boolean started = false; while (e.hasMoreElements()) { final Coordinates c = (Coordinates) e.nextElement(); final double x1 = c.X; final double y1 = c.Y; if (!started) { dmin = Math.sqrt((P.getX() - x1) * (P.getX() - x1) + (P.getY() - y1) * (P.getY() - y1)); x0 = x = x1; y0 = y = y1; started = true; } else { if (c.flag) { double h = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); if (h < 1e-10) { h = 1e-10; } double g = (P.getX() - x0) * (x1 - x0) + (P.getY() - y0) * (y1 - y0); if (g < 0) { g = 0; } if (g > h) { g = h; } final double x2 = x0 + g / h * (x1 - x0), y2 = y0 + g / h * (y1 - y0); final double d = Math.sqrt((P.getX() - x2) * (P.getX() - x2) + (P.getY() - y2) * (P.getY() - y2)); if (d < dmin) { dmin = d; x = x2; y = y2; } } x0 = x1; y0 = y1; } } if (started) { P.Valid = true; final double dd = Math.sqrt((P.getX() - x) * (P.getX() - x) + (P.getY() - y) * (P.getY() - y)); return (int) Math.round(dd * Cn.getPixel()); } else { P.Valid = false; } return Integer.MAX_VALUE; } @Override public String getDisplayValue() { try { return "" + getSum(); } catch (final Exception e) { return "???"; } } public void project(final PointObject P, final double alpha) { project(P); } @Override public boolean canDisplayName() { return false; } public boolean Fixed = false, StartFix; @Override public boolean isFixed() { return Fixed; } @Override public void setFixed(final boolean f) { Fixed = f; if (Fixed) { StartFix = true; } } public void setDMin(final double dmin) { DMin = dmin; } public double getDMin() { return DMin; } @Override public int getType() { return Type; } @Override public void setType(final int type) { Type = type; } public boolean isDiscrete() { return Discrete; } public void setDiscrete(final boolean discrete) { Discrete = discrete; } public boolean canInteresectWith(final ConstructionObject o) { return true; } public void repulse(final PointObject P) { project(P); } }