/*
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.
*/
/*
* AlgoIntersectPolyLineConic.java
*
* Created on 29. May 2015, 14:49
*/
package org.geogebra.common.kernel.algos;
import java.util.ArrayList;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.StringTemplate;
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.GeoPoint;
import org.geogebra.common.kernel.geos.GeoPoly;
import org.geogebra.common.kernel.geos.GeoSegment;
import org.geogebra.common.kernel.geos.GeoVec3D;
import org.geogebra.common.kernel.kernelND.GeoPointND;
/**
* AlgoIntersect class for finding intersection points of both polyLine-conic
* and polygon(br)-conic combinations. In the constructor boolean isPolyClosed
* is used to define whether the GeoPoly is a polygon or a polyLine.
*
* @author thilina
*
*/
public class AlgoIntersectPolyLineConic extends AlgoIntersect {
/** Input poly **/
protected GeoPoly poly;
/** Input conic **/
protected GeoConic conic;
/** internal dummy segment */
protected GeoSegment dummySegment;
/** internal dummy points */
protected GeoPoint dummyPoint1;
protected GeoPoint dummyPoint2;
protected GeoPoint[] dummyOutputPoints;
protected boolean isPolyClosed;
/** outputHandler for variable no of output points */
protected OutputHandler<GeoElement> intersectingPoints;
/** computed list of intersecting coordinates */
protected ArrayList<Coords> intersectingCoords;
/**
*
* @param cons
* construction
* @param labels
* labels for the output
* @param poly
* input poly (can be polyLine or polygon as boundary)
* @param conic
* input conic
*/
public AlgoIntersectPolyLineConic(Construction cons, String[] labels,
GeoConic conic, GeoPoly poly, boolean isPolyClosed) {
this(cons, conic, poly, isPolyClosed);
setLabels(labels);
update();
}
/**
* common constructor
*
* @param cons
* construction
* @param poly
* input poly (can be polyLine or polygon as boundary)
* @param conic
* input conic
* @param isPolyClosed
* whether the geopoly is a polygon or not(i.e a polyLine)
*/
public AlgoIntersectPolyLineConic(Construction cons, GeoConic conic,
GeoPoly poly, boolean isPolyClosed) {
super(cons);
this.conic = conic;
this.poly = poly;
this.isPolyClosed = isPolyClosed;
initElements();
setInputOutput(); // for AlgoElement
initForNearToRelationship();
compute();
addIncidence(); // must be after compute()
}
@Override
public void initForNearToRelationship() {
// TODO
}
@Override
public GeoPoint[] getIntersectionPoints() {
// TODO
return null;
}
@Override
protected GeoPoint[] getLastDefinedIntersectionPoints() {
// TODO
return null;
}
@Override
public boolean isNearToAlgorithm() {
return true;
}
private void addIncidence() {
for (int i = 0; i < intersectingPoints.size(); i++) {
((GeoPoint) intersectingPoints.getElement(i))
.addIncidence((GeoElement) this.poly, false);
((GeoPoint) intersectingPoints.getElement(i))
.addIncidence(this.conic, false);
}
}
private void initElements() {
this.dummySegment = new GeoSegment(getConstruction());
this.dummyPoint1 = new GeoPoint(getConstruction());
this.dummyPoint2 = new GeoPoint(getConstruction());
this.dummyOutputPoints = new GeoPoint[2];
this.dummyOutputPoints[0] = new GeoPoint(getConstruction());
this.dummyOutputPoints[1] = new GeoPoint(getConstruction());
intersectingPoints = createOutputPoints();
intersectingCoords = new ArrayList<Coords>();
}
@Override
protected void noUndefinedPointsInAlgebraView() {
GeoElement[] temp = new GeoElement[2];
GeoElement[] points = intersectingPoints.getOutput(temp);
for (GeoElement el : points) {
((GeoPoint) el).showUndefinedInAlgebraView(false);
}
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = (GeoElement) this.poly;
input[1] = this.conic;
setDependencies(); // done by AlgoElement
}
@Override
public void compute() {
// calculate intersecting coordinates
this.intersectingCoords(this.conic, this.poly, this.intersectingCoords);
// update and/or create points
this.intersectingPoints
.adjustOutputSize(this.intersectingCoords.size() > 0
? this.intersectingCoords.size() : 1);
// affect new computed points
int index = 0;
for (; index < this.intersectingCoords.size(); index++) {
Coords coords = this.intersectingCoords.get(index);
GeoPointND point = (GeoPointND) this.intersectingPoints
.getElement(index);
point.setCoords(coords, false);
point.updateCoords();
}
// other points are undefined
for (; index < this.intersectingPoints.size(); index++) {
this.intersectingPoints.getElement(index).setUndefined();
}
intersectingPoints.updateLabels();
}
/**
* Does the actual calculation of the intersecting points.
*
* @param c
* GeoConic - considered as a full conic in the calculation
* @param p
* GeoPolyLine - segments of the polyLine considered as full
* lines in the calculation
* @param coords
* ArrayList of Coords to store the calculated intersecting
* coords
*/
protected void intersectingCoords(GeoConic c, GeoPoly p,
ArrayList<Coords> coords) {
GeoPointND[] polyPoints = p.getPoints();
int noOfSegments = isPolyClosed ? polyPoints.length
: polyPoints.length - 1;
coords.clear();
for (int i = 0; i < noOfSegments; i++) {
this.dummyPoint1.setCoords(p.getPoint(i));
this.dummyPoint2.setCoords(p.getPoint((i + 1) % polyPoints.length));
this.dummySegment.setStartPoint(dummyPoint1);
this.dummySegment.setEndPoint(dummyPoint2);
GeoVec3D.lineThroughPoints(this.dummyPoint1, this.dummyPoint2,
this.dummySegment);
/*
* Here both conic and conic parts are considered as full conics in
* the calculation. Segments in the polyline are considered as full
* lines in the calculation. Thus explicit checking needed to check
* whether the intersecting points are actually lying on both conic
* and polyline.
*/
AlgoIntersectLineConic.intersectLineConic(dummySegment, c,
dummyOutputPoints, Kernel.MIN_PRECISION);
/*
* checks the validitiy and the incidence on both conic and polyline
* of intersection point
*/
if (dummyOutputPoints[0].isDefined()) {
if (dummySegment.isOnPath(dummyOutputPoints[0],
Kernel.MIN_PRECISION)
&& c.isOnPath(dummyOutputPoints[0],
Kernel.MIN_PRECISION)) {
coords.add(dummyOutputPoints[0].getCoords());
}
}
if (dummyOutputPoints[1].isDefined()) {
if (dummySegment.isOnPath(dummyOutputPoints[1],
Kernel.MIN_PRECISION)
&& c.isOnPath(dummyOutputPoints[1],
Kernel.MIN_PRECISION)) {
coords.add(dummyOutputPoints[1].getCoords());
}
}
}
}
@Override
public Commands getClassName() {
return Commands.Intersect;
}
@Override
public int getRelatedModeID() {
return EuclidianConstants.MODE_INTERSECT;
}
/**
* if only one label (e.g. "A") for more than one output, new labels will be
* A_1, A_2, ...
*
* @param labels
*/
protected void setLabels(String[] labels) {
// if only one label (e.g. "A") for more than one output, new labels
// will be A_1, A_2, ...
if (labels != null && labels.length == 1 &&
// outputPoints.size() > 1 &&
labels[0] != null && !labels[0].equals("")) {
this.intersectingPoints.setIndexLabels(labels[0]);
} else {
this.intersectingPoints.setLabels(labels);
this.intersectingPoints.setIndexLabels(this.intersectingPoints
.getElement(0).getLabel(StringTemplate.defaultTemplate));
}
}
/**
*
* @return handler for output points
*/
protected OutputHandler<GeoElement> createOutputPoints() {
return new OutputHandler<GeoElement>(new elementFactory<GeoElement>() {
@Override
public GeoPoint newElement() {
GeoPoint p = new GeoPoint(getConstruction());
p.setCoords(0, 0, 1);
p.setParentAlgorithm(AlgoIntersectPolyLineConic.this);
return p;
}
});
}
}