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 AlgoPolyhedronNetPrism extends AlgoPolyhedronNet { /** * @param c * construction * @param labels * output labels * @param p * polyhedron * @param v * index */ public AlgoPolyhedronNetPrism(Construction c, String[] labels, GeoPolyhedron p, NumberValue v) { super(c, labels, p, v); } @Override protected int getPointLengthFromLabelsLength(int length) { return length / 10; } @Override protected void createNet(int n) { GeoPolyhedronNet net = getNet(); outputPointsBottom.adjustOutputSize(n, false); outputPointsSide.adjustOutputSize(2 * n, false); outputPointsTop.adjustOutputSize(n - 2, false); // create bottom face 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); } // create top face net.startNewFace(); net.addPointToCurrentFace(outputPointsSide.getElement(0)); net.addPointToCurrentFace(outputPointsSide.getElement(1)); for (int i = 0; i < n - 2; i++) { net.addPointToCurrentFace(outputPointsTop.getElement(i)); } net.endCurrentFace(); } @Override protected void setOutputSideTop(int n, GeoPolygon3D polygon, int step, GeoSegmentND[] segments) { if (step == n + 2) { // top outputPolygonsTop.addOutput(polygon, false); for (int i = 1; i < segments.length; i++) { outputSegmentsTop.addOutput((GeoSegment3D) segments[i], false); } } else { setOutputSide(polygon); } } private void setOutputSide(GeoPolygon3D polygon) { outputPolygonsSide.addOutput(polygon, false); outputSegmentsSide.addOutput((GeoSegment3D) polygon.getSegments()[3], false); outputSegmentsSide.addOutput((GeoSegment3D) polygon.getSegments()[2], false); outputSegmentsSide.addOutput((GeoSegment3D) polygon.getSegments()[1], false); } private Coords pp1; @Override public void compute(double fUnsigned, GeoPolygon bottomPolygon, Coords[] points) { double f = fUnsigned; if (pp1 == null) { pp1 = new Coords(4); } int sz = points.length; Coords[] topP = getPointsCoords(p.getTopFace()); Coords topCo = topP[0]; topCo.projectPlane(bottomPolygon.getCoordSys().getMatrixOrthonormal(), pp1); double dd1 = p.getOrientedHeight(); if (dd1 < 0) { // top point below the bottom face : negative rotation f *= -1; dd1 *= -1; } Coords faceDirection = bottomPolygon.getDirectionInD3(); if (bottomPolygon.isConvexInverseDirection()) { f *= -1; faceDirection = faceDirection.mul(-1); } GeoPoint3D wpoint1 = null; GeoPoint3D wpoint2 = null; GeoPoint3D wpoint3 = null; Coords cCoord = null; // Coords of the current top point for (int i = 0; i < sz; i++) { // triple creation of top points wpoint1 = outputPointsSide.getElement(2 * i); int j = 2 * i - 1; if (j < 0) { j = 2 * sz - 1; } wpoint2 = outputPointsSide.getElement(j); cCoord = topP[i]; wpoint1.setCoords(cCoord); wpoint2.setCoords(cCoord); if (i > 1) { // wpoint3 is for the top face, except 2 first points // (already exist) wpoint3 = outputPointsTop.getElement(i - 2); wpoint3.setCoords(cCoord); } } Coords[] bottomSegsDirections = new Coords[sz]; Coords p1 = points[sz - 1]; Coords p2 = points[0]; bottomSegsDirections[sz - 1] = p2.sub(p1).normalized(); for (int i = 0; i < sz - 1; i++) { p1 = p2; p2 = points[i + 1]; bottomSegsDirections[i] = p2.sub(p1).normalized(); } // rotation of the top face around first top segment Coords o = topP[1]; Coords vs = bottomSegsDirections[0]; GeoPolygon side0 = p.getFirstSideFace(); for (int i = 0; i < sz - 2; i++) { wpoint3 = outputPointsTop.getElement(i); cCoord = wpoint3.getInhomCoordsInD3(); cCoord.projectPlane(side0.getCoordSys().getMatrixOrthonormal(), pp1); double dist = pp1.distance(cCoord); rotate(wpoint3, cCoord, pp1, o, vs, f, side0.getDirectionInD3(), dist, true); } for (int i = 0; i < 2 * sz; i += 2) { // rotate wpoint1 // angle between side face and bottom face o = points[i / 2]; vs = bottomSegsDirections[i / 2]; wpoint1 = outputPointsSide.getElement(i); cCoord = wpoint1.getInhomCoordsInD3(); cCoord.projectPlane( bottomPolygon.getCoordSys().getMatrixOrthonormal(), pp1); rotate(wpoint1, cCoord, pp1, o, vs, f, faceDirection, dd1, false); // rotate wpoint2 wpoint2 = outputPointsSide.getElement(i + 1); cCoord = wpoint2.getInhomCoordsInD3(); cCoord.projectPlane( bottomPolygon.getCoordSys().getMatrixOrthonormal(), pp1); rotate(wpoint2, cCoord, pp1, o, vs, f, faceDirection, dd1, false); if (i == 0) { // the rotation for the top face is made with the same // angle for (int j = 0; j < sz - 2; j++) { wpoint3 = outputPointsTop.getElement(j); rotate(wpoint3, cCoord, pp1, o, vs, f, faceDirection, dd1, false); } } } getNet().setArea(p.getArea()); } @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() / 2; if (newBottomPointsLength > nOld) { // adjust top points length outputPointsTop.adjustOutputSize(newBottomPointsLength - 2, false); if (setLabels) { outputPointsTop.setLabels(null); } // create new top segments GeoPolyhedronNet net = getNet(); for (int i = nOld; i < newBottomPointsLength - 1; i++) { GeoSegment3D segmentTop = (GeoSegment3D) net.createSegment( outputPointsTop.getElement(i - 2), outputPointsTop.getElement(i - 1)); outputSegmentsTop.addOutput(segmentTop, false); } GeoSegment3D segmentTop = (GeoSegment3D) net.createSegment( outputPointsTop.getElement(newBottomPointsLength - 3), outputPointsSide.getElement(0)); outputSegmentsTop.addOutput(segmentTop, false); if (setLabels) { outputSegmentsTop.setLabels(null); } // refreshOutput() will be done below } // 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)); // update top segments GeoSegmentND segmenTop = outputSegmentsTop.getElement(i - 2); segmenTop.modifyInputPoints(outputPointsTop.getElement(i - 3), outputPointsTop.getElement(i - 2)); } for (int i = bottomPointsLength - 1; i < newBottomPointsLength && i < nOld; i++) { // update last sides updateSide(i, newBottomPointsLength); } } // create sides if needed if (newBottomPointsLength > nOld) { // adjust side points length outputPointsSide.adjustOutputSize(newBottomPointsLength * 2, 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 + 2); // +2 shift for // bottom // and top 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); updateTop(newBottomPointsLength); } else if (newBottomPointsLength < bottomPointsLength) { // update points for (int i = newBottomPointsLength; i < bottomPointsLength; i++) { outputPointsBottom.getElement(i).setUndefined(); outputPointsSide.getElement(2 * i).setUndefined(); outputPointsSide.getElement(2 * i + 1).setUndefined(); outputPointsTop.getElement(i - 2).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 top segment GeoSegmentND segmentTop = outputSegmentsTop .getElement(newBottomPointsLength - 2); segmentTop.modifyInputPoints( outputPointsTop.getElement(newBottomPointsLength - 3), outputPointsSide.getElement(0)); // update top face updateTop(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 pointSide2 = outputPointsSide.getElement(2 * index); GeoPointND pointSide1 = outputPointsSide .getElement((2 * index + 1) % (2 * newBottomPointsLength)); // update segments GeoSegmentND segmentBottom = outputSegmentsBottom.getElement(index); GeoSegmentND segmentSide3 = outputSegmentsSide.getElement(3 * index); GeoSegmentND segmentSide2 = outputSegmentsSide .getElement(3 * index + 1); GeoSegmentND segmentSide1 = outputSegmentsSide .getElement((3 * index + 2) % (3 * newBottomPointsLength)); segmentSide1.modifyInputPoints(pointBottom2, pointSide1); segmentSide2.modifyInputPoints(pointSide1, pointSide2); segmentSide3.modifyInputPoints(pointSide2, pointBottom1); // update side GeoPolygon polygon = outputPolygonsSide.getElement(index); GeoPointND[] points = new GeoPointND[4]; points[0] = pointBottom1; points[1] = pointBottom2; points[2] = pointSide1; points[3] = pointSide2; polygon.modifyInputPoints(points); GeoSegmentND[] s = new GeoSegmentND[4]; s[0] = segmentBottom; s[1] = segmentSide1; s[2] = segmentSide2; s[2] = segmentSide3; polygon.setSegments(s); polygon.calcArea(); } 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((2 * index + 1) % (2 * newBottomPointsLength))); net.addPointToCurrentFace(outputPointsSide.getElement(2 * index)); net.endCurrentFace(); } /** * update top face for new length * * @param newBottomPointsLength * new bottom points length */ protected void updateTop(int newBottomPointsLength) { GeoPolygon polygon = outputPolygonsTop.getElement(0); GeoPoint3D[] points = new GeoPoint3D[newBottomPointsLength]; GeoSegment3D[] segments = new GeoSegment3D[newBottomPointsLength]; points[0] = outputPointsSide.getElement(0); points[1] = outputPointsSide.getElement(1); for (int i = 2; i < newBottomPointsLength; i++) { points[i] = outputPointsTop.getElement(i - 2); } segments[0] = outputSegmentsSide.getElement(0); for (int i = 1; i < newBottomPointsLength; i++) { segments[i] = outputSegmentsTop.getElement(i - 1); } polygon.modifyInputPoints(points); polygon.setSegments(segments); polygon.calcArea(); } }