@@ -52,7 +52,7 @@ public class Plane {
52
52
* 0.00000001;
53
53
*/
54
54
55
- public static final double EPSILON = 1.0e-9 ;
55
+ public static final double EPSILON = 1.0e-11 ;
56
56
public static final double EPSILON_Point = EPSILON ;
57
57
public static final double EPSILON_duplicate = 1.0e-4 ;
58
58
/**
@@ -102,35 +102,35 @@ public static Plane createFromPoints(List<Vertex> vertices) {
102
102
Vector3d n = computeNormal (vertices );
103
103
return new Plane (n , n .dot (a ));
104
104
}
105
+
105
106
public static Vector3d computeNormal (List <Vertex > vertices ) {
106
- if (vertices == null || vertices .size () < 3 ) {
107
- return new Vector3d (0 , 0 , 1 ); // Default normal for degenerate cases
108
- }
109
-
110
- // First attempt: Newell's method
111
- Vector3d normal = new Vector3d (0 , 0 , 0 );
112
- int n = vertices .size ();
113
- for (int i = 0 ; i < n ; i ++) {
114
- Vector3d current = vertices .get (i ).pos ;
115
- Vector3d next = vertices .get ((i + 1 ) % n ).pos ;
116
-
117
- double d = current .z + next .z ;
118
- double e = current .z - next .z ;
119
- double e2 = current .y - next .y ;
120
- double f = current .x + next .x ;
121
- double f2 = current .x - next .x ;
122
- double g = current .y + next .y ;
123
-
124
- normal .x += e2 * d ;
125
- normal .y += e * f ;
126
- normal .z += f2 * g ;
127
- }
128
- Vector3d normalized = normal .normalized ();
129
-
130
- if (isValidNormal (normalized , EPSILON )) {
131
- return normalized ;
132
- }
133
- throw new RuntimeException ("Mesh has problems, can not work around it" );
107
+ if (vertices == null || vertices .size () < 3 ) {
108
+ return new Vector3d (0 , 0 , 1 ); // Default normal for degenerate cases
109
+ }
110
+
111
+ // First attempt: Newell's method
112
+ Vector3d normal = new Vector3d (0 , 0 , 0 );
113
+ int n = vertices .size ();
114
+ Vector3d lastValid = null ;
115
+ for (int i = 0 ; i < n ; i ++) {
116
+ Vector3d current = vertices .get (i ).pos ;
117
+ Vector3d next = vertices .get ((i + 1 ) % n ).pos ;
118
+
119
+ // Correct Newell's Method formulas
120
+ normal .x += (current .y - next .y ) * (current .z + next .z ); // (y1-y2)(z1+z2)
121
+ normal .y += (current .z - next .z ) * (current .x + next .x ); // (z1-z2)(x1+x2)
122
+ normal .z += (current .x - next .x ) * (current .y + next .y );
123
+ if (n >= 3 ) {
124
+ Vector3d normalized = normal .normalized ();
125
+ if (isValidNormal (normalized , EPSILON / 10 )) {
126
+ lastValid = normalized ;
127
+ }
128
+ }
129
+ }
130
+ if (isValidNormal (lastValid , EPSILON / 10 )) {
131
+ return lastValid ;
132
+ }
133
+ throw new RuntimeException ("Mesh has problems, can not work around it" );
134
134
// // Second attempt: Find three non-colinear points
135
135
//
136
136
// normal = findNormalFromNonColinearPoints(vertices);
@@ -151,104 +151,102 @@ public static Vector3d computeNormal(List<Vertex> vertices) {
151
151
}
152
152
153
153
private static boolean isValidNormal (Vector3d normal , double epsilon ) {
154
- if (Double .isFinite (normal .x )&& Double .isFinite (normal .y )&& Double .isFinite (normal .z )) {
155
- double lengthSquared = Math .abs (normal .length ());
156
- return lengthSquared >= epsilon ;
154
+ if (Double .isFinite (normal .x ) && Double .isFinite (normal .y ) && Double .isFinite (normal .z )) {
155
+ double lengthSquared = Math .abs (normal .length ());
156
+ return lengthSquared >= epsilon ;
157
157
}
158
158
return false ;
159
159
}
160
160
161
161
private static Vector3d findNormalFromNonColinearPoints (List <Vertex > vertices ) {
162
- int n = vertices .size ();
163
- Vector3d firstPoint = vertices .get (0 ).pos ;
164
-
165
- // Try to find two vectors that aren't parallel
166
- for (int i = 1 ; i < n ; i ++) {
167
- Vector3d v1 = vertices .get (i ).pos .minus (firstPoint );
168
- for (int j = i + 1 ; j < n ; j ++) {
169
- Vector3d v2 = vertices .get (j ).pos .minus (firstPoint );
170
- Vector3d cross = v1 .cross (v2 );
171
- if (isValidNormal (cross , EPSILON )) {
172
- return cross .normalized ();
173
- }
174
- }
175
- }
176
- return null ;
162
+ int n = vertices .size ();
163
+ Vector3d firstPoint = vertices .get (0 ).pos ;
164
+
165
+ // Try to find two vectors that aren't parallel
166
+ for (int i = 1 ; i < n ; i ++) {
167
+ Vector3d v1 = vertices .get (i ).pos .minus (firstPoint );
168
+ for (int j = i + 1 ; j < n ; j ++) {
169
+ Vector3d v2 = vertices .get (j ).pos .minus (firstPoint );
170
+ Vector3d cross = v1 .cross (v2 );
171
+ if (isValidNormal (cross , EPSILON )) {
172
+ return cross .normalized ();
173
+ }
174
+ }
175
+ }
176
+ return null ;
177
177
}
178
178
179
179
private static Vector3d findPrincipalDirection (List <Vertex > vertices ) {
180
- // Find the direction with maximum spread
181
- double maxX = Double .NEGATIVE_INFINITY ;
182
- double minX = Double .POSITIVE_INFINITY ;
183
- double maxY = Double .NEGATIVE_INFINITY ;
184
- double minY = Double .POSITIVE_INFINITY ;
185
- double maxZ = Double .NEGATIVE_INFINITY ;
186
- double minZ = Double .POSITIVE_INFINITY ;
187
-
188
- for (Vertex vertex : vertices ) {
189
- Vector3d pos = vertex .pos ;
190
- maxX = Math .max (maxX , pos .x );
191
- minX = Math .min (minX , pos .x );
192
- maxY = Math .max (maxY , pos .y );
193
- minY = Math .min (minY , pos .y );
194
- maxZ = Math .max (maxZ , pos .z );
195
- minZ = Math .min (minZ , pos .z );
196
- }
197
-
198
- double rangeX = maxX - minX ;
199
- double rangeY = maxY - minY ;
200
- double rangeZ = maxZ - minZ ;
201
-
202
- // Use the axis with minimum spread as normal direction
203
- if (rangeX <= rangeY && rangeX <= rangeZ ) {
204
- return new Vector3d (1 , 0 , 0 );
205
- } else if (rangeY <= rangeX && rangeY <= rangeZ ) {
206
- return new Vector3d (0 , 1 , 0 );
207
- } else {
208
- return new Vector3d (0 , 0 , 1 );
209
- }
180
+ // Find the direction with maximum spread
181
+ double maxX = Double .NEGATIVE_INFINITY ;
182
+ double minX = Double .POSITIVE_INFINITY ;
183
+ double maxY = Double .NEGATIVE_INFINITY ;
184
+ double minY = Double .POSITIVE_INFINITY ;
185
+ double maxZ = Double .NEGATIVE_INFINITY ;
186
+ double minZ = Double .POSITIVE_INFINITY ;
187
+
188
+ for (Vertex vertex : vertices ) {
189
+ Vector3d pos = vertex .pos ;
190
+ maxX = Math .max (maxX , pos .x );
191
+ minX = Math .min (minX , pos .x );
192
+ maxY = Math .max (maxY , pos .y );
193
+ minY = Math .min (minY , pos .y );
194
+ maxZ = Math .max (maxZ , pos .z );
195
+ minZ = Math .min (minZ , pos .z );
196
+ }
197
+
198
+ double rangeX = maxX - minX ;
199
+ double rangeY = maxY - minY ;
200
+ double rangeZ = maxZ - minZ ;
201
+
202
+ // Use the axis with minimum spread as normal direction
203
+ if (rangeX <= rangeY && rangeX <= rangeZ ) {
204
+ return new Vector3d (1 , 0 , 0 );
205
+ } else if (rangeY <= rangeX && rangeY <= rangeZ ) {
206
+ return new Vector3d (0 , 1 , 0 );
207
+ } else {
208
+ return new Vector3d (0 , 0 , 1 );
209
+ }
210
210
}
211
211
212
212
private static Vector3d determineStatisticalNormal (List <Vertex > vertices ) {
213
- // Calculate center of mass
214
- Vector3d center = new Vector3d (0 , 0 , 0 );
215
- for (Vertex vertex : vertices ) {
216
- center = center .plus (vertex .pos );
217
- }
218
- center = center .times (1.0 / vertices .size ());
219
-
220
- // Calculate covariance matrix
221
- double [][] covariance = new double [3 ][3 ];
222
- for (Vertex vertex : vertices ) {
223
- Vector3d diff = vertex .pos .minus (center );
224
- covariance [0 ][0 ] += diff .x * diff .x ;
225
- covariance [0 ][1 ] += diff .x * diff .y ;
226
- covariance [0 ][2 ] += diff .x * diff .z ;
227
- covariance [1 ][1 ] += diff .y * diff .y ;
228
- covariance [1 ][2 ] += diff .y * diff .z ;
229
- covariance [2 ][2 ] += diff .z * diff .z ;
230
- }
231
- covariance [1 ][0 ] = covariance [0 ][1 ];
232
- covariance [2 ][0 ] = covariance [0 ][2 ];
233
- covariance [2 ][1 ] = covariance [1 ][2 ];
234
-
235
- // Use the eigenvector corresponding to the smallest eigenvalue
236
- // For simplicity, we'll use power iteration to find it
237
- Vector3d normal = new Vector3d (1 , 1 , 1 );
238
- for (int i = 0 ; i < 10 ; i ++) {
239
- normal = multiplyMatrixVector (covariance , normal );
240
- normal = normal .normalized ();
241
- }
242
-
243
- return normal ;
213
+ // Calculate center of mass
214
+ Vector3d center = new Vector3d (0 , 0 , 0 );
215
+ for (Vertex vertex : vertices ) {
216
+ center = center .plus (vertex .pos );
217
+ }
218
+ center = center .times (1.0 / vertices .size ());
219
+
220
+ // Calculate covariance matrix
221
+ double [][] covariance = new double [3 ][3 ];
222
+ for (Vertex vertex : vertices ) {
223
+ Vector3d diff = vertex .pos .minus (center );
224
+ covariance [0 ][0 ] += diff .x * diff .x ;
225
+ covariance [0 ][1 ] += diff .x * diff .y ;
226
+ covariance [0 ][2 ] += diff .x * diff .z ;
227
+ covariance [1 ][1 ] += diff .y * diff .y ;
228
+ covariance [1 ][2 ] += diff .y * diff .z ;
229
+ covariance [2 ][2 ] += diff .z * diff .z ;
230
+ }
231
+ covariance [1 ][0 ] = covariance [0 ][1 ];
232
+ covariance [2 ][0 ] = covariance [0 ][2 ];
233
+ covariance [2 ][1 ] = covariance [1 ][2 ];
234
+
235
+ // Use the eigenvector corresponding to the smallest eigenvalue
236
+ // For simplicity, we'll use power iteration to find it
237
+ Vector3d normal = new Vector3d (1 , 1 , 1 );
238
+ for (int i = 0 ; i < 10 ; i ++) {
239
+ normal = multiplyMatrixVector (covariance , normal );
240
+ normal = normal .normalized ();
241
+ }
242
+
243
+ return normal ;
244
244
}
245
245
246
246
private static Vector3d multiplyMatrixVector (double [][] matrix , Vector3d vector ) {
247
- return new Vector3d (
248
- matrix [0 ][0 ] * vector .x + matrix [0 ][1 ] * vector .y + matrix [0 ][2 ] * vector .z ,
249
- matrix [1 ][0 ] * vector .x + matrix [1 ][1 ] * vector .y + matrix [1 ][2 ] * vector .z ,
250
- matrix [2 ][0 ] * vector .x + matrix [2 ][1 ] * vector .y + matrix [2 ][2 ] * vector .z
251
- );
247
+ return new Vector3d (matrix [0 ][0 ] * vector .x + matrix [0 ][1 ] * vector .y + matrix [0 ][2 ] * vector .z ,
248
+ matrix [1 ][0 ] * vector .x + matrix [1 ][1 ] * vector .y + matrix [1 ][2 ] * vector .z ,
249
+ matrix [2 ][0 ] * vector .x + matrix [2 ][1 ] * vector .y + matrix [2 ][2 ] * vector .z );
252
250
}
253
251
// public static Vector3d computeNormal(List<Vertex> vertices) {
254
252
// Vector3d normal = new Vector3d(0, 0, 0);
@@ -346,11 +344,13 @@ public void splitPolygon(Polygon polygon, List<Polygon> coplanarFront, List<Poly
346
344
for (int i = 0 ; i < polygon .vertices .size (); i ++) {
347
345
double t = polygon .plane .getNormal ().dot (polygon .vertices .get (i ).pos ) - polygon .plane .getDist ();
348
346
if (t > posEpsilon ) {
349
- // com.neuronrobotics.sdk.common.Log.error("Non flat polygon, increasing positive epsilon "+t);
347
+ // com.neuronrobotics.sdk.common.Log.error("Non flat polygon, increasing
348
+ // positive epsilon "+t);
350
349
posEpsilon = t + Plane .EPSILON ;
351
350
}
352
351
if (t < negEpsilon ) {
353
- // com.neuronrobotics.sdk.common.Log.error("Non flat polygon, decreasing negative epsilon "+t);
352
+ // com.neuronrobotics.sdk.common.Log.error("Non flat polygon, decreasing
353
+ // negative epsilon "+t);
354
354
negEpsilon = t - Plane .EPSILON ;
355
355
}
356
356
}
@@ -411,12 +411,12 @@ else if (somePointsInBack) {
411
411
if (f .size () >= 3 ) {
412
412
try {
413
413
front .add (new Polygon (f , polygon .getStorage ()).setColor (polygon .getColor ()));
414
- } catch (NumberFormatException ex ) {
415
- //ex.printStackTrace( );
414
+ } catch (Exception ex ) {
415
+ System . err . println ( "Pruning bad polygon Plane::splitPolygon" );
416
416
// skip adding broken polygon here
417
417
}
418
418
} else {
419
- //com.neuronrobotics.sdk.common.Log.error("Front Clip Fault!");
419
+ // com.neuronrobotics.sdk.common.Log.error("Front Clip Fault!");
420
420
}
421
421
if (b .size () >= 3 ) {
422
422
try {
@@ -426,7 +426,7 @@ else if (somePointsInBack) {
426
426
System .err .println ("Pruning bad polygon Plane::splitPolygon" );
427
427
}
428
428
} else {
429
- //com.neuronrobotics.sdk.common.Log.error("Back Clip Fault!");
429
+ // com.neuronrobotics.sdk.common.Log.error("Back Clip Fault!");
430
430
}
431
431
break ;
432
432
}
0 commit comments