Revision a5bbbfb2
Added by Leszek Koltunski over 2 years ago
src/main/java/org/distorted/objectlib/touchcontrol/TouchControlShapeChanging.java | ||
---|---|---|
209 | 209 |
} |
210 | 210 |
|
211 | 211 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
212 |
// input: four co-planar points in 3D. Guaranteed point1 != point2 != p2 |
|
213 |
// |
|
214 |
// Draw a line through point1 and point2. This line splits the plana into two parts. |
|
215 |
// Return true iff points 'p1' and 'p2' are located in different parts. |
|
216 |
// |
|
217 |
// Points 'p1' and 'p2' are in different parts iff vectors |
|
218 |
// (p1-point2)x(point2-point1) and (p2-point2)x(point2-point1) |
|
219 |
// (which should be parallel because they are both normal to the plane) point in different directions. |
|
220 |
// |
|
221 |
// Two (almost) parallel vectors 'v1' and 'v2' point in different directions iff |v1+v2| < |v1-v2| |
|
212 |
// points A, B, C are co-linear. Return true iff B is between A and C on this line. |
|
213 |
// Compute D1 = A-B, D2=C-B. Then D1 and D2 are parallel vectors. |
|
214 |
// They disagree in direction iff |D1+D2|<|D1-D2| |
|
222 | 215 |
|
223 |
private boolean areOnDifferentSides(float[] p1, float[] p2, float[] point1, float[] point2 ) |
|
216 |
private boolean isBetween(float ax, float ay, float az, |
|
217 |
float bx, float by, float bz, |
|
218 |
float cx, float cy, float cz) |
|
224 | 219 |
{ |
225 |
float a1 = point2[0] - point1[0]; |
|
226 |
float a2 = point2[1] - point1[1]; |
|
227 |
float a3 = point2[2] - point1[2]; |
|
228 |
float b1 = p1[0] - point2[0]; |
|
229 |
float b2 = p1[1] - point2[1]; |
|
230 |
float b3 = p1[2] - point2[2]; |
|
231 |
float c1 = p2[0] - point2[0]; |
|
232 |
float c2 = p2[1] - point2[1]; |
|
233 |
float c3 = p2[2] - point2[2]; |
|
234 |
|
|
235 |
float vx1 = a2*b3-a3*b2; |
|
236 |
float vy1 = a3*b1-a1*b3; |
|
237 |
float vz1 = a1*b2-a2*b1; |
|
238 |
|
|
239 |
float vx2 = a2*c3-a3*c2; |
|
240 |
float vy2 = a3*c1-a1*c3; |
|
241 |
float vz2 = a1*c2-a2*c1; |
|
242 |
|
|
243 |
float sx = vx1+vx2; |
|
244 |
float sy = vy1+vy2; |
|
245 |
float sz = vz1+vz2; |
|
246 |
|
|
247 |
float dx = vx1-vx2; |
|
248 |
float dy = vy1-vy2; |
|
249 |
float dz = vz1-vz2; |
|
220 |
float d1x = ax-bx; |
|
221 |
float d1y = ay-by; |
|
222 |
float d1z = az-bz; |
|
223 |
|
|
224 |
float d2x = cx-bx; |
|
225 |
float d2y = cy-by; |
|
226 |
float d2z = cz-bz; |
|
227 |
|
|
228 |
float sx = d1x+d2x; |
|
229 |
float sy = d1y+d2y; |
|
230 |
float sz = d1z+d2z; |
|
231 |
|
|
232 |
float dx = d1x-d2x; |
|
233 |
float dy = d1y-d2y; |
|
234 |
float dz = d1z-d2z; |
|
250 | 235 |
|
251 | 236 |
return sx*sx+sy*sy+sz*sz < dx*dx+dy*dy+dz*dz; |
252 | 237 |
} |
253 | 238 |
|
254 | 239 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
255 |
// vertices are counterclockwise |
|
240 |
// General algorithm: shoot a half-line from the 'point' and count how many |
|
241 |
// sides of the polygon it intersects with. The point is inside iff this number |
|
242 |
// is odd. Note that this works also in case of concave polygons. |
|
243 |
// |
|
244 |
// Arbitrarily take point P on the plane ( we have decided on P=(vert[0]+vert[1])/2 ) |
|
245 |
// as the other point defining the half-line. |
|
246 |
// 'point' and 'P' define a line L1 in 3D. Then for each side the pair of its vertices |
|
247 |
// defines a line L2. If L1||L2 return false. Otherwise, the lines are skew so it's |
|
248 |
// possible to compute points C1 and C2 on lines L1 and L2 which are closest to the |
|
249 |
// other line and check if |
|
250 |
// |
|
251 |
// a) C1 and P are on the same side of 'point' |
|
252 |
// (which happens iff 'point' is not in between of C1 and P) |
|
253 |
// b) C2 is between the two vertices. |
|
254 |
// |
|
255 |
// Both a) and b) together mean that the half-line intersects with side defined by (p2,d2) |
|
256 |
// |
|
257 |
// C1 and C2 can be computed in the following way: |
|
258 |
// Let n = d1 x d2 - then vector n is perpendicular to both d1 and d2 --> (c1-c2) is |
|
259 |
// parallel to n. |
|
260 |
// There exist real numbers A,B,C such that |
|
261 |
// c1 = p1 + A*d1 |
|
262 |
// c2 = p2 + B*d2 and |
|
263 |
// c2 = c1 + C*n so that |
|
264 |
// p1 + A*d1 + C*n = p2 + B*d2 --> (p1-p2) + A*d1 = B*d2 - C*n (*) |
|
265 |
// Let n2 = n x d2. Let's multiply both sides of (*) by n2. Then |
|
266 |
// (p1-p2)*n2 + A*(d1*n2) = 0 (0 because d1*n2 = n*n2 = 0) |
|
267 |
// and from that A = [(p1-p2)*n2]/[d1*n2] |
|
268 |
// Similarly B = [(p2-p1)*n1]/[d2*n1] where n1 = n x d1. |
|
256 | 269 |
|
257 | 270 |
private boolean isInside(float[] point, float[][] vertices) |
258 | 271 |
{ |
259 |
int numVert = vertices.length; |
|
272 |
float e1x = (vertices[0][0]+vertices[1][0])/2; |
|
273 |
float e1y = (vertices[0][1]+vertices[1][1])/2; |
|
274 |
float e1z = (vertices[0][2]+vertices[1][2])/2; |
|
275 |
|
|
276 |
float d1x = e1x - point[0]; |
|
277 |
float d1y = e1y - point[1]; |
|
278 |
float d1z = e1z - point[2]; |
|
279 |
|
|
280 |
float ax = vertices[0][0] - vertices[1][0]; |
|
281 |
float ay = vertices[0][1] - vertices[1][1]; |
|
282 |
float az = vertices[0][2] - vertices[1][2]; |
|
283 |
|
|
284 |
float normX = d1y*az - d1z*ay; |
|
285 |
float normY = d1z*ax - d1x*az; |
|
286 |
float normZ = d1x*ay - d1y*ax; |
|
287 |
|
|
288 |
float n1x = d1y*normZ - d1z*normY; |
|
289 |
float n1y = d1z*normX - d1x*normZ; |
|
290 |
float n1z = d1x*normY - d1y*normX; |
|
291 |
|
|
292 |
float p1x = point[0]; |
|
293 |
float p1y = point[1]; |
|
294 |
float p1z = point[2]; |
|
295 |
|
|
296 |
int len = vertices.length; |
|
297 |
int numCrossings = 0; |
|
260 | 298 |
|
261 |
for(int i=0; i<numVert; i++)
|
|
299 |
for(int side=0; side<len; side++)
|
|
262 | 300 |
{ |
263 |
int index1= i==numVert-1 ? 0 : i+1; |
|
264 |
int index2= i==0 ? numVert-1 : i-1; |
|
265 |
if( areOnDifferentSides(point,vertices[index2],vertices[i],vertices[index1]) ) return false; |
|
301 |
float p2x = vertices[side][0]; |
|
302 |
float p2y = vertices[side][1]; |
|
303 |
float p2z = vertices[side][2]; |
|
304 |
|
|
305 |
int next = side==len-1 ? 0 : side+1; |
|
306 |
|
|
307 |
float e2x = vertices[next][0]; |
|
308 |
float e2y = vertices[next][1]; |
|
309 |
float e2z = vertices[next][2]; |
|
310 |
|
|
311 |
float d2x = e2x-p2x; |
|
312 |
float d2y = e2y-p2y; |
|
313 |
float d2z = e2z-p2z; |
|
314 |
|
|
315 |
float nx = d2y*d1z - d2z*d1y; |
|
316 |
float ny = d2z*d1x - d2x*d1z; |
|
317 |
float nz = d2x*d1y - d2y*d1x; |
|
318 |
|
|
319 |
float n2x = d2y*nz - d2z*ny; |
|
320 |
float n2y = d2z*nx - d2x*nz; |
|
321 |
float n2z = d2x*ny - d2y*nx; |
|
322 |
|
|
323 |
float dpx = p1x-p2x; |
|
324 |
float dpy = p1y-p2y; |
|
325 |
float dpz = p1z-p2z; |
|
326 |
|
|
327 |
float A1 =-dpx*n2x-dpy*n2y-dpz*n2z; |
|
328 |
float B1 = d1x*n2x+d1y*n2y+d1z*n2z; |
|
329 |
|
|
330 |
float A2 = dpx*n1x+dpy*n1y+dpz*n1z; |
|
331 |
float B2 = d2x*n1x+d2y*n1y+d2z*n1z; |
|
332 |
|
|
333 |
if( B1==0 || B2==0 ) continue; |
|
334 |
|
|
335 |
float C1 = A1/B1; |
|
336 |
float C2 = A2/B2; |
|
337 |
|
|
338 |
float c1x = p1x + C1*d1x; |
|
339 |
float c1y = p1y + C1*d1y; |
|
340 |
float c1z = p1z + C1*d1z; |
|
341 |
|
|
342 |
float c2x = p2x + C2*d2x; |
|
343 |
float c2y = p2y + C2*d2y; |
|
344 |
float c2z = p2z + C2*d2z; |
|
345 |
|
|
346 |
if( !isBetween(c1x,c1y,c1z, p1x,p1y,p1z, e1x,e1y,e1z ) && |
|
347 |
isBetween(p2x,p2y,p2z, c2x,c2y,c2z, e2x,e2y,e2z ) ) |
|
348 |
{ |
|
349 |
numCrossings++; |
|
350 |
} |
|
266 | 351 |
} |
267 | 352 |
|
268 |
return true;
|
|
353 |
return (numCrossings%2)==1;
|
|
269 | 354 |
} |
270 | 355 |
|
271 | 356 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
Also available in: Unified diff
Adjust ShapeChanging so that it can handle concave cubit faces.
Now it is working also in case of the Ivy corner cubits.