package org.geogebra.common.geogebra3D.kernel3D.algos;
import java.util.ArrayList;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.Matrix.CoordMatrixUtil;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.GetCommand;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
/**
* Algo for finding intersect points for 3D polygons
*
* @author thilina
*
*/
public class AlgoIntersectPolygons3D extends AlgoElement3D {
// input
protected GeoPolygon polyA, polyB;
// output
protected OutputHandler<GeoElement> outputPoints;
// intersections
protected ArrayList<Coords> intersectingCoords;
// temporary lines
private GeoSegmentND[] segA, segB;
/**
* constructor with labels
*
* @param c
* @param labels
* @param polyA
* @param polyB
*/
public AlgoIntersectPolygons3D(Construction c, String[] labels,
GeoPolygon polyA, GeoPolygon polyB) {
super(c);
this.polyA = polyA;
this.polyB = polyB;
this.outputPoints = createOutputPoints();
segA = polyA.getSegments();
segB = polyB.getSegments();
this.intersectingCoords = new ArrayList<Coords>();
compute();
setInputOutput();
setLabels(labels);
update();
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = this.polyA;
input[1] = this.polyB;
setDependencies();
}
/**
* @return
*/
protected OutputHandler<GeoElement> createOutputPoints() {
return new OutputHandler<GeoElement>(new elementFactory<GeoElement>() {
@Override
public GeoPoint3D newElement() {
GeoPoint3D p = new GeoPoint3D(cons);
p.setCoords(0, 0, 0, 1);
p.setParentAlgorithm(AlgoIntersectPolygons3D.this);
return p;
}
});
}
/**
* 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.outputPoints.setIndexLabels(labels[0]);
} else {
this.outputPoints.setLabels(labels);
this.outputPoints.setIndexLabels(this.outputPoints.getElement(0)
.getLabel(StringTemplate.defaultTemplate));
}
}
@Override
public void compute() {
// clears the point map
this.intersectingCoords.clear();
Coords o1, d1, o2, d2;
Coords[] project;
for (int i = 0; i < segA.length; i++) {
o1 = segA[i].getPointInD(3, 0).getInhomCoordsInSameDimension();
d1 = segA[i].getPointInD(3, 1).getInhomCoordsInSameDimension()
.sub(o1);
for (int k = 0; k < segB.length; k++) {
o2 = segB[k].getPointInD(3, 0).getInhomCoordsInSameDimension();
d2 = segB[k].getPointInD(3, 1).getInhomCoordsInSameDimension()
.sub(o2);
project = CoordMatrixUtil.nearestPointsFromTwoLines(o1, d1, o2,
d2);
if (project != null && !Double.isNaN(project[2].get(1))
&& project[0].equalsForKernel(project[1],
Kernel.STANDARD_PRECISION)) {
double t1 = project[2].get(1); // parameter on line 1
double t2 = project[2].get(2); // parameter on line 2
if (t1 > segA[i].getMinParameter()
- Kernel.STANDARD_PRECISION
&& t1 < segA[i].getMaxParameter()
+ Kernel.STANDARD_PRECISION
&& t2 > segB[k].getMinParameter()
- Kernel.STANDARD_PRECISION
&& t2 < segB[k].getMaxParameter()
+ Kernel.STANDARD_PRECISION) {
intersectingCoords.add(new Coords(project[0]));
}
}
}
}
// update and/or create points
this.outputPoints.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);
GeoPoint3D point = (GeoPoint3D) this.outputPoints.getElement(index);
point.setCoords(coords);
point.updateCoords();
}
// other points are undefined
for (; index < this.outputPoints.size(); index++) {
this.outputPoints.getElement(index).setUndefined();
}
outputPoints.updateLabels();
}
@Override
public GetCommand getClassName() {
return Commands.Intersect;
}
}