public static ConcaveHullFactoryResult createConcaveHull(List<Point2D> pointCloud2d, ConcaveHullFactoryParameters parameters) { return createConcaveHull(pointCloud2d, null, parameters); }
public static MultiPoint filterAndCreateMultiPoint(List<Point2D> pointCloud2d, List<LineSegment2D> lineConstraints, double tolerance) { List<Point2D> filteredPointCloud2d = new ArrayList<>(); for (Point2D point : pointCloud2d) { if (!isTooCloseToConstraintSegments(point, lineConstraints, tolerance)) filteredPointCloud2d.add(point); } return createMultiPoint(filteredPointCloud2d); }
public static ConcaveHullFactoryResult createConcaveHull(List<Point2D> pointCloud2d, List<LineSegment2D> lineConstraints, ConcaveHullFactoryParameters parameters) { if (pointCloud2d.size() <= 3) return null; MultiPoint sites = filterAndCreateMultiPoint(pointCloud2d, lineConstraints, 0.01); MultiLineString constraintSegments = createMultiLineString(lineConstraints); ConcaveHullFactoryResult result = new ConcaveHullFactoryResult(); ConcaveHullVariables initialVariables = initializeTriangulation(sites, constraintSegments, result); List<ConcaveHullVariables> variablesList = computeConcaveHullBorderEdgesRecursive(parameters, initialVariables); result.intermediateVariables.addAll(variablesList); for (ConcaveHullVariables variables : result.intermediateVariables) { ConcaveHull concaveHull = computeConcaveHull(variables.getOrderedBorderEdges()); if (concaveHull != null) { concaveHull.ensureClockwiseOrdering(); result.concaveHullCollection.add(concaveHull); } } return result; }
currentCase = determineCase(candidateEntry, parameters, variables); if (currentCase == Case.KEEP_TRIANGLE) removeTriangleWithOneBorderEdge(variables, candidateEntry); currentIteration.increment(); return computeConcaveHullBorderEdgesRecursive(parameters, variables, currentIteration); case TWO_BORDER_EDGES_THREE_BORDER_VERTICES: removeTriangleWithTwoBorderEdges(variables, candidateEntry); currentIteration.increment(); return computeConcaveHullBorderEdgesRecursive(parameters, variables, currentIteration); case ONE_BORDER_EDGES_THREE_BORDER_VERTICES: List<ConcaveHullVariables> subVariablesList = removeTriangleAndDivideHull(variables, candidateEntry); return computeConcaveHullBorderEdgesRecursive(parameters, subVariablesList, currentIteration); List<ConcaveHullVariables> subVariablesList = divideHullAtIntersectionTriangle(variables, candidateEntry); return computeConcaveHullBorderEdgesRecursive(parameters, subVariablesList, currentIteration);
while (!doesVertexBelongToQuadEdge(intersectionVertex, orderedBorderEdges.get(subHullEndIndex))) checkOrderedBorderEdgeListValid(subOrderedBorderEdges); subBorderEdges.addAll(subOrderedBorderEdges); subBorderEdges.forEach(borderEdge -> subBorderVertices.add(borderEdge.orig())); sortedByLengthQueue.stream() .filter(pair -> isBorderEdge(pair.getLeft(), subBorderEdges)) .forEach(subSortedByLengthQueue::add); subSortedByLengthQueue.forEach(pair -> subBorderTriangles.add(pair.getRight()));
if (isEdgeCollinearWithALineSemgentOfMultiLineString(edge, constraintSegments)) if (isBorderEdge(currentIncidentEdge, borderEdges)) currentDestVertex = currentEdge.dest(); checkOrderedBorderEdgeListValid(orderedBorderEdges);
return computeIntermediateVariables(allTriangles, constraintSegments);
QuadEdge secondEdge; if (doesVertexBelongToQuadEdge(previousVertex, newEdge1)) if (!doesVertexBelongToQuadEdge(nextVertex, newEdge2)) throw new RuntimeException("newEdge2 is not connected to nextVertex."); else if (doesVertexBelongToQuadEdge(previousVertex, newEdge2)) if (!doesVertexBelongToQuadEdge(nextVertex, newEdge1)) throw new RuntimeException("newEdge1 is not connected to nextVertex."); checkOrderedBorderEdgeListValid(orderedBorderEdges);
private static QuadEdgeSubdivision createQuadEdgeSubdivision(PlanarRegionSegmentationRawData rawData) { List<Point2D> point2ds = rawData.getPointCloudInPlane(); MultiPoint multiPoint = SimpleConcaveHullFactory.createMultiPoint(point2ds); ConformingDelaunayTriangulationBuilder conformingDelaunayTriangulationBuilder = new ConformingDelaunayTriangulationBuilder(); conformingDelaunayTriangulationBuilder.setSites(multiPoint); return conformingDelaunayTriangulationBuilder.getSubdivision(); }
public static ConcaveHullCollection createConcaveHullCollection(List<Point2D> pointCloud2d, ConcaveHullFactoryParameters parameters) { return createConcaveHullCollection(pointCloud2d, null, parameters); }
private static List<ConcaveHullVariables> computeConcaveHullBorderEdgesRecursive(ConcaveHullFactoryParameters parameters, List<ConcaveHullVariables> variables, MutableInt currentIteration) { List<ConcaveHullVariables> result = new ArrayList<>(); for (ConcaveHullVariables hullVariables : variables) { currentIteration.increment(); result.addAll(computeConcaveHullBorderEdgesRecursive(parameters, hullVariables, currentIteration)); } return result; }
checkOrderedBorderEdgeListValid(orderedBorderEdges);
@SuppressWarnings("unchecked") private static Node createOrderedBorderEdgesGraphics(QuadEdgeSubdivision quadEdgeSubdivision, PlanarRegionSegmentationRawData rawData) { List<QuadEdgeTriangle> delaunayTriangles = QuadEdgeTriangle.createOn(quadEdgeSubdivision); List<QuadEdge> orderedBorderEdges = SimpleConcaveHullFactory.computeIntermediateVariables(delaunayTriangles, null).getOrderedBorderEdges(); JavaFXMultiColorMeshBuilder meshBuilder = new JavaFXMultiColorMeshBuilder(new TextureColorAdaptivePalette(16)); Point3D planeOrigin = rawData.getOrigin(); Quaternion planeOrientation = rawData.getOrientation(); double startHue = 0.0; double endHue = 240.0; double lineStartBirghtness = 0.2; double lineEndBirghtness = 1.0; for (int edgeIndex = 0; edgeIndex < orderedBorderEdges.size(); edgeIndex++) { QuadEdge edge = orderedBorderEdges.get(edgeIndex); Point3D dest = PolygonizerTools.toPointInWorld(edge.dest().getX(), edge.dest().getY(), planeOrigin, planeOrientation); Point3D orig = PolygonizerTools.toPointInWorld(edge.orig().getX(), edge.orig().getY(), planeOrigin, planeOrientation); double alpha = edgeIndex / (double) orderedBorderEdges.size(); double lineHue = (1.0 - alpha) * startHue + alpha * endHue; Color startColor = Color.hsb(lineHue, 0.9, lineStartBirghtness); Color endColor = Color.hsb(lineHue, 0.9, lineEndBirghtness); meshBuilder.addLine(orig, dest, 0.002, startColor, endColor); } MeshView meshView = new MeshView(meshBuilder.generateMesh()); meshView.setMaterial(meshBuilder.generateMaterial()); return meshView; }
ConcaveHullCollection concaveHullCollection = SimpleConcaveHullFactory.createConcaveHullCollection(pointCloudInPlane, intersections, concaveHullFactoryParameters);
/** * Computes the border edges {@link QuadEdge} that will define the concave hull. * This is an iterative process that starts a first guess of the concave hull, and then each iteration consists "breaking" edges that are too long according to the {@code edgeLengthThreshold}. * The algorithm is based on the <a href="https://en.wikipedia.org/wiki/Delaunay_triangulation"> Delaunay triangulation </a>. * @param edgeLengthThreshold maximum edge length the concave hull can have. * @param maxNumberOfIterations option to limit the maximum number of iterations of this algorithm. * @param removeAllTrianglesWithTwoBorderEdges when set to true, any triangle with two border edges with be removed regardless of the edges length. This tends to smoothen the resulting concave hull in general. * @param variables the set of variables pre-initialized used internally to find the border edges of the concave hull. * @return list of new intermediate variables containing the sets of edges defining the concave hull(s). */ private static List<ConcaveHullVariables> computeConcaveHullBorderEdgesRecursive(ConcaveHullFactoryParameters parameters, ConcaveHullVariables variables) { return computeConcaveHullBorderEdgesRecursive(parameters, variables, new MutableInt(0)); }
public static ConcaveHullCollection createConcaveHullCollection(List<Point2D> pointCloud2d, List<LineSegment2D> lineConstraints, ConcaveHullFactoryParameters parameters) { if (pointCloud2d.size() <= 3) return new ConcaveHullCollection(pointCloud2d); return createConcaveHull(pointCloud2d, lineConstraints, parameters).getConcaveHullCollection(); }
public static void main(String[] args) throws IOException { PlanarRegionSegmentationRawDataImporter dataImporter = new PlanarRegionSegmentationRawDataImporter(new File("../../Data/20161210_185643_PlanarRegionSegmentation_Atlas_CB")); dataImporter.loadPlanarRegionSegmentationData(); List<PlanarRegionSegmentationRawData> regionsRawData = dataImporter.getPlanarRegionSegmentationRawData(); ConcaveHullFactoryParameters parameters = new ConcaveHullFactoryParameters(); while (true) { for (PlanarRegionSegmentationRawData rawData : regionsRawData) { List<Point2D> pointsInPlane = rawData.getPointCloudInPlane(); SimpleConcaveHullFactory.createConcaveHull(pointsInPlane, parameters); } } } }
ConcaveHullFactoryResult concaveHullFactoryResult = SimpleConcaveHullFactory.createConcaveHull(pointsInPlane, intersections, parameters);