package org.geogebra.common.kernel.algos;
import java.util.ArrayList;
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.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.GeoConicNDConstants;
import org.geogebra.common.util.debug.Log;
public class AlgoIntersectPolyLineConicRegion extends AlgoIntersect {
protected GeoPoly poly;
protected GeoConic conic;
protected boolean polyClosed;
protected boolean hasLabels;
protected int numOfOutputSegments, segCountOfPoly, polyPointCount;
protected OutputHandler<GeoSegment> outputSegments;
private ArrayList<CalcDetails> intersectPaths;
private GeoPoint[] tempSegEndPoints;
private GeoSegment tempSeg;
private GeoPoint[] intersectPoints, endPoints, closureIntersect;
private GeoPoint midPoint;
private GeoSegment[] closureSegments;
/**
* constructor with label assignment for output
*
* @param cons
* construction
* @param labels
* labels for the output
* @param poly
* input poly, can be polyLine or polyGon
* @param conic
* input conic
* @param isPolyClosed
* indicate whether the input poly is polgon(closed) or
* polyLine(no closed)
*/
public AlgoIntersectPolyLineConicRegion(Construction cons, String[] labels,
GeoPoly poly, GeoConic conic, boolean isPolyClosed) {
this(cons, poly, conic, isPolyClosed);
if (!cons.isSuppressLabelsActive()) {
setLabels(labels);
hasLabels = true;
}
update();
}
/**
* Common constructor for AlgoIntersectPolyLineConicRegion.
*
* @param cons
* construction
* @param labels
* labels for the output
* @param poly
* input poly, can be polyLine or polyGon
* @param conic
* input conic
* @param isPolyClosed
* indicate whether the input poly is polygon(closed) or
* polyLine(no closed)
*/
public AlgoIntersectPolyLineConicRegion(Construction cons, GeoPoly poly,
GeoConic conic, boolean isPolyClosed) {
super(cons);
this.poly = poly;
this.conic = conic;
this.polyClosed = isPolyClosed;
initElements();
setInputOutput();
setDependencies();
compute();
}
@Override
public void compute() {
numOfOutputSegments = 0;
intersectPaths = new ArrayList<CalcDetails>();
// calculate intersectpaths between poly and conic
for (int index = 0; index < segCountOfPoly; index++) {
tempSegEndPoints[0] = getPoly().getPoint(index);
tempSegEndPoints[1] = getPoly()
.getPoint((index + 1) % polyPointCount);
GeoVec3D.lineThroughPoints(tempSegEndPoints[0], tempSegEndPoints[1],
tempSeg);
tempSeg.setPoints(tempSegEndPoints[0], tempSegEndPoints[1]);
calcIntersectPaths(tempSeg, index);
}
// assign output segments
outputSegments.adjustOutputSize(numOfOutputSegments, false);
int count = 0;
for (int index = 0; index < segCountOfPoly; index++) {
CalcDetails cd = intersectPaths.get(index);
GeoSegment seg;
if (index == cd.segmentIndex && cd.intersectPathcount != -1) {
for (int i = 0; i < (cd.intersectPathcount * 2); i += 2) {
seg = outputSegments.getElement(count);
count++;
GeoVec3D.lineThroughPointsCoords(cd.intersectPathCoords[i],
cd.intersectPathCoords[i + 1], seg);
seg.getStartPoint().setCoords(cd.intersectPathCoords[i],
false);
seg.getEndPoint().setCoords(cd.intersectPathCoords[i + 1],
true);
seg.calcLength();
Log.debug("intersectPathcount: " + count
+ " segmentindex: " + index);
Log.debug("outputSegmentDefined: " + seg.isDefined());
}
}
}
if (hasLabels) {
outputSegments.updateLabels();
}
}
/**
* calculate intersectpaths between given segment and conic. Then add those
* details into intersectPaths arrayList
*
* @param segment
* interested temporary segment
* @param segIndex
* index of the segment (indicate the corresponding segment no.
* in the poly
*/
private void calcIntersectPaths(GeoSegment segment, int segIndex) {
CalcDetails cd = new CalcDetails();
cd.segmentIndex = segIndex;
int intersectPathIndex = 0;
// calculate intersect point between input segment and input Conic curve
AlgoIntersectSegmentConicRegion.intersectSegmentConic(segment,
getConic(), intersectPoints);
// if conic is a conic part
if (getConic().getType() == GeoConicNDConstants.CONIC_CIRCLE
&& getConic().isLimitedPath()) {
// derive midpoint, endpoint, closure segments of the input conic
AlgoIntersectSegmentConicRegion.calcConicClosure(getConic(),
midPoint, endPoints, closureSegments);
// calculate intersection points between input segment and closure
// segments
AlgoIntersectSegmentConicRegion
.intersectSegmentConicClosureSegments(segment, getConic(),
closureSegments, closureIntersect, intersectPoints);
}
int numberOfLineParts = 1;
// decide number of line parts using calculated intersection points
for (int i = 0; i < 2; i++) {
if (intersectPoints[i].isDefined()) {
numberOfLineParts += 1;
}
if (closureIntersect[i].isDefined()) {
numberOfLineParts += 1;
}
}
GeoPoint P;
GeoPoint Q;
switch (numberOfLineParts) {
case 1: {
P = segment.getStartPoint();
Q = segment.getEndPoint();
if (getConic().isInRegion((P.inhomX + Q.inhomX) / 2.0d,
(P.inhomY + Q.inhomY) / 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = P.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = Q.getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
Log.debug("case 1");
break;
}
Log.debug("case 1");
break;
}
case 2: {
P = segment.getStartPoint();
Q = segment.getEndPoint();
// select intersection point
GeoPoint pnt;
if (intersectPoints[0].isDefined()) {
pnt = intersectPoints[0];
} else if (intersectPoints[1].isDefined()) {
pnt = intersectPoints[1];
} else if (closureIntersect[0].isDefined()) {
pnt = closureIntersect[0];
} else {
pnt = closureIntersect[1];
}
// set output intersect segments
if (!Kernel.isZero(P.distance(pnt))) {
if (getConic().isInRegion((P.inhomX + pnt.inhomX) / 2.0d,
(P.inhomY + pnt.inhomY) / 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = P.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = pnt
.getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
Log.debug("case 2");
break;
}
}
if (!Kernel.isZero(pnt.distance(Q))) {
if (getConic().isInRegion((pnt.inhomX + Q.inhomX) / 2.0d,
(pnt.inhomY + Q.inhomY) / 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = pnt
.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = Q
.getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
Log.debug("case 2");
break;
}
}
Log.debug("case 2");
break;
}
case 3: {
double t1, t2;
int order[] = { 0, 1, 2, 3 };
// select the intersecting points
GeoPoint pnt[] = new GeoPoint[4];
pnt[0] = segment.getStartPoint();
int count = 1;
if (intersectPoints[0].isDefined()) {
pnt[count] = intersectPoints[0];
count++;
}
if (intersectPoints[1].isDefined()) {
pnt[count] = intersectPoints[1];
count++;
}
if (closureIntersect[0].isDefined()) {
pnt[count] = closureIntersect[0];
count++;
}
if (closureIntersect[1].isDefined()) {
pnt[count] = closureIntersect[1];
count++;
}
pnt[3] = segment.getEndPoint();
// sorting intersection points
t1 = segment.getPossibleParameter(pnt[1].getCoords());
t2 = segment.getPossibleParameter(pnt[2].getCoords());
if (t1 > t2) {
double temp = t1;
t1 = t2;
t2 = temp;
int intTemp = order[1];
order[1] = order[2];
order[2] = intTemp;
}
// counting no of output segments and assigning them as output
for (int i = 0; i < 3; i++) {
if (!Kernel.isZero(pnt[order[i]].distance(pnt[order[i + 1]]))) {
if (getConic().isInRegion(
(pnt[order[i]].inhomX + pnt[order[i + 1]].inhomX)
/ 2.0d,
(pnt[order[i]].inhomY + pnt[order[i + 1]].inhomY)
/ 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = pnt[order[i]]
.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = pnt[order[i
+ 1]].getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
}
}
}
Log.debug("case 3");
break;
}
case 4: {
double t1, t2, t3;
int order[] = { 0, 1, 2, 3, 4 };
// select the intersecting points
GeoPoint[] pnt = new GeoPoint[5];
int count = 1;
pnt[0] = segment.getStartPoint();
if (intersectPoints[0].isDefined()) {
pnt[count] = intersectPoints[0];
count++;
}
if (intersectPoints[1].isDefined()) {
pnt[count] = intersectPoints[1];
count++;
}
if (closureIntersect[0].isDefined()) {
pnt[count] = closureIntersect[0];
count++;
}
if (closureIntersect[1].isDefined()) {
pnt[count] = closureIntersect[1];
count++;
}
pnt[4] = segment.getEndPoint();
// sorting intersection points order on input segment starting from
// inputsegment.getStartPoint()
double temp;
t1 = segment.getPossibleParameter(pnt[1].getCoords());
t2 = segment.getPossibleParameter(pnt[2].getCoords());
t3 = segment.getPossibleParameter(pnt[3].getCoords());
int intTemp;
if (t1 > t2) {
temp = t1;
t1 = t2;
t2 = temp;
intTemp = order[1];
order[1] = order[2];
order[2] = intTemp;
}
if (t1 > t3) {
temp = t1;
t1 = t3;
t3 = temp;
intTemp = order[1];
order[1] = order[3];
order[3] = intTemp;
}
if (t2 > t3) {
temp = t2;
t2 = t3;
t3 = temp;
intTemp = order[2];
order[2] = order[3];
order[3] = intTemp;
}
// counting no of output segments and assining them as output
for (int i = 0; i < 4; i++) {
if (!Kernel.isZero(pnt[order[i]].distance(pnt[order[i + 1]]))) {
if (getConic().isInRegion(
(pnt[order[i]].inhomX + pnt[order[i + 1]].inhomX)
/ 2.0d,
(pnt[order[i]].inhomY + pnt[order[i + 1]].inhomY)
/ 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = pnt[order[i]]
.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = pnt[order[i
+ 1]].getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
}
}
}
Log.debug("case 4");
break;
}
case 5: {
double t1, t2, t3, t4, temp;
int[] order = { 0, 1, 2, 3, 4 };
int intTemp;
// get intersect point on segment
GeoPoint[] pnt = { segment.getStartPoint(), intersectPoints[0],
intersectPoints[1], closureIntersect[0],
closureIntersect[1], segment.getEndPoint() };
// sorting intersection points order on input segment starting from
// inputsegment.getStartPoint()
t1 = segment.getPossibleParameter(pnt[1].getCoords());
t2 = segment.getPossibleParameter(pnt[2].getCoords());
t3 = segment.getPossibleParameter(pnt[3].getCoords());
t4 = segment.getPossibleParameter(pnt[4].getCoords());
if (t1 > t2) {
temp = t1;
t1 = t2;
t2 = temp;
intTemp = order[1];
order[1] = order[2];
order[2] = intTemp;
}
if (t1 > t3) {
temp = t1;
t1 = t3;
t3 = temp;
intTemp = order[1];
order[1] = order[3];
order[3] = intTemp;
}
if (t1 > t4) {
temp = t1;
t1 = t4;
t4 = temp;
intTemp = order[1];
order[1] = order[4];
order[4] = intTemp;
}
if (t2 > t3) {
temp = t2;
t2 = t3;
t3 = temp;
intTemp = order[2];
order[2] = order[3];
order[3] = intTemp;
}
if (t2 > t4) {
temp = t2;
t2 = t4;
t4 = temp;
intTemp = order[2];
order[2] = order[4];
order[4] = intTemp;
}
if (t3 > t4) {
temp = t3;
t3 = t4;
t4 = temp;
intTemp = order[3];
order[3] = order[4];
order[4] = intTemp;
}
// counting no of output segments and assining them as output
for (int i = 0; i < 4; i++) {
if (!Kernel.isZero(pnt[order[i]].distance(pnt[order[i + 1]]))) {
if (getConic().isInRegion(
(pnt[order[i]].inhomX + pnt[order[i + 1]].inhomX)
/ 2.0d,
(pnt[order[i]].inhomY + pnt[order[i + 1]].inhomY)
/ 2.0d)) {
cd.intersectPathCoords[intersectPathIndex] = pnt[order[i]]
.getCoords();
cd.intersectPathCoords[++intersectPathIndex] = pnt[order[i
+ 1]].getCoords();
intersectPathIndex++;
cd.intersectPathcount++;
}
}
}
Log.debug("case 5");
break;
}
default: {
// outputSegments.adjustOutputSize(1, false);
// outputSegments.getElement(0).setUndefined();
Log.debug("case default-no intersectPaths");
}
}
numOfOutputSegments += cd.intersectPathcount;
intersectPaths.add(cd);
}
/**
* initialize Elements. CreateOutput is called inside
*/
protected void initElements() {
numOfOutputSegments = 0;
polyPointCount = (getPoly().getPoints()).length;
segCountOfPoly = isPolyClosed() ? polyPointCount : polyPointCount - 1;
outputSegments = createOutputSegments();
intersectPaths = new ArrayList<CalcDetails>();
tempSegEndPoints = new GeoPoint[2];
intersectPoints = new GeoPoint[2];
endPoints = new GeoPoint[2];
closureSegments = new GeoSegment[2];
closureIntersect = new GeoPoint[2];
for (int i = 0; i < tempSegEndPoints.length; i++) {
tempSegEndPoints[i] = new GeoPoint(getConstruction());
intersectPoints[i] = new GeoPoint(getConstruction());
endPoints[i] = new GeoPoint(getConstruction());
closureSegments[i] = new GeoSegment(getConstruction());
closureIntersect[i] = new GeoPoint(getConstruction());
}
tempSeg = new GeoSegment(getConstruction());
midPoint = new GeoPoint(getConstruction());
}
/**
* sets the labels of the output segments
*
* @param labels
* String[]
*/
protected void setLabels(String[] labels) {
if (labels != null && labels.length == 1 && outputSegments.size() > 1
&& labels[0] != null && !labels[0].equals("")) {
outputSegments.setIndexLabels(labels[0]);
} else {
outputSegments.setLabels(labels);
}
}
/**
* create the necessary output handlers
*
* @return OutputHandler<GeoSegment>
*/
protected OutputHandler<GeoSegment> createOutputSegments() {
return new OutputHandler<GeoSegment>(new elementFactory<GeoSegment>() {
@Override
public GeoSegment newElement() {
GeoSegment a = new GeoSegment(cons);
GeoPoint aS = new GeoPoint(cons);
aS.setCoords(0, 0, 1);
GeoPoint aE = new GeoPoint(cons);
aE.setCoords(0, 0, 1);
a.setPoints(aS, aE);
a.setParentAlgorithm(AlgoIntersectPolyLineConicRegion.this);
setSegmentVisualProperties(a);
return a;
}
});
}
/**
* set visual style for new segments
*
* @param segment
* GeoElement segment
*/
public void setSegmentVisualProperties(GeoElement segment) {
if (outputSegments.size() > 0) {
GeoElement seg0 = outputSegments.getElement(0);
segment.setAllVisualProperties(seg0, false);
segment.setViewFlags(seg0.getViewSet());
segment.setVisibleInView3D(seg0);
}
}
@Override
public GeoPoint[] getIntersectionPoints() {
// TODO Auto-generated method stub
return null;
}
@Override
protected GeoPoint[] getLastDefinedIntersectionPoints() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = (GeoElement) getPoly();
input[1] = getConic();
}
@Override
public GetCommand getClassName() {
return Commands.IntersectPath;
}
/**
* getter of input conic
*
* @return GeoConic
*/
public GeoConic getConic() {
return this.conic;
}
/**
* getter of input poly
*
* @return GeoPoly
*/
public GeoPoly getPoly() {
return this.poly;
}
/**
* Returns number of intersection path segments
*
* @return int
*/
public int getOutputSize() {
return this.numOfOutputSegments;
}
/**
* Returns whether the poly closed or not
*
* @return boolean
*/
public boolean isPolyClosed() {
return this.polyClosed;
}
/**
* helping class for keeping calculated records
*
* @author thilina
*/
private static class CalcDetails {
int segmentIndex, intersectPathcount;
Coords[] intersectPathCoords;
public CalcDetails() {
segmentIndex = -1;
intersectPathcount = 0;
intersectPathCoords = new Coords[4];
}
}
}