package org.geogebra.common.geogebra3D.kernel3D.algos;
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.GeoPolyhedronNet;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoSegment3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
/**
* Algo that compute the net for a polyhedron
*
* @author Vincent
*
*/
public class AlgoPolyhedronNetPyramid extends AlgoPolyhedronNet {
/**
* @param c
* construction
* @param labels
* labels
* @param p
* polyhedron
* @param v
* index
*/
public AlgoPolyhedronNetPyramid(Construction c, String[] labels,
GeoPolyhedron p, NumberValue v) {
super(c, labels, p, v);
}
@Override
protected int getPointLengthFromLabelsLength(int length) {
return (length - 2) / 6;
}
@Override
protected void createNet(int n) {
GeoPolyhedronNet net = getNet();
// create bottom face
outputPointsBottom.adjustOutputSize(n, false);
outputPointsSide.adjustOutputSize(n, false);
net.startNewFace();
for (int i = 0; i < n; i++) {
net.addPointToCurrentFace(outputPointsBottom.getElement(i));
}
net.endCurrentFace();
// create side faces
for (int i = 0; i < n; i++) {
createSideFace(net, i, n);
}
}
private void createSideFace(GeoPolyhedronNet net, int index,
int newBottomPointsLength) {
net.startNewFace();
net.addPointToCurrentFace(outputPointsBottom.getElement(index));
net.addPointToCurrentFace(outputPointsBottom
.getElement((index + 1) % newBottomPointsLength));
net.addPointToCurrentFace(outputPointsSide.getElement(index));
net.endCurrentFace();
}
@Override
protected void setOutputSideTop(int n, GeoPolygon3D polygon, int step,
GeoSegmentND[] segments) {
setOutputSide(polygon);
}
private void setOutputSide(GeoPolygon3D polygon) {
outputPolygonsSide.addOutput(polygon, false);
outputSegmentsSide.addOutput((GeoSegment3D) polygon.getSegments()[2],
false);
outputSegmentsSide.addOutput((GeoSegment3D) polygon.getSegments()[1],
false);
}
@Override
protected void adjustOutputSize(int newBottomPointsLength) {
adjustOutputSize(newBottomPointsLength, true);
}
@Override
protected void adjustOutputSize(int newBottomPointsLength,
boolean setLabels) {
super.adjustOutputSize(newBottomPointsLength);
// current length
int nOld = outputPointsSide.size();
// update existing segments / sides
if (newBottomPointsLength > bottomPointsLength) {
for (int i = bottomPointsLength; i < newBottomPointsLength
&& i <= nOld; i++) {
// update bottom segments
GeoSegmentND segmentBottom = outputSegmentsBottom
.getElement(i - 1);
segmentBottom.modifyInputPoints(
outputPointsBottom.getElement(i - 1),
outputPointsBottom.getElement(i));
}
for (int i = bottomPointsLength - 1; i < newBottomPointsLength
&& i < nOld; i++) {
// update last sides
updateSide(i, newBottomPointsLength);
}
}
// create sides if needed
if (newBottomPointsLength > nOld) {
// update side points
outputPointsSide.adjustOutputSize(newBottomPointsLength, false);
if (setLabels) {
outputPointsSide.setLabels(null);
}
// create new sides
GeoPolyhedronNet net = getNet();
for (int i = nOld; i < newBottomPointsLength; i++) {
createSideFace(net, i, newBottomPointsLength);
GeoPolygon3D polygon = net.createPolygon(i + 1); // +1 shift
// since
// bottom is
// face #0
setOutputSide(polygon);
outputSegmentsBottom.addOutput(
(GeoSegment3D) polygon.getSegments()[0], false); // add
// segment
// to
// bottom
// list
// now
}
if (setLabels) {
outputSegmentsBottom.setLabels(null);
outputSegmentsSide.setLabels(null);
outputPolygonsSide.setLabels(null);
}
refreshOutput();
}
// updates
if (newBottomPointsLength > bottomPointsLength) {
// update bottom
updateBottom(newBottomPointsLength);
} else if (newBottomPointsLength < bottomPointsLength) {
// update side points
for (int i = newBottomPointsLength; i < bottomPointsLength; i++) {
outputPointsSide.getElement(i).setUndefined();
outputPointsBottom.getElement(i).setUndefined();
}
// update bottom segment
GeoSegmentND segmentBottom = outputSegmentsBottom
.getElement(newBottomPointsLength - 1);
segmentBottom.modifyInputPoints(
outputPointsBottom.getElement(newBottomPointsLength - 1),
outputPointsBottom.getElement(0));
// update bottom face
updateBottom(newBottomPointsLength);
// update last side
updateSide(newBottomPointsLength - 1, newBottomPointsLength);
}
bottomPointsLength = newBottomPointsLength;
}
private void updateSide(int index, int newBottomPointsLength) {
GeoPointND pointBottom1 = outputPointsBottom.getElement(index);
GeoPointND pointBottom2 = outputPointsBottom
.getElement((index + 1) % newBottomPointsLength);
GeoPointND pointSide = outputPointsSide.getElement(index);
// update segments
GeoSegmentND segmentBottom = outputSegmentsBottom.getElement(index);
GeoSegmentND segmentSide1 = outputSegmentsSide.getElement(2 * index);
GeoSegmentND segmentSide2 = outputSegmentsSide
.getElement((2 * index + 1) % (2 * newBottomPointsLength));
segmentSide2.modifyInputPoints(pointBottom2, pointSide);
segmentSide1.modifyInputPoints(pointSide, pointBottom1);
// update side
GeoPolygon polygon = outputPolygonsSide.getElement(index);
GeoPointND[] points = new GeoPointND[3];
points[0] = pointBottom1;
points[1] = pointBottom2;
points[2] = pointSide;
polygon.modifyInputPoints(points);
GeoSegmentND[] s = new GeoSegmentND[3];
s[0] = segmentBottom;
s[1] = segmentSide2;
s[2] = segmentSide1;
polygon.setSegments(s);
polygon.calcArea();
}
private Coords p1;
@Override
public void compute(double f0, GeoPolygon bottomPolygon, Coords[] points) {
if (p1 == null) {
p1 = new Coords(4);
}
Coords topCoords = p.getTopPoint();
topCoords.projectPlane(
bottomPolygon.getCoordSys().getMatrixOrthonormal(), p1);
double d1 = p.getOrientedHeight();
double f = f0;
Coords faceDirection = bottomPolygon.getDirectionInD3();
if (d1 < 0) { // top point below the bottom face : negative rotation
f *= -1;
d1 *= -1;
}
if (bottomPolygon.isConvexInverseDirection()) {
f *= -1;
faceDirection = faceDirection.mul(-1);
}
int n = points.length;
Coords o2 = points[0];
for (int i = 0; i < n; i++) {
GeoPoint3D wpoint = outputPointsSide.getElement(i);
wpoint.setCoords(topCoords, false);
// angle between side face and bottom face
Coords o = o2;
o2 = points[(i + 1) % n];
Coords vs = o2.sub(o).normalized();
rotate(wpoint, topCoords, p1, o, vs, f, faceDirection, d1, false);
}
getNet().setArea(p.getArea());
}
}