/*
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.
*/
/*
* AlgoIntersectLines.java
*
* Created on 30. August 2001, 21:37
*/
package org.geogebra.common.geogebra3D.kernel3D.algos;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPlane3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolygon3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolyhedron;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoSegment3D;
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.GeoElement;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
/**
* Algo for intersection of a plane with a polyhedron, outputs polygons
*
* @author matthieu
*/
public class AlgoIntersectRegionPlanePolyhedron
extends AlgoIntersectPathPlanePolygon3D {
private GeoPolyhedron polyhedron;
private OutputHandler<GeoPolygon3D> outputPolygons;
private OutputHandler<GeoPoint3D> outputPoints;
/** output segments for polyhedron */
protected OutputHandler<GeoSegment3D> outputSegmentsPolyhedron;
private boolean hasLabels = false;
/**
* class extending Coords with reference to parent geo
*
*/
private static class CoordsWithParent extends Coords
implements Comparable<CoordsWithParent> {
protected GeoElementND parent;
private Double parameter;
public CoordsWithParent(Double parameter, Coords v,
GeoElementND parent) {
super(v);
this.parent = parent;
this.parameter = parameter;
}
@Override
public int compareTo(CoordsWithParent o) {
// first compare parameters
if (Kernel.isGreater(parameter, o.parameter)) {
return 1;
}
if (Kernel.isGreater(o.parameter, parameter)) {
return -1;
}
// if same parameter, compare parents
return compareParentTo(o);
}
@Override
public boolean equals(Object o) {
if (o instanceof CoordsWithParent) {
return compareTo((CoordsWithParent) o) == 0;
}
return false;
}
@Override
public int hashCode() {
return Double.hashCode(parameter) ^ parent.hashCode();
}
/**
* compare parent to o
*
* @param o
* other coords
* @return comparison result
*/
public int compareParentTo(CoordsWithParent o) {
return parent.toGeoElement().compareTo(o.parent.toGeoElement());
}
}
private TreeSet<GeoPolygon> getPolygons(CoordsWithParent coords) {
return parentToPolygons.get(coords.parent);
}
/**
* coords for each face
*/
protected TreeSet<CoordsWithParent> newCoords;
/**
* bi-point for each intersection segment
*
*/
private static class Segment {
protected CoordsWithParent p1, p2;
public Segment(CoordsWithParent p1, CoordsWithParent p2) {
this.p1 = p1;
this.p2 = p2;
}
}
/**
* List of coords than can be compared
*
* @author mathieu
*
*/
@SuppressWarnings("serial")
private static class Vertices extends ArrayList<Coords>
implements Comparable<Vertices> {
// index for the lowest vertex
private int lowest = -1;
// direction for neighbor
private short direction = 0;
// index for currently looked (see next() method)
private int current;
protected Vertices() {
// avoid synth access error
}
@Override
public boolean add(Coords e) {
if (lowest == -1) { // no lowest element for now
lowest = 0; // first element is the lowest
} else {
if (COORDS_COMPARATOR.compare(e, get(lowest)) < 0) {
lowest = size();
}
}
return super.add(e);
}
/**
* find direction from lowest to lowest neighbor
*/
public void setDirection() {
int n1 = lowest - 1;
int n2 = lowest + 1;
if (n1 < 0) {
n1 = size() - 1;
} else if (n2 >= size()) {
n2 = 0;
}
if (COORDS_COMPARATOR.compare(get(n1), get(n2)) < 0) {
direction = -1;
} else {
direction = 1;
}
}
/**
* Set current index to next element
*
* @return next element regarding direction
*/
private Coords next() {
current += direction;
if (current >= size()) {
current = 0;
} else if (current < 0) {
current = size() - 1;
}
return get(current);
}
private void start() {
current = lowest;
}
@Override
public int compareTo(Vertices o) {
// first compare sizes
if (this.size() < o.size()) {
return -1;
}
if (o.size() < this.size()) {
return 1;
}
// compare lowest coords
if (COORDS_COMPARATOR.compare(get(lowest), o.get(o.lowest)) < 0) {
return -1;
}
if (COORDS_COMPARATOR.compare(get(lowest), o.get(o.lowest)) > 0) {
return 1;
}
// compare neighbors
start();
o.start();
int visited = 0;
while (visited < size()) {
Coords thisCoords = next();
Coords oCoords = o.next();
if (COORDS_COMPARATOR.compare(thisCoords, oCoords) < 0) {
return -1;
}
if (COORDS_COMPARATOR.compare(thisCoords, oCoords) > 0) {
return 1;
}
visited++;
}
// equal
return 0;
}
}
/**
* common constructor
*
* @param c
* @param plane
* plane
* @param p
* polyhedron
*/
public AlgoIntersectRegionPlanePolyhedron(Construction c, GeoPlane3D plane,
GeoPolyhedron p) {
this(c, plane, p, false);
}
private AlgoIntersectRegionPlanePolyhedron(Construction c, GeoPlane3D plane,
GeoPolyhedron p, boolean hasLabels) {
super(c);
this.hasLabels = hasLabels;
setFirstInput(plane);
setSecondInput(p);
createOutput();
setInputOutput(); // for AlgoElement
}
/**
* common constructor
*
* @param c
* @param labels
* @param plane
* plane
* @param p
* polyhedron
* @param outputSizes
* output sizes
*/
public AlgoIntersectRegionPlanePolyhedron(Construction c, String[] labels,
GeoPlane3D plane, GeoPolyhedron p, int[] outputSizes) {
this(c, plane, p, true);
// set labels
if (labels == null) {
outputPolygons.setLabels(null);
outputPoints.setLabels(null);
outputSegmentsPolyhedron.setLabels(null);
} else {
int labelsLength = labels.length;
if (labelsLength > 1) {
// Log.debug("\nici :
// "+outputSizes[0]+","+outputSizes[1]+","+outputSizes[2]);
if (outputSizes != null) {
// set output sizes
outputPolygons.adjustOutputSize(outputSizes[0], false);
outputPoints.adjustOutputSize(outputSizes[1], false);
outputSegmentsPolyhedron.adjustOutputSize(outputSizes[2],
false);
// set labels
int i1 = 0;
int i2 = 0;
while (i1 < outputSizes[0]) {
outputPolygons.getElement(i1).setLabel(labels[i2]);
i1++;
i2++;
}
i1 = 0;
while (i1 < outputSizes[1]) {
outputPoints.getElement(i1).setLabel(labels[i2]);
i1++;
i2++;
}
i1 = 0;
while (i1 < outputSizes[2]) {
outputSegmentsPolyhedron.getElement(i1)
.setLabel(labels[i2]);
i1++;
i2++;
}
} else {
// set default
outputPolygons.setLabels(null);
outputSegmentsPolyhedron.setLabels(null);
outputPoints.setLabels(null);
}
} else if (labelsLength == 1) {
outputPolygons.setIndexLabels(labels[0]);
}
}
update();
}
@Override
protected void setSecondInput(GeoElement geo) {
this.polyhedron = (GeoPolyhedron) geo;
}
@Override
protected GeoElement getSecondInput() {
return polyhedron;
}
/**
* set for all intersection points coords. Used for intersections equal to
* just one point.
*/
private TreeSet<Coords> polyhedronVertices;
/**
* map from intersection parents to set of polygons
*/
private TreeMap<GeoElementND, TreeSet<GeoPolygon>> parentToPolygons;
@Override
protected void addCoords(double parameter, Coords coords,
GeoElementND parent) {
Coords c = coords.copyVector();
newCoords.add(new CoordsWithParent(parameter, c, parent));
if (parent instanceof GeoPointND) {
// boolean b=
polyhedronVertices.add(c);
// Log.debug("\nb: "+b+"\nparent: "+parent+"\ncoords:\n"+coords);
}
}
private TreeMap<GeoPolygon, ArrayList<Segment>> newCoordsList;
@Override
protected void setNewCoords() {
if (newCoordsList == null) {
newCoordsList = new TreeMap<GeoPolygon, ArrayList<Segment>>();
} else {
newCoordsList.clear();
}
if (parentToPolygons == null) {
parentToPolygons = new TreeMap<GeoElementND, TreeSet<GeoPolygon>>();
} else {
parentToPolygons.clear();
}
// for polyhedron vertices
if (polyhedronVertices == null) {
polyhedronVertices = new TreeSet<Coords>(COORDS_COMPARATOR);
} else {
polyhedronVertices.clear();
}
/*
* if (originalEdges==null) originalEdges = new TreeMap<GeoElement,
* TreeMap<GeoElement,Segment>>(); else originalEdges.clear();
*/
for (GeoPolygon polygon : polyhedron.getPolygons()) {
p = polygon;
setNewCoordsList();
}
for (GeoPolygon polygon : polyhedron.getPolygonsLinked()) {
p = polygon;
setNewCoordsList();
}
}
private void setNewCoordsList() {
// check if the polygon is defined (e.g. when regular polygon as pyramid
// bottom)
if (!p.isDefined()) {
return;
}
// line origin and direction
setIntersectionLine();
// check if polygon is included in the plane
if (d1.isZero() && !(Kernel.isZero(o1.getW()))) {// then include all
// edges of the
// polygon
GeoPointND[] points = p.getPointsND();
Vertices vertices = new Vertices();
for (GeoPointND point : points) {
vertices.add(point.getInhomCoordsInD3());
}
vertices.setDirection();
// add to specific list to be added later
polyhedronFaces.add(vertices);
/*
* //check if this list has not already be computed
* if(checkVerticesList.add(vertices)){ addToVerticesList(vertices);
* }
*/
/*
* segmentCoords = new ArrayList<Segment>(); GeoPointND p2 =
* points[0]; for (int i = 0; i<points.length; i++){ GeoPointND p1 =
* p2; p2 = points[(i+1)%(points.length)];
*
* segmentCoords.add(new Segment( new CoordsWithParent((double) i,
* p1.getInhomCoordsInD3(), p1), new CoordsWithParent((double) i+1,
* p2.getInhomCoordsInD3(), p2)));
*
* newCoordsList.put(p, segmentCoords); //Log.debug(
* "\npoly (included):"
* +p+"\nsegmentCoords.size():"+segmentCoords.size()); }
*/
} else {// regular case: polygon not included in plane
// fill a new points map
if (newCoords == null) {
newCoords = new TreeSet<CoordsWithParent>();
} else {
newCoords.clear();
}
// add intersection coords
intersectionsCoords(p);
// add polygon points
addPolygonPoints();
if (newCoords.size() > 1) { // save it only if at least two points
segmentCoords = getSegmentsCoords();
// add (polygon,segments) to newCoordsList
if (segmentCoords.size() > 0) {
newCoordsList.put(p, segmentCoords);
// Log.debug("\npoly:"+p+"\nnewCoords.size():"+newCoords.size()+"\nsegmentCoords.size():"+segmentCoords.size());
}
}
}
}
/*
* segments equal to original edges
*/
// private TreeMap<GeoElement,TreeMap<GeoElement,Segment>> originalEdges;
private ArrayList<Segment> getSegmentsCoords() {
ArrayList<Segment> ret = new ArrayList<Segment>();
Iterator<CoordsWithParent> it = newCoords.iterator();
CoordsWithParent b = it.next();
// use start/end of segment to merge following segments
CoordsWithParent startSegment = null;
CoordsWithParent endSegment = null;
while (it.hasNext()) {
CoordsWithParent a = b;
b = it.next();
// check if the segment is included in the polygon: check the
// midpoint
if (checkMidpoint(p, a, b)) {
if (startSegment == null)
{
startSegment = a; // new start segment
}
endSegment = b; // extend segment to b
} else {
if (startSegment != null) {// add last correct segment
addSegment(startSegment, endSegment, ret);
startSegment = null;
}
}
}
if (startSegment != null) {
addSegment(startSegment, endSegment, ret);
}
return ret;
}
private void addSegment(CoordsWithParent startSegment,
CoordsWithParent endSegment, ArrayList<Segment> segmentList) {
// add new segment to list
segmentList.add(new Segment(startSegment, endSegment));
// add map parent to polygon
addParentToPolygons(startSegment.parent);
addParentToPolygons(endSegment.parent);
}
private void addParentToPolygons(GeoElementND parent) {
TreeSet<GeoPolygon> polygons = parentToPolygons.get(parent);
if (polygons == null) {
polygons = new TreeSet<GeoPolygon>();
parentToPolygons.put(parent, polygons);
}
polygons.add(p);
}
@SuppressWarnings("serial")
private static class VerticesList extends ArrayList<ArrayList<Coords>> {
protected int cumulateSize = 0;
protected VerticesList() {
// avoid synth access error
}
@Override
public boolean add(ArrayList<Coords> vertices) {
cumulateSize += vertices.size();
return super.add(vertices);
}
@Override
public void clear() {
cumulateSize = 0;
super.clear();
}
}
private VerticesList verticesList;
private ArrayList<Vertices> polyhedronFaces;
private TreeSet<Vertices> checkVerticesList;
private ArrayList<Segment> segmentCoords;
/**
* find next vertex linking the start point of the polygon with new
* intersection segment
*
* @param p2
* @param startPoint
* @param oldPoint
* vertex before startPoint
* @return next vertex
*/
private CoordsWithParent nextVertex(GeoPolygon p2,
CoordsWithParent startPoint, GeoElementND oldPoint) {
// get intersection segments coords for this polygon
segmentCoords = newCoordsList.get(p2);
CoordsWithParent a;
CoordsWithParent b = null;
// Log.debug("\nstart parent:"+startPoint.parent+"\nold
// parent:"+oldPoint.parent);
// check if for a segment, one of the vertex as same parent as starting
// vertex
// then take the second point as next vertex
boolean notFound = true;
int i;
for (i = 0; i < segmentCoords.size() && notFound; i++) {
Segment segment = segmentCoords.get(i);
a = segment.p1;
if (a.parent == startPoint.parent) {
b = segment.p2;
// Log.debug("\ni:"+i+"\na:"+a.parent+"\nb:"+b.parent);
if (b.parent != oldPoint) { // prevent immediate return
notFound = false;
}
} else {
b = a;
a = segment.p2;
if (a.parent == startPoint.parent) {
// Log.debug("\ni:"+i+"\na:"+a.parent+"\nb:"+b.parent);
if (b.parent != oldPoint) { // prevent immediate return
notFound = false;
}
}
}
}
if (notFound) {
b = null;
} else {
// remove the segment found: not usable anymore
// removeSegmentCoords(i-1,p2);
removeSegmentCoordsIndex = i - 1;
removeSegmentCoordsPolygon = p2;
}
return b;
}
private int removeSegmentCoordsIndex;
private GeoPolygon removeSegmentCoordsPolygon;
private void removeSegmentCoords() {
removeSegmentCoords(removeSegmentCoordsIndex,
removeSegmentCoordsPolygon);
}
private void removeSegmentCoords(int index, GeoPolygon p2) {
segmentCoords.remove(index);
// Log.debug("\np2:"+p2+"\nsize="+segmentCoords.size());
if (segmentCoords.size() == 0) {
newCoordsList.remove(p2);
}
}
/**
* find next vertex linking a vertex of the polyhedron to next segment
*
* @param startPoint
* start vertex
* @param oldParent
* vertex before startPoint
* @return next vertex
*/
private CoordsWithParent nextVertex(CoordsWithParent startPoint,
GeoElementND oldParent, GeoElementND firstParent) {
CoordsWithParent b;
CoordsWithParent bFirstPoint = null;
GeoPolygon pFirstPoint = null;
int indexFirstPoint = 0;
// 1) try keep same poly (interior point)
if (newCoordsList.containsKey(p)) {
b = nextVertex(p, startPoint, oldParent);
if (b != null) {
if (b.parent == firstParent) { // we may try another face to get
// greater polygon
bFirstPoint = b;
pFirstPoint = p;
indexFirstPoint = removeSegmentCoordsIndex;
} else {
// Log.debug("same: "+startPoint.parent+" -- "+oldParent+" :
// "+b);
removeSegmentCoords();
return b;
}
}
}
// 2) try other polygons
TreeSet<GeoPolygon> polySet = getPolygons(startPoint);
Iterator<GeoPolygon> it = polySet.iterator();
GeoPolygon p2 = null;
while (it.hasNext()) {
p2 = it.next();
// Log.debug("\np2:"+p2+"\np2==p:"+(p2==p)+"\nkey:"+newCoordsList.containsKey(p2));
// find other polygon, contained as a key
if (p2 != p && newCoordsList.containsKey(p2)) {
// Log.debug("\npoly2:"+p2);
// try to find next vertex
b = nextVertex(p2, startPoint, oldParent);
if (b != null) { // if found
if (b.parent == firstParent) { // we may try another face to
// get greater polygon
bFirstPoint = b;
pFirstPoint = p2;
indexFirstPoint = removeSegmentCoordsIndex;
} else { // this one is ok
p = p2;
removeSegmentCoords();
// Log.debug("other: "+firstParent+" -- "+b.parent);
return b;
}
}
}
}
// 3) return same as first point
if (bFirstPoint != null) {
removeSegmentCoords(indexFirstPoint, pFirstPoint);
p = pFirstPoint;
return bFirstPoint;
}
// 4) return null: no next vertex
return null;
}
/**
* Add vertices from one to the next
*
* @return vertices list
*/
private Vertices addVertices() {
Vertices vertices = new Vertices();
// take first segment for the face p
segmentCoords = newCoordsList.get(p);
if (segmentCoords.isEmpty()) {
// may occur when the plane goes through some edge
newCoordsList.remove(p);
return null;
}
// start with first point of the segment
CoordsWithParent firstPoint = segmentCoords.get(0).p1;
CoordsWithParent startPoint = segmentCoords.get(0).p2;
removeSegmentCoords(0, p);
vertices.add(firstPoint);
// Log.debug("\na.parent:"+firstPoint.parent);//Log.debug("\n\n\n\n\n");
// Log.debug("\nb.parent:"+startPoint.parent+"\npoly:"+p);//Log.debug("\n\n\n\n\n");
// at first oldParent is null, so polygons A-B-A are possible
GeoElementND oldParent = null;
while (startPoint.parent != firstPoint.parent) {
vertices.add(startPoint);
CoordsWithParent c = nextVertex(startPoint, oldParent,
firstPoint.parent);
if (c == null) {
return null;
}
oldParent = startPoint.parent;
startPoint = c;
// Log.debug("\nb.parent:"+startPoint.parent+"\npoly:"+p);//Log.debug("\n\n\n\n\n");
}
return vertices;
}
/**
* set polyhedron vertices as dummy polygons output
*
* @param indexPolygon0
* start index for polygons
* @param indexPoint0
* start index for points
* @param indexSegment
* start index for segments
*/
private void addPolyhedronVerticesToOutput(int indexPolygon0,
int indexPoint0, int indexSegment0) {
int indexPolygon = indexPolygon0;
int indexSegment = indexSegment0;
int indexPoint = indexPoint0;
for (Coords coords : polyhedronVertices) {
GeoPolygon outputPoly = outputPolygons.getElement(indexPolygon);
GeoPoint3D point = outputPoints.getElement(indexPoint);
point.setCoords(coords);
GeoSegment3D seg = outputSegmentsPolyhedron
.getElement(indexSegment);
seg.modifyInputPolyAndPoints(outputPoly, point, point);
outputPoly.setPoints(new GeoPoint3D[] { point, point }, null,
false); // don't
// create
// segments
outputPoly.setSegments(new GeoSegment3D[] { seg, seg });
outputPoly.calcArea();
indexPolygon++;
indexPoint++;
indexSegment++;
}
}
private void addToVerticesList(Vertices vertices) {
verticesList.add(vertices);
// remove polyhedron vertices for empty polygons for these points,
// since these points are already on a polygon
if (polyhedronVertices.size() > 0) {
for (Coords coords : vertices) {
polyhedronVertices.remove(coords);
}
}
}
private void updateLabels(
@SuppressWarnings("rawtypes") OutputHandler outputHandler) {
if (hasLabels) {
outputHandler.updateLabels();
}
}
@Override
public void compute() {
// set intersection vertices
// (set it here since maybe some faces are included in the plane)
if (verticesList == null) {
verticesList = new VerticesList();
} else {
verticesList.clear();
}
if (checkVerticesList == null) {
checkVerticesList = new TreeSet<Vertices>();
} else {
checkVerticesList.clear();
}
if (polyhedronFaces == null) {
polyhedronFaces = new ArrayList<Vertices>();
} else {
polyhedronFaces.clear();
}
// set the point map
setNewCoords();
// Log.debug("\noriginalEdges:"+originalEdges);
/*
* for (GeoElementND parent : parentToPolygons.keySet()){ Log.debug(
* "\nparent: " +parent+"\npolygons: "+parentToPolygons.get(parent)); }
*/
// Log.debug(polyhedronVertices);
// set output
if (newCoordsList.size() == 0 && polyhedronFaces.size() == 0) { // no
// intersection,
// no
// face
// contained
// set points, segments and polygons equal to intersection with
// polyhedron vertices
outputPolygons.adjustOutputSize(polyhedronVertices.size(), false);
outputPoints.adjustOutputSize(polyhedronVertices.size(), false);
outputSegmentsPolyhedron.adjustOutputSize(polyhedronVertices.size(),
false);
addPolyhedronVerticesToOutput(0, 0, 0);
} else {
// start with one face, set a polygon, then get a new face, etc.
while (newCoordsList.size() != 0) {
// Log.debug(""+newCoordsList.keySet());
p = newCoordsList.firstKey();
Vertices vertices = addVertices();
if (vertices != null) { // prevent not matching search
vertices.setDirection();
// check if this list has not already be computed
if (checkVerticesList.add(vertices)) {
addToVerticesList(vertices);
}
}
}
// add polyhedron faces contained in the plane
for (Vertices vertices : polyhedronFaces) {
// check if this list has not already be computed
if (checkVerticesList.add(vertices)) {
addToVerticesList(vertices);
}
}
// Log.debug(newCoordsList.keySet());
// set output points
outputPoints.adjustOutputSize(
verticesList.cumulateSize + polyhedronVertices.size(),
false);
updateLabels(outputPoints);
int segmentIndex = 0;
for (ArrayList<Coords> vertices : verticesList) {
int length = vertices.size();
for (int i = 0; i < length; i++) {
GeoPoint3D point = outputPoints.getElement(segmentIndex);
point.setCoords(vertices.get(i));
segmentIndex++;
}
}
// adjust output polygons size
outputPolygons.adjustOutputSize(
verticesList.size() + polyhedronVertices.size(), false);
updateLabels(outputPolygons);
// get points list
GeoPoint3D[] points = new GeoPoint3D[verticesList.cumulateSize];
points = outputPoints.getOutput(points);
// set output segments and polygons
outputSegmentsPolyhedron.adjustOutputSize(
verticesList.cumulateSize + polyhedronVertices.size(),
false);
updateLabels(outputSegmentsPolyhedron);
int pointIndex = 0;
int polygonIndex = 0;
segmentIndex = 0;
for (ArrayList<Coords> vertices : verticesList) {
int length = vertices.size();
// Log.debug("polygonIndex: "+polygonIndex);
GeoPolygon outputPoly = outputPolygons.getElement(polygonIndex);
GeoPoint3D[] polyPoints = new GeoPoint3D[length];
GeoSegment3D[] polySegments = new GeoSegment3D[length];
for (int i = 0; i < length; i++) {
// Log.debug(points[polygonOffset + i]);
outputSegmentsPolyhedron.getElement(segmentIndex)
.modifyInputPolyAndPoints(outputPoly,
points[pointIndex + i],
points[pointIndex + (i + 1) % length]);
polyPoints[i] = points[pointIndex + i];
polySegments[i] = outputSegmentsPolyhedron
.getElement(segmentIndex);
segmentIndex++;
}
// update polygon
outputPoly.setPoints(polyPoints, null, false); // don't create
// segments
outputPoly.setSegments(polySegments);
outputPoly.calcArea();
pointIndex += length;
polygonIndex++;
}
// add isolate polyhedron vertices
addPolyhedronVerticesToOutput(polygonIndex, pointIndex,
segmentIndex);
}
}
@Override
protected boolean checkParameter(double t1) {
return true; // nothing to check here
}
@Override
public final Commands getClassName() {
return Commands.IntersectPath;
}
private final void createOutput() {
outputPolygons = new OutputHandler<GeoPolygon3D>(
new elementFactory<GeoPolygon3D>() {
@Override
public GeoPolygon3D newElement() {
GeoPolygon3D p1 = new GeoPolygon3D(cons, true);
p1.setParentAlgorithm(
AlgoIntersectRegionPlanePolyhedron.this);
if (outputPolygons.size() > 0) {
p1.setAllVisualProperties(
outputPolygons.getElement(0), false);
}
p1.setViewFlags(getFirstInput().getViewSet());
p1.setVisibleInView3D(getFirstInput());
p1.setVisibleInViewForPlane(getFirstInput());
p1.setNotFixedPointsLength(true);
p1.setOrthoNormalRegionCS();
if (hasLabels) {
p1.setInitLabelsCalled(true);
}
return p1;
}
});
outputPolygons.adjustOutputSize(1, false);
outputPoints = new OutputHandler<GeoPoint3D>(
new elementFactory<GeoPoint3D>() {
@Override
public GeoPoint3D newElement() {
GeoPoint3D newPoint = new GeoPoint3D(cons);
newPoint.setCoords(0, 0, 0, 1);
newPoint.setParentAlgorithm(
AlgoIntersectRegionPlanePolyhedron.this);
newPoint.setAuxiliaryObject(true);
newPoint.setViewFlags(getFirstInput().getViewSet());
newPoint.setVisibleInView3D(getFirstInput());
newPoint.setVisibleInViewForPlane(getFirstInput());
int size = outputPoints.size();
if (size > 0) { // check if at least one element is
// visible
boolean visible = false;
boolean labelVisible = false;
for (int i = 0; i < size && !visible
&& !labelVisible; i++) {
visible = visible || outputPoints.getElement(i)
.isEuclidianVisible();
labelVisible = labelVisible || outputPoints
.getElement(i).getLabelVisible();
}
newPoint.setEuclidianVisible(visible);
if (!visible) { // if not visible, we don't want
// setParentAlgorithm() to change it
newPoint.dontSetEuclidianVisibleBySetParentAlgorithm();
}
newPoint.setLabelVisible(labelVisible);
}
if (outputPolygons.size() > 0) {
GeoPolygon polygon = outputPolygons.getElement(0);
if (polygon.getShowObjectCondition() != null) {
try {
newPoint.setShowObjectCondition(
polygon.getShowObjectCondition());
} catch (Exception e) {
// circular definition
}
}
}
return newPoint;
}
});
outputPoints.adjustOutputSize(1, false);
outputSegmentsPolyhedron = // createOutputSegments();
new OutputHandler<GeoSegment3D>(
new elementFactory<GeoSegment3D>() {
@Override
public GeoSegment3D newElement() {
GeoSegment3D segment = (GeoSegment3D) outputPolygons
.getElement(0).createSegment(cons,
outputPoints.getElement(0),
outputPoints.getElement(0),
true);
segment.setAuxiliaryObject(true);
// segment.setLabelVisible(showNewSegmentsLabels);
segment.setViewFlags(
getFirstInput().getViewSet());
segment.setVisibleInView3D(getFirstInput());
segment.setVisibleInViewForPlane(
getFirstInput());
return segment;
}
});
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = getFirstInput();
input[1] = getSecondInput();
// set dependencies
for (int i = 0; i < input.length; i++) {
input[i].addAlgorithm(this);
}
cons.addToAlgorithmList(this);
}
@Override
protected void getCmdOutputXML(StringBuilder sb, StringTemplate tpl) {
// add output sizes (polygons, points, segments)
sb.append("\t<outputSizes val=\"");
sb.append(outputPolygons.size());
sb.append(",");
sb.append(outputPoints.size());
sb.append(",");
sb.append(outputSegmentsPolyhedron.size());
sb.append("\"");
sb.append("/>\n");
// common method
super.getCmdOutputXML(sb, tpl);
}
@Override
public String toString(StringTemplate tpl) {
return getLoc().getPlain("IntersectionOfAandB",
getFirstInput().getLabel(tpl), getSecondInput().getLabel(tpl));
}
/**
* comparator using Kernel precision (compare x, then y, then z, then ...)
*/
public static final Comparator<Coords> COORDS_COMPARATOR = new Comparator<Coords>() {
@Override
public int compare(Coords o1, Coords o) {
// 1) check vectors lengths
if (o1.val.length < o.val.length) {
return -1;
}
if (o1.val.length > o.val.length) {
return 1;
}
// 2) check if one value is lower
for (int i = 0; i < o1.val.length; i++) {
if (Kernel.isGreater(o.val[i], o1.val[i])) {
return -1;
}
if (Kernel.isGreater(o1.val[i], o.val[i])) {
return 1;
}
}
// 3) vectors are equal
return 0;
}
};
}