/* 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. */ /* * AlgoIntersectLineConic.java * * Created on 30. August 2001, 21:37 */ package org.geogebra.common.kernel.algos; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoConic; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoRay; import org.geogebra.common.kernel.geos.GeoSegment; import org.geogebra.common.kernel.kernelND.GeoConicNDConstants; /** * */ public class AlgoIntersectLineConicRegion extends AlgoIntersectLineConic { private GeoLine[] lines; // output private int numberOfLineParts; private int numberOfOutputLines; // private SortedSet<Double> paramSet; private Double tMin, tMax; // private GeoPoint[] outputPoints; private boolean currentPartIsInRegion; @Override public Commands getClassName() { return Commands.IntersectPath; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_INTERSECTION_CURVE; } public AlgoIntersectLineConicRegion(Construction cons, String[] labels, GeoLine g, GeoConic c) { super(cons, g, c); GeoElement.setLabels(labels, getIntersectionLines()); } @Override protected void initElements() { super.initElements(); for (int i = 0; i < P.length; i++) { setOutputDependencies(P[i]); } tMin = g.getMinParameter(); tMax = g.getMaxParameter(); // TODO: this initialization of input assumes the type // of the line and the conic // and will NOT update anymore. // should change to a more dynamic version. lines = new GeoLine[4]; lines[0] = (GeoLine) g.copyInternal(cons); if (Double.isInfinite(tMin)) { lines[1] = new GeoRay(cons); } else { lines[1] = new GeoSegment(cons); } lines[2] = new GeoSegment(cons); if (Double.isInfinite(tMax)) { lines[3] = new GeoRay(cons); } else { lines[3] = new GeoSegment(cons); } for (int i = 0; i < 4; i++) { setOutputDependencies(lines[i]); } } public GeoLine[] getIntersectionLines() { GeoLine[] ret = new GeoLine[numberOfOutputLines]; for (int i = 0; i < numberOfOutputLines; i++) { ret[i] = (GeoLine) super.getOutput(i); } return ret; } public int getNumOfLineParts() { return numberOfLineParts; } public int getOutputSize() { return numberOfOutputLines; } @Override public void compute() { super.compute(); // build lines numberOfOutputLines = 0; initCurrentPartIsInRegion(); switch (intersectionType) { case INTERSECTION_PRODUCING_LINE: // contained in degenerate conic case INTERSECTION_ASYMPTOTIC_LINE: // intersect at no point case INTERSECTION_PASSING_LINE: // intersect at no point lines[1].setUndefined(); lines[2].setUndefined(); lines[3].setUndefined(); if (!currentPartIsInRegion) { lines[0].setUndefined(); } else { lines[0].set(g); numberOfOutputLines++; } break; default: case INTERSECTION_MEETING_LINE: lines[0].setUndefined(); lines[2].setUndefined(); if (currentPartIsInRegion) { lines[3].setUndefined(); // set line[1] double t = g.getPossibleParameter(Q[0].getCoords()); if (tMin.isInfinite()) { ((GeoRay) lines[1]).set(Q[0], g); lines[1].changeSign(); numberOfOutputLines++; } else { if (Kernel.isGreater(tMin, t)) { lines[1].setUndefined(); } else { ((GeoSegment) lines[3]).set(Q[0], g.endPoint, g); numberOfOutputLines++; } } } else { lines[1].setUndefined(); // set line[3] double t = g.getPossibleParameter(Q[0].getCoords()); if (tMax.isInfinite()) { ((GeoRay) lines[3]).set(Q[0], g); numberOfOutputLines++; } else { if (Kernel.isGreater(tMin, t)) { lines[1].setUndefined(); } else { ((GeoSegment) lines[3]).set(Q[0], g.endPoint, g); numberOfOutputLines++; } } } break; case INTERSECTION_TANGENT_LINE: // tangent at one point lines[0].setUndefined(); if (currentPartIsInRegion) { // set line[1] and line[3] double t = g.getPossibleParameter(Q[0].getCoords()); if (tMin.isInfinite()) { ((GeoRay) lines[1]).set(Q[0], g); lines[1].changeSign(); numberOfOutputLines++; } else { if (Kernel.isGreater(tMin, t)) { lines[1].setUndefined(); } else { ((GeoSegment) lines[3]).set(Q[0], g.endPoint, g); numberOfOutputLines++; } } if (tMax.isInfinite()) { ((GeoRay) lines[3]).set(Q[0], g); numberOfOutputLines++; } else { if (Kernel.isGreater(tMin, t)) { lines[1].setUndefined(); } else { ((GeoSegment) lines[3]).set(Q[0], g.endPoint, g); numberOfOutputLines++; } } } else { lines[1].setUndefined(); lines[3].setUndefined(); } break; case INTERSECTION_SECANT_LINE: // intersect at two points // get parameters of two intersection points double t1 = g.getPossibleParameter(Q[0].getCoords()); double t2 = g.getPossibleParameter(Q[1].getCoords()); int j0 = 0; int j1 = 1; // let t1<=t2. if not, swap the index of the points if (t1 > t2) { double temp = t1; t1 = t2; t2 = temp; j1 = 0; j0 = 1; } lines[0].setUndefined(); if (currentPartIsInRegion) { lines[2].setUndefined(); // set line[1] and line[3] if (tMin.isInfinite()) { ((GeoRay) lines[1]).set(Q[j0], g); lines[1].changeSign(); numberOfOutputLines++; } else { if (Kernel.isGreater(tMin, t1)) { lines[1].setUndefined(); } else { ((GeoSegment) lines[1]).set(Q[j0], g.endPoint, g); numberOfOutputLines++; } } if (tMax.isInfinite()) { ((GeoRay) lines[3]).set(Q[j1], g); numberOfOutputLines++; } else { if (Kernel.isGreater(t2, tMax)) { lines[3].setUndefined(); } else { ((GeoSegment) lines[3]).set(Q[j1], g.endPoint, g); numberOfOutputLines++; } } } else { lines[1].setUndefined(); lines[3].setUndefined(); // set line[2] if (Kernel.isGreater(t1, tMax) || Kernel.isGreater(tMin, t2)) { lines[2].setUndefined(); } else { ((GeoSegment) lines[2]).set( Kernel.isGreater(tMin, t1) ? g.startPoint : Q[j0], Kernel.isGreater(t2, tMax) ? g.endPoint : Q[j1], g); numberOfOutputLines++; } } break; } refreshOutput(); // setLabelsForPointsAndLines(); } /* * private void setLabelsForPointsAndLines() { * * if ( (labelPrefixForLines==null || "".equals(labelPrefixForLines)) && * numberOfOutputLines!=0) labelPrefixForLines = * ((GeoElement)P[0]).getFreeLabel * (P[0].getLabel(StringTemplate.defaultTemplate).toLowerCase()); * * * GeoElement.setLabels(labelPrefixForLines,lines); } */ @Override protected void refreshOutput() { super.setOutputLength(numberOfOutputLines); int index = 0; for (int i = 0; i < lines.length; i++) { if (lines[i].isDefined()) { super.setOutput(index, lines[i]); index++; } } } // for AlgoElement @Override public void setInputOutput() { input = new GeoElement[2]; input[0] = c; input[1] = g; // output = lines; setDependencies(); // done by AlgoElement } private static boolean inOpenInterval(double t, double a, double b) { return Kernel.isGreater(b, t) && Kernel.isGreater(t, a); } void initCurrentPartIsInRegion() { switch (intersectionType) { case INTERSECTION_PRODUCING_LINE: // contained in degenerate conic case INTERSECTION_ASYMPTOTIC_LINE: // intersect at no point case INTERSECTION_PASSING_LINE: // intersect at no point numberOfLineParts = 1; break; case INTERSECTION_MEETING_LINE: numberOfLineParts = 2; break; case INTERSECTION_TANGENT_LINE: // tangent at one point case INTERSECTION_SECANT_LINE: // intersect at two points numberOfLineParts = 3; break; default: numberOfLineParts = -1; } // decide whether the full line starts inside or outside the region currentPartIsInRegion = false; Coords ex = null; double t0, t1 = 0; switch (c.type) { case GeoConicNDConstants.CONIC_PARABOLA: ex = c.getEigenvec(0); if (numberOfLineParts == 2) { currentPartIsInRegion = Kernel.isGreater(0, g.getCoords().dotproduct(ex)); } break; case GeoConicNDConstants.CONIC_HYPERBOLA: ex = c.getEigenvec(0); if (numberOfLineParts == 2) { c.pointChanged(Q[0]); t0 = Q[0].getPathParameter().getT(); currentPartIsInRegion = Kernel.isGreater(1, t0) ^ Kernel.isGreater(g.getCoords().dotproduct(ex), 0); } else if (numberOfLineParts == 3) { c.pointChanged(Q[0]); c.pointChanged(Q[1]); t0 = Q[0].getPathParameter().getT(); t1 = Q[1].getPathParameter().getT(); // infinite part is in region if and only if // two intersection points are on different branches // namely: truth value of [t0 in (-1,1)] and [t1 in (-1,1)] // should be different currentPartIsInRegion = Kernel.isGreater(1, t0) ^ Kernel.isGreater(1, t1); } break; case GeoConicNDConstants.CONIC_INTERSECTING_LINES: ex = c.getEigenvec(0); if (numberOfLineParts == 1) { currentPartIsInRegion = true; } else if (numberOfLineParts == 2) { c.pointChanged(Q[0]); t0 = Q[0].getPathParameter().getT(); currentPartIsInRegion = (inOpenInterval(t0, 1, 2) || inOpenInterval(t0, -1, 0)) ^ Kernel.isGreater(g.getCoords().dotproduct(ex), 0); } else if (numberOfLineParts == 3) { c.pointChanged(Q[0]); c.pointChanged(Q[1]); t0 = Q[0].getPathParameter().getT(); t1 = Q[1].getPathParameter().getT(); currentPartIsInRegion = (inOpenInterval(t0, -1, 0) && inOpenInterval(t1, 1, 2)) || (inOpenInterval(t1, -1, 0) && inOpenInterval(t0, 1, 2)) || (inOpenInterval(t0, 0, 1) && inOpenInterval(t1, 2, 3)) || (inOpenInterval(t1, 0, 1) && inOpenInterval(t0, 2, 3)); } break; case GeoConicNDConstants.CONIC_PARALLEL_LINES: if (numberOfLineParts == 1) { if (Kernel.isGreater(-g.z / ((g.x) * (g.x) + (g.y) * (g.y)), 0)) { currentPartIsInRegion = true; } } break; default: // currentPartIsInRegion = false; break; } currentPartIsInRegion ^= c.isInverseFill(); } }