Skip to content

Commit 9296ca3

Browse files
committed
add distanceTree()
1 parent be756ff commit 9296ca3

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
* `forEachShape()` and `forEachShapeWithIndex()`* to `PGS_Processing`. Applies a specified transformation function of a desired type `T` to each child of the given PShape, returning a list of `T` (*additionally with child's index).
1414
* `maximumInscribedTriangle()` to `PGS_Optimisation`. Finds an approximate largest area triangle (of arbitrary orientation) contained within a polygon.
1515
* `closestPoint()` to `PGS_Optimisation`. Finds the closest point in a collection of points to a specified point.
16+
* `distanceTree()` to `PGS_Contour`. Generates a tree structure representing the shortest paths from a start point to all other vertices in a mesh.
1617

1718
### Changes
1819
* Optimised `PGS_CirclePacking.tangencyPack()`. It's now around 1.5-2x faster and has higher precision.

src/main/java/micycle/pgs/PGS_Contour.java

+51
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import javax.vecmath.Point3d;
1919

20+
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm;
21+
import org.jgrapht.alg.shortestpath.BFSShortestPath;
2022
import org.jgrapht.graph.DefaultEdge;
2123
import org.jgrapht.graph.SimpleGraph;
2224
import org.joml.Vector2d;
@@ -636,6 +638,55 @@ public static PShape distanceField(PShape shape, double spacing) {
636638
return i;
637639
}
638640

641+
/**
642+
* Generates a tree structure representing the shortest paths from a given start
643+
* point to all other vertices in the provided mesh. The paths are computed
644+
* using the existing connectivity of the mesh edges, ensuring that the
645+
* shortest-path tree respects the original mesh structure. The tree is
646+
* constructed using a Breadth-First Search (BFS) algorithm.
647+
* <p>
648+
* The shortest-path tree represents the minimal set of mesh edges required to
649+
* connect the start point to all other vertices in the mesh, following the
650+
* mesh's inherent connectivity. This ensures that the paths are constrained by
651+
* the mesh's topology rather than creating arbitrary connections between
652+
* vertices.
653+
* <p>
654+
* If the provided start point does not exactly match a vertex in the mesh, the
655+
* closest vertex in the mesh to the start point is used as the actual starting
656+
* point for the shortest-path computation.
657+
*
658+
* @param mesh A GROUP shape representing a mesh from which the graph is
659+
* constructed. The mesh defines the connectivity between
660+
* vertices via its edges.
661+
* @param startPoint The starting point from which the shortest paths are
662+
* calculated. If this point does not exactly match a vertex
663+
* in the mesh, the closest vertex in the mesh will be used as
664+
* the starting point.
665+
* @return A PShape object representing the tree of shortest paths from the
666+
* start point to all other vertices in the mesh. The paths are
667+
* visualized with a semi-transparent pink stroke and are constrained by
668+
* the mesh's edge connectivity.
669+
* @since 2.1
670+
*/
671+
public static PShape distanceTree(PShape mesh, PVector source) {
672+
var g = PGS_Conversion.toGraph(mesh);
673+
ShortestPathAlgorithm<PVector, PEdge> spa = new BFSShortestPath<>(g);
674+
675+
final PVector sourceActual = PGS_Optimisation.closestPoint(g.vertexSet(), source);
676+
var paths = spa.getPaths(sourceActual);
677+
678+
// var edges = g.vertexSet().stream().filter(v -> !v.equals(sourceActual)) // Exclude the source vertex
679+
// .flatMap(v -> paths.getPath(v).getEdgeList().stream()) // Flatten the edge lists into a single stream
680+
// .collect(Collectors.toSet()); // Collect the edges into a Set to remove duplicates
681+
682+
var pathLines = g.vertexSet().stream() //
683+
.filter(v -> v != sourceActual) // Exclude the source vertex
684+
.map(v -> PGS_Conversion.fromPVector(paths.getPath(v).getVertexList())).toList();
685+
var group = PGS_Conversion.flatten(pathLines);
686+
PGS_Conversion.setAllStrokeColor(group, ColorUtils.setAlpha(Colors.PINK, 50), 2);
687+
return group;
688+
}
689+
639690
/**
640691
* Calculates the longest center line passing through a given shape (using
641692
* default straightness weighting and smoothing parameters).

0 commit comments

Comments
 (0)