package org.geogebra.common.geogebra3D.kernel3D.algos; import java.util.ArrayList; import java.util.TreeSet; 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.ConstructionElementCycle; 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.kernelND.GeoPointND; import org.geogebra.common.util.debug.Log; import com.github.quickhull3d.Point3d; import com.github.quickhull3d.QuickHull3D; public class AlgoPolyhedronConvex extends AlgoElement3D { private GeoPointND[] pointList; protected OutputHandler<GeoPolyhedron> outputPolyhedron; protected OutputHandler<GeoSegment3D> outputSegments; protected OutputHandler<GeoPolygon3D> outputPolygons; // convex hull stuff private Point3d[] point3dList; private QuickHull3D quickHull3D; /** * @param c * construction */ public AlgoPolyhedronConvex(Construction c, String[] labels, GeoElement[] pointList) { super(c); this.pointList = new GeoPointND[pointList.length]; point3dList = new Point3d[pointList.length]; for (int i = 0; i < pointList.length; i++) { this.pointList[i] = (GeoPointND) pointList[i]; point3dList[i] = new Point3d(); } quickHull3D = new QuickHull3D(); // set input input = pointList; for (int i = 0; i < input.length; i++) { input[i].addAlgorithm(this); } outputPolyhedron = new OutputHandler<GeoPolyhedron>( new elementFactory<GeoPolyhedron>() { @Override public GeoPolyhedron newElement() { GeoPolyhedron p = new GeoPolyhedron(cons); p.setParentAlgorithm(AlgoPolyhedronConvex.this); return p; } }); outputPolyhedron.adjustOutputSize(1); outputPolygons = createOutputPolygons(); outputSegments = createOutputSegments(); // temporary code updateHull(); GeoPolyhedron p = getPolyhedron(); int[][] faceIndices = quickHull3D .getFaces(QuickHull3D.POINT_RELATIVE | QuickHull3D.CLOCKWISE); for (int i = 0; i < faceIndices.length; i++) { p.startNewFace(); for (int k = 0; k < faceIndices[i].length; k++) { int index = faceIndices[i][k]; System.out.print(index + " "); p.addPointToCurrentFace(this.pointList[index]); } p.endCurrentFace(); System.out.println(""); } p.createFaces(); refreshOutput(); // set labels setLabels(labels); update(); updateOutputSegmentsAndPolygonsParentAlgorithms(); } private void updateHull() { for (int i = 0; i < pointList.length; i++) { Coords coords = pointList[i].getInhomCoordsInD3(); point3dList[i].set(coords.getX(), coords.getY(), coords.getZ()); } quickHull3D.build(point3dList); } @Override public void compute() { updateHull(); GeoPolyhedron p = getPolyhedron(); ArrayList<ConstructionElementCycle> newFaces = new ArrayList<ConstructionElementCycle>(); TreeSet<Integer> availableIndices = new TreeSet<Integer>(); availableIndices.addAll(p.getPolygonsIndices()); int[][] faceIndices = quickHull3D .getFaces(QuickHull3D.POINT_RELATIVE | QuickHull3D.CLOCKWISE); for (int i = 0; i < faceIndices.length; i++) { p.startNewFace(); for (int k = 0; k < faceIndices[i].length; k++) { int index = faceIndices[i][k]; p.addPointToCurrentFace(this.pointList[index]); } Integer index = p.getCurrentFaceIndex(); if (index == null) { newFaces.add(p.getCurrentFace()); } else { availableIndices.remove(index); } } StringBuilder sb = new StringBuilder("\nnew faces:"); for (ConstructionElementCycle face : newFaces) { sb.append("\n "); sb.append(face); } sb.append("\navailable indices:"); for (Integer index : availableIndices) { sb.append(" "); sb.append(index); } Log.debug(sb); } /** * @return the polyhedron */ public GeoPolyhedron getPolyhedron() { return outputPolyhedron.getElement(0); } @Override public GetCommand getClassName() { return Commands.Polyhedron; } private OutputHandler<GeoSegment3D> createOutputSegments() { return new OutputHandler<GeoSegment3D>( new elementFactory<GeoSegment3D>() { @Override public GeoSegment3D newElement() { GeoSegment3D s = new GeoSegment3D(cons); // s.setParentAlgorithm(AlgoPolyhedron.this); return s; } }); } private OutputHandler<GeoPolygon3D> createOutputPolygons() { return new OutputHandler<GeoPolygon3D>( new elementFactory<GeoPolygon3D>() { @Override public GeoPolygon3D newElement() { GeoPolygon3D p = new GeoPolygon3D(cons); // p.setParentAlgorithm(AlgoPolyhedron.this); return p; } }); } private void setLabels(String[] labels) { if (labels == null || labels.length <= 1) { getPolyhedron().initLabels(labels); } else { getPolyhedron().setAllLabelsAreSet(true); for (int i = 0; i < labels.length; i++) { getOutput(i).setLabel(labels[i]); } } } /** * force update for segments and polygons at creation */ private void updateOutputSegmentsAndPolygonsParentAlgorithms() { outputSegments.updateParentAlgorithm(); outputPolygons.updateParentAlgorithm(); } /* * @Override public int getRelatedModeID() { return * EuclidianConstants.MODE_NET; } */ }