Project

General

Profile

« Previous | Next » 

Revision a5bbbfb2

Added by Leszek Koltunski over 2 years ago

Adjust ShapeChanging so that it can handle concave cubit faces.
Now it is working also in case of the Ivy corner cubits.

View differences:

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