@@ -1060,32 +1060,43 @@ public static SimpleGraph<PVector, PEdge> toCentroidDualGraph(PShape mesh) {
1060
1060
*/
1061
1061
static SimpleGraph <PShape , DefaultEdge > toDualGraph (Collection <PShape > meshFaces ) {
1062
1062
final SimpleGraph <PShape , DefaultEdge > graph = new SimpleGraph <>(DefaultEdge .class );
1063
- // map of which edge belong to each face; used to detect half-edges
1064
- final HashMap <PEdge , PShape > edgesMap = new HashMap <>(meshFaces .size () * 4 );
1063
+ final Map <PEdge , List <PShape >> edgeFacesMap = new HashMap <>();
1065
1064
1065
+ // Phase 1: Collect edges and their associated faces
1066
1066
for (PShape face : meshFaces ) {
1067
- graph .addVertex (face ); // always add child so disconnected shapes are colored
1067
+ graph .addVertex (face );
1068
1068
for (int i = 0 ; i < face .getVertexCount (); i ++) {
1069
- final PVector a = face .getVertex (i );
1070
- final PVector b = face .getVertex ((i + 1 ) % face .getVertexCount ());
1069
+ PVector a = face .getVertex (i );
1070
+ PVector b = face .getVertex ((i + 1 ) % face .getVertexCount ());
1071
1071
if (a .equals (b )) {
1072
1072
continue ;
1073
1073
}
1074
- final PEdge e = new PEdge (a , b );
1075
- final PShape neighbour = edgesMap .get (e );
1076
1074
1077
- if (neighbour != null ) {
1078
- // edge seen before, so faces must be adjacent; create edge between faces
1079
- if (neighbour .equals (face )) { // probably bad input (3 edges the same)
1080
- System .err .println ("toDualGraph(): Bad input — saw the same edge 3 times." );
1081
- continue ; // continue to prevent self-loop in graph
1082
- }
1083
- graph .addEdge (neighbour , face );
1084
- } else {
1085
- edgesMap .put (e , face ); // edge is new
1086
- }
1075
+ PEdge edge = new PEdge (a , b );
1076
+ edgeFacesMap .computeIfAbsent (edge , k -> new ArrayList <>()).add (face );
1087
1077
}
1088
1078
}
1079
+
1080
+ // Phase 2: Process edges in sorted order for graph iteration consistency
1081
+ edgeFacesMap .entrySet ().stream ().sorted (Comparator .comparing (e -> e .getKey ())) // Sort edges to ensure deterministic processing
1082
+ .forEach (entry -> {
1083
+ List <PShape > faces = entry .getValue ();
1084
+ if (faces .size () == 2 ) {
1085
+ // If exactly two faces share this edge, connect them in the dual graph
1086
+ PShape f1 = faces .get (0 );
1087
+ PShape f2 = faces .get (1 );
1088
+ if (!f1 .equals (f2 )) {
1089
+ graph .addEdge (f1 , f2 ); // Avoid self-loops
1090
+ } else {
1091
+ // Handle case where the same face is associated with the edge twice
1092
+ System .err .println ("toDualGraph(): Bad input — saw the same edge 3+ times for face: " + f1 );
1093
+ }
1094
+ } else if (faces .size () > 2 ) {
1095
+ // Handle edges shared by more than two faces
1096
+ System .err .println ("toDualGraph(): Bad input — edge shared by more than two faces: " + entry .getKey ().toString ());
1097
+ }
1098
+ });
1099
+
1089
1100
return graph ;
1090
1101
}
1091
1102
@@ -1738,14 +1749,27 @@ public static PShape disableAllStroke(PShape shape) {
1738
1749
* narrow gaps can appear between otherwise flush shapes. If the shape is a
1739
1750
* GROUP, the rounding is applied to all child shapes.
1740
1751
*
1741
- * @param shape the PShape to round vertex coordinates for
1742
- * @return a rounded copy of the input shape
1752
+ * @param shape the PShape to round vertex coordinates for.
1753
+ * @return a rounded copy of the input shape.
1754
+ * @see #roundVertexCoords(PShape, int)
1743
1755
* @since 1.1.3
1744
1756
*/
1745
1757
public static PShape roundVertexCoords (PShape shape ) {
1746
1758
return roundVertexCoords (shape , 0 );
1747
1759
}
1748
1760
1761
+ /**
1762
+ * Rounds the x and y coordinates (to <code>n</code> decimal places) of all
1763
+ * vertices belonging to the shape. This can sometimes fix a visual problem in
1764
+ * Processing where narrow gaps can appear between otherwise flush shapes. If
1765
+ * the shape is a GROUP, the rounding is applied to all child shapes.
1766
+ *
1767
+ * @param shape the PShape to round vertex coordinates for.
1768
+ * @param n The number of decimal places to which the coordinates should be
1769
+ * rounded.
1770
+ * @return a rounded copy of the input shape.
1771
+ * @since 2.1
1772
+ */
1749
1773
public static PShape roundVertexCoords (PShape shape , int n ) {
1750
1774
return PGS_Processing .transform (shape , s -> {
1751
1775
var c = copy (s );
0 commit comments