package org.geogebra.common.euclidian; import java.util.ArrayList; import org.geogebra.common.euclidian.event.AbstractEvent; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Path; import org.geogebra.common.kernel.PathNormalizer; import org.geogebra.common.kernel.Region; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.algos.AlgoCirclePointRadius; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.AlgoJoinPointsSegment; import org.geogebra.common.kernel.algos.AlgoMidpoint; import org.geogebra.common.kernel.algos.AlgoPolarLine; import org.geogebra.common.kernel.geos.GeoAngle; import org.geogebra.common.kernel.geos.GeoConic; import org.geogebra.common.kernel.geos.GeoCurveCartesian; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoFunction; import org.geogebra.common.kernel.geos.GeoFunctionable; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoNumberValue; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.geos.GeoPolygon; import org.geogebra.common.kernel.geos.GeoSegment; import org.geogebra.common.kernel.geos.GeoVector; import org.geogebra.common.kernel.kernelND.GeoConicND; 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.GeoSegmentND; import org.geogebra.common.kernel.kernelND.GeoVectorND; import org.geogebra.common.main.Feature; import org.geogebra.common.plugin.EuclidianStyleConstants; /** * Class that creates geos for EuclidianController. Needed for special 3D stuff. * * @author mathieu * */ public class EuclidianControllerCompanion { /** controller */ protected EuclidianController ec; /** * @param ec * controller */ public EuclidianControllerCompanion(EuclidianController ec) { setEuclidianController(ec); } /** * @param ec * controller */ protected void setEuclidianController(EuclidianController ec) { this.ec = ec; } /** * @param A * point * @param B * point * @param C * point * @return angle */ protected GeoAngle createAngle(GeoPointND A, GeoPointND B, GeoPointND C) { ec.checkZooming(); return ec.getAlgoDispatcher().Angle(null, (GeoPoint) A, (GeoPoint) B, (GeoPoint) C); } /** * @param p * polygon * @return angles */ protected GeoElement[] createAngles(GeoPolygon p) { return ec.getAlgoDispatcher().Angles(null, p); } /** * @param v1 * vector * @param v2 * vector * @return angle between vectors */ protected GeoAngle createAngle(GeoVectorND v1, GeoVectorND v2) { return ec.getAlgoDispatcher().Angle(null, (GeoVector) v1, (GeoVector) v2); } /** * @param A * point * @param B * apex * @param num * angle size * @param clockWise * orientation * @return angle with given size */ public GeoAngle createAngle(GeoPointND A, GeoPointND B, GeoNumberValue num, boolean clockWise) { return (GeoAngle) ec.getAlgoDispatcher().Angle(null, (GeoPoint) A, (GeoPoint) B, num, !clockWise)[0]; } /** * @param g * line * @param h * line * @return angle between lines */ protected GeoAngle createLineAngle(GeoLineND g, GeoLineND h) { return ec.getAlgoDispatcher().createLineAngle((GeoLine) g, (GeoLine) h); } /** * @param geo * preimage * @param vec * translation vector * @return translated object */ protected GeoElement[] translate(GeoElement geo, GeoVectorND vec) { ec.checkZooming(); return ec.getAlgoDispatcher().Translate(null, geo, (GeoVector) vec); } /** * @param geo * preimage * @param point * mirror * @return reflected element */ protected GeoElement[] mirrorAtPoint(GeoElement geo, GeoPointND point) { return ec.getAlgoDispatcher().Mirror(null, geo, (GeoPoint) point); } /** * @param geo * preimage * @param line * mirror * @return reflected element */ protected GeoElement[] mirrorAtLine(GeoElement geo, GeoLineND line) { return ec.getAlgoDispatcher().Mirror(null, geo, (GeoLine) line); } /** * @param geo * preimage * @param num * coefficient * @param point * point * @return dilated element */ public GeoElement[] dilateFromPoint(GeoElement geo, GeoNumberValue num, GeoPointND point) { return ec.kernel.getAlgoDispatcher().Dilate(null, geo, num, (GeoPoint) point); } /** * * @param a * first geo * @param b * second geo * @param coords2D * closest coords * @return single intersection points from geos a,b */ public GeoPointND getSingleIntersectionPoint(GeoElement a, GeoElement b, boolean coords2D) { GeoPointND point = null; // first hit is a line if (a.isGeoLine()) { if (b.isGeoLine()) { if (!((GeoLine) a).linDep((GeoLine) b)) { point = ec.getAlgoDispatcher().IntersectLines(null, (GeoLine) a, (GeoLine) b); } else { return null; } } else if (b.isGeoConic()) { point = ec.getAlgoDispatcher().IntersectLineConicSingle(null, (GeoLine) a, (GeoConic) b, ec.xRW, ec.yRW); } else if (b.isGeoCurveCartesian()) { return (GeoPointND) ec.getAlgoDispatcher().IntersectLineCurve( null, (GeoLine) a, (GeoCurveCartesian) b)[0]; } else if (b.isGeoFunctionable()) { // line and function GeoFunction f = ((GeoFunctionable) b).getGeoFunction(); if (f.isPolynomialFunction(false)) { point = ec.getAlgoDispatcher() .IntersectPolynomialLineSingle(null, f, (GeoLine) a, ec.xRW, ec.yRW); } GeoPoint initPoint = new GeoPoint(ec.kernel.getConstruction()); initPoint.setCoords(ec.xRW, ec.yRW, 1.0); point = ec.getAlgoDispatcher().IntersectFunctionLine(null, f, (GeoLine) a, initPoint); } else { return null; } } // first hit is a conic else if (a.isGeoConic()) { if (b.isGeoLine()) { point = ec.getAlgoDispatcher().IntersectLineConicSingle(null, (GeoLine) b, (GeoConic) a, ec.xRW, ec.yRW); } else if (b.isGeoConic() && !a.isEqual(b)) { point = ec.getAlgoDispatcher().IntersectConicsSingle(null, (GeoConic) a, (GeoConic) b, ec.xRW, ec.yRW); } else { return null; } } // first hit is a function else if (a.isGeoFunctionable()) { GeoFunction aFun = ((GeoFunctionable) a).getGeoFunction(); if (b.isGeoLine()) { // line and function if (aFun.isPolynomialFunction(false)) { point = ec.getAlgoDispatcher() .IntersectPolynomialLineSingle(null, aFun, (GeoLine) b, ec.xRW, ec.yRW); } else { GeoPoint initPoint = new GeoPoint( ec.kernel.getConstruction()); initPoint.setCoords(ec.xRW, ec.yRW, 1.0); point = ec.getAlgoDispatcher().IntersectFunctionLine(null, aFun, (GeoLine) b, initPoint); } } else if (b.isGeoFunctionable()) { GeoFunction bFun = ((GeoFunctionable) b).getGeoFunction(); if (aFun.isPolynomialFunction(false) && bFun.isPolynomialFunction(false)) { return ec.getAlgoDispatcher().IntersectPolynomialsSingle( null, aFun, bFun, ec.xRW, ec.yRW); } GeoPoint initPoint = new GeoPoint(ec.kernel.getConstruction()); initPoint.setCoords(ec.xRW, ec.yRW, 1.0); point = ec.getAlgoDispatcher().IntersectFunctions(null, aFun, bFun, initPoint); } else { return null; } } else if (a.isGeoCurveCartesian()) { if (b.isGeoCurveCartesian()) { return (GeoPointND) ec.getAlgoDispatcher() .IntersectCurveCurveSingle(null, (GeoCurveCartesian) a, (GeoCurveCartesian) b, ec.xRW, ec.yRW)[0]; } else if (b.isGeoLine()) { return (GeoPointND) ec.getAlgoDispatcher().IntersectLineCurve( null, (GeoLine) b, (GeoCurveCartesian) a)[0]; } } if (point != null) { if (!coords2D) { point.setCartesian3D(); point.update(); } } return point; } protected GeoElement[] orthogonal(GeoPointND point, GeoLineND line) { ec.checkZooming(); return new GeoElement[] { ec.getAlgoDispatcher().OrthogonalLine(null, (GeoPoint) point, (GeoLine) line) }; } /** * * @param forPreviewable * @param path * @param x * @param y * @param z * @param complex * @param coords2D * @return new point for the path */ public GeoPointND createNewPoint(String label, boolean forPreviewable, Path path, double x, double y, double z, boolean complex, boolean coords2D) { return ec.createNewPoint2D(label, forPreviewable, path, x, y, complex, coords2D); } /** * * @param segment * @return midpoint for segment */ protected GeoElement midpoint(GeoSegmentND segment) { GeoElement mp = ec.getAlgoDispatcher().Midpoint((GeoSegment) segment); mp.setLabel(null); return mp; } /** * * @param conic * @return center of conic */ protected GeoElement midpoint(GeoConicND conic) { return (GeoElement) ec.getAlgoDispatcher().Center(null, conic); } /** * * @param p1 * first point * @param p2 * second point * @return midpoint for two points */ protected GeoElement midpoint(GeoPointND p1, GeoPointND p2) { AlgoMidpoint algo = new AlgoMidpoint(ec.kernel.getConstruction(), (GeoPoint) p1, (GeoPoint) p2); return algo.getPoint(); } /** * * @param geoPoint1 * first point * @param geoPoint2 * second point * @param value * n vertices * @return regular polygon */ public GeoElement[] regularPolygon(GeoPointND geoPoint1, GeoPointND geoPoint2, GeoNumberValue value) { ec.kernel.addingPolygon(); GeoElement[] elms = ec.getAlgoDispatcher().RegularPolygon(null, geoPoint1, geoPoint2, value); ec.kernel.notifyPolygonAdded(); return elms; // return kernel.getAlgoDispatcher().RegularPolygon(null, geoPoint1, // geoPoint2, value); } /** * * @param cons * @param p1 * @param p2 * @return segment [p1 p2] algorithm */ protected AlgoElement segmentAlgo(Construction cons, GeoPointND p1, GeoPointND p2) { return new AlgoJoinPointsSegment(cons, (GeoPoint) p1, (GeoPoint) p2, null, true); } protected GeoElement[] createCircle2(GeoPointND p0, GeoPointND p1) { return new GeoElement[] { ec.getAlgoDispatcher().Circle(null, (GeoPoint) p0, (GeoPoint) p1) }; } protected GeoElement semicircle(GeoPointND A, GeoPointND B) { return ec.getAlgoDispatcher().Semicircle(null, (GeoPoint) A, (GeoPoint) B); } protected GeoConicND circle(Construction cons, GeoPointND center, GeoNumberValue radius) { AlgoCirclePointRadius algo = new AlgoCirclePointRadius(cons, (GeoPoint) center, radius); algo.getCircle().setLabel(null); return algo.getCircle(); } protected GeoElement[] angularBisector(GeoLineND g, GeoLineND h) { return ec.getAlgoDispatcher().AngularBisector(null, (GeoLine) g, (GeoLine) h); } protected GeoElement angularBisector(GeoPointND A, GeoPointND B, GeoPointND C) { return ec.getAlgoDispatcher().AngularBisector(null, (GeoPoint) A, (GeoPoint) B, (GeoPoint) C); } protected GeoElement circleArcSector(GeoPointND p1, GeoPointND p2, GeoPointND p3, int type) { return ec.getAlgoDispatcher().CircleArcSector(null, (GeoPoint) p1, (GeoPoint) p2, (GeoPoint) p3, type); } protected GeoElement circumcircleArc(GeoPointND p1, GeoPointND p2, GeoPointND p3) { return ec.getAlgoDispatcher().CircumcircleArc(null, (GeoPoint) p1, (GeoPoint) p2, (GeoPoint) p3); } protected GeoElement circumcircleSector(GeoPointND p1, GeoPointND p2, GeoPointND p3) { return ec.getAlgoDispatcher().CircumcircleSector(null, (GeoPoint) p1, (GeoPoint) p2, (GeoPoint) p3); } public void movePoint(boolean repaint, AbstractEvent event) { ec.movedGeoPoint.setCoords(Kernel.checkDecimalFraction(ec.xRW), Kernel.checkDecimalFraction(ec.yRW), 1.0); if (event.isAltDown()) { // 1/24 -> steps of 15 degrees (for circle) // otherwise use Object Properties -> Algebra -> Increment // double multiplier = event.isAltDown() ? 1.0/24.0 : // movedGeoPoint.getAnimationStep(); double multiplier = ec.movedGeoPoint.getAnimationStep(); int n = (int) Math.ceil(1.0 / multiplier); if (n < 1) { n = 1; } if (ec.movedGeoPoint.isPointOnPath()) { double dist = Double.MAX_VALUE; Path path = ec.movedGeoPoint.getPath(); double t = ec.movedGeoPoint.getPathParameter().t; // convert to 0 <= t < 1 t = PathNormalizer.toNormalizedPathParameter(t, path.getMinParameter(), path.getMaxParameter()); double t_1 = t; // find closest parameter // avoid rounding errors by using an int & multiplier for (int i = 0; i < n; i++) { if (Math.abs(t - i * multiplier) < dist) { t_1 = i * multiplier; dist = Math.abs(t - i * multiplier); } } ec.movedGeoPoint.getPathParameter().t = PathNormalizer .toParentPathParameter(t_1, path.getMinParameter(), path.getMaxParameter()); path.pathChanged(ec.movedGeoPoint); ec.movedGeoPoint.updateCoords(); } } ((GeoElement) ec.movedGeoPoint).updateCascade(); if (repaint) { ec.kernel.notifyRepaint(); } } /** * move plane * * @param repaint * @param event */ protected void movePlane(boolean repaint, AbstractEvent event) { // only used in 3D } /** * @param forPreviewable * in 3D we might want a preview */ protected GeoPointND createNewPoint(boolean forPreviewable, boolean complex) { ec.checkZooming(forPreviewable); GeoPointND ret = ec.getAlgoDispatcher().Point( Kernel.checkDecimalFraction(ec.xRW), Kernel.checkDecimalFraction(ec.yRW), complex); ret.setLabel(null); return ret; } protected GeoPointND createNewPoint(boolean forPreviewable, Path path, boolean complex) { return createNewPoint(null, forPreviewable, path, Kernel.checkDecimalFraction(ec.xRW), Kernel.checkDecimalFraction(ec.yRW), 0, complex, true); } protected GeoPointND createNewPoint(boolean forPreviewable, Region region, boolean complex) { return ec.createNewPoint(null, forPreviewable, region, Kernel.checkDecimalFraction(ec.xRW), Kernel.checkDecimalFraction(ec.yRW), 0, complex, true); } protected void processModeLock(GeoPointND point) { Coords coords = point.getInhomCoordsInD2(); ec.xRW = coords.getX(); ec.yRW = coords.getY(); } protected void processModeLock(Path path) { ec.checkZooming(); GeoPoint p = ec.getAlgoDispatcher().Point(null, path, ec.xRW, ec.yRW, false, false, true); p.update(); ec.xRW = p.inhomX; ec.yRW = p.inhomY; p.remove(); } public ArrayList<GeoElement> removeParentsOfView( ArrayList<GeoElement> list) { return list; } /** * * @param clockwise * input orientation * @return clockwise (resp. not(clockwise)) if clockwise is displayed as it * in the view (used for EuclidianViewForPlane) */ public boolean viewOrientationForClockwise(boolean clockwise) { return clockwise; } public GeoElement[] rotateByAngle(GeoElement geoRot, GeoNumberValue phi, GeoPointND Q) { return ec.kernel.getAlgoDispatcher().Rotate(null, geoRot, phi, Q); } /** * * @param a * point * @param c * conic * @return tangent point/conic */ protected GeoElement[] tangent(GeoPointND a, GeoConicND c) { return ec.getAlgoDispatcher().Tangent(null, a, c); } /** * @param l * line * @param c * conic * @return tangent line/conic */ protected GeoElement[] tangent(GeoLineND l, GeoConicND c) { return ec.getAlgoDispatcher().Tangent(null, l, c); } /** * @param c1 * conic * @param c2 * conic * @return tangent conic/conic */ protected GeoElement[] tangent(GeoConicND c1, GeoConicND c2) { return ec.getAlgoDispatcher().CommonTangents(null, c1, c2); } /** * polar line to P relativ to c * * @param P * point * @param c * conic * @return polar line */ protected GeoElementND polarLine(GeoPointND P, GeoConicND c) { AlgoPolarLine algo = new AlgoPolarLine(ec.kernel.getConstruction(), null, c, P); return algo.getLine(); } /** * @param l * line * @param c * conic * @return diameter line */ protected GeoElement diameterLine(GeoLineND l, GeoConicND c) { return ec.getAlgoDispatcher().DiameterLine(null, l, c); } /** * @param v * vector * @param c * conic * @return diameter line */ protected GeoElement diameterLine(GeoVectorND v, GeoConicND c) { return ec.getAlgoDispatcher().DiameterLine(null, v, c); } /** * * @param segment * segment * @return segment perpendicular bisector */ protected GeoElement lineBisector(GeoSegmentND segment) { return ec.getAlgoDispatcher().LineBisector(null, (GeoSegment) segment); } /** * * @param a * first point * @param b * second point * @return [ab] perpendicular bisector */ protected GeoElement lineBisector(GeoPointND a, GeoPointND b) { return ec.getAlgoDispatcher().LineBisector(null, (GeoPoint) a, (GeoPoint) b); } /** * @param points * points * @return conic throught 5 points */ protected GeoConicND conic5(GeoPointND[] points) { GeoPoint[] p = new GeoPoint[5]; for (int i = 0; i < 5; i++) { p[i] = (GeoPoint) points[i]; } return ec.getAlgoDispatcher().Conic(null, p); } /** * * @param a * first focus * @param b * second focus * @param c * point on ellipse/hyperbola * @param type * ellipse/hyperbola * @return ellipse/hyperbola */ protected GeoConicND ellipseHyperbola(GeoPointND a, GeoPointND b, GeoPointND c, int type) { return ec.getAlgoDispatcher().EllipseHyperbola(null, a, b, c, type); } /** * * @param a * focus * @param l * line * @return parabola */ protected GeoConicND parabola(GeoPointND a, GeoLineND l) { return ec.getAlgoDispatcher().Parabola(null, a, l); } /** * * @param a * start point * @param v * vector * @return vector equal to v with a for start point */ protected GeoElement vectorPoint(GeoPointND a, GeoVectorND v) { GeoPoint endPoint = (GeoPoint) ec.getAlgoDispatcher().Translate(null, (GeoPoint) a, (GeoVector) v)[0]; return ec.getAlgoDispatcher().Vector(null, (GeoPoint) a, endPoint); } /** * * @param a * dependent point * @param b * point on path * @return locus */ protected GeoElement locus(GeoPointND a, GeoPointND b) { return ec.getAlgoDispatcher().Locus(null, a, b); } /** * set coords of the point to mouse loc * * @param loc * point * @return true if set to real world coords, false if set to absolute * position on screen */ public boolean setCoordsToMouseLoc(GeoPointND loc) { loc.setCoords(ec.mouseLoc.x, ec.mouseLoc.y, 1.0); return !ec.getApplication().has(Feature.ABSOLUTE_TEXTS); } public void setMouseLocation(AbstractEvent event) { ec.setMouseLocation(event.isAltDown(), event.getX(), event.getY()); } /** * * @return percentage for which we capture point to grid */ public double getPointCapturingPercentage() { return EuclidianStyleConstants.POINT_CAPTURING_GRID; } }