/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is 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. */ /* * GeoPoint.java * * The point (x,y) has homogenous coordinates (x,y,1) * * Created on 30. August 2001, 17:39 */ package org.geogebra.common.geogebra3D.kernel3D.geos; import java.util.ArrayList; import java.util.TreeSet; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.geogebra3D.euclidian3D.draw.Drawable3D; import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoDependentPoint3D; import org.geogebra.common.geogebra3D.kernel3D.transform.MirrorableAtPlane; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.LocateableList; import org.geogebra.common.kernel.MatrixTransformable; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.Path; import org.geogebra.common.kernel.PathMover; import org.geogebra.common.kernel.PathNormalizer; import org.geogebra.common.kernel.PathOrPoint; import org.geogebra.common.kernel.PathParameter; import org.geogebra.common.kernel.Region; import org.geogebra.common.kernel.RegionParameters; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.Matrix.CoordMatrix4x4; import org.geogebra.common.kernel.Matrix.CoordSys; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.advanced.AlgoDynamicCoordinates3D; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.arithmetic.ExpressionNode; import org.geogebra.common.kernel.arithmetic.ExpressionValue; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.arithmetic.ValidExpression; import org.geogebra.common.kernel.arithmetic.ValueType; import org.geogebra.common.kernel.arithmetic3D.MyVec3DNode; import org.geogebra.common.kernel.commands.ParametricProcessor; import org.geogebra.common.kernel.geos.ChangeableCoordParent; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.geos.GeoVec3D; import org.geogebra.common.kernel.geos.PointProperties; import org.geogebra.common.kernel.geos.Transformable; import org.geogebra.common.kernel.kernelND.GeoConicND; import org.geogebra.common.kernel.kernelND.GeoCoordSys2D; import org.geogebra.common.kernel.kernelND.GeoDirectionND; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.kernel.kernelND.GeoLineND; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.kernel.kernelND.GeoQuadricNDConstants; import org.geogebra.common.kernel.kernelND.Region3D; import org.geogebra.common.kernel.kernelND.RotateableND; import org.geogebra.common.plugin.GeoClass; import org.geogebra.common.plugin.Operation; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.debug.Log; /** * * @author Markus + ggb3D */ public class GeoPoint3D extends GeoVec4D implements GeoPointND, PathOrPoint, MatrixTransformable, RotateableND, Transformable, MirrorableAtPlane { private boolean isInfinite, isDefined; private int pointSize; // mouse moving private Coords willingCoords = null; // = new Ggb3DVector( new double[] // {0,0,0,1.0}); private Coords willingDirection = null; // new Ggb3DVector( new double[] // {0,0,1,0.0}); // paths private Path path; private PathParameter pp; // region private Region region; private RegionParameters regionParameters; /** 2D coord sys when point is on a region */ // private GeoCoordSys2D coordSys2D = null; /** 2D x-coord when point is on a region */ private double x2D = 0; /** 2D y-coord when point is on a region */ private double y2D = 0; /** 2D z-coord when point is on a region (distance) */ private double z2D = 0; /** temp inhomogeneous coordinates */ public Coords inhom = Coords.createInhomCoorsInD3(); // list of Locateables (GeoElements) that this point is start point of // if this point is removed, the Locateables have to be notified private LocateableList locateableList; private ArrayList<NumberValue> changeableCoordNumbers = null; private boolean hasPolarParentNumbers = false; /** * @return whether getCoordParentNumbers() returns polar variables (r; phi). */ private boolean hasPolarParentNumbers() { return hasPolarParentNumbers; } /** * @param c * construction */ public GeoPoint3D(Construction c) { super(c); setDrawingMatrix(CoordMatrix4x4.Identity()); setCartesian3D(); setUndefined(); this.setIncidenceList(null); } /** * Creates point on path * * @param c * construction * @param path * path */ public GeoPoint3D(Construction c, Path path) { super(c); setDrawingMatrix(CoordMatrix4x4.Identity()); setCartesian3D(); setPath(path); } @Override public void setVisualStyle(GeoElement geo) { super.setVisualStyle(geo); if (geo.isGeoPoint()) { setPointSize(((GeoPointND) geo).getPointSize()); setPointStyle(((GeoPointND) geo).getPointStyle()); } else if (geo instanceof PointProperties) { setPointSize(((PointProperties) geo).getPointSize()); setPointStyle(((PointProperties) geo).getPointStyle()); } } @Override public void setPath(Path path) { this.path = path; } /** * Creates point in region * * @param c * construction * @param region * region */ public GeoPoint3D(Construction c, Region region) { super(c); setDrawingMatrix(CoordMatrix4x4.Identity()); setCartesian3D(); setRegion(region); } @Override public void setRegion(Region region) { this.region = region; } // ///////////////////////////////////////////////////////// // GeoPointND interface (TODO move it to abstract method) @Override public double distance(GeoPointND P) { return getInhomCoordsInD3().distance(P.getInhomCoordsInD3()); } // ///////////////////////////////////////////////////////// // COORDINATES @Override public double getX() { return getCoords().get(1); } @Override public double getY() { return getCoords().get(2); } @Override public double getZ() { return getCoords().get(3); } /** * Sets homogenous coordinates and updates inhomogenous coordinates * * @param v * coords * @param doPathOrRegion * says if path (or region) calculations have to be done */ @Override final public void setCoords(Coords v, boolean doPathOrRegion) { super.setCoords(v); updateCoords(); if (doPathOrRegion) { // region if (hasRegion()) { // Application.printStacktrace(getLabel()); region.pointChangedForRegion(this); } // path if (isPointOnPath()) { // remember path parameter for undefined case // PathParameter tempPathParameter = getTempPathparameter(); // tempPathParameter.set(getPathParameter()); path.pointChanged(this); // make sure animation starts from the correct place animationValue = PathNormalizer.toNormalizedPathParameter( getPathParameter().t, path.getMinParameter(), path.getMaxParameter()); } updateCoords(); } else if (isPointOnPath()) { // make sure animation value is consistent with path parameter animationValue = PathNormalizer.toNormalizedPathParameter( getPathParameter().t, path.getMinParameter(), path.getMaxParameter()); } } @Override final public void setCoords(Coords v) { setCoords(v, true); } @Override public void setCoordsFromPoint(GeoPointND point) { setCoords(point.getInhomCoordsInD3()); } @Override final public void setCoords(double x, double y, double z, double w) { setWillingCoordsUndefined(); setCoords(new Coords(x, y, z, w)); } // sets from 2D coords @Override final public void setCoords(double x, double y, double z) { setCoords(x, y, 0, z); } @Override final public void updateCoords() { // Application.printStacktrace(getLabel()); // infinite point // #5202 if (!Double.isNaN(v.getW()) && Kernel.isEpsilon(v.getW(), v.getX(), v.getY(), v.getZ())) { isInfinite = true; isDefined = !(Double.isNaN(v.get(1)) || Double.isNaN(v.get(2)) || Double.isNaN(v.get(3))); inhom.setX(Double.NaN); inhom.setY(Double.NaN); inhom.setZ(Double.NaN); } // finite point else { isInfinite = false; isDefined = v.isDefined(); if (isDefined) { // make sure the z coordinate is always positive // this is important for the orientation of a line or ray // computed using two points P, Q with cross(P, Q) // TODO cast in GgbVector if (v.get(4) < 0) { for (int i = 1; i <= 4; i++) { v.set(i, (v.get(i)) * (-1.0)); } } // update inhomogenous coords if (v.get(4) == 1.0) { inhom.set(1, v.get(1)); inhom.set(2, v.get(2)); inhom.set(3, v.get(3)); } else { inhom.set(1, v.get(1) / v.get(4)); inhom.set(2, v.get(2) / v.get(4)); inhom.set(3, v.get(3) / v.get(4)); } } else { inhom.setX(Double.NaN); inhom.setY(Double.NaN); inhom.setZ(Double.NaN); } } // Application.debug("v=\n"+v+"\ninhom="+inhom); // sets the drawing matrix to coords getDrawingMatrix().setOrigin(getCoords()); } /** * @param v * inhomogeneous coordinates */ final public void setCoords(GeoVec3D v) { setCoords(v.x, v.y, v.z, 1.0); } /** * Returns (x/w, y/w, z/w) GgbVector. */ @Override final public Coords getInhomCoords() { return inhom; } @Override public Coords getInhomCoordsInD(int dimension) { switch (dimension) { case 3: return getInhomCoordsInD3(); case 2: return getInhomCoordsInD2(); default: return null; } } private Coords inhom2D; @Override public Coords getInhomCoordsInD2() { if (inhom2D == null) { inhom2D = new Coords(2); } inhom2D.setX(inhom.getX()); inhom2D.setY(inhom.getY()); return inhom2D; } @Override public Coords getInhomCoordsInD3() { return inhom; } @Override final public double getInhomX() { return inhom.getX(); } @Override final public double getInhomY() { return inhom.getY(); } @Override final public double getInhomZ() { return inhom.getZ(); } private CoordMatrix4x4 tmpMatrix4x4; private Coords tmpCoordsLength3; @Override public Coords getCoordsInD2IfInPlane(CoordSys coordSys) { if (setCoords2D(coordSys)) { return tmpCoordsLength3; } return null; } @Override public Coords getCoordsInD2(CoordSys coordSys) { setCoords2D(coordSys); return tmpCoordsLength3; } private boolean setCoords2D(CoordSys coordSys) { Coords coords; if (tmpCoords1 == null) { tmpCoords1 = Coords.createInhomCoorsInD3(); } if (hasWillingCoords()) { coords = getWillingCoords(); } else { // use real coords coords = getCoords(); } // matrix for projection if (tmpMatrix4x4 == null) { tmpMatrix4x4 = new CoordMatrix4x4(); } if (coordSys == null) { // project on plane xOy CoordMatrix4x4.Identity(tmpMatrix4x4); } else { tmpMatrix4x4.set(coordSys.getMatrixOrthonormal()); } if (!hasWillingDirection()) { // projection coords.projectPlaneInPlaneCoords(tmpMatrix4x4, tmpCoords1); } else { // use willing direction for projection coords.projectPlaneThruVIfPossibleInPlaneCoords(tmpMatrix4x4, getWillingDirection(), tmpCoords1); } if (tmpCoordsLength3 == null) { tmpCoordsLength3 = new Coords(3); } double w = tmpCoords1.getW(); tmpCoordsLength3.setX(tmpCoords1.getX() / w); tmpCoordsLength3.setY(tmpCoords1.getY() / w); tmpCoordsLength3.setZ(1); return Kernel.isZero(tmpCoords1.getZ()); } @Override public Coords getCoordsInD(int dimension) { switch (dimension) { case 3: return getCoords(); case 2: // Application.debug("willingCoords=\n"+willingCoords+"\nwillingDirection=\n"+willingDirection); /* * GgbVector coords; if (getWillingCoords()!=null) if * (getWillingDirection()!=null){ //TODO use region matrix in place * of identity * coords=getWillingCoords().projectPlaneThruV(GgbMatrix4x4 * .Identity(), getWillingDirection())[1]; }else * coords=getWillingCoords * ().projectPlane(GgbMatrix4x4.Identity())[1]; else * coords=getCoords(); GgbVector v = new GgbVector(3); * v.setX(coords.getX()); v.setY(coords.getY()); * v.setZ(coords.getW()); return v; */ return getCoordsInD2(); default: return null; } } @Override public Coords getCoordsInD2() { return getCoordsInD2(CoordSys.Identity3D); } @Override public Coords getCoordsInD3() { return getCoords(); } /** * Returns (x/w, y/w, z/w) GgbVector. */ @Override final public void getInhomCoords(double[] d) { double[] coords = getInhomCoords().get(); for (int i = 0; i < d.length; i++) { d[i] = coords[i]; } } @Override final public double[] vectorTo(GeoPointND QI) { GeoPoint3D Q = (GeoPoint3D) QI; // Application.debug("v=\n"+Q.getCoords().sub(getCoords()).get()); return Q.getCoords().sub(getCoords()).get(); } @Override public boolean movePoint(Coords rwTransVec, Coords endPosition) { boolean movedGeo = false; if (endPosition != null) { // setCoords(endPosition.x, endPosition.y, 1); // movedGeo = true; } // translate point else { Coords coords; Coords current = getInhomCoords(); if (current.getLength() < rwTransVec.getLength()) { coords = current.add(rwTransVec); } else { coords = current.addSmaller(rwTransVec); } setCoords(coords); movedGeo = true; } return movedGeo; } // ///////////////////////////////////////////////////////// // PATHS @Override final public boolean isPointOnPath() { return path != null; } @Override public Path getPath() { return path; } @Override final public PathParameter getPathParameter() { if (pp == null) { pp = new PathParameter(0); } return pp; } /** * Updates coords from path */ final public void doPath() { path.pointChanged(this); // check if the path is a 2D path : in this case, 2D coords have been // modified if (!(path.toGeoElement().isGeoElement3D() || path.toGeoElement().isGeoList())) { updateCoordsFrom2D(false, null); } updateCoords(); } // copied on GeoPoint @Override public boolean isPointerChangeable() { return GeoPoint.isPointChangeable(this); } // ///////////////////////////////////////////////////////// // REGION /** * says if the point is in a Region * * @return true if the point is in a Region */ @Override final public boolean hasRegion() { return region != null; } @Override final public boolean isPointInRegion() { return region != null; } /** * Updates coords from region */ final public void doRegion() { region.pointChangedForRegion(this); updateCoords(); } @Override final public RegionParameters getRegionParameters() { if (regionParameters == null) { regionParameters = new RegionParameters(); } return regionParameters; } @Override final public Region getRegion() { return region; } /** * set the 2D coord sys where the region lies * * @param cs * 2D coord sys */ /* * public void setCoordSys2D(GeoCoordSys2D cs){ this.coordSys2D = cs; } */ /** * update the 2D coords on the region (regarding willing coords and * direction) */ @Override public void updateCoords2D() { if (region != null) { // use region 2D coord sys updateCoords2D(region, true); } else {// project on xOy plane x2D = getX(); y2D = getY(); z2D = getZ(); } } /** * update the 2D coords on the region (regarding willing coords and * direction) * * @param reg * region * @param updateParameters * whether to update regionParameters */ public void updateCoords2D(Region reg, boolean updateParameters) { Coords coords; Coords[] project; if (!(reg instanceof Region3D)) { Log.warn(reg + " is not 3D region"); return; } if (hasWillingCoords()) { coords = getWillingCoords(); } else { // use real coords coords = getCoords(); } if (!hasWillingDirection()) { // use normal direction for // projection project = ((Region3D) reg).getNormalProjection(coords); // coords.projectPlane(coordSys2D.getMatrix4x4()); } else { // use willing direction for projection project = ((Region3D) reg).getProjection(getCoords(), coords, getWillingDirection()); // project = // coords.projectPlaneThruV(coordSys2D.getMatrix4x4(),getWillingDirection()); } x2D = project[1].get(1); y2D = project[1].get(2); z2D = project[1].get(3); if (updateParameters) { RegionParameters rp = getRegionParameters(); rp.setT1(project[1].get(1)); rp.setT2(project[1].get(2)); rp.setNormal(((GeoElement) reg).getMainDirection()); } } /** * set 2D coords * * @param x * x-coord * @param y * y-coord */ @Override public void setCoords2D(double x, double y, double z) { x2D = x / z; y2D = y / z; } @Override public double getX2D() { return x2D; } @Override public double getY2D() { return y2D; } /** * @return inhomogenous 2D z */ public double getZ2D() { return z2D; } /** * update 3D coords regarding 2D coords (if coordsys!=null, use it; else if * region!=null, use its coord sys; else project on xOy plane) * * @param doPathOrRegion * says if the path or the region calculations have to be done */ @Override public void updateCoordsFrom2D(boolean doPathOrRegion, CoordSys coordsys) { if (coordsys != null) { setCoords(coordsys.getPoint(getX2D(), getY2D()), doPathOrRegion); } else if (region != null) { /* * if (getLabel().contains("B1")){ * Application.debug(getX2D()+","+getY2D()); if (getX2D()>3) * Application.printStacktrace("ici"); } */ setCoords(((Region3D) region).getPoint(getX2D(), getY2D(), new Coords(4)), doPathOrRegion); } else { setCoords(new Coords(getX2D(), getY2D(), 0, 1), doPathOrRegion); } } @Override public void updateCoordsFrom2D(boolean doPathOrRegion) { updateCoordsFrom2D(doPathOrRegion, CoordSys.Identity3D); } // ///////////////////////////////////////////////////////// // WILLING COORDS /** * @param willingCoords * willing coordinates */ public void setWillingCoords(Coords willingCoords) { if (this.willingCoords == null) { this.willingCoords = Coords.createInhomCoorsInD3(); } if (willingCoords == null || !willingCoords.isDefined()) { this.willingCoords.setUndefined(); } else { this.willingCoords.set(willingCoords); } } /** * Make willing coordinates undefined */ public void setWillingCoordsUndefined() { if (this.willingCoords == null) { this.willingCoords = Coords.createInhomCoorsInD3(); } this.willingCoords.setUndefined(); } /** * @param x * x-coord * @param y * y-coord * @param z * z-coord * @param w * inhomogeneous w */ public void setWillingCoords(double x, double y, double z, double w) { if (this.willingCoords == null) { this.willingCoords = Coords.createInhomCoorsInD3(); } willingCoords.setX(x); willingCoords.setY(y); willingCoords.setZ(z); willingCoords.setW(w); } /** * @param willingDirection * willing direction */ public void setWillingDirection(Coords willingDirection) { if (this.willingDirection == null) { this.willingDirection = new Coords(4); } if (willingDirection == null || !willingDirection.isDefined()) { this.willingDirection.setUndefined(); } else { this.willingDirection.set(willingDirection); } } /** * Make willing direction undefined */ public void setWillingDirectionUndefined() { if (this.willingDirection == null) { this.willingDirection = new Coords(4); } this.willingDirection.setUndefined(); } /** * @return willing coordinates */ public Coords getWillingCoords() { return willingCoords; } /** * @return whether willing coordinates exist and are defined */ public boolean hasWillingCoords() { return willingCoords != null && willingCoords.isDefined(); } /** * @return willing direction */ public Coords getWillingDirection() { return willingDirection; } /** * @return whether willing direction exist and are defined */ public boolean hasWillingDirection() { return willingDirection != null && willingDirection.isDefined(); } private double zScale = 1; /** * set current zScale from this point (should be set from 3D view) * @param scale z scale */ public void setZScale(double scale) { zScale = scale; } @Override public double getZScale() { return zScale; } // ///////////////////////////////////////////////////////// // COMMON STUFF @Override public GeoClass getGeoClassType() { return GeoClass.POINT3D; } /** * Copy constructor * * @param point * original */ public GeoPoint3D(GeoPointND point) { super(point.getConstruction()); setDrawingMatrix(CoordMatrix4x4.Identity()); set(point); } @Override public GeoPoint3D copy() { return new GeoPoint3D(this); } @Override final public boolean isGeoPoint() { return true; } @Override public boolean isDefined() { return isDefined; } /* * public void set(GeoPointND P){ set((GeoElement) P); } */ @Override public void set(GeoElementND geo) { set(geo, true); } @Override public void set(GeoElementND geo, boolean macroFeedback) { if (geo.isGeoPoint()) { GeoPointND p = (GeoPointND) geo; if (p.getPathParameter() != null) { PathParameter pathParameter = getPathParameter(); pathParameter.set(p.getPathParameter()); } animationValue = p.getAnimationValue(); setCoords(p); // TODO ? moveMode = p.getMoveMode(); updateCoords(); setMode(p.getMode()); // complex etc } /* * TODO else if (geo.isGeoVector()) { GeoVector v = (GeoVector) geo; * setCoords(v.x, v.y, 1d); setMode(v.toStringMode); // complex etc } */ } @Override public void setUndefined() { setCoords(new Coords(Double.NaN, Double.NaN, Double.NaN, Double.NaN), false); setWillingCoordsUndefined(); isDefined = false; isInfinite = false; } @Override public boolean showInEuclidianView() { return isDefined && !isInfinite; } @Override final public String toString(StringTemplate tpl) { StringBuilder sbToString = getSbToString(); sbToString.setLength(0); sbToString.append(label); GeoPoint.addEqualSignToString(sbToString, toStringMode, tpl.getCoordStyle(kernel.getCoordStyle())); sbToString.append(toValueString(tpl)); return sbToString.toString(); } @Override public boolean hasValueStringChangeableRegardingView() { return true; } @Override public String toValueString(StringTemplate tpl) { if (isInfinite()) { return "?"; } if (tpl.hasCASType() && getDefinition() != null) { return getDefinition().toValueString(tpl); } StringBuilder sbToString = getSbBuildValueString(); // boolean isVisibleInView2D = false; Coords p = getInhomCoordsInD3(); if (getMode() == Kernel.COORD_CARTESIAN_3D) { GeoPoint.buildValueStringCoordCartesian3D(kernel, tpl, p.getX(), p.getY(), p.getZ(), sbToString); } else if (getMode() == Kernel.COORD_SPHERICAL) { GeoPoint.buildValueStringCoordSpherical(kernel, tpl, p.getX(), p.getY(), p.getZ(), sbToString); } else if (!Kernel.isZero(p.getZ())) { if (getMode() == Kernel.COORD_POLAR) { GeoPoint.buildValueStringCoordSpherical(kernel, tpl, p.getX(), p.getY(), p.getZ(), sbToString); } else { GeoPoint.buildValueStringCoordCartesian3D(kernel, tpl, p.getX(), p.getY(), p.getZ(), sbToString); } } else { GeoPoint.buildValueString(kernel, tpl, getMode(), p.getX(), p.getY(), sbToString); } return sbToString.toString(); } @Override public boolean isEqual(GeoElementND geo) { if (!geo.isGeoPoint()) { return false; } return isEqualPointND((GeoPointND) geo); } @Override public boolean isEqualPointND(GeoPointND P) { if (!(isDefined() && P.isDefined())) { return false; } // both finite if (isFinite() && P.isFinite()) { Coords c1 = getInhomCoords(); Coords c2 = P.getInhomCoordsInD3(); return Kernel.isEqual(c1.getX(), c2.getX()) && Kernel.isEqual(c1.getY(), c2.getY()) && Kernel.isEqual(c1.getZ(), c2.getZ()); } else if (isInfinite() && P.isInfinite()) { Coords c1 = getCoords(); Coords c2 = P.getCoordsInD3(); return c1.crossProduct(c2).equalsForKernel(0, Kernel.STANDARD_PRECISION); } else { return false; } } // ///////////////////////////////////// // PointProperties @Override public int getPointSize() { return pointSize; } @Override public int getPointStyle() { // TODO return 0; } @Override public void setPointSize(int size) { pointSize = size; } @Override public void setPointStyle(int type) { // TODO } // //////////////////////////////// // XML /** * returns all class-specific xml tags for saveXML GeoGebra File Format */ @Override protected void getXMLtags(StringBuilder sb) { super.getXMLtags(sb); // polar or cartesian coords switch (toStringMode) { case Kernel.COORD_POLAR: sb.append("\t<coordStyle style=\"polar\"/>\n"); break; case Kernel.COORD_COMPLEX: sb.append("\t<coordStyle style=\"complex\"/>\n"); break; case Kernel.COORD_CARTESIAN: sb.append("\t<coordStyle style=\"cartesian\"/>\n"); break; case Kernel.COORD_SPHERICAL: sb.append("\t<coordStyle style=\"spherical\"/>\n"); break; default: // don't save default (Kernel.COORD_CARTESIAN_3D) } // point size sb.append("\t<pointSize val=\""); sb.append(pointSize); sb.append("\"/>\n"); } @Override public String getStartPointXML() { StringBuilder sb = new StringBuilder(); sb.append("\t<startPoint "); if (isAbsoluteStartPoint()) { sb.append("x=\""); sb.append(getCoords().get(1)); sb.append("\" y=\""); sb.append(getCoords().get(2)); sb.append("\" z=\""); sb.append(getCoords().get(3)); sb.append("\" w=\""); sb.append(getCoords().get(4)); sb.append("\"/>\n"); } else { sb.append("exp=\""); StringUtil.encodeXML(sb, getLabel(StringTemplate.xmlTemplate)); sb.append("\"/>\n"); } return sb.toString(); } @Override final public boolean isAbsoluteStartPoint() { return isIndependent() && !isLabelSet(); } // //////////////////////////////// // LocateableList @Override public LocateableList getLocateableList() { if (locateableList == null) { locateableList = new LocateableList(this); } return locateableList; } @Override public boolean hasLocateableList() { return locateableList != null; } @Override public void setLocateableList(LocateableList locateableList) { this.locateableList = locateableList; } /** * Tells Locateables that their start point is removed and calls * super.remove() */ @Override public void doRemove() { if (locateableList != null) { locateableList.doRemove(); } super.doRemove(); } /** * Calls super.update() and updateCascade() for all registered locateables. */ @Override public void update(boolean drag) { super.update(drag); // update all registered locatables (they have this point as start // point) if (locateableList != null) { GeoElement.updateCascadeLocation(locateableList, cons); } } private static TreeSet<AlgoElement> tempSet; protected static TreeSet<AlgoElement> getTempSet() { if (tempSet == null) { tempSet = new TreeSet<AlgoElement>(); } return tempSet; } // //////////////////////////////// // GeoPoint2 interface @Override public boolean isFinite() { return isDefined && !isInfinite; } @Override public boolean isInfinite() { return isInfinite; } @Override public double[] getPointAsDouble() { return getInhomCoords().get(); } @Override public Geo3DVec getVector() { return new Geo3DVec(kernel, getX(), getY(), getZ()); } // //////////////////////////////// // display in a 2D view ? /* * public boolean isVisibleInView(Object view){ if (view==((Application3D) * app).getEuclidianView3D()) return true; * * if (view==((Application3D) app).getEuclidianView()) return * AbstractKernel.isZero(getCoords().getZ()); * * return false; * * } */ // //////////////////////////////// // GeoElement3DInterface interface @Override public Coords getLabelPosition() { // Application.debug(inhom.toString()); return getInhomCoordsInD3(); } // /////////////////////////////////////// // MOVING THE POINT (3D) // /////////////////////////////////////// /** move mode */ protected int moveMode = MOVE_MODE_TOOL_DEFAULT; @Override public void switchMoveMode(int mode) { switch (moveMode) { case MOVE_MODE_XY: moveMode = MOVE_MODE_Z; break; case MOVE_MODE_Z: moveMode = MOVE_MODE_XY; break; case MOVE_MODE_TOOL_DEFAULT: if (mode == EuclidianConstants.MODE_MOVE) { moveMode = MOVE_MODE_Z; } else { moveMode = MOVE_MODE_XY; } break; default: // do nothing break; } } /** * @param flag * move mode */ public void setMoveMode(int flag) { moveMode = flag; } @Override public int getMoveMode() { if (changeableCoordParent != null) { return MOVE_MODE_NONE; } if (this.hasChangeableCoordParentNumbers()) { return moveMode; } if (!isIndependent()) { AlgoElement algo = getParentAlgorithm(); if (algo instanceof AlgoDynamicCoordinates3D) { return moveMode; } return MOVE_MODE_NONE; } if (isLocked()) { return MOVE_MODE_NONE; } if (isPointOnPath()) { return MOVE_MODE_NONE; // too complicated to use MOVE_MODE_Z when // not lines } if (hasRegion()) { GeoElement geo = (GeoElement) region; if (geo.isGeoQuadric() && ((GeoQuadric3D) geo) .getType() == GeoQuadricNDConstants.QUADRIC_LINE) { return MOVE_MODE_NONE; } return MOVE_MODE_XY; } return moveMode; } /** * * @return value of moveMode */ public int getRealMoveMode() { return moveMode; } private Coords moveNormalDirection; /** * sets the normal to moving directions (for region points) * * @param d * direction */ public void setMoveNormalDirection(Coords d) { moveNormalDirection = d.copyVector(); } /** * * @return the normal to moving directions (for region points) */ public Coords getMoveNormalDirection() { return moveNormalDirection; } private boolean showUndefinedInAlgebraView = true; @Override public void showUndefinedInAlgebraView(boolean flag) { showUndefinedInAlgebraView = flag; } @Override public final boolean showInAlgebraView() { return (isDefined || showUndefinedInAlgebraView); } @Override public void setParentAlgorithm(AlgoElement algorithm) { super.setParentAlgorithm(algorithm); if (algorithm != null) { setConstructionDefaults(setEuclidianVisibleBySetParentAlgorithm); // set // colors // to // dependent // colors } } private boolean setEuclidianVisibleBySetParentAlgorithm = true; /** * if the point has a parent algorithm, we may don't want its visibility to * be changed */ public void dontSetEuclidianVisibleBySetParentAlgorithm() { setEuclidianVisibleBySetParentAlgorithm = false; } @Override public void updateColumnHeadingsForTraceValues() { resetSpreadsheetColumnHeadings(); spreadsheetColumnHeadings.add(getColumnHeadingText(new ExpressionNode( kernel, kernel.getAlgebraProcessor().getXBracket(), // "x(" Operation.PLUS, new ExpressionNode(kernel, getNameGeo(), // Name[this] Operation.PLUS, kernel.getAlgebraProcessor().getCloseBracket())))); // ")" spreadsheetColumnHeadings.add(getColumnHeadingText(new ExpressionNode( kernel, kernel.getAlgebraProcessor().getYBracket(), // "y(" Operation.PLUS, new ExpressionNode(kernel, getNameGeo(), // Name[this] Operation.PLUS, kernel.getAlgebraProcessor().getCloseBracket())))); // ")" spreadsheetColumnHeadings.add(getColumnHeadingText(new ExpressionNode( kernel, kernel.getAlgebraProcessor().getZBracket(), // "z(" Operation.PLUS, new ExpressionNode(kernel, getNameGeo(), // Name[this] Operation.PLUS, kernel.getAlgebraProcessor().getCloseBracket())))); // ")" } @Override public TraceModesEnum getTraceModes() { return TraceModesEnum.SEVERAL_VALUES_OR_COPY; } @Override public String getTraceDialogAsValues() { String name = getLabelTextOrHTML(false); StringBuilder sb1 = new StringBuilder(); sb1.append("x("); sb1.append(name); sb1.append("), y("); sb1.append(name); sb1.append("), z("); sb1.append(name); sb1.append(")"); return sb1.toString(); } @Override public void addToSpreadsheetTraceList( ArrayList<GeoNumeric> spreadsheetTraceList) { GeoNumeric xx = new GeoNumeric(cons, inhom.getX()); spreadsheetTraceList.add(xx); GeoNumeric yy = new GeoNumeric(cons, inhom.getY()); spreadsheetTraceList.add(yy); GeoNumeric zz = new GeoNumeric(cons, inhom.getZ()); spreadsheetTraceList.add(zz); } @Override public void matrixTransform(double a, double b, double c, double d) { double x = getX(); double y = getY(); Double x1 = a * x + b * y; Double y1 = c * x + d * y; setCoords(x1, y1, getZ(), getW()); } @Override public void matrixTransform(double a00, double a01, double a02, double a10, double a11, double a12, double a20, double a21, double a22) { double x = getX(); double y = getY(); double z = getZ(); double x1 = a00 * x + a01 * y + a02 * z; double y1 = a10 * x + a11 * y + a12 * z; double z1 = a20 * x + a21 * y + a22 * z; setCoords(x1, y1, z1, getW()); } @Override public boolean isMatrixTransformable() { return true; } @Override public int getDimension() { return 3; } @Override final public boolean isCasEvaluableObject() { return true; } @Override public void setCartesian() { setMode(Kernel.COORD_CARTESIAN); } @Override public void setCartesian3D() { setMode(Kernel.COORD_CARTESIAN_3D); } @Override public void setSpherical() { setMode(Kernel.COORD_SPHERICAL); } @Override public void setPolar() { setMode(Kernel.COORD_POLAR); } @Override public void setComplex() { setMode(Kernel.COORD_COMPLEX); } @Override final public void rotate(NumberValue phiValue) { double phi = phiValue.getDouble(); double cos = Math.cos(phi); double sin = Math.sin(phi); double x = getX(); double y = getY(); double z = getZ(); setCoords(x * cos - y * sin, x * sin + y * cos, z, getW()); } @Override final public void rotate(NumberValue phiValue, GeoPointND point) { rotate(phiValue, point.getInhomCoords()); } @Override final public void rotate(NumberValue phiValue, Coords point) { double phi = phiValue.getDouble(); double cos = Math.cos(phi); double sin = Math.sin(phi); double x = getX(); double y = getY(); double z = getZ(); double w = getW(); Coords Q = point; double qx = w * Q.getX(); double qy = w * Q.getY(); setCoords((x - qx) * cos + (qy - y) * sin + qx, (x - qx) * sin + (y - qy) * cos + qy, z, w); } @Override public void rotate(NumberValue phiValue, GeoPointND S, GeoDirectionND orientation) { Coords o1 = S.getInhomCoordsInD3(); Coords vn = orientation.getDirectionInD3(); rotate(phiValue, o1, vn); } private void rotate(NumberValue phiValue, Coords o1, Coords vn) { rotate(phiValue.getDouble(), o1, vn); } private Coords tmpCoords1, tmpCoords2, tmpCoords3; /** * rotate around line (point + vector) with angle phi * * @param phi * angle * @param o1 * point * @param vn * vector */ public void rotate(double phi, Coords o1, Coords vn) { if (vn.isZero() || Double.isNaN(phi)) { setUndefined(); return; } Coords point = getInhomCoordsInD3(); if (tmpCoords1 == null) { tmpCoords1 = Coords.createInhomCoorsInD3(); } point.projectLine(o1, vn, tmpCoords1, null); // point projected on the // line if (tmpCoords2 == null) { tmpCoords2 = new Coords(4); } tmpCoords2.setSub(point, tmpCoords1); double cos = Math.cos(phi); double sin = Math.sin(phi); double l = vn.calcNorm(); if (tmpCoords3 == null) { tmpCoords3 = new Coords(4); } tmpCoords3.setCrossProduct(vn, tmpCoords2); tmpCoords3.setW(0); setCoords(tmpCoords1.setAdd(tmpCoords1, tmpCoords2.setAdd( tmpCoords2.mulInside(cos), tmpCoords3.mulInside(sin / l)))); } @Override public void rotate(NumberValue phiValue, GeoLineND line) { rotate(phiValue.getDouble(), line); } /** * rotate around line with angle phi * * @param phi * angle * @param line * line */ public void rotate(double phi, GeoLineND line) { Coords o1 = line.getStartInhomCoords(); Coords vn = line.getDirectionInD3(); rotate(phi, o1, vn); } // /////////////////////////// // PATH OR POINT INTERFACE // /////////////////////////// @Override public void pointChanged(GeoPointND p) { if (p.isGeoElement3D()) { ((GeoPoint3D) p).setCoords(this.getCoords(), false); } else { Coords coords = this.getCoords(); if (!Kernel.isZero(coords.getZ())) { p.setUndefined(); } else { GeoPoint.pointChanged(p, coords.getX(), coords.getY(), coords.getW()); } } p.getPathParameter().setT(0); } @Override public void pathChanged(GeoPointND PI) { pointChanged(PI); } @Override public boolean isOnPath(GeoPointND PI, double eps) { return isEqual(PI); } @Override public double getMinParameter() { return 0; } @Override public double getMaxParameter() { return 0; } @Override public boolean isClosedPath() { return false; } @Override public PathMover createPathMover() { return null; } private Coords tmpWillingCoords, tmpWillingDirection, tmpCoordsOld; @Override public double distanceToPath(PathOrPoint path1) { if (tmpCoordsOld == null) { tmpCoordsOld = new Coords(4); } tmpCoordsOld.set(getInhomCoords()); if (tmpWillingCoords == null) { tmpWillingCoords = Coords.createInhomCoorsInD3(); } if (tmpWillingDirection == null) { tmpWillingDirection = new Coords(4); } boolean hadWillingCoords; if (hasWillingCoords()) { hadWillingCoords = true; tmpWillingCoords.set(getWillingCoords()); } else { hadWillingCoords = false; tmpWillingCoords.set(tmpCoordsOld); } if (hasWillingDirection()) { tmpWillingDirection.set(getWillingDirection()); } else { tmpWillingDirection.setUndefined(); } path1.pointChanged(this); double d; if (!tmpWillingDirection.isDefined()) { d = getInhomCoords().distance(tmpWillingCoords); } else { d = getInhomCoords().distLine(tmpWillingCoords, tmpWillingDirection); setWillingDirection(tmpWillingDirection); } if (hadWillingCoords) { setWillingCoords(tmpWillingCoords); } setCoords(tmpCoordsOld, false); return d; } /** matrix used as orientation by the {@link Drawable3D} */ private CoordMatrix4x4 m_drawingMatrix = null; /** * returns a 4x4 matrix for drawing the {@link Drawable3D} * * @return the drawing matrix */ public CoordMatrix4x4 getDrawingMatrix() { return m_drawingMatrix; } /** * sets the 4x4 matrix for drawing the {@link Drawable3D} and the label * * @param a_drawingMatrix * the drawing matrix */ public void setDrawingMatrix(CoordMatrix4x4 a_drawingMatrix) { this.m_drawingMatrix = a_drawingMatrix; } private boolean trace; @Override public boolean isTraceable() { return true; } @Override public void setTrace(boolean trace) { this.trace = trace; } @Override public boolean getTrace() { return trace; } // ////////////////////// // MIRROR // ////////////////////// @Override public void mirror(Coords Q) { double w = getW(); double qx = w * Q.getX(); double qy = w * Q.getY(); double qz = w * Q.getZ(); setCoords(2.0 * qx - getX(), 2.0 * qy - getY(), 2.0 * qz - getZ(), w); } @Override public void mirror(GeoLineND line) { Coords o1 = line.getStartInhomCoords(); Coords vn = line.getDirectionInD3(); Coords point = getInhomCoordsInD3(); if (tmpCoords1 == null) { tmpCoords1 = Coords.createInhomCoorsInD3(); } point.projectLine(o1, vn, tmpCoords1, null); // point projected on the // line // mirror at projected point mirror(tmpCoords1); } @Override public void mirror(GeoCoordSys2D plane) { if (tmpCoords1 == null) { tmpCoords1 = Coords.createInhomCoorsInD3(); } getInhomCoordsInD3().projectPlane( plane.getCoordSys().getMatrixOrthonormal(), tmpCoords1); mirror(tmpCoords1); } // ////////////////////// // DILATE // ////////////////////// @Override public void dilate(NumberValue rval, Coords S) { double r = rval.getDouble(); double temp = (1 - r); double w = getW(); setCoords(r * getX() + temp * S.getX() * w, r * getY() + temp * S.getY() * w, r * getZ() + temp * S.getZ() * w, w); } // for identifying incidence by construction // case by case. // currently implemented for // lines: line by two point, intersect lines, line/conic, point on line // TODO: parallel line, perpenticular line private ArrayList<GeoElement> incidenceList; private ArrayList<GeoElement> nonIncidenceList; /** * @return list of objects incident by construction */ @Override public ArrayList<GeoElement> getIncidenceList() { return incidenceList; } /** * @return list of objects NOT incident by construction */ public ArrayList<GeoElement> getNonIncidenceList() { return nonIncidenceList; } /** * @param list * list of objects incident by construction */ public void setIncidenceList(ArrayList<GeoElement> list) { if (list == null) { incidenceList = new ArrayList<GeoElement>(); } else { incidenceList = new ArrayList<GeoElement>(list); } } /** * initialize incidenceList */ public void createIncidenceList() { incidenceList = new ArrayList<GeoElement>(); } /** * Resets the list of object that are not incident by construction */ public void createNonIncidenceList() { nonIncidenceList = new ArrayList<GeoElement>(); } /** * add geo to incidenceList of this, and also add this to pointsOnConic * (when geo is a conic) or to pointsOnLine (when geo is a line) * * @param geo * incident object */ @Override public void addIncidence(GeoElement geo, boolean isStartPoint) { if (incidenceList == null) { createIncidenceList(); } if (!incidenceList.contains(geo)) { incidenceList.add(geo); } // GeoConicND, GeoLine, GeoPoint are the three types who have an // incidence list if (geo.isGeoConic()) { ((GeoConicND) geo).addPointOnConic(this);// GeoConicND } else if (geo.isGeoLine() && !isStartPoint) { ((GeoLineND) geo).addPointOnLine(this); } } /** * Add non-incident object * * @param geo * object thatisnot incident by construction */ public void addNonIncidence(GeoElement geo) { if (nonIncidenceList == null) { createNonIncidenceList(); } if (!nonIncidenceList.contains(geo)) { nonIncidenceList.add(geo); } } /** * @param geo * incident geo to be removed */ @Override public final void removeIncidence(GeoElement geo) { if (incidenceList != null) { incidenceList.remove(geo); } if (geo.isGeoConic()) { ((GeoConicND) geo).removePointOnConic(this); } else if (geo.isGeoLine()) { ((GeoLineND) geo).removePointOnLine(this); } } @Override public boolean evaluatesTo3DVector() { return true; } @Override public void set(double param1, double param2, MyPoint leftPoint, MyPoint rightPoint) { setCoords(new Coords(param2 * leftPoint.x + param1 * rightPoint.x, param2 * leftPoint.y + param1 * rightPoint.y, param2 * leftPoint.getZ() + param1 * rightPoint.getZ(), 1.0), false); updateCoords(); } @Override final public HitType getLastHitType() { return HitType.ON_BOUNDARY; } @Override public void translate(Coords v0) { if (tmpCoords2 == null) { tmpCoords2 = new Coords(4); } tmpCoords2.setMul(v0, v.getW()); v.addInside(tmpCoords2); setCoords(v); } @Override public GeoElementND doAnimationStep(double frameRate, GeoList parent) { return GeoPoint.doAnimationStep(frameRate, this, path, parent); } @Override public boolean isAnimatable() { return isPointOnPath() && isPointerChangeable(); } private double animationValue; @Override public double getAnimationValue() { return animationValue; } @Override public void setAnimationValue(double val) { animationValue = val; } @Override public ValueType getValueType() { return ValueType.VECTOR3D; } @Override public ValidExpression toValidExpression() { return getVector(); } @Override public void removePath() { path = null; pp = null; } /** * @return parent sliders if this is defined as (a+a0,b+b0,c+c0) */ final public ArrayList<NumberValue> getCoordParentNumbers() { // init changeableCoordNumbers if (changeableCoordNumbers == null) { changeableCoordNumbers = new ArrayList<NumberValue>(3); AlgoElement parentAlgo = getParentAlgorithm(); // dependent point of form P = (a, b) if (parentAlgo instanceof AlgoDependentPoint3D) { AlgoDependentPoint3D algo = (AlgoDependentPoint3D) parentAlgo; ExpressionNode en = algo.getExpression(); // (xExpression, yExpression) if (en.isLeaf() && en.getLeft() instanceof MyVec3DNode) { // (xExpression, yExpression) MyVec3DNode vn = (MyVec3DNode) en.getLeft(); hasPolarParentNumbers = vn .getMode() == Kernel.COORD_SPHERICAL || vn.getMode() == Kernel.COORD_POLAR; try { // try to get free number variables used in coords for // this point // don't allow expressions like "a + x(A)" for polar // coords (r; phi) ExpressionValue xcoord = vn.getX(); ExpressionValue ycoord = vn.getY(); ExpressionValue zcoord = vn.getZ(); ParametricProcessor proc = kernel.getAlgebraProcessor() .getParamProcessor(); NumberValue xNum = proc.getCoordNumber(xcoord); NumberValue yNum = proc.getCoordNumber(ycoord); NumberValue zNum = proc.getCoordNumber(zcoord); if (xNum instanceof GeoNumeric && ((GeoNumeric) xNum).isPointerChangeable()) { changeableCoordNumbers.add(xNum); } else { changeableCoordNumbers.add(null); } if (yNum instanceof GeoNumeric && ((GeoNumeric) yNum).isPointerChangeable()) { changeableCoordNumbers.add(yNum); } else { changeableCoordNumbers.add(null); } if (zNum instanceof GeoNumeric && ((GeoNumeric) zNum).isPointerChangeable()) { changeableCoordNumbers.add(zNum); } else { changeableCoordNumbers.add(null); } } catch (Throwable e) { changeableCoordNumbers.clear(); e.printStackTrace(); } } } } return changeableCoordNumbers; } /** * Used for polyhedron net: first polygon set it * * @param ccp * changeable coord parent * */ @Override final public void setChangeableCoordParentIfNull( ChangeableCoordParent ccp) { if (changeableCoordParent == null) { changeableCoordParent = ccp; } } private ChangeableCoordParent changeableCoordParent = null; @Override public void recordChangeableCoordParentNumbers(EuclidianView view) { if (changeableCoordParent != null) { changeableCoordParent.record(view); } } /** * Returns whether this point has three changeable numbers as coordinates, * e.g. point A = (a, b, c) where a, b and c are free GeoNumeric objects. */ @Override final public boolean hasChangeableCoordParentNumbers() { // TODO why does this check only x,y? if (isLocked()) { return false; } if (changeableCoordParent != null) { return true; } ArrayList<NumberValue> coords = getCoordParentNumbers(); if (coords.size() == 0) { return false; } NumberValue num1 = coords.get(0); NumberValue num2 = coords.get(1); if (num1 == null && num2 == null) { return false; } if (num1 instanceof GeoNumeric && num2 instanceof GeoNumeric) { GeoElement maxObj1 = GeoElement .as(((GeoNumeric) num1).getIntervalMaxObject()); GeoElement maxObj2 = GeoElement .as(((GeoNumeric) num2).getIntervalMaxObject()); GeoElement minObj1 = GeoElement .as(((GeoNumeric) num1).getIntervalMinObject()); GeoElement minObj2 = GeoElement .as(((GeoNumeric) num2).getIntervalMinObject()); if (maxObj1 != null && maxObj1.isChildOrEqual((GeoElement) num2)) { return false; } if (minObj1 != null && minObj1.isChildOrEqual((GeoElement) num2)) { return false; } if (maxObj2 != null && maxObj2.isChildOrEqual((GeoElement) num1)) { return false; } if (minObj2 != null && minObj2.isChildOrEqual((GeoElement) num1)) { return false; } } boolean ret = (num1 instanceof GeoNumeric && ((GeoNumeric) num1).isPointerChangeable()) || (num2 instanceof GeoNumeric && ((GeoNumeric) num2).isPointerChangeable()); return ret; } @Override public boolean moveFromChangeableCoordParentNumbers(Coords rwTransVec, Coords targetPosition, Coords viewDirection, ArrayList<GeoElement> updateGeos, ArrayList<GeoElement> tempMoveObjectList, EuclidianView view) { if (changeableCoordParent != null) { return changeableCoordParent.move(rwTransVec, targetPosition, viewDirection, updateGeos, tempMoveObjectList, view); } Coords endPosition = targetPosition; if (!hasChangeableCoordParentNumbers()) { return false; } if (endPosition == null) { endPosition = getInhomCoords().add(rwTransVec); } // translate x and y coordinates by changing the parent coords // accordingly ArrayList<NumberValue> freeCoordNumbers = getCoordParentNumbers(); NumberValue xvar = freeCoordNumbers.get(0); NumberValue yvar = freeCoordNumbers.get(1); NumberValue zvar = freeCoordNumbers.get(2); // polar coords (r; phi) if (hasPolarParentNumbers()) { // don't move } // cartesian coords (xvar + constant, yvar + constant) else { // only change if GeoNumeric if (xvar instanceof GeoNumeric) { double newXval = xvar.getDouble() - getInhomX() + endPosition.getX(); ((GeoNumeric) xvar).setValue(newXval); } if (xvar != yvar && yvar instanceof GeoNumeric) { double newYval = yvar.getDouble() - getInhomY() + endPosition.getY(); ((GeoNumeric) yvar).setValue(newYval); } if (zvar != yvar && zvar != xvar && zvar instanceof GeoNumeric) { double newZval = zvar.getDouble() - getInhomZ() + endPosition.getZ(); ((GeoNumeric) zvar).setValue(newZval); } } if (xvar instanceof GeoNumeric) { addChangeableCoordParentNumberToUpdateList((GeoNumeric) xvar, updateGeos, tempMoveObjectList); } if (yvar instanceof GeoNumeric) { addChangeableCoordParentNumberToUpdateList((GeoNumeric) yvar, updateGeos, tempMoveObjectList); } if (zvar instanceof GeoNumeric) { addChangeableCoordParentNumberToUpdateList((GeoNumeric) zvar, updateGeos, tempMoveObjectList); } return true; } }