1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10
11
12 #include <dx/dx.h>
13 #include <math.h>
14
15 #if defined(HAVE_STRING_H)
16 #include <string.h>
17 #endif
18
19 #define ZOFFSET 1.0
20 #define SENSITIVITY 4.0
21
22 typedef struct
23 {
24 float x, y;
25 } Point2D;
26
27 typedef struct
28 {
29 int depth;
30 int pickPath[10240];
31 Array picks;
32 Array paths;
33 Array weights;
34 } PickBuf;
35
36 typedef struct
37 {
38 Point xyz;
39 int index;
40 int pathlen;
41 int poke;
42 } Pick;
43
44 typedef struct
45 {
46 int segment;
47 int nweights;
48 } PickWts;
49
50 #define BOX_HIT 1
51 #define BOX_MISS 0
52 #define BOX_ERROR -1
53
54 static Error GetObjectAndCameraFromCache(char *, Object *, Camera *);
55 static Field GetPicksFromCache(char *, Object *);
56 static Error PutPicksIntoCache(char *, Object *, Field);
57
58 static Error PickObject(Object object, PickBuf *pick, int, Point2D *,
59 Matrix *stack, int, float, float,
60 float, float, Camera);
61
62 static Error PickField(Field f, PickBuf *p, int, Point2D,
63 Matrix *s, int, float, float,
64 float, float);
65 static int PickBox(Field f, Point2D, Matrix *s, int, float);
66 static Point *TransformArray(Array src, Matrix *m);
67 static int TriangleHit(Point **, Point2D *, Point *, int, float *);
68
69 static Error PickTriangles(Field, PickBuf *, int, Point2D,
70 Matrix *, int, float, float,
71 float, float);
72 static Error PickQuads(Field, PickBuf *, int, Point2D,
73 Matrix *, int, float, float,
74 float, float);
75 static Error Elt2D_Perspective(PickBuf *, int, Point2D, Point *,
76 int *, int, int, int,
77 float, int *, float,
78 float, float);
79 static Error Elt2D_NoPerspective(PickBuf *, int, Point2D, Point *,
80 int *, int, int, int,
81 float, int *, float,
82 float, float);
83
84 static Error PickLines(Field, PickBuf *, int, Point2D,
85 Matrix *, int, float, float,
86 float, float);
87 static Error Elt1D_Perspective(PickBuf *, int, Point2D, Point *,
88 int *, int, int, float, float,
89 float, float);
90 static Error Elt1D_NoPerspective(PickBuf *, int, Point2D, Point *,
91 int *, int, int, float, float,
92 float, float);
93
94 static Error PickPoints(Field, PickBuf *, int, Point2D,
95 Matrix *, int, float, float,
96 float, float);
97 static Error Elt0D_Perspective(PickBuf *, int, Point2D, Point *,
98 int, float, float,
99 float, float);
100 static Error Elt0D_NoPerspective(PickBuf *, int, Point2D, Point *,
101 int, float, float,
102 float, float);
103
104 static Error PickFLE(Field, PickBuf *, int, Point2D,
105 Matrix *, int, float, float,
106 float, float);
107 static Error FLE_NoPerspective(PickBuf *, int, Point2D, Point *, int,
108 int *, int, int *, int, int *, int,
109 float, float,
110 float, float);
111 static Error FLE_Perspective(PickBuf *, int, Point2D, Point *, int,
112 int *, int, int *, int, int *, int,
113 float, float,
114 float, float);
115
116 static Error PickPolylines(Field, PickBuf *, int, Point2D,
117 Matrix *, int, float, float,
118 float, float);
119
120 static Error Polyline_Perspective(PickBuf *, int, Point2D, Point *,
121 int *, int *, int, int, int, float,
122 float, float, float);
123
124 static Error Polyline_NoPerspective(PickBuf *, int, Point2D, Point *,
125 int *, int *, int, int, int, float,
126 float, float, float);
127
128 static Error AddPick(PickBuf *, int, Point, int, int, float *);
129 static Field PickBufToField(PickBuf *, Matrix);
130 static Field GetFirstHits(Field);
131 static Error PickInterpolate(Object, Field, int);
132
133 extern Error _dxfLoadStereoModes();
134 extern Error _dxfInitializeStereoCameraMode(void *, Object);
135
136 #define CACHE_PICKS 1
137 #define NO_CACHE_PICKS 0
138
139 #define FIRST_HIT_ONLY 1
140 #define ALL_HITS 0
141
142 #define PICK_TAG_ARG 0
143 #define IMAGE_TAG_ARG 1
144 #define LIST_ARG 2
145 #define STEP_ARG 3
146 #define FIRST_ARG 4
147 #define PERSISTENCE_ARG 5
148 #define INTERPOLATE_ARG 6
149 #define OBJECT_ARG 7
150 #define CAMERA_ARG 8
151
152 #define NO_INTERP 0
153 #define CLOSEST_VERTEX 1
154 #define INTERPOLATE 2
155
156 /*
157 * Used only by StereoPick
158 */
159 #define STEREO_ARG 9
160 #define WHERE_ARG 10
161
162 static Array getXY(Array);
163
164 Error
m_Pick(Object * in,Object * out)165 m_Pick(Object *in, Object *out)
166 {
167 Object cacheObject = NULL, object = NULL;
168 Array list = NULL;
169 Camera camera = NULL;
170 PickBuf pick;
171 int nPicks, nDim, i;
172 Matrix initialMatrix, cameraMatrix, invCameraMatrix;
173 Point2D *xy, *xyPicks = NULL;
174 int persp;
175 float nearPlane;
176 float width;
177 float xCenter, yCenter;
178 int xRes, yRes;
179 Field result = NULL, field = NULL;
180 float sensitivity;
181 char *ptag, *itag;
182 int persistence;
183 int first;
184 int interpolate = NO_INTERP;
185
186 pick.picks = NULL;
187 pick.paths = NULL;
188 pick.weights = NULL;
189 pick.depth = 0;
190
191 out[0] = NULL;
192
193 if (in[CAMERA_ARG])
194 {
195 if (in[OBJECT_ARG] == NULL)
196 {
197 DXSetError(ERROR_MISSING_DATA, "#10000", "object");
198 goto error;
199 }
200 object = in[OBJECT_ARG];
201
202 if (in[CAMERA_ARG] == NULL)
203 {
204 DXSetError(ERROR_MISSING_DATA, "#10000", "camera");
205 goto error;
206 }
207 camera = (Camera)in[CAMERA_ARG];
208
209 if (in[FIRST_ARG])
210 {
211 if (! DXExtractInteger(in[FIRST_ARG], &first))
212 {
213 DXSetError(ERROR_BAD_PARAMETER, "first must be integer");
214 goto error;
215 }
216
217 if (first != FIRST_HIT_ONLY && first != ALL_HITS)
218 {
219 DXSetError(ERROR_BAD_PARAMETER, "first must be 0 or 1");
220 goto error;
221 }
222 }
223 else
224 first = FIRST_HIT_ONLY;
225
226 if (in[INTERPOLATE_ARG])
227 {
228 if (! DXExtractInteger(in[INTERPOLATE_ARG], &interpolate))
229 {
230 DXSetError(ERROR_BAD_PARAMETER, "interpolate must be integer");
231 goto error;
232 }
233
234 if (interpolate != NO_INTERP &&
235 interpolate != CLOSEST_VERTEX &&
236 interpolate != INTERPOLATE)
237 {
238 DXSetError(ERROR_BAD_PARAMETER, "interpolate must be %d %d or %d",
239 NO_INTERP, CLOSEST_VERTEX, INTERPOLATE);
240 goto error;
241 }
242 }
243
244 list = (Array)in[LIST_ARG];
245 if (list)
246 {
247 list = getXY(list);
248 if (!list && DXGetError() != ERROR_NONE)
249 goto error;
250 }
251
252 if (object && camera && list)
253 {
254 DXGetArrayInfo(list, &nPicks, NULL, NULL, NULL, &nDim);
255 if (nDim != 2)
256 {
257 DXSetError(ERROR_DATA_INVALID, "pick list must be 2-D");
258 goto error;
259 }
260
261 xyPicks = (Point2D *)DXAllocate(nPicks*sizeof(Point2D));
262 if (! xyPicks)
263 goto error;
264
265 if (! DXExtractParameter((Object)list, TYPE_FLOAT,
266 2, nPicks, (Pointer)xyPicks))
267 goto error;
268
269 cameraMatrix = DXGetCameraMatrix(camera);
270 cameraMatrix = DXConcatenate(cameraMatrix,
271 DXTranslate(DXPt(0.0,0.0,ZOFFSET)));
272 invCameraMatrix = DXInvert(cameraMatrix);
273
274 DXGetCameraResolution(camera, &xRes, &yRes);
275
276 persp = 0;
277 if (! DXGetOrthographic(camera, &width, NULL))
278 {
279 DXGetPerspective(camera, &width, NULL);
280 persp = 1;
281 nearPlane = -0.001;
282 }
283 else
284 {
285 nearPlane = DXD_MAX_FLOAT;
286 }
287
288 xCenter = xRes / 2.0;
289 yCenter = yRes / 2.0;
290
291 sensitivity = SENSITIVITY;
292
293 initialMatrix = cameraMatrix;
294
295
296 xy = xyPicks;
297 for (i = 0; i < nPicks; i++, xy ++)
298 {
299 xy->x = xy->x - xCenter;
300 xy->y = (yRes-xy->y) - yCenter;
301
302 if (! PickObject(object, &pick, i, xy, &initialMatrix, persp,
303 nearPlane, sensitivity, -DXD_MAX_FLOAT, DXD_MAX_FLOAT,
304 camera))
305 goto error;
306 }
307
308 field = PickBufToField(&pick, invCameraMatrix);
309 if (! field)
310 goto error;
311
312
313 if (! DXSetAttribute((Object)field, "pick object", object))
314 goto error;
315
316 }
317
318 if (field)
319 {
320 object = DXGetAttribute((Object)field, "pick object");
321 if (! object)
322 {
323 DXSetError(ERROR_MISSING_DATA,
324 "unable to access pick object attribute");
325 goto error;
326 }
327
328 if (first == FIRST_HIT_ONLY)
329 result = GetFirstHits(field);
330 else
331 {
332 result = (Field)DXCopy((Object)field, COPY_STRUCTURE);
333 DXSetAttribute((Object)result, "pick object", NULL);
334 }
335
336 if (! result)
337 goto error;
338
339 if (interpolate && !DXEmptyField(result))
340 {
341 Array array;
342 int n, nn, i;
343
344 if (! PickInterpolate(object, result, interpolate))
345 goto error;
346
347 /*
348 * error check to verify that all picks got all data
349 */
350
351 array = (Array)DXGetComponentValue(result, "positions");
352 DXGetArrayInfo(array, &n, NULL, NULL, NULL, NULL);
353
354 for (i = 0;
355 NULL != (array =
356 (Array)DXGetEnumeratedComponentValue(result, i, NULL));
357 i++)
358 {
359 Object attr = DXGetAttribute((Object)array, "dep");
360 if (! attr)
361 continue;
362
363 if (! strcmp("positions", DXGetString((String)attr)))
364 {
365 DXGetArrayInfo(array, &nn, NULL, NULL, NULL, NULL);
366 if (nn != n)
367 {
368 DXSetError(ERROR_DATA_INVALID,
369 "component mismatch in pick object");
370 goto error;
371 }
372 }
373 }
374 }
375
376 DXDeleteComponent(result, "pick weights");
377
378 DXDelete(DXReference((Object)field));
379 }
380 else
381 {
382 result = DXNewField();
383 if (! result)
384 goto error;
385 }
386 }
387 else
388 {
389 if (in[PICK_TAG_ARG] == NULL)
390 {
391 DXSetError(ERROR_MISSING_DATA, "#10000", "pickTag");
392 goto error;
393 }
394
395 if (! DXExtractString(in[PICK_TAG_ARG], &ptag))
396 {
397 DXSetError(ERROR_DATA_INVALID, "pickTag must be STRING");
398 goto error;
399 }
400
401 if (in[IMAGE_TAG_ARG] == NULL)
402 {
403 if (in[LIST_ARG] != NULL)
404 {
405 DXSetError(ERROR_MISSING_DATA, "#10000", "imageTag");
406 goto error;
407 }
408 }
409 else
410 {
411 if (! DXExtractString(in[IMAGE_TAG_ARG], &itag))
412 {
413 DXSetError(ERROR_DATA_INVALID, "imageTag must be STRING");
414 goto error;
415 }
416
417 if (! GetObjectAndCameraFromCache(itag, &cacheObject, &camera))
418 goto error;
419 }
420
421 if (in[PERSISTENCE_ARG])
422 {
423 if (! DXExtractInteger(in[PERSISTENCE_ARG], &persistence))
424 {
425 DXSetError(ERROR_BAD_PARAMETER, "persistence must be integer");
426 goto error;
427 }
428
429 if (persistence != CACHE_PICKS && persistence != NO_CACHE_PICKS)
430 {
431 DXSetError(ERROR_BAD_PARAMETER, "persistence must be 0 or 1");
432 goto error;
433 }
434 }
435 else
436 persistence = CACHE_PICKS;
437
438 if (in[FIRST_ARG])
439 {
440 if (! DXExtractInteger(in[FIRST_ARG], &first))
441 {
442 DXSetError(ERROR_BAD_PARAMETER, "first must be integer");
443 goto error;
444 }
445
446 if (first != FIRST_HIT_ONLY && first != ALL_HITS)
447 {
448 DXSetError(ERROR_BAD_PARAMETER, "first must be 0 or 1");
449 goto error;
450 }
451 }
452 else
453 first = FIRST_HIT_ONLY;
454
455 if (in[INTERPOLATE_ARG])
456 {
457 if (! DXExtractInteger(in[INTERPOLATE_ARG], &interpolate))
458 {
459 DXSetError(ERROR_BAD_PARAMETER, "interpolate must be integer");
460 goto error;
461 }
462
463 if (interpolate != NO_INTERP &&
464 interpolate != CLOSEST_VERTEX &&
465 interpolate != INTERPOLATE)
466 {
467 DXSetError(ERROR_BAD_PARAMETER, "interpolate must be %d %d or %d",
468 NO_INTERP, CLOSEST_VERTEX, INTERPOLATE);
469 goto error;
470 }
471 }
472
473 object = in[OBJECT_ARG];
474 if (! object)
475 object = cacheObject;
476
477 list = (Array)in[LIST_ARG];
478
479 if (object && camera && list)
480 {
481 if (DXGetObjectClass((Object)list) != CLASS_ARRAY)
482 {
483 DXSetError(ERROR_DATA_INVALID, "pick list must be class ARRAY");
484 goto error;
485 }
486
487 DXGetArrayInfo(list, &nPicks, NULL, NULL, NULL, &nDim);
488 if (nDim != 2)
489 {
490 DXSetError(ERROR_DATA_INVALID, "pick list must be 2-D");
491 goto error;
492 }
493
494 xyPicks = (Point2D *)DXAllocate(nPicks*sizeof(Point2D));
495 if (! xyPicks)
496 goto error;
497
498 if (! DXExtractParameter((Object)list, TYPE_FLOAT,
499 2, nPicks, (Pointer)xyPicks))
500 goto error;
501
502 cameraMatrix = DXGetCameraMatrix(camera);
503 cameraMatrix = DXConcatenate(cameraMatrix,
504 DXTranslate(DXPt(0.0,0.0,ZOFFSET)));
505 invCameraMatrix = DXInvert(cameraMatrix);
506
507 DXGetCameraResolution(camera, &xRes, &yRes);
508
509 persp = 0;
510 if (! DXGetOrthographic(camera, &width, NULL))
511 {
512 DXGetPerspective(camera, &width, NULL);
513 persp = 1;
514 nearPlane = -0.001;
515 }
516 else
517 {
518 nearPlane = DXD_MAX_FLOAT;
519 }
520
521 xCenter = xRes / 2.0;
522 yCenter = yRes / 2.0;
523
524 sensitivity = SENSITIVITY;
525
526 initialMatrix = cameraMatrix;
527
528 xy = xyPicks;
529 for (i = 0; i < nPicks; i++, xy ++)
530 {
531 xy->x = xy->x - xCenter;
532 xy->y = xy->y - yCenter;
533
534 if (! PickObject(object, &pick, i, xy, &initialMatrix, persp,
535 nearPlane, sensitivity, -DXD_MAX_FLOAT, DXD_MAX_FLOAT,
536 camera))
537 goto error;
538 }
539
540 field = PickBufToField(&pick, invCameraMatrix);
541 if (! field)
542 goto error;
543
544
545 if (! DXSetAttribute((Object)field, "pick object", object))
546 goto error;
547
548 if (! PutPicksIntoCache(ptag, in, field))
549 goto error;
550
551 }
552 else if (persistence == CACHE_PICKS)
553 {
554 field = GetPicksFromCache(ptag, in);
555 }
556
557 if (field)
558 {
559 object = DXGetAttribute((Object)field, "pick object");
560 if (! object)
561 {
562 DXSetError(ERROR_MISSING_DATA,
563 "unable to access pick object attribute");
564 goto error;
565 }
566
567 if (first == FIRST_HIT_ONLY)
568 result = GetFirstHits(field);
569 else
570 {
571 result = (Field)DXCopy((Object)field, COPY_STRUCTURE);
572 DXSetAttribute((Object)result, "pick object", NULL);
573 }
574
575 if (! result)
576 goto error;
577
578 if (interpolate && !DXEmptyField(result))
579 {
580 Array array;
581 int n, nn, i;
582
583 if (! PickInterpolate(object, result, interpolate))
584 goto error;
585
586 /*
587 * error check to verify that all picks got all data
588 */
589
590 array = (Array)DXGetComponentValue(result, "positions");
591 DXGetArrayInfo(array, &n, NULL, NULL, NULL, NULL);
592
593 for (i = 0;
594 NULL != (array =
595 (Array)DXGetEnumeratedComponentValue(result, i, NULL));
596 i++)
597 {
598 Object attr = DXGetAttribute((Object)array, "dep");
599 if (! attr)
600 continue;
601
602 if (! strcmp("positions", DXGetString((String)attr)))
603 {
604 DXGetArrayInfo(array, &nn, NULL, NULL, NULL, NULL);
605 if (nn != n)
606 {
607 DXSetError(ERROR_DATA_INVALID,
608 "component mismatch in pick object");
609 goto error;
610 }
611 }
612 }
613 }
614
615 DXDeleteComponent(result, "pick weights");
616
617 DXDelete(DXReference((Object)field));
618 }
619 else
620 {
621 result = DXNewField();
622 if (! result)
623 goto error;
624 }
625
626 }
627
628 if (camera != (Camera)in[CAMERA_ARG])
629 DXDelete((Object)camera);
630
631 if (list && (Object)list != in[LIST_ARG])
632 DXDelete((Object)list);
633
634 if (! result)
635 out[0] = (Object)DXNewField();
636 else
637 out[0] = (Object)result;
638
639 DXDelete((Object)cacheObject);
640 DXDelete((Object)pick.picks);
641 DXDelete((Object)pick.paths);
642 DXDelete((Object)pick.weights);
643
644 DXFree((Pointer)xyPicks);
645
646 return OK;
647
648 error:
649 if (list && (Object)list != in[LIST_ARG])
650 DXDelete((Object)list);
651
652 if (camera != (Camera)in[CAMERA_ARG])
653 DXDelete((Object)camera);
654
655 DXDelete((Object)cacheObject);
656 DXDelete((Object)camera);
657
658 if (field)
659 DXDelete(DXReference((Object)field));
660
661 DXDelete((Object)result);
662 DXDelete((Object)pick.picks);
663 DXDelete((Object)pick.paths);
664 DXDelete((Object)pick.weights);
665 DXFree((Pointer)xyPicks);
666
667 out[0] = NULL;
668
669 return ERROR;
670 }
671
672 extern Error _dxfGetStereoCameras(void *, Camera, Camera *, Camera *);
673 extern void *_dxfGetStereoWindowInfo(char *, void *, void *);
674
m_StereoPick(Object * in,Object * out)675 Error m_StereoPick(Object *in, Object *out)
676 {
677 Camera camera, lcamera, rcamera;
678 char *where;
679 void *globals;
680
681 out[0] = NULL;
682
683 if (! in[LIST_ARG])
684 return OK;
685
686 in[LIST_ARG] = (Object)getXY((Array)in[LIST_ARG]);
687 if (! in[LIST_ARG])
688 return OK;
689
690 if (! in[STEREO_ARG])
691 {
692 DXSetError(ERROR_BAD_PARAMETER, "stereo arg must be given");
693 return ERROR;
694 }
695
696 if (! in[WHERE_ARG] || ! DXExtractString(in[WHERE_ARG], &where))
697 {
698 DXSetError(ERROR_BAD_PARAMETER, "where must be given");
699 return ERROR;
700 }
701
702 if (! _dxfLoadStereoModes())
703 {
704 DXSetError(ERROR_BAD_PARAMETER, "error loading stereo code");
705 return ERROR;
706 }
707
708 globals = _dxfGetStereoWindowInfo(where, NULL, NULL);
709 if (! globals)
710 {
711 DXSetError(ERROR_BAD_PARAMETER, "error accessing stereo window info");
712 return ERROR;
713 }
714
715 if (! in[CAMERA_ARG])
716 {
717 DXSetError(ERROR_BAD_PARAMETER, "camera arg must be given");
718 return ERROR;
719 }
720
721 camera = (Camera)in[CAMERA_ARG];
722
723 _dxfLoadStereoModes();
724
725 if (! _dxfInitializeStereoCameraMode(globals, in[STEREO_ARG]))
726 {
727 DXSetError(ERROR_BAD_PARAMETER, "error initting stereo mode");
728 return ERROR;
729 }
730
731 if (! _dxfGetStereoCameras(globals, camera, &lcamera, &rcamera))
732 {
733 DXSetError(ERROR_BAD_PARAMETER, "error getting stereo cameras");
734 return ERROR;
735 }
736
737 return m_Pick(in, out);
738 }
739
740 static Field
GetPicksFromCache(char * tag,Object * in)741 GetPicksFromCache(char *tag, Object *in)
742 {
743 Object obj;
744 char *buf = (char *)DXAllocate(strlen(tag) + strlen(".picks") + 1);
745 if (! buf)
746 return ERROR;
747
748 sprintf(buf, "%s.picks", tag);
749
750 obj = DXGetCacheEntry(buf, 0, 1, in[OBJECT_ARG]);
751
752 DXFree((Pointer)buf);
753 return (Field)obj;
754 }
755
756 static Error
PutPicksIntoCache(char * tag,Object * in,Field f)757 PutPicksIntoCache(char *tag, Object *in, Field f)
758 {
759 Error e;
760 char *buf = (char *)DXAllocate(strlen(tag) + strlen(".picks") + 1);
761 if (! buf)
762 return ERROR;
763
764 sprintf(buf, "%s.picks", tag);
765
766 e = DXSetCacheEntry((Object)f, CACHE_PERMANENT, buf, 0, 1,
767 in[OBJECT_ARG]);
768
769 DXFree((Pointer)buf);
770 return e;
771 }
772
773 static Error
AddPick(PickBuf * p,int poke,Point xyz,int nwts,int seg,float * wts)774 AddPick(PickBuf *p, int poke, Point xyz, int nwts, int seg, float *wts)
775 {
776 int nPicks, nPathElts, depth = p->depth + 2, wtLnth;
777 Pick pick;
778 PickWts pickWts;
779
780 if (p->picks == NULL)
781 {
782 p->picks = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 1, sizeof(Pick));
783 p->paths = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
784 p->weights = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0);
785 if (! p->picks || ! p->paths || ! p->weights)
786 return ERROR;
787
788 DXReference((Object)p->picks);
789 DXReference((Object)p->paths);
790 DXReference((Object)p->weights);
791 }
792
793 DXGetArrayInfo(p->picks, &nPicks, NULL, NULL, NULL, NULL);
794 DXGetArrayInfo(p->paths, &nPathElts, NULL, NULL, NULL, NULL);
795
796 pick.xyz = xyz;
797 pick.index = nPathElts;
798 pick.poke = poke;
799 pick.pathlen = depth;
800
801 if (! DXAddArrayData(p->picks, nPicks, 1, (Pointer)&pick))
802 return ERROR;
803
804 if (! DXAddArrayData(p->paths, nPathElts, depth, (Pointer)p->pickPath))
805 return ERROR;
806
807 pickWts.nweights = nwts;
808 pickWts.segment = seg;
809
810 DXGetArrayInfo(p->weights, &wtLnth, NULL, NULL, NULL, NULL);
811 if (! DXAddArrayData(p->weights, wtLnth, sizeof(pickWts), (Pointer)&pickWts))
812 return ERROR;
813
814 if (nwts)
815 {
816 wtLnth += sizeof(pickWts);
817 if (! DXAddArrayData(p->weights, wtLnth, nwts*sizeof(float), (Pointer)wts))
818 return ERROR;
819 }
820
821 return OK;
822 }
823
824 #define TYPE Pick
825 #define LT(a,b) ((a)->poke < (b)->poke || \
826 (((a)->poke == (b)->poke) && (a)->xyz.z > (b)->xyz.z))
827 #define GT(a,b) ((a)->poke > (b)->poke || \
828 (((a)->poke == (b)->poke) && (a)->xyz.z < (b)->xyz.z))
829 #define QUICKSORT picksort
830
831 #include "../libdx/qsort.c"
832
833 static Field
PickBufToField(PickBuf * p,Matrix m)834 PickBufToField(PickBuf *p, Matrix m)
835 {
836 Array positions = NULL;
837 Array pokes = NULL;
838 Array indices = NULL;
839 Array paths = NULL;
840 Field field = NULL;
841 int nPicks, nPokes, nPathElts;
842 Pick *picks;
843 Point *posPtr;
844 int *pokPtr;
845 int *idxPtr;
846 int *pathSrc, *pathDst;
847 int i, j, lastPoke;
848
849 if (p->picks == NULL)
850 return DXNewField();
851
852 DXGetArrayInfo(p->picks, &nPicks, NULL, NULL, NULL, NULL);
853 DXGetArrayInfo(p->paths, &nPathElts, NULL, NULL, NULL, NULL);
854
855 picks = (Pick *)DXGetArrayData(p->picks);
856
857 picksort(picks, nPicks);
858
859 /*
860 * Count the pokes
861 */
862 nPokes = 1;
863 i = picks[0].poke;
864 for (j = 1; j < nPicks; j++)
865 if (i != picks[j].poke)
866 {
867 nPokes ++;
868 i = picks[j].poke;
869 }
870
871 positions = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3);
872 pokes = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
873 indices = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
874 paths = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
875
876 if (! positions || ! pokes || ! indices || ! paths)
877 return NULL;
878
879 if (! DXAddArrayData(positions, 0, nPicks, NULL) ||
880 ! DXAddArrayData(pokes, 0, nPokes, NULL) ||
881 ! DXAddArrayData(indices, 0, nPicks, NULL) ||
882 ! DXAddArrayData(paths, 0, nPathElts, NULL))
883 return NULL;
884
885 posPtr = (Point *)DXGetArrayData(positions);
886 pokPtr = (int *)DXGetArrayData(pokes);
887 idxPtr = (int *)DXGetArrayData(indices);
888
889 pathSrc = (int *)DXGetArrayData(p->paths);
890 pathDst = (int *)DXGetArrayData(paths);
891
892 lastPoke = -1;
893 for (i = j = 0; i < nPicks; i++, picks ++)
894 {
895 *posPtr++ = DXApply(picks->xyz, m);
896 *idxPtr++ = j;
897
898 memcpy(pathDst, pathSrc+picks->index, picks->pathlen*sizeof(int));
899 pathDst += picks->pathlen;
900 j += picks->pathlen;
901
902 if (picks->poke != lastPoke)
903 {
904 *pokPtr++ = i;
905 lastPoke = picks->poke;
906 }
907 }
908
909 field = DXNewField();
910 if (! field)
911 goto error;
912
913 if ((! DXSetStringAttribute((Object)positions, "dep", "positions")) ||
914 (! DXSetStringAttribute((Object)pokes, "ref", "picks")) ||
915 (! DXSetStringAttribute((Object)indices, "dep", "positions")) ||
916 (! DXSetStringAttribute((Object)indices, "ref", "pick paths")))
917 goto error;
918
919 if (! DXSetComponentValue(field, "positions", (Object)positions))
920 goto error;
921 positions = NULL;
922
923 if (! DXSetComponentValue(field, "pokes", (Object)pokes))
924 goto error;
925 pokes = NULL;
926
927 if (! DXSetComponentValue(field, "picks", (Object)indices))
928 goto error;
929 indices = NULL;
930
931 if (! DXSetComponentValue(field, "pick paths", (Object)paths))
932 goto error;
933 paths = NULL;
934
935 if (! DXSetComponentValue(field, "pick weights", (Object)p->weights))
936 goto error;
937
938 return field;
939
940 error:
941 DXDelete((Object)positions);
942 DXDelete((Object)pokes);
943 DXDelete((Object)indices);
944 DXDelete((Object)paths);
945 DXDelete((Object)field);
946 return NULL;
947 }
948
949 static Error
GetObjectAndCameraFromCache(char * tag,Object * object,Camera * camera)950 GetObjectAndCameraFromCache(char *tag, Object *object, Camera *camera)
951 {
952 char *buf;
953
954 if (object)
955 {
956 buf = (char *)DXAllocate(strlen(tag) + strlen(".object") + 1);
957 if (! buf)
958 goto error;
959
960 sprintf(buf, "%s.object", tag);
961
962 *object = DXGetCacheEntry(buf, 0, 0);
963 DXFree((Pointer)buf);
964 }
965
966 if (camera)
967 {
968 buf = (char *)DXAllocate(strlen(tag) + strlen(".camera") + 1);
969 if (! buf)
970 goto error;
971
972 sprintf(buf, "%s.camera", tag);
973
974 *camera = (Camera)DXGetCacheEntry(buf, 0, 0);
975 DXFree((Pointer)buf);
976 }
977
978 return OK;
979
980 error:
981 return ERROR;
982 }
983
984 static Error
PickObject(Object object,PickBuf * pick,int poke,Point2D * xy,Matrix * stack,int persp,float nearPlane,float sens,float min,float max,Camera camera)985 PickObject(Object object, PickBuf *pick, int poke, Point2D *xy,
986 Matrix *stack, int persp, float nearPlane, float sens,
987 float min, float max, Camera camera)
988 {
989 Object attr = DXGetAttribute(object, "pickable");
990 int pickable;
991
992 if (attr)
993 {
994 if (! DXExtractInteger(attr, &pickable))
995 {
996 DXSetError(ERROR_DATA_INVALID,
997 "pickable attribute must be an integer");
998 return ERROR;
999 }
1000
1001 if (! pickable)
1002 return OK;
1003 }
1004
1005 switch(DXGetObjectClass(object))
1006 {
1007 case CLASS_XFORM:
1008 {
1009 Object child;
1010 Matrix matrix, product;
1011
1012 if (! DXGetXformInfo((Xform)object, &child, &matrix))
1013 goto error;
1014
1015 product = DXConcatenate(matrix, *stack);
1016
1017 pick->pickPath[pick->depth++] = 0;
1018
1019 if (! PickObject(child, pick, poke, xy,
1020 &product, persp, nearPlane,
1021 sens, min, max, camera))
1022 return ERROR;
1023
1024 pick->depth --;
1025 return OK;
1026 }
1027
1028 case CLASS_CLIPPED:
1029 {
1030 Object child;
1031 Object clipper;
1032 PickBuf clipPick;
1033
1034 clipPick.picks = NULL;
1035 clipPick.paths = NULL;
1036 clipPick.depth = pick->depth;
1037
1038 if (! DXGetClippedInfo((Clipped)object, &child, &clipper))
1039 goto error;
1040
1041 pick->pickPath[pick->depth++] = 0;
1042
1043 if (! PickObject(clipper, &clipPick, poke, xy, stack,
1044 persp, nearPlane, sens, min, max, camera))
1045 return ERROR;
1046
1047 if (clipPick.picks)
1048 {
1049 int nPicks;
1050 Pick *picks = (Pick *)DXGetArrayData(clipPick.picks);
1051
1052 DXGetArrayInfo(clipPick.picks, &nPicks, NULL, NULL, NULL, NULL);
1053
1054 if (nPicks == 1)
1055 {
1056 max = picks->xyz.z;
1057 }
1058 else
1059 {
1060 picksort(picks, nPicks);
1061 max = picks[0].xyz.z;
1062 min = picks[nPicks-1].xyz.z;
1063 }
1064
1065 DXDelete((Object)clipPick.picks);
1066 DXDelete((Object)clipPick.paths);
1067 }
1068
1069 if (! PickObject(child, pick, poke, xy, stack,
1070 persp, nearPlane, sens, min, max, camera))
1071 return ERROR;
1072
1073 pick->depth --;
1074
1075 return OK;
1076 }
1077
1078 case CLASS_GROUP:
1079 {
1080 Object child;
1081 int i;
1082
1083 pick->depth ++;
1084
1085 for (i = 0;;i++)
1086 {
1087 child = DXGetEnumeratedMember((Group)object, i, NULL);
1088 if (! child)
1089 break;
1090
1091 pick->pickPath[pick->depth-1] = i;
1092
1093 if (! PickObject(child, pick, poke, xy,
1094 stack, persp, nearPlane, sens, min, max, camera))
1095 return ERROR;
1096 }
1097
1098 pick->depth --;
1099
1100 return OK;
1101 }
1102
1103 case CLASS_FIELD:
1104 {
1105 return PickField((Field)object, pick, poke, *xy,
1106 stack, persp, nearPlane, sens, min, max);
1107 }
1108
1109 case CLASS_SCREEN:
1110 {
1111 Object child;
1112 int fixed, z, width, height;
1113 Matrix new = *stack;
1114
1115 if (! DXGetScreenInfo((Screen)object, &child, &fixed, &z))
1116 goto error;
1117
1118 DXGetCameraResolution(camera, &width, &height);
1119
1120 if (fixed == SCREEN_VIEWPORT)
1121 {
1122 new.b[0] = new.b[0]*width - width/2;
1123 new.b[1] = new.b[1]*height - height/2;
1124 }
1125 else if (fixed == SCREEN_PIXEL)
1126 {
1127 new.b[0] -= width/2;
1128 new.b[1] -= height/2;
1129 }
1130 else if (fixed == SCREEN_WORLD)
1131 {
1132 Matrix cm;
1133
1134 cm = DXGetCameraMatrix(camera);
1135 new = DXConcatenate(*stack, cm);
1136
1137 if (DXGetPerspective(camera, NULL, NULL))
1138 {
1139 new.b[0] = - new.b[0] / new.b[2];
1140 new.b[1] = - new.b[1] / new.b[2];
1141 }
1142 }
1143 else if (fixed == SCREEN_STATIONARY)
1144 new.b[0] = new.b[1] = new.b[2] = 0.0;
1145
1146 new.A[0][0] = 1.0; new.A[0][1] = 0.0; new.A[0][2] = 0.0;
1147 new.A[1][0] = 0.0; new.A[1][1] = 1.0; new.A[1][2] = 0.0;
1148 new.A[2][0] = 0.0; new.A[2][1] = 0.0; new.A[2][2] = 1.0;
1149
1150 pick->pickPath[pick->depth++] = 0;
1151
1152 if (! PickObject(child, pick, poke, xy,
1153 &new, persp, nearPlane, sens, min, max, camera))
1154 return ERROR;
1155
1156 pick->depth --;
1157 return OK;
1158 }
1159
1160 default:
1161 {
1162 return OK;
1163 }
1164 }
1165
1166 error:
1167 return ERROR;
1168 }
1169
1170 static Error
PickField(Field f,PickBuf * p,int poke,Point2D xy,Matrix * s,int persp,float nearPlane,float sens,float min,float max)1171 PickField(Field f, PickBuf *p, int poke, Point2D xy, Matrix *s,
1172 int persp, float nearPlane, float sens, float min, float max)
1173 {
1174 Object c;
1175 char *str;
1176 int pb;
1177
1178 if (DXEmptyField(f))
1179 return OK;
1180
1181 pb = PickBox(f, xy, s, persp, nearPlane);
1182
1183 if (pb == BOX_ERROR)
1184 return ERROR;
1185 else if (pb == BOX_HIT)
1186 {
1187
1188 if (NULL != (c = DXGetComponentValue(f, "connections")))
1189 {
1190 if (! DXGetStringAttribute(c, "element type", &str))
1191 {
1192 DXSetError(ERROR_MISSING_DATA, "element type attribute");
1193 return ERROR;
1194 }
1195
1196 if (! strcmp(str, "triangles"))
1197 return PickTriangles(f, p, poke, xy, s,
1198 persp, nearPlane, sens, min, max);
1199 else if (! strcmp(str, "quads"))
1200 return PickQuads(f, p, poke, xy, s,
1201 persp, nearPlane, sens, min, max);
1202 else if (! strcmp(str, "lines"))
1203 return PickLines(f, p, poke, xy, s,
1204 persp, nearPlane, sens, min, max);
1205 else
1206 {
1207 DXSetError(ERROR_DATA_INVALID,
1208 "unable to pick when element type is %s", str);
1209 return ERROR;
1210 }
1211 }
1212 else if (DXGetComponentValue(f, "faces"))
1213 {
1214 return PickFLE(f, p, poke, xy, s, persp, nearPlane, sens, min, max);
1215 }
1216 else if (DXGetComponentValue(f, "polylines"))
1217 {
1218 return PickPolylines(f, p, poke, xy, s,
1219 persp, nearPlane, sens, min, max);
1220 }
1221 else
1222 return PickPoints(f, p, poke, xy, s, persp, nearPlane, sens, min, max);
1223 }
1224
1225 return OK;
1226 }
1227
1228 static Point *
TransformArray(Array src,Matrix * m)1229 TransformArray(Array src, Matrix *m)
1230 {
1231 int i;
1232 Point *dst = NULL;
1233 ArrayHandle handle = NULL;
1234 int nPts, nDim;
1235 Pointer buf = NULL;
1236
1237 DXGetArrayInfo(src, &nPts, NULL, NULL, NULL, &nDim);
1238
1239 dst = DXAllocate(nPts*sizeof(Point));
1240 if (! dst)
1241 goto error;
1242
1243 handle = DXCreateArrayHandle(src);
1244 if (! handle)
1245 goto error;
1246
1247 buf = DXAllocate(DXGetItemSize(src));
1248 if (! buf)
1249 goto error;
1250
1251 for (i = 0; i < nPts; i++)
1252 {
1253 Point d;
1254 float *s;
1255
1256 s = (float *)DXGetArrayEntry(handle, i, buf);
1257
1258 if (nDim == 1)
1259 d.x = s[0], d.y = d.z = 0.0;
1260 if (nDim == 2)
1261 d.x = s[0], d.y = s[1], d.z = 0.0;
1262 else
1263 d.x = s[0], d.y = s[1], d.z = s[2];
1264
1265 dst[i] = DXApply(d, *m);
1266 }
1267
1268 DXFreeArrayHandle(handle);
1269 DXFree(buf);
1270
1271 return dst;
1272
1273 error:
1274 DXFreeArrayHandle(handle);
1275 DXFree(buf);
1276 DXFree((Pointer)dst);
1277
1278 return NULL;
1279 }
1280
1281
1282 static int box_triangles[] =
1283 {
1284 0, 1, 3,
1285 0, 3, 2,
1286 1, 5, 7,
1287 1, 7, 3,
1288 5, 4, 6,
1289 5, 6, 7,
1290 4, 0, 2,
1291 4, 2, 6,
1292 3, 7, 6,
1293 3, 6, 2,
1294 0, 1, 5,
1295 0, 5, 4
1296 };
1297
1298 static int
PickBox(Field field,Point2D xy,Matrix * s,int persp,float nearPlane)1299 PickBox(Field field, Point2D xy, Matrix *s, int persp, float nearPlane)
1300 {
1301 Point points[8];
1302 int i, f;
1303
1304 if (! DXBoundingBox((Object)field, points))
1305 return ERROR;
1306
1307 if (s)
1308 for (i = 0; i < 8; i++)
1309 points[i] = DXApply(points[i], *s);
1310
1311 if (persp)
1312 {
1313 if (!Elt2D_Perspective(NULL, 0, xy, points, box_triangles,
1314 8, 12, 3, nearPlane, &f, 0.0, -DXD_MAX_FLOAT, DXD_MAX_FLOAT))
1315 goto error;
1316 }
1317 else
1318 {
1319 if (!Elt2D_NoPerspective(NULL, 0, xy, points, box_triangles,
1320 8, 12, 3, nearPlane, &f, 0.0, -DXD_MAX_FLOAT, DXD_MAX_FLOAT))
1321 goto error;
1322 }
1323
1324 return f;
1325
1326 error:
1327 return -1;
1328 }
1329
1330 static int
TriangleHit(Point ** tri,Point2D * xy,Point * xyz,int persp,float * wts)1331 TriangleHit(Point **tri, Point2D *xy, Point *xyz, int persp, float *wts)
1332 {
1333 int i, side = 0;
1334 float a[3];
1335
1336 for (i = 0; i < 3; i++)
1337 {
1338 int j = (i == 2) ? 0 : i+1;
1339 float x0 = tri[j]->x - tri[i]->x;
1340 float y0 = tri[j]->y - tri[i]->y;
1341 float x1 = xy->x - tri[i]->x;
1342 float y1 = xy->y - tri[i]->y;
1343 float cross = x0*y1 - x1*y0;
1344
1345 if ((cross < 0.0 && side == 1) || (cross > 0 && side == -1))
1346 return 0;
1347
1348 if (side == 0) {
1349 if (cross < 0)
1350 side = -1;
1351 else if (cross > 0)
1352 side = 1;
1353 }
1354
1355 a[i] = cross;
1356 }
1357
1358 if (side == 0)
1359 return 0;
1360
1361 if (xyz || wts)
1362 {
1363 float A = 1.0 / (a[0] + a[1] + a[2]);
1364 float a0 = A*a[0];
1365 float a1 = A*a[1];
1366 float a2 = A*a[2];
1367
1368 if (xyz)
1369 {
1370 xyz->x = xy->x;
1371 xyz->y = xy->y;
1372 xyz->z = a0*tri[2]->z + a1*tri[0]->z + a2*tri[1]->z;
1373
1374 if (persp)
1375 {
1376 float z = xyz->z = (ZOFFSET * xyz->z) / (1.0 + xyz->z);
1377 float depth = ZOFFSET - z;
1378 xyz->x *= depth;
1379 xyz->y *= depth;
1380 }
1381 }
1382
1383 if (wts)
1384 {
1385 wts[0] = a1;
1386 wts[1] = a2;
1387 wts[2] = a0;
1388 }
1389 }
1390
1391 return 1;
1392 }
1393
1394 static Error
PickTriangles(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)1395 PickTriangles(Field f, PickBuf *p, int poke, Point2D xy,
1396 Matrix *m, int perspective, float nearPlane, float sens, float min, float max)
1397 {
1398 Array pA;
1399 Array tA;
1400 Point *xPoints = NULL;
1401 int nPts, nTris;
1402 int *tris;
1403
1404 pA = (Array)DXGetComponentValue(f, "positions");
1405 tA = (Array)DXGetComponentValue(f, "connections");
1406 if (! tA || ! pA)
1407 {
1408 DXSetError(ERROR_MISSING_DATA, "positions or connections");
1409 goto error;
1410 }
1411
1412 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
1413 DXGetArrayInfo(tA, &nTris, NULL, NULL, NULL, NULL);
1414
1415 /*
1416 * Transform points
1417 */
1418 xPoints = TransformArray(pA, m);
1419 if (! xPoints)
1420 return ERROR;
1421
1422 tris = (int *)DXGetArrayData(tA);
1423
1424 if (perspective)
1425 {
1426 if (! Elt2D_Perspective(p, poke, xy, xPoints, tris,
1427 nPts, nTris, 3, nearPlane, NULL, sens, min, max))
1428 goto error;
1429 }
1430 else
1431 {
1432 if (! Elt2D_NoPerspective(p, poke, xy, xPoints, tris,
1433 nPts, nTris, 3, nearPlane, NULL, sens, min, max))
1434 goto error;
1435 }
1436
1437 DXFree((Pointer)xPoints);
1438 return OK;
1439
1440 error:
1441 DXFree((Pointer)xPoints);
1442 return ERROR;
1443 }
1444
1445 static Error
PickQuads(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)1446 PickQuads(Field f, PickBuf *p, int poke, Point2D xy,
1447 Matrix *m, int perspective, float nearPlane, float sens, float min, float max)
1448 {
1449 Array pA;
1450 Array qA;
1451 Point *xPoints = NULL;
1452 int nPts, nQuads;
1453 int *quads;
1454
1455 pA = (Array)DXGetComponentValue(f, "positions");
1456 qA = (Array)DXGetComponentValue(f, "connections");
1457 if (! qA || ! pA)
1458 {
1459 DXSetError(ERROR_MISSING_DATA, "positions or connections");
1460 goto error;
1461 }
1462
1463 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
1464 DXGetArrayInfo(qA, &nQuads, NULL, NULL, NULL, NULL);
1465
1466 /*
1467 * Transform points
1468 */
1469 xPoints = TransformArray(pA, m);
1470 if (! xPoints)
1471 return ERROR;
1472
1473 quads = (int *)DXGetArrayData(qA);
1474
1475 if (perspective)
1476 {
1477 if (! Elt2D_Perspective(p, poke, xy, xPoints, quads,
1478 nPts, nQuads, 4, nearPlane, NULL, sens, min, max))
1479 goto error;
1480 }
1481 else
1482 {
1483 if (! Elt2D_NoPerspective(p, poke, xy, xPoints, quads,
1484 nPts, nQuads, 4, nearPlane, NULL, sens, min, max))
1485 goto error;
1486 }
1487
1488 DXFree((Pointer)xPoints);
1489 return OK;
1490
1491 error:
1492 DXFree((Pointer)xPoints);
1493 return ERROR;
1494 }
1495
1496 static int triTab[] = {0, 1, 2};
1497 static int quadTab[] = {0, 1, 3, 2};
1498
1499 static Error
Elt2D_Perspective(PickBuf * p,int poke,Point2D xy,Point * xPoints,int * elts,int nPts,int nElts,int vPerE,float nearPlane,int * found,float sens,float min,float max)1500 Elt2D_Perspective(PickBuf *p, int poke, Point2D xy, Point *xPoints, int *elts,
1501 int nPts, int nElts, int vPerE, float nearPlane, int *found, float sens,
1502 float min, float max)
1503 {
1504 int i, j;
1505 float dNear;
1506 Point xyz;
1507 int *table = (vPerE == 3) ? triTab : (vPerE == 4) ? quadTab : NULL;
1508 Point *sPoints = (Point *)DXAllocate(nPts*sizeof(Point));
1509 float *weights = (float *)DXAllocate(vPerE*sizeof(float));
1510 if (! sPoints || ! weights)
1511 goto error;
1512
1513 nearPlane += ZOFFSET;
1514 dNear = -1.0 / nearPlane;
1515
1516 /*
1517 * perform perspective on all unclipped transformed points
1518 */
1519 for (i = 0; i < nPts; i++)
1520 {
1521 float z = xPoints[i].z;
1522 if (z < nearPlane)
1523 {
1524 float invDepth = 1.0 / (-z + ZOFFSET);
1525 sPoints[i].x = xPoints[i].x * invDepth;
1526 sPoints[i].y = xPoints[i].y * invDepth;
1527 sPoints[i].z = xPoints[i].z * invDepth;
1528 }
1529 }
1530
1531 if (found)
1532 *found = 0;
1533
1534 for (i = 0; i < nElts; i++, elts += vPerE)
1535 {
1536 int last, next, ngood, nclip;
1537 Point *sclipped[12];
1538 Point sclippt[12];
1539 int orig[12];
1540 int lastClipped, nextClipped;
1541
1542 if (table)
1543 last = elts[table[vPerE-1]];
1544 else
1545 last = elts[vPerE-1];
1546
1547 lastClipped = xPoints[last].z >= nearPlane;
1548
1549 ngood = 0;
1550 nclip = 0;
1551 for (j = 0; j < vPerE; j++)
1552 {
1553 if (table)
1554 next = elts[table[j]];
1555 else
1556 next = elts[j];
1557
1558 nextClipped = xPoints[next].z >= nearPlane;
1559
1560 if (! lastClipped)
1561 {
1562 sclipped[ngood] = sPoints + last;
1563 orig[ngood] = last;
1564 ngood ++;
1565 }
1566
1567 if (lastClipped != nextClipped)
1568 {
1569 Point *lxp = xPoints + last;
1570 Point *nxp = xPoints + next;
1571 float x, y, d = (nearPlane - lxp->z) / (nxp->z - lxp->z);
1572
1573 x = lxp->x + d*(nxp->x - lxp->x);
1574 y = lxp->y + d*(nxp->y - lxp->y);
1575 /* z = nearPlane; */
1576
1577 sclippt[nclip].x = dNear * x;
1578 sclippt[nclip].y = dNear * y;
1579 sclippt[nclip].y = dNear * y;
1580
1581 sclipped[ngood] = sclippt + nclip;
1582 orig[ngood] = -1;
1583
1584 nclip++;
1585 ngood++;
1586 }
1587
1588 last = next;
1589 lastClipped = nextClipped;
1590 }
1591
1592 /*
1593 * If a fragment survived clipping...
1594 */
1595
1596 for (j = 2; j < ngood; j++)
1597 {
1598 Point *sc[3];
1599 int si[3];
1600
1601 sc[0] = sclipped[si[0] = 0];
1602 sc[1] = sclipped[si[1] = j-1];
1603 sc[2] = sclipped[si[2] = j];
1604
1605 if (TriangleHit(sc, &xy, &xyz, 1, NULL))
1606 {
1607 int ni=0, k;
1608 float nearPlane = DXD_MAX_FLOAT;
1609
1610 if (found)
1611 *found = 1;
1612
1613 if (! p)
1614 goto done;
1615
1616 if (xyz.z > min && xyz.z < max)
1617 {
1618 Point *tpts[3];
1619
1620 for (k = 0; k < 3; k++)
1621 if (orig[si[k]] != -1)
1622 {
1623 float dx = sPoints[orig[si[k]]].x - xy.x;
1624 float dy = sPoints[orig[si[k]]].y - xy.y;
1625 float n = sqrt(dx*dx + dy*dy);
1626 if (n < nearPlane)
1627 {
1628 ni = orig[si[k]];
1629 nearPlane = n;
1630 }
1631 }
1632
1633 /*
1634 * find an *original* triangle containing the pick
1635 * point.
1636 */
1637
1638 if (table)
1639 {
1640 tpts[0] = sPoints + elts[table[0]];
1641 tpts[2] = sPoints + elts[table[1]];
1642 }
1643 else
1644 {
1645 tpts[0] = sPoints + elts[0];
1646 tpts[2] = sPoints + elts[1];
1647 }
1648
1649 for (k = 2; k < vPerE; k++)
1650 {
1651 float wts[3];
1652
1653 tpts[1] = tpts[2];
1654 if (table)
1655 tpts[2] = sPoints + elts[table[k]];
1656 else
1657 tpts[2] = sPoints + elts[k];
1658
1659 if (TriangleHit(tpts, &xy, NULL, 1, wts))
1660 {
1661 int l;
1662
1663 for (l = 0; l < vPerE; l++)
1664 weights[l] = 0;
1665
1666 if (table)
1667 {
1668 weights[table[0]] = wts[0];
1669 weights[table[k-1]] = wts[1];
1670 weights[table[k]] = wts[2];
1671 }
1672 else
1673 {
1674 weights[0] = wts[0];
1675 weights[k-1] = wts[1];
1676 weights[k] = wts[2];
1677 }
1678
1679 break;
1680 }
1681 }
1682
1683 if (k == vPerE)
1684 {
1685 DXSetError(ERROR_INTERNAL,
1686 "found in clipped but not in original");
1687 goto error;
1688 }
1689
1690 p->pickPath[p->depth+0] = i;
1691 p->pickPath[p->depth+1] = ni;
1692 if (! AddPick(p, poke, xyz, vPerE, -1, weights))
1693 goto error;
1694 }
1695
1696 break;
1697 }
1698 }
1699 }
1700
1701 done:
1702 DXFree((Pointer)sPoints);
1703 DXFree((Pointer)weights);
1704 return OK;
1705
1706 error:
1707 DXFree((Pointer)sPoints);
1708 DXFree((Pointer)weights);
1709 return ERROR;
1710 }
1711
1712 static Error
Elt2D_NoPerspective(PickBuf * p,int poke,Point2D xy,Point * xPoints,int * elts,int nPts,int nElts,int vPerE,float nearPlane,int * found,float sens,float min,float max)1713 Elt2D_NoPerspective(PickBuf *p, int poke, Point2D xy, Point *xPoints, int *elts,
1714 int nPts, int nElts, int vPerE, float nearPlane, int *found, float sens,
1715 float min, float max)
1716 {
1717 Point xyz;
1718 int i, j, k, ni=0;
1719 int *table = (vPerE == 3) ? triTab : (vPerE == 4) ? quadTab : NULL;
1720 float nearest;
1721 int indices[3];
1722 Point *pts[3];
1723 float wts[3], *weights = (float *)DXAllocate(vPerE*sizeof(float));
1724
1725 if (! weights) goto error;
1726
1727 if (found)
1728 *found = 0;
1729
1730 for (i = 0; i < nElts; i++, elts += vPerE)
1731 {
1732 if (table)
1733 {
1734 indices[0] = elts[table[0]];
1735 indices[2] = elts[table[1]];
1736 }
1737 else
1738 {
1739 indices[0] = elts[0];
1740 indices[2] = elts[1];
1741 }
1742
1743 pts[0] = xPoints + indices[0];
1744 pts[2] = xPoints + indices[2];
1745
1746 for (j = 2; j < vPerE; j++)
1747 {
1748 indices[1] = indices[2];
1749 pts[1] = pts[2];
1750
1751 if (table)
1752 indices[2] = elts[table[j]];
1753 else
1754 indices[2] = elts[j];
1755
1756 pts[2] = xPoints + indices[2];
1757
1758 if (TriangleHit(pts, &xy, &xyz, 0, wts))
1759 {
1760 if (!p)
1761 {
1762 if (found)
1763 *found = 1;
1764 goto done;
1765 }
1766
1767 if (xyz.z >= nearPlane)
1768 continue;
1769
1770 if (found)
1771 *found = 1;
1772
1773 for (k = 0; k < vPerE; k++)
1774 weights[k] = 0;
1775
1776 if (table)
1777 {
1778 weights[table[0]] = wts[0];
1779 weights[table[j-1]] = wts[1];
1780 weights[table[j]] = wts[2];
1781 }
1782 else
1783 {
1784 weights[0] = wts[0];
1785 weights[j-1] = wts[1];
1786 weights[j] = wts[2];
1787 }
1788
1789 for (k = 0, nearest = DXD_MAX_FLOAT; k < 3; k++)
1790 {
1791 if (pts[k]->z < nearPlane)
1792 {
1793 float dx = pts[k]->x - xy.x;
1794 float dy = pts[k]->y - xy.y;
1795 float n = sqrt(dx*dx + dy*dy);
1796
1797 if (n < nearest)
1798 {
1799 ni = indices[k];
1800 nearest = n;
1801 }
1802 }
1803 }
1804
1805 p->pickPath[p->depth+0] = i;
1806 p->pickPath[p->depth+1] = ni;
1807 if (! AddPick(p, poke, xyz, vPerE, -1, weights))
1808 goto error;
1809
1810 break;
1811 }
1812 }
1813 }
1814
1815 done:
1816 DXFree((Pointer)weights);
1817 return OK;
1818
1819 error:
1820 DXFree((Pointer)weights);
1821 return ERROR;
1822 }
1823
1824 static Error
PickLines(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)1825 PickLines(Field f, PickBuf *p, int poke, Point2D xy, Matrix *m,
1826 int perspective, float nearPlane, float sens, float min, float max)
1827 {
1828 Array pA;
1829 Array lA;
1830 Point *xPoints = NULL;
1831 int nPts, nLines;
1832 int *lines;
1833
1834 pA = (Array)DXGetComponentValue(f, "positions");
1835 lA = (Array)DXGetComponentValue(f, "connections");
1836 if (! lA || ! pA)
1837 {
1838 DXSetError(ERROR_MISSING_DATA, "positions or connections");
1839 goto error;
1840 }
1841
1842 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
1843 DXGetArrayInfo(lA, &nLines, NULL, NULL, NULL, NULL);
1844
1845 /*
1846 * Transform points
1847 */
1848 xPoints = TransformArray(pA, m);
1849 if (! xPoints)
1850 return ERROR;
1851
1852 lines = (int *)DXGetArrayData(lA);
1853
1854 if (perspective)
1855 {
1856 if (! Elt1D_Perspective(p, poke, xy, xPoints, lines, nPts,
1857 nLines, nearPlane, sens, min, max))
1858 goto error;
1859 }
1860 else
1861 {
1862 if (! Elt1D_NoPerspective(p, poke, xy, xPoints, lines, nPts,
1863 nLines, nearPlane, sens, min, max))
1864 goto error;
1865 }
1866
1867 DXFree((Pointer)xPoints);
1868 return OK;
1869
1870 error:
1871 DXFree((Pointer)xPoints);
1872 return ERROR;
1873 }
1874
1875
1876 static Error
Elt1D_Perspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int * elts,int nPts,int nElts,float nearPlane,float sens,float min,float max)1877 Elt1D_Perspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
1878 int *elts, int nPts, int nElts, float nearPlane, float sens,
1879 float min, float max)
1880 {
1881 int i;
1882 Point *sPoints;
1883
1884 sPoints = (Point *)DXAllocate(nPts*sizeof(Point));
1885 if (! sPoints)
1886 goto error;
1887
1888 nearPlane += ZOFFSET;
1889
1890 /*
1891 * perform perspective on all unclipped transformed points
1892 */
1893 for (i = 0; i < nPts; i++)
1894 {
1895 float z = xPoints[i].z;
1896 if (z < nearPlane)
1897 {
1898 float invDepth = 1.0 / (-z + ZOFFSET);
1899 sPoints[i].x = xPoints[i].x * invDepth;
1900 sPoints[i].y = xPoints[i].y * invDepth;
1901 sPoints[i].z = xPoints[i].z * invDepth;
1902 }
1903 }
1904
1905 for (i = 0; i < nElts; i++, elts += 2)
1906 {
1907 int p, q;
1908 Point *px, *qx;
1909 Point *ps, *qs, *sclipped[2];
1910 Point sclippt;
1911 float x, y, z, a, b, c, D, dx, dy, depth;
1912 Point xyz;
1913 int orig[2];
1914
1915 p = elts[0];
1916 q = elts[1];
1917
1918 px = xPoints + p;
1919 qx = xPoints + q;
1920
1921 ps = sPoints + p;
1922 qs = sPoints + q;
1923
1924 if (px->z > nearPlane && qx->z > nearPlane)
1925 continue;
1926
1927 if (px->z <= nearPlane && qx->z <= nearPlane)
1928 {
1929 /*xclipped[0] = px;*/
1930 /*xclipped[1] = qx;*/
1931
1932 sclipped[0] = ps;
1933 sclipped[1] = qs;
1934
1935 orig[0] = p;
1936 orig[1] = q;
1937 }
1938 else if (px->z > nearPlane && qx->z <= nearPlane)
1939 {
1940 float d = (nearPlane - qx->z) / (px->z - qx->z);
1941
1942 /*xclippt.x = qx->x + d*(px->x - qx->x);*/
1943 /*xclippt.y = qx->y + d*(px->y - qx->y);*/
1944 /*xclippt.z = nearPlane;*/
1945 /*xclipped[0] = &xclippt;*/
1946 /*xclipped[1] = qx;*/
1947
1948 sclippt.x = qs->x + d*(ps->x - qs->x);
1949 sclippt.y = qs->y + d*(ps->y - qs->y);
1950 sclippt.z = nearPlane;
1951 sclipped[0] = &sclippt;
1952 sclipped[1] = qs;
1953
1954 orig[0] = -1;
1955 orig[1] = q;
1956 }
1957 else
1958 {
1959 float d = (nearPlane - qx->z) / (px->z - qx->z);
1960
1961 /*xclippt.x = qx->x + d*(px->x - qx->x);*/
1962 /*xclippt.y = qx->y + d*(px->y - qx->y);*/
1963 /*xclippt.z = nearPlane;*/
1964 /*xclipped[0] = &xclippt;*/
1965 /*xclipped[1] = px;*/
1966
1967 sclippt.x = qs->x + d*(ps->x - qs->x);
1968 sclippt.y = qs->y + d*(ps->y - qs->y);
1969 sclippt.z = nearPlane;
1970 sclipped[0] = &sclippt;
1971 sclipped[1] = ps;
1972
1973 orig[0] = -1;
1974 orig[1] = p;
1975 }
1976
1977 dx = sclipped[1]->x - sclipped[0]->x;
1978 dy = sclipped[1]->y - sclipped[0]->y;
1979
1980 if (dx == 0 && dy == 0)
1981 continue;
1982
1983 D = 1.0 / sqrt(dx*dx + dy*dy);
1984
1985 a = dy * D;
1986 b = -dx * D;
1987 c = -(a*sclipped[0]->x + b*sclipped[0]->y);
1988
1989 D = a*xy.x + b*xy.y + c;
1990
1991 if (-sens < D && D < sens)
1992 {
1993 /*
1994 * step along line normal by -D to get closest point on line
1995 */
1996 x = xy.x - D*a;
1997 y = xy.y - D*b;
1998
1999 if ((((sclipped[0]->x-sens) <= x && x <= (sclipped[1]->x+sens)) ||
2000 ((sclipped[0]->x+sens) >= x && x >= (sclipped[1]->x-sens))) &&
2001 (((sclipped[0]->y-sens) <= y && y <= (sclipped[1]->y+sens)) ||
2002 ((sclipped[0]->y+sens) >= y && y >= (sclipped[1]->y-sens))))
2003 {
2004 float nearPlane = DXD_MAX_FLOAT;
2005 int k, ni=0;
2006
2007 if (fabs(dx) > fabs(dy))
2008 D = (x - sclipped[0]->x)/(sclipped[1]->x - sclipped[0]->x);
2009 else
2010 D = (y - sclipped[0]->y)/(sclipped[1]->y - sclipped[0]->y);
2011
2012 /*
2013 * interpolate on screen
2014 */
2015 x = sclipped[0]->x + D*(sclipped[1]->x - sclipped[0]->x);
2016 y = sclipped[0]->y + D*(sclipped[1]->y - sclipped[0]->y);
2017 z = sclipped[0]->z + D*(sclipped[1]->z - sclipped[0]->z);
2018
2019 /*
2020 * Perspective transformation is zp = z / depth, where
2021 * depth = -z + d. To regain original z, z = d(zp) / 1 + zp.
2022 */
2023 xyz.z = (ZOFFSET * z) / (1.0 + z);
2024
2025 if (xyz.z > min && xyz.z < max)
2026 {
2027 float weights[2];
2028
2029 /*
2030 * now undo perspective on xy by multiplying by depth
2031 */
2032 depth = -xyz.z + ZOFFSET;
2033 xyz.x = x * depth;
2034 xyz.y = y * depth;
2035
2036 for (k = 0; k < 2; k++)
2037 if (orig[k] != -1)
2038 {
2039 float dx = sPoints[orig[k]].x - xy.x;
2040 float dy = sPoints[orig[k]].y - xy.y;
2041 float n = sqrt(dx*dx + dy*dy);
2042 if (n < nearPlane)
2043 {
2044 ni = orig[k];
2045 nearPlane = n;
2046 }
2047 }
2048
2049 if (fabs(dx) > fabs(dy))
2050 D = (x - sPoints[p].x)/(sPoints[q].x - sPoints[p].x);
2051 else
2052 D = (y - sPoints[p].y)/(sPoints[q].y - sPoints[p].y);
2053
2054 weights[0] = 1.0 - D;
2055 weights[1] = D;
2056
2057 pick->pickPath[pick->depth+0] = i;
2058 pick->pickPath[pick->depth+1] = ni;
2059 if (! AddPick(pick, poke, xyz, 2, -1, weights))
2060 goto error;
2061 }
2062 }
2063
2064 }
2065 }
2066
2067 DXFree((Pointer)sPoints);
2068 return OK;
2069
2070 error:
2071 DXFree((Pointer)sPoints);
2072 return ERROR;
2073 }
2074
2075 static Error
Elt1D_NoPerspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int * elts,int nPts,int nElts,float nearPlane,float sens,float min,float max)2076 Elt1D_NoPerspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2077 int *elts, int nPts, int nElts, float nearPlane, float sens,
2078 float min, float max)
2079 {
2080 int i;
2081 int orig[2];
2082
2083 nearPlane += ZOFFSET;
2084
2085 for (i = 0; i < nElts; i++, elts += 2)
2086 {
2087 int p, q;
2088 Point *px, *qx, *xclipped[2];
2089 Point xclippt;
2090 float x, y, a, b, c, D, dx, dy;
2091 Point xyz;
2092
2093 p = elts[0];
2094 q = elts[1];
2095
2096 px = xPoints + p;
2097 qx = xPoints + q;
2098
2099 if (px->z > nearPlane && qx->z > nearPlane)
2100 continue;
2101
2102 if (px->z <= nearPlane && qx->z <= nearPlane)
2103 {
2104 xclipped[0] = px;
2105 xclipped[1] = qx;
2106
2107 orig[0] = p;
2108 orig[1] = q;
2109 }
2110 else if (px->z > nearPlane && qx->z <= nearPlane)
2111 {
2112 float d = (nearPlane - qx->z) / (px->z - qx->z);
2113
2114 xclippt.x = qx->x + d*(px->x - qx->x);
2115 xclippt.y = qx->y + d*(px->y - qx->y);
2116 xclippt.z = nearPlane;
2117 xclipped[0] = &xclippt;
2118 xclipped[1] = qx;
2119
2120 orig[0] = -1;
2121 orig[1] = q;
2122 }
2123 else
2124 {
2125 float d = (nearPlane - qx->z) / (px->z - qx->z);
2126
2127 xclippt.x = qx->x + d*(px->x - qx->x);
2128 xclippt.y = qx->y + d*(px->y - qx->y);
2129 xclippt.z = nearPlane;
2130 xclipped[0] = &xclippt;
2131 xclipped[1] = px;
2132
2133 orig[0] = -1;
2134 orig[1] = p;
2135 }
2136
2137 dx = xclipped[1]->x - xclipped[0]->x;
2138 dy = xclipped[1]->y - xclipped[0]->y;
2139
2140 if (dx == 0 && dy == 0)
2141 continue;
2142
2143 D = 1.0 / sqrt(dx*dx + dy*dy);
2144
2145 a = dy * D;
2146 b = -dx * D;
2147 c = -(a*xclipped[0]->x + b*xclipped[0]->y);
2148
2149 D = a*xy.x + b*xy.y + c;
2150
2151 if (-sens < D && D < sens)
2152 {
2153
2154 /*
2155 * step along line normal by -D to get closest point on line
2156 */
2157 x = xy.x - D*a;
2158 y = xy.y - D*b;
2159
2160 if ((((xclipped[0]->x-sens) <= x && x <= (xclipped[1]->x+sens)) ||
2161 ((xclipped[0]->x+sens) >= x && x >= (xclipped[1]->x-sens))) &&
2162 (((xclipped[0]->y-sens) <= y && y <= (xclipped[1]->y+sens)) ||
2163 ((xclipped[0]->y+sens) >= y && y >= (xclipped[1]->y-sens))))
2164 {
2165 float nearPlane = DXD_MAX_FLOAT;
2166 int k, ni=0;
2167
2168 if (fabs(dx) > fabs(dy))
2169 D = (x - xclipped[0]->x)/(xclipped[1]->x - xclipped[0]->x);
2170 else
2171 D = (y - xclipped[0]->y)/(xclipped[1]->y - xclipped[0]->y);
2172
2173 /*
2174 * interpolate on screen
2175 */
2176 xyz.x = x;
2177 xyz.y = y;
2178 xyz.z = xclipped[0]->z + D*(xclipped[1]->z - xclipped[0]->z);
2179
2180 if (xyz.z > min && xyz.z < max)
2181 {
2182 float weights[2];
2183
2184 for (k = 0; k < 2; k++)
2185 if (orig[k] != -1)
2186 {
2187 float dx = xPoints[orig[k]].x - xy.x;
2188 float dy = xPoints[orig[k]].y - xy.y;
2189 float n = sqrt(dx*dx + dy*dy);
2190 if (n < nearPlane)
2191 {
2192 ni = orig[k];
2193 nearPlane = n;
2194 }
2195 }
2196
2197 if (fabs(dx) > fabs(dy))
2198 D = (x - xPoints[p].x)/(xPoints[q].x - xPoints[p].x);
2199 else
2200 D = (y - xPoints[p].y)/(xPoints[q].y - xPoints[p].y);
2201
2202 weights[0] = 1.0 - D;
2203 weights[1] = D;
2204
2205 pick->pickPath[pick->depth+0] = i;
2206 pick->pickPath[pick->depth+1] = ni;
2207 if (! AddPick(pick, poke, xyz, 2, -1, weights))
2208 goto error;
2209 }
2210 }
2211 }
2212
2213 }
2214
2215 return OK;
2216
2217 error:
2218 return ERROR;
2219 }
2220
2221 static Error
PickPolylines(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)2222 PickPolylines(Field f, PickBuf *p, int poke, Point2D xy, Matrix *m,
2223 int perspective, float nearPlane, float sens, float min, float max)
2224 {
2225 Array pA;
2226 Array plA, eA;
2227 Point *xPoints = NULL;
2228 int nPts, nPolylines, nEdges;
2229 int *polylines, *edges;
2230
2231 pA = (Array)DXGetComponentValue(f, "positions");
2232 plA = (Array)DXGetComponentValue(f, "polylines");
2233 eA = (Array)DXGetComponentValue(f, "edges");
2234 if (! plA || ! pA || ! eA)
2235 {
2236 DXSetError(ERROR_MISSING_DATA, "positions, polylines or edges");
2237 goto error;
2238 }
2239
2240 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
2241 DXGetArrayInfo(plA, &nPolylines, NULL, NULL, NULL, NULL);
2242 DXGetArrayInfo(eA, &nEdges, NULL, NULL, NULL, NULL);
2243
2244 /*
2245 * Transform points
2246 */
2247 xPoints = TransformArray(pA, m);
2248 if (! xPoints)
2249 return ERROR;
2250
2251 polylines = (int *)DXGetArrayData(plA);
2252 edges = (int *)DXGetArrayData(eA);
2253
2254 if (perspective)
2255 {
2256 if (! Polyline_Perspective(p, poke, xy, xPoints, polylines, edges,
2257 nPts, nPolylines, nEdges, nearPlane, sens, min, max))
2258 goto error;
2259 }
2260 else
2261 {
2262 if (! Polyline_NoPerspective(p, poke, xy, xPoints, polylines, edges,
2263 nPts, nPolylines, nEdges, nearPlane, sens, min, max))
2264 goto error;
2265 }
2266
2267 DXFree((Pointer)xPoints);
2268 return OK;
2269
2270 error:
2271 DXFree((Pointer)xPoints);
2272 return ERROR;
2273 }
2274
2275 static Error
Polyline_Perspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int * plines,int * edges,int nPts,int nPl,int nE,float nearPlane,float sens,float min,float max)2276 Polyline_Perspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2277 int *plines, int *edges, int nPts, int nPl, int nE, float nearPlane,
2278 float sens, float min, float max)
2279 {
2280 int pline;
2281 int i;
2282 Point *sPoints;
2283
2284 sPoints = (Point *)DXAllocate(nPts*sizeof(Point));
2285 if (! sPoints)
2286 goto error;
2287
2288 nearPlane += ZOFFSET;
2289
2290 /*
2291 * perform perspective on all unclipped transformed points
2292 */
2293 for (i = 0; i < nPts; i++)
2294 {
2295 float z = xPoints[i].z;
2296 if (z < nearPlane)
2297 {
2298 float invDepth = 1.0 / (-z + ZOFFSET);
2299 sPoints[i].x = xPoints[i].x * invDepth;
2300 sPoints[i].y = xPoints[i].y * invDepth;
2301 sPoints[i].z = xPoints[i].z * invDepth;
2302 }
2303 }
2304
2305 for (pline = 0; pline < nPl; pline++)
2306 {
2307 int estart = plines[pline];
2308 int eend = (pline == nPl-1) ? nE : plines[pline+1];
2309 int e, eIndex;
2310
2311 for (e = estart, eIndex = 0; e < eend; e++, eIndex++)
2312 {
2313 int p, q;
2314 Point *px, *qx;
2315 Point *ps, *qs, *sclipped[2];
2316 Point sclippt;
2317 float x, y, z, a, b, c, D, dx, dy, depth;
2318 Point xyz;
2319 int orig[2];
2320
2321 p = edges[e];
2322 q = edges[(e == eend-1) ? estart : e+1];
2323
2324 px = xPoints + p;
2325 qx = xPoints + q;
2326
2327 ps = sPoints + p;
2328 qs = sPoints + q;
2329
2330 if (px->z > nearPlane && qx->z > nearPlane)
2331 continue;
2332
2333 if (px->z <= nearPlane && qx->z <= nearPlane)
2334 {
2335 /*xclipped[0] = px;*/
2336 /*xclipped[1] = qx;*/
2337
2338 sclipped[0] = ps;
2339 sclipped[1] = qs;
2340
2341 orig[0] = p;
2342 orig[1] = q;
2343 }
2344 else if (px->z > nearPlane && qx->z <= nearPlane)
2345 {
2346 float d = (nearPlane - qx->z) / (px->z - qx->z);
2347
2348 /*xclippt.x = qx->x + d*(px->x - qx->x);*/
2349 /*xclippt.y = qx->y + d*(px->y - qx->y);*/
2350 /*xclippt.z = nearPlane;*/
2351 /*xclipped[0] = &xclippt;*/
2352 /*xclipped[1] = qx;*/
2353
2354 sclippt.x = qs->x + d*(ps->x - qs->x);
2355 sclippt.y = qs->y + d*(ps->y - qs->y);
2356 sclippt.z = nearPlane;
2357 sclipped[0] = &sclippt;
2358 sclipped[1] = qs;
2359
2360 orig[0] = -1;
2361 orig[1] = q;
2362 }
2363 else
2364 {
2365 float d = (nearPlane - qx->z) / (px->z - qx->z);
2366
2367 /*xclippt.x = qx->x + d*(px->x - qx->x);*/
2368 /*xclippt.y = qx->y + d*(px->y - qx->y);*/
2369 /*xclippt.z = nearPlane;*/
2370 /*xclipped[0] = &xclippt;*/
2371 /*xclipped[1] = px;*/
2372
2373 sclippt.x = qs->x + d*(ps->x - qs->x);
2374 sclippt.y = qs->y + d*(ps->y - qs->y);
2375 sclippt.z = nearPlane;
2376 sclipped[0] = &sclippt;
2377 sclipped[1] = ps;
2378
2379 orig[0] = -1;
2380 orig[1] = p;
2381 }
2382
2383 dx = sclipped[1]->x - sclipped[0]->x;
2384 dy = sclipped[1]->y - sclipped[0]->y;
2385
2386 if (dx == 0 && dy == 0)
2387 continue;
2388
2389 D = 1.0 / sqrt(dx*dx + dy*dy);
2390
2391 a = dy * D;
2392 b = -dx * D;
2393 c = -(a*sclipped[0]->x + b*sclipped[0]->y);
2394
2395 D = a*xy.x + b*xy.y + c;
2396
2397 if (-sens < D && D < sens)
2398 {
2399 /*
2400 * step along line normal by -D to get closest point on line
2401 */
2402 x = xy.x - D*a;
2403 y = xy.y - D*b;
2404
2405 if ((((sclipped[0]->x-sens) <= x && x <= (sclipped[1]->x+sens)) ||
2406 ((sclipped[0]->x+sens) >= x && x >= (sclipped[1]->x-sens))) &&
2407 (((sclipped[0]->y-sens) <= y && y <= (sclipped[1]->y+sens)) ||
2408 ((sclipped[0]->y+sens) >= y && y >= (sclipped[1]->y-sens))))
2409 {
2410 float nearPlane = DXD_MAX_FLOAT;
2411 int k, ni=0;
2412
2413 if (fabs(dx) > fabs(dy))
2414 D = (x - sclipped[0]->x)/(sclipped[1]->x - sclipped[0]->x);
2415 else
2416 D = (y - sclipped[0]->y)/(sclipped[1]->y - sclipped[0]->y);
2417
2418 /*
2419 * interpolate on screen
2420 */
2421 x = sclipped[0]->x + D*(sclipped[1]->x - sclipped[0]->x);
2422 y = sclipped[0]->y + D*(sclipped[1]->y - sclipped[0]->y);
2423 z = sclipped[0]->z + D*(sclipped[1]->z - sclipped[0]->z);
2424
2425 /*
2426 * Perspective transformation is zp = z / depth, where
2427 * depth = -z + d. To regain original z, z = d(zp) / 1 + zp.
2428 */
2429 xyz.z = (ZOFFSET * z) / (1.0 + z);
2430
2431 if (xyz.z > min && xyz.z < max)
2432 {
2433 float weights[2];
2434
2435 /*
2436 * now undo perspective on xy by multiplying by depth
2437 */
2438 depth = -xyz.z + ZOFFSET;
2439 xyz.x = x * depth;
2440 xyz.y = y * depth;
2441
2442 for (k = 0; k < 2; k++)
2443 if (orig[k] != -1)
2444 {
2445 float dx = sPoints[orig[k]].x - xy.x;
2446 float dy = sPoints[orig[k]].y - xy.y;
2447 float n = sqrt(dx*dx + dy*dy);
2448 if (n < nearPlane)
2449 {
2450 ni = orig[k];
2451 nearPlane = n;
2452 }
2453 }
2454
2455 if (fabs(dx) > fabs(dy))
2456 D = (x - sPoints[p].x)/(sPoints[q].x - sPoints[p].x);
2457 else
2458 D = (y - sPoints[p].y)/(sPoints[q].y - sPoints[p].y);
2459
2460 weights[0] = 1.0 - D;
2461 weights[1] = D;
2462
2463 pick->pickPath[pick->depth+0] = pline;
2464 pick->pickPath[pick->depth+1] = ni;
2465 if (! AddPick(pick, poke, xyz, 2, eIndex, weights))
2466 goto error;
2467 }
2468 }
2469 }
2470 }
2471 }
2472
2473 DXFree((Pointer)sPoints);
2474 return OK;
2475
2476 error:
2477 DXFree((Pointer)sPoints);
2478 return ERROR;
2479 }
2480
2481 static Error
Polyline_NoPerspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int * plines,int * edges,int nPts,int nPl,int nE,float nearPlane,float sens,float min,float max)2482 Polyline_NoPerspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2483 int *plines, int *edges, int nPts, int nPl, int nE, float nearPlane,
2484 float sens, float min, float max)
2485 {
2486 int pline;
2487 int orig[2];
2488
2489 nearPlane += ZOFFSET;
2490
2491 for (pline = 0; pline < nPl; pline++)
2492 {
2493 int estart = plines[pline];
2494 int eend = (pline == nPl-1) ? nE : plines[pline+1];
2495 int e, eIndex;
2496
2497 for (e = estart, eIndex = 0; e < eend; e++, eIndex++)
2498 {
2499 int p, q;
2500 Point *px, *qx, *xclipped[2];
2501 Point xclippt;
2502 float x, y, a, b, c, D, dx, dy;
2503 Point xyz;
2504
2505 p = edges[e];
2506 q = edges[(e == eend-1) ? estart : e+1];
2507
2508 px = xPoints + p;
2509 qx = xPoints + q;
2510
2511 if (px->z > nearPlane && qx->z > nearPlane)
2512 continue;
2513
2514 if (px->z <= nearPlane && qx->z <= nearPlane)
2515 {
2516 xclipped[0] = px;
2517 xclipped[1] = qx;
2518
2519 orig[0] = p;
2520 orig[1] = q;
2521 }
2522 else if (px->z > nearPlane && qx->z <= nearPlane)
2523 {
2524 float d = (nearPlane - qx->z) / (px->z - qx->z);
2525
2526 xclippt.x = qx->x + d*(px->x - qx->x);
2527 xclippt.y = qx->y + d*(px->y - qx->y);
2528 xclippt.z = nearPlane;
2529 xclipped[0] = &xclippt;
2530 xclipped[1] = qx;
2531
2532 orig[0] = -1;
2533 orig[1] = q;
2534 }
2535 else
2536 {
2537 float d = (nearPlane - qx->z) / (px->z - qx->z);
2538
2539 xclippt.x = qx->x + d*(px->x - qx->x);
2540 xclippt.y = qx->y + d*(px->y - qx->y);
2541 xclippt.z = nearPlane;
2542 xclipped[0] = &xclippt;
2543 xclipped[1] = px;
2544
2545 orig[0] = -1;
2546 orig[1] = p;
2547 }
2548
2549 dx = xclipped[1]->x - xclipped[0]->x;
2550 dy = xclipped[1]->y - xclipped[0]->y;
2551
2552 if (dx == 0 && dy == 0)
2553 continue;
2554
2555 D = 1.0 / sqrt(dx*dx + dy*dy);
2556
2557 a = dy * D;
2558 b = -dx * D;
2559 c = -(a*xclipped[0]->x + b*xclipped[0]->y);
2560
2561 D = a*xy.x + b*xy.y + c;
2562
2563 if (-sens < D && D < sens)
2564 {
2565
2566 /*
2567 * step along line normal by -D to get closest point on line
2568 */
2569 x = xy.x - D*a;
2570 y = xy.y - D*b;
2571
2572 if ((((xclipped[0]->x-sens) <= x && x <= (xclipped[1]->x+sens)) ||
2573 ((xclipped[0]->x+sens) >= x && x >= (xclipped[1]->x-sens))) &&
2574 (((xclipped[0]->y-sens) <= y && y <= (xclipped[1]->y+sens)) ||
2575 ((xclipped[0]->y+sens) >= y && y >= (xclipped[1]->y-sens))))
2576 {
2577 float nearPlane = DXD_MAX_FLOAT;
2578 int k, ni=0;
2579
2580 if (fabs(dx) > fabs(dy))
2581 D = (x - xclipped[0]->x)/(xclipped[1]->x - xclipped[0]->x);
2582 else
2583 D = (y - xclipped[0]->y)/(xclipped[1]->y - xclipped[0]->y);
2584
2585 /*
2586 * interpolate on screen
2587 */
2588 xyz.x = x;
2589 xyz.y = y;
2590 xyz.z = xclipped[0]->z + D*(xclipped[1]->z - xclipped[0]->z);
2591
2592 if (xyz.z > min && xyz.z < max)
2593 {
2594 float weights[2];
2595
2596 for (k = 0; k < 2; k++)
2597 if (orig[k] != -1)
2598 {
2599 float dx = xPoints[orig[k]].x - xy.x;
2600 float dy = xPoints[orig[k]].y - xy.y;
2601 float n = sqrt(dx*dx + dy*dy);
2602 if (n < nearPlane)
2603 {
2604 ni = orig[k];
2605 nearPlane = n;
2606 }
2607 }
2608
2609 if (fabs(dx) > fabs(dy))
2610 D = (x - xPoints[p].x)/(xPoints[q].x - xPoints[p].x);
2611 else
2612 D = (y - xPoints[p].y)/(xPoints[q].y - xPoints[p].y);
2613
2614 weights[0] = 1.0 - D;
2615 weights[1] = D;
2616
2617 pick->pickPath[pick->depth+0] = pline;
2618 pick->pickPath[pick->depth+1] = ni;
2619 if (! AddPick(pick, poke, xyz, 2, eIndex, weights))
2620 goto error;
2621 }
2622 }
2623 }
2624 }
2625
2626 }
2627
2628 return OK;
2629
2630 error:
2631 return ERROR;
2632 }
2633
2634
2635 static Error
PickPoints(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)2636 PickPoints(Field f, PickBuf *p, int poke, Point2D xy, Matrix *m,
2637 int perspective, float nearPlane, float sens, float min, float max)
2638 {
2639 Array pA;
2640 Point *xPoints = NULL;
2641 int nPts;
2642
2643 pA = (Array)DXGetComponentValue(f, "positions");
2644 if (! pA)
2645 {
2646 DXSetError(ERROR_MISSING_DATA, "positions");
2647 goto error;
2648 }
2649
2650 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
2651
2652 /*
2653 * Transform points
2654 */
2655 xPoints = TransformArray(pA, m);
2656 if (! xPoints)
2657 return ERROR;
2658
2659 if (perspective)
2660 {
2661 if (! Elt0D_Perspective(p, poke, xy, xPoints,
2662 nPts, nearPlane, sens, min, max))
2663 goto error;
2664 }
2665 else
2666 {
2667 if (! Elt0D_NoPerspective(p, poke, xy, xPoints,
2668 nPts, nearPlane, sens, min, max))
2669 goto error;
2670 }
2671
2672 DXFree((Pointer)xPoints);
2673 return OK;
2674
2675 error:
2676 DXFree((Pointer)xPoints);
2677 return ERROR;
2678 }
2679
2680 static Error
Elt0D_Perspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int nPts,float nearPlane,float sens,float min,float max)2681 Elt0D_Perspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2682 int nPts, float nearPlane, float sens, float min, float max)
2683 {
2684 int i;
2685 Point2D *sPoints;
2686
2687 sPoints = (Point2D *)DXAllocate(nPts*sizeof(Point2D));
2688 if (! sPoints)
2689 goto error;
2690
2691 nearPlane += ZOFFSET;
2692
2693 /*
2694 * perform perspective on all unclipped transformed points
2695 */
2696 for (i = 0; i < nPts; i++)
2697 {
2698 float z = xPoints[i].z;
2699 if (z < nearPlane)
2700 {
2701 float invDepth = 1.0 / (-z + ZOFFSET);
2702 sPoints[i].x = xPoints[i].x * invDepth;
2703 sPoints[i].y = xPoints[i].y * invDepth;
2704 }
2705 }
2706
2707 for (i = 0; i < nPts; i++)
2708 {
2709 if (xPoints[i].z < nearPlane &&
2710 fabs(sPoints[i].x - xy.x) < sens &&
2711 fabs(sPoints[i].y - xy.y) < sens)
2712 {
2713 if (xPoints[i].z > min && xPoints[i].z < max)
2714 {
2715 pick->pickPath[pick->depth+0] = i;
2716 pick->pickPath[pick->depth+1] = i;
2717 if (! AddPick(pick, poke, xPoints[i], 0, -1, NULL))
2718 goto error;
2719 }
2720 }
2721 }
2722
2723 DXFree((Pointer)sPoints);
2724 return OK;
2725
2726 error:
2727 DXFree((Pointer)sPoints);
2728 return ERROR;
2729 }
2730
2731 static Error
Elt0D_NoPerspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int nPts,float nearPlane,float sens,float min,float max)2732 Elt0D_NoPerspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2733 int nPts, float nearPlane, float sens, float min, float max)
2734 {
2735 int i;
2736
2737 nearPlane += ZOFFSET;
2738
2739 for (i = 0; i < nPts; i++)
2740 {
2741 if (xPoints[i].z < nearPlane &&
2742 fabs(xPoints[i].x - xy.x) < sens &&
2743 fabs(xPoints[i].y - xy.y) < sens)
2744 {
2745 if (xPoints[i].z > min && xPoints[i].z < max)
2746 {
2747 pick->pickPath[pick->depth+0] = i;
2748 pick->pickPath[pick->depth+1] = i;
2749 if (! AddPick(pick, poke, xPoints[i], 0, -1, NULL))
2750 goto error;
2751 }
2752 }
2753 }
2754
2755 return OK;
2756
2757 error:
2758 return ERROR;
2759 }
2760
2761 static Error
PickFLE(Field f,PickBuf * p,int poke,Point2D xy,Matrix * m,int perspective,float nearPlane,float sens,float min,float max)2762 PickFLE(Field f, PickBuf *p, int poke, Point2D xy, Matrix *m,
2763 int perspective, float nearPlane, float sens, float min, float max)
2764 {
2765 Array pA;
2766 Array fA, lA, eA;
2767 Point *xPoints = NULL;
2768 int nPts, nFaces, nLoops, nEdges;
2769 int *faces, *loops, *edges;
2770
2771 pA = (Array)DXGetComponentValue(f, "positions");
2772 fA = (Array)DXGetComponentValue(f, "faces");
2773 lA = (Array)DXGetComponentValue(f, "loops");
2774 eA = (Array)DXGetComponentValue(f, "edges");
2775 if (! lA || ! pA)
2776 {
2777 DXSetError(ERROR_MISSING_DATA, "positions, faces, loops or edges");
2778 goto error;
2779 }
2780
2781 DXGetArrayInfo(pA, &nPts, NULL, NULL, NULL, NULL);
2782 DXGetArrayInfo(fA, &nFaces, NULL, NULL, NULL, NULL);
2783 DXGetArrayInfo(lA, &nLoops, NULL, NULL, NULL, NULL);
2784 DXGetArrayInfo(eA, &nEdges, NULL, NULL, NULL, NULL);
2785
2786 /*
2787 * Transform points
2788 */
2789 xPoints = TransformArray(pA, m);
2790 if (! xPoints)
2791 return ERROR;
2792
2793 faces = (int *)DXGetArrayData(fA);
2794 loops = (int *)DXGetArrayData(lA);
2795 edges = (int *)DXGetArrayData(eA);
2796
2797 if (perspective)
2798 {
2799 if (! FLE_Perspective(p, poke, xy, xPoints, nPts,
2800 faces, nFaces, loops, nLoops, edges, nEdges, nearPlane, sens,
2801 min, max))
2802 goto error;
2803 }
2804 else
2805 {
2806 if (! FLE_NoPerspective(p, poke, xy, xPoints, nPts,
2807 faces, nFaces, loops, nLoops, edges, nEdges, nearPlane, sens,
2808 min, max))
2809 goto error;
2810 }
2811
2812 DXFree((Pointer)xPoints);
2813 return OK;
2814
2815 error:
2816 DXFree((Pointer)xPoints);
2817 return ERROR;
2818 }
2819
2820 static Error
FLE_NoPerspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int nPts,int * faces,int nFaces,int * loops,int nLoops,int * edges,int nEdges,float nearPlane,float sens,float min,float max)2821 FLE_NoPerspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
2822 int nPts, int *faces, int nFaces, int *loops, int nLoops, int *edges,
2823 int nEdges, float nearPlane, float sens, float min, float max)
2824 {
2825 int f, found;
2826 int l, fl, ll;
2827 int e, fe, le;
2828
2829 for (f = 0; f < nFaces; f++)
2830 {
2831 int count = 0;
2832
2833 fl = faces[f];
2834 ll = (f == nFaces-1) ? nLoops - 1 : faces[f+1] - 1;
2835
2836 for (l = fl, found = 0; l <= ll && !found; l++)
2837 {
2838 int start, end;
2839
2840 fe = loops[l];
2841 le = (l == nLoops-1) ? nEdges - 1 : loops[l+1] - 1;
2842
2843 end = edges[le];
2844 for (e = fe; e <= le && !found; e++)
2845 {
2846 float x0, x1;
2847 float y0, y1;
2848
2849 start = end;
2850 end = edges[e];
2851
2852 x0 = xPoints[start].x;
2853 y0 = xPoints[start].y;
2854
2855 x1 = xPoints[end].x;
2856 y1 = xPoints[end].y;
2857
2858 if (y0 == y1)
2859 continue;
2860
2861 if (y0 > y1)
2862 {
2863 float tt;
2864 tt = x0;
2865 x0 = x1;
2866 x1 = tt;
2867 tt = y0;
2868 y0 = y1;
2869 y1 = tt;
2870 }
2871
2872 /*
2873 * If the edge's y-range (closed at the top) spans
2874 * the xy y value, we may have a hit.
2875 */
2876 if (xy.y > y0 && xy.y <= y1)
2877 {
2878 /*
2879 * If both edge endpoints are to the right of
2880 * the xy x point, we have a hit. Otherwise, if
2881 * the edge x-range spans the xy point, we get
2882 * the intersection of the edge with the y = xy.y
2883 * line. If this intersection is to the right of
2884 * the xy point, we have a hit.
2885 */
2886 if (x0 > xy.x && x1 >= xy.x)
2887 {
2888 count ++;
2889 }
2890 else if ((x0 < xy.x && x1 >= xy.x) ||
2891 (x0 > xy.x && x1 <= xy.x))
2892 {
2893 float x, d = (xy.y - y0) / (y1 - y0);
2894 x = x0 + d*(x1 - x0);
2895 if (x == xy.x)
2896 found = 1;
2897
2898 else if (x > xy.x)
2899 count ++;
2900 }
2901 }
2902 }
2903 }
2904
2905 /*
2906 * If count is odd, then xy is inside the FLE. Determine the xyz point
2907 * and add it to the pick buf. Find the point by computing a planar
2908 * equation and evaluating it for Z at the xy point
2909 */
2910 if (found || count & 0x1)
2911 {
2912 Vector v0, v1, vn, normal;
2913 float l0, l0i=0;
2914 float l1=0, l1i=0;
2915 float l, a, b, c, d;
2916 int p, q, r, k;
2917 Point xyz;
2918 float nearPlane = DXD_MAX_FLOAT;
2919 int ni=0;
2920
2921 /*
2922 * Compute a planar equation from the first loop in the face
2923 */
2924
2925 fe = loops[fl];
2926 le = (fl == nLoops-1) ? nEdges - 1 : loops[fl+1] - 1;
2927
2928 normal = DXPt(0.0,0.0,0.0);
2929
2930 q = edges[le];
2931 r = edges[fe];
2932 for (e = fe; e <= le; e++)
2933 {
2934 p = q;
2935 q = r;
2936 r = (e == le) ? edges[fe] : edges[e+1];
2937
2938 if (e == fe)
2939 {
2940 v0 = DXSub(xPoints[q], xPoints[p]);
2941 l0 = DXLength(v0);
2942 if (l0 != 0.0)
2943 l0i = 1.0 / l0;
2944 }
2945 else
2946 {
2947 v0 = v1;
2948 l0 = l1;
2949 l0i = l1i;
2950 }
2951
2952 v1 = DXSub(xPoints[r], xPoints[q]);
2953 l1 = DXLength(v1);
2954
2955 if (l1 == 0.0 || l0 == 0.0)
2956 continue;
2957
2958 l1i = 1.0 / l1;
2959
2960 vn = DXMul(DXCross(v0, v1), l0i*l1i);
2961
2962 l = DXLength(vn);
2963 if (l > 0.0001)
2964 normal = DXAdd(DXMul(vn, 1.0/l), normal);
2965 }
2966
2967 l = DXLength(normal);
2968 if (l == 0.0)
2969 {
2970 DXSetError(ERROR_INTERNAL, "hit a zero area FLE?");
2971 return ERROR;
2972 }
2973
2974 l = 1.0 / l;
2975 a = normal.x * l;
2976 b = normal.y * l;
2977 c = normal.z * l;
2978
2979 if (c == 0.0)
2980 {
2981 DXSetError(ERROR_INTERNAL, "hit an edge-on FLE?");
2982 return ERROR;
2983 }
2984
2985 d = -(a*xPoints[q].x + b*xPoints[q].y + c*xPoints[q].z);
2986
2987 xyz.x = xy.x;
2988 xyz.y = xy.y;
2989 xyz.z = -(a*xy.x + b*xy.y + d) / c;
2990
2991 for (k = fl; k <= ll; k++)
2992 {
2993 fe = loops[k];
2994 le = (k == nLoops-1) ? nEdges - 1 : loops[k+1] - 1;
2995
2996 for (e = fe; e <= le && !found; e++)
2997 {
2998 float dx = xPoints[edges[e]].x - xy.x;
2999 float dy = xPoints[edges[e]].y - xy.y;
3000 float n = sqrt(dx*dx + dy*dy);
3001 if (n < nearPlane)
3002 {
3003 ni = edges[e];
3004 nearPlane = n;
3005 }
3006 }
3007 }
3008
3009 if (xyz.z > min && xyz.z < max)
3010 {
3011 pick->pickPath[pick->depth+0] = f;
3012 pick->pickPath[pick->depth+1] = ni;
3013 if (! AddPick(pick, poke, xyz, 0, -1, NULL))
3014 goto error;
3015 }
3016 }
3017 }
3018
3019 return OK;
3020
3021 error:
3022 return ERROR;
3023 }
3024
3025 #define MAX_CLIPPTS 100
3026
3027 static Error
FLE_Perspective(PickBuf * pick,int poke,Point2D xy,Point * xPoints,int nPts,int * faces,int nFaces,int * loops,int nLoops,int * edges,int nEdges,float nearPlane,float sens,float min,float max)3028 FLE_Perspective(PickBuf *pick, int poke, Point2D xy, Point *xPoints,
3029 int nPts, int *faces, int nFaces, int *loops, int nLoops, int *edges,
3030 int nEdges, float nearPlane, float sens, float min, float max)
3031 {
3032 int i, f, found;
3033 int l, fl, ll;
3034 int e, fe, le;
3035 float dNear, z, depth;
3036 int vKnt=0, cKnt, vLen = 100;
3037 Point cPoints[MAX_CLIPPTS];
3038 Point **cLoop = (Point **)DXAllocate(vLen*sizeof(Pointer));
3039 Point *sPoints = (Point *)DXAllocate(nPts*sizeof(Point));
3040 if (! sPoints || ! cLoop)
3041 goto error;
3042
3043 nearPlane += ZOFFSET;
3044 dNear = -1.0 / nearPlane;
3045
3046 /*
3047 * perform perspective on all unclipped transformed points
3048 */
3049 for (i = 0; i < nPts; i++)
3050 {
3051 float z = xPoints[i].z;
3052 if (z < nearPlane)
3053 {
3054 float invDepth = 1.0 / (-z + ZOFFSET);
3055 sPoints[i].x = xPoints[i].x * invDepth;
3056 sPoints[i].y = xPoints[i].y * invDepth;
3057 sPoints[i].z = xPoints[i].z * invDepth;
3058 }
3059 }
3060
3061 for (f = 0; f < nFaces; f++)
3062 {
3063 int count = 0;
3064
3065 fl = faces[f];
3066 ll = (f == nFaces-1) ? nLoops - 1 : faces[f+1] - 1;
3067
3068 for (l = fl, found = 0; l <= ll && !found; l++)
3069 {
3070 Point *start, *end;
3071
3072 fe = loops[l];
3073 le = (l == nLoops-1) ? nEdges - 1 : loops[l+1] - 1;
3074
3075 vKnt = cKnt = 0;
3076 for (e = fe; e <= le; e++)
3077 {
3078 int tv, nv;
3079 int ne = (e == le) ? fe : e + 1;
3080 tv = edges[e];
3081 nv = edges[ne];
3082
3083 if (xPoints[tv].z <= nearPlane)
3084 {
3085 if (vKnt == vLen)
3086 {
3087 cLoop = (Point **)DXReAllocate(cLoop,
3088 2*vLen*sizeof(Pointer));
3089 if (cLoop == NULL)
3090 goto error;
3091 vLen *= 2;
3092 }
3093
3094 cLoop[vKnt++] = sPoints + tv;
3095 }
3096
3097 if ((xPoints[tv].z < nearPlane && xPoints[nv].z > nearPlane) ||
3098 (xPoints[tv].z > nearPlane && xPoints[nv].z < nearPlane))
3099 {
3100 float d = (nearPlane - sPoints[tv].z) /
3101 (sPoints[nv].z - sPoints[tv].z);
3102
3103 if (cKnt == MAX_CLIPPTS)
3104 {
3105 DXSetError(ERROR_DATA_INVALID, "too many clip points");
3106 goto error;
3107 }
3108
3109 cPoints[cKnt].x = dNear*(xPoints[tv].x + d*(xPoints[nv].x-xPoints[tv].x));
3110 cPoints[cKnt].y = dNear*(xPoints[tv].y + d*(xPoints[nv].y-xPoints[tv].y));
3111 cPoints[cKnt].z = dNear*(xPoints[tv].z + d*(xPoints[nv].z-xPoints[tv].z));
3112
3113 cLoop[vKnt++] = cPoints + cKnt++;
3114 }
3115 }
3116
3117 if (vKnt < 3)
3118 continue;
3119
3120 end = cLoop[vKnt-1];
3121 for (e = 0; e < vKnt && !found; e++)
3122 {
3123 float x0, x1;
3124 float y0, y1;
3125
3126 start = end;
3127 end = cLoop[e];
3128
3129 x0 = start->x;
3130 y0 = start->y;
3131
3132 x1 = end->x;
3133 y1 = end->y;
3134
3135 if (y0 == y1)
3136 continue;
3137
3138 if (y0 > y1)
3139 {
3140 float tt;
3141 tt = x0;
3142 x0 = x1;
3143 x1 = tt;
3144 tt = y0;
3145 y0 = y1;
3146 y1 = tt;
3147 }
3148
3149 /*
3150 * If the edge's y-range (closed at the top) spans
3151 * the xy y value, we may have a hit.
3152 */
3153 if (xy.y > y0 && xy.y <= y1)
3154 {
3155 /*
3156 * If both edge endpoints are to the right of
3157 * the xy x point, we have a hit. Otherwise, if
3158 * the edge x-range spans the xy point, we get
3159 * the intersection of the edge with the y = xy.y
3160 * line. If this intersection is to the right of
3161 * the xy point, we have a hit.
3162 */
3163 if (x0 > xy.x && x1 >= xy.x)
3164 {
3165 count ++;
3166 }
3167 else if ((x0 < xy.x && x1 >= xy.x) ||
3168 (x0 > xy.x && x1 <= xy.x))
3169 {
3170 float x, d = (xy.y - y0) / (y1 - y0);
3171 x = x0 + d*(x1 - x0);
3172 if (x == xy.x)
3173 found = 1;
3174
3175 else if (x > xy.x)
3176 count ++;
3177 }
3178 }
3179 }
3180 }
3181
3182 /*
3183 * If count is odd, then xy is inside the FLE. Determine the xyz point
3184 * and add it to the pick buf. Find the point by computing a planar
3185 * equation and evaluating it for Z at the xy point
3186 */
3187 if (found || count & 0x1)
3188 {
3189 Vector v0, v1, vn, normal;
3190 float l0, l0i=0;
3191 float l1=0, l1i=0;
3192 float l, a, b, c, d;
3193 Point *p, *q, *r;
3194 Point xyz;
3195 int k, ni=0;
3196
3197 /*
3198 * Compute a planar equation
3199 */
3200
3201 normal = DXPt(0.0,0.0,0.0);
3202
3203 q = cLoop[vKnt-1];
3204 r = cLoop[0];
3205 for (e = 0; e < vKnt; e++)
3206 {
3207 p = q;
3208 q = r;
3209 r = (e == vKnt-1) ? cLoop[0] : cLoop[e+1];
3210
3211 if (e == 0)
3212 {
3213 v0 = DXSub(*q, *p);
3214 l0 = DXLength(v0);
3215 if (l0 != 0.0)
3216 l0i = 1.0 / l0;
3217 }
3218 else
3219 {
3220 v0 = v1;
3221 l0 = l1;
3222 l0i = l1i;
3223 }
3224
3225 v1 = DXSub(*r, *q);
3226 l1 = DXLength(v1);
3227
3228 if (l1 == 0.0 || l0 == 0.0)
3229 continue;
3230
3231 l1i = 1.0 / l1;
3232
3233 vn = DXMul(DXCross(v0, v1), l0i*l1i);
3234
3235 l = DXLength(vn);
3236 if (l > 0.0001)
3237 normal = DXAdd(DXMul(vn, 1.0/l), normal);
3238 }
3239
3240 l = DXLength(normal);
3241 if (l == 0.0)
3242 {
3243 DXSetError(ERROR_INTERNAL, "hit a zero area FLE?");
3244 return ERROR;
3245 }
3246
3247 l = 1.0 / l;
3248 a = normal.x * l;
3249 b = normal.y * l;
3250 c = normal.z * l;
3251
3252 if (c == 0.0)
3253 {
3254 DXSetError(ERROR_INTERNAL, "hit an edge-on FLE?");
3255 return ERROR;
3256 }
3257
3258 d = -(a*q->x + b*q->y + c*q->z);
3259
3260 xyz.x = xy.x;
3261 xyz.y = xy.y;
3262 xyz.z = -(a*xy.x + b*xy.y + d) / c;
3263
3264 z = xyz.z = (ZOFFSET * xyz.z) / (1.0 + xyz.z);
3265 depth = ZOFFSET - z;
3266 xyz.x *= depth;
3267 xyz.y *= depth;
3268
3269
3270 for (k = fl; k <= ll; k++)
3271 {
3272 fe = loops[k];
3273 le = (k == nLoops-1) ? nEdges - 1 : loops[k+1] - 1;
3274
3275 for (e = fe; e <= le && !found; e++)
3276 if (xPoints[edges[e]].z < nearPlane)
3277 {
3278 float dx = sPoints[edges[e]].x - xy.x;
3279 float dy = sPoints[edges[e]].y - xy.y;
3280 float n = sqrt(dx*dx + dy*dy);
3281 if (n < nearPlane)
3282 {
3283 ni = edges[e];
3284 nearPlane = n;
3285 }
3286 }
3287 }
3288
3289 if (xyz.z > min && xyz.z < max)
3290 {
3291 pick->pickPath[pick->depth+0] = f;
3292 pick->pickPath[pick->depth+1] = ni;
3293 if (! AddPick(pick, poke, xyz, 0, -1, NULL))
3294 goto error;
3295 }
3296 }
3297 }
3298
3299 DXFree((Pointer)cLoop);
3300 DXFree((Pointer)sPoints);
3301 return OK;
3302
3303 error:
3304 DXFree((Pointer)cLoop);
3305 DXFree((Pointer)sPoints);
3306 return ERROR;
3307 }
3308
3309 static Field
GetFirstHits(Field field)3310 GetFirstHits(Field field)
3311 {
3312 int i;
3313 Field newField = NULL;
3314 Array inPointsA, inPicksA, inPokesA, inPathsA, inWeightsA;
3315 Array outPointsA = NULL, outPicksA = NULL,
3316 outPokesA = NULL, outPathsA = NULL,
3317 outWeightsA = NULL;
3318 float *inPoints, *outPoints;
3319 int *inPicks, *outPicks;
3320 int *inPokes, *outPokes;
3321 int *inPaths, *outPaths;
3322 ubyte *inWeights, *outWeights;
3323 PickWts *wts;
3324 int wtSz;
3325 int pathSz;
3326 int nPokes, nPicks, nPaths;
3327
3328 if (DXEmptyField(field))
3329 return DXEndField(DXNewField());
3330
3331 inPointsA = (Array)DXGetComponentValue(field, "positions");
3332 inPicksA = (Array)DXGetComponentValue(field, "picks");
3333 inPokesA = (Array)DXGetComponentValue(field, "pokes");
3334 inPathsA = (Array)DXGetComponentValue(field, "pick paths");
3335 inWeightsA = (Array)DXGetComponentValue(field, "pick weights");
3336
3337 if (! inPointsA || ! inPicksA || ! inPokesA || ! inPathsA)
3338 {
3339 DXSetError(ERROR_MISSING_DATA, "pick result");
3340 goto error;
3341 }
3342
3343 DXGetArrayInfo(inPokesA, &nPokes, NULL, NULL, NULL, NULL);
3344 DXGetArrayInfo(inPathsA, &nPaths, NULL, NULL, NULL, NULL);
3345 DXGetArrayInfo(inPicksA, &nPicks, NULL, NULL, NULL, NULL);
3346
3347 inPicks = (int *)DXGetArrayData(inPicksA);
3348 inPokes = (int *)DXGetArrayData(inPokesA);
3349 inPaths = (int *)DXGetArrayData(inPathsA);
3350 inPoints = (float *)DXGetArrayData(inPointsA);
3351 inWeights = (ubyte *)DXGetArrayData(inWeightsA);
3352
3353 pathSz = 0; wtSz = 0; wts = (PickWts *)inWeights;
3354 for (i = 0; i < nPokes; i++)
3355 {
3356 int poke = inPokes[i];
3357 int pick = inPicks[poke];
3358 int np = ((i == nPokes-1) ? nPicks : inPokes[i+1]) - poke;
3359 int psz = ((poke == nPicks-1) ? nPaths : inPicks[poke+1]) - pick;
3360 int k;
3361
3362 pathSz += psz;
3363
3364 for (k = 0; k < np; k++)
3365 {
3366 int n = wts->nweights;
3367 int wsz = sizeof(PickWts) + n*sizeof(float);
3368
3369 if (k == 0)
3370 wtSz += wsz;
3371
3372 wts = (PickWts *)(((ubyte *)wts) + wsz);
3373 }
3374 }
3375
3376 outPointsA = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3);
3377 outPicksA = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
3378 outPokesA = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
3379 outPathsA = DXNewArray(TYPE_INT, CATEGORY_REAL, 0);
3380 outWeightsA = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0);
3381
3382 if (!outPointsA || !outPicksA || !outPokesA || !outPathsA || !outWeightsA)
3383 goto error;
3384
3385 if (! DXAddArrayData(outPointsA, 0, nPokes, NULL) ||
3386 ! DXAddArrayData(outPokesA, 0, nPokes, NULL) ||
3387 ! DXAddArrayData(outPicksA, 0, nPokes, NULL) ||
3388 ! DXAddArrayData(outPathsA, 0, pathSz, NULL) ||
3389 ! DXAddArrayData(outWeightsA, 0, wtSz, NULL))
3390 goto error;
3391
3392 outPicks = (int *)DXGetArrayData(outPicksA);
3393 outPokes = (int *)DXGetArrayData(outPokesA);
3394 outPaths = (int *)DXGetArrayData(outPathsA);
3395 outPoints = (float *)DXGetArrayData(outPointsA);
3396 outWeights = (ubyte *)DXGetArrayData(outWeightsA);
3397
3398 pathSz = 0; wtSz = 0; wts = (PickWts *)inWeights;
3399 for (i = 0; i < nPokes; i++)
3400 {
3401 int poke = inPokes[i];
3402 int pick = inPicks[poke];
3403 int np = ((i == nPokes-1) ? nPicks : inPokes[i+1]) - poke;
3404 int psz = ((poke == nPicks-1) ? nPaths : inPicks[poke+1]) - pick;
3405 int k;
3406
3407 memcpy((char *)outPoints, (char *)(inPoints+3*poke), 3*sizeof(float));
3408 outPoints += 3;
3409
3410 outPokes[i] = i;
3411 outPicks[i] = pathSz;
3412
3413 memcpy((char *)outPaths, (char *)(inPaths+pick), psz*sizeof(int));
3414 outPaths += psz;
3415 pathSz += psz;
3416
3417 for (k = 0; k < np; k++)
3418 {
3419 int n = wts->nweights;
3420 int wsz = sizeof(PickWts) + n*sizeof(float);
3421
3422 if (k == 0)
3423 {
3424 memcpy((char *)outWeights, (char *)wts, wsz);
3425 outWeights += wsz;
3426 }
3427
3428 wts = (PickWts *)(((ubyte *)wts) + wsz);
3429 }
3430 }
3431
3432 newField = DXNewField();
3433 if (! newField)
3434 goto error;
3435
3436 if ((! DXSetStringAttribute((Object)outPointsA, "dep", "positions")) ||
3437 (! DXSetStringAttribute((Object)outPokesA, "ref", "picks")) ||
3438 (! DXSetStringAttribute((Object)outPicksA, "dep", "positions")) ||
3439 (! DXSetStringAttribute((Object)outPicksA, "ref", "pick paths")))
3440 goto error;
3441
3442 if (! DXSetComponentValue(newField, "positions", (Object)outPointsA))
3443 goto error;
3444 outPointsA = NULL;
3445
3446 if (! DXSetComponentValue(newField, "pokes", (Object)outPokesA))
3447 goto error;
3448 outPokesA = NULL;
3449
3450 if (! DXSetComponentValue(newField, "picks", (Object)outPicksA))
3451 goto error;
3452 outPicksA = NULL;
3453
3454 if (! DXSetComponentValue(newField, "pick paths", (Object)outPathsA))
3455 goto error;
3456 outPathsA = NULL;
3457
3458 if (! DXSetComponentValue(newField, "pick weights", (Object)outWeightsA))
3459 goto error;
3460 outPathsA = NULL;
3461
3462 return newField;
3463
3464 error:
3465 DXDelete((Object)outWeightsA);
3466 DXDelete((Object)outPointsA);
3467 DXDelete((Object)outPicksA);
3468 DXDelete((Object)outPokesA);
3469 DXDelete((Object)outPathsA);
3470 DXDelete((Object)newField);
3471 return NULL;
3472 }
3473
3474 static Error PickTraverse(Object, Matrix *, Point,
3475 int *, int, int, int, Field, int, int, float *);
3476
3477 static Error
PickInterpolate(Object object,Field picks,int flag)3478 PickInterpolate(Object object, Field picks, int flag)
3479 {
3480 Array array, wArray = NULL;
3481 PickWts *wPtr;
3482 Point *point;
3483 int npokes, npicks;
3484 int i, j;
3485
3486 if (DXEmptyField(picks))
3487 return OK;
3488
3489 array = (Array)DXGetComponentValue(picks, "positions");
3490 point = (Point *)DXGetArrayData(array);
3491
3492 wArray = (Array)DXGetComponentValue(picks, "pick weights");
3493 if (! wArray)
3494 {
3495 DXSetError(ERROR_MISSING_DATA, "pick weights");
3496 goto error;
3497 }
3498
3499 DXReference((Object)wArray);
3500 DXDeleteComponent(picks, "pick weights");
3501
3502 wPtr = (PickWts *)DXGetArrayData(wArray);
3503
3504 if (! DXQueryPokeCount(picks, &npokes))
3505 goto error;
3506
3507 for (i = 0; i < npokes; i++)
3508 {
3509
3510 if (! DXQueryPickCount(picks, i, &npicks))
3511 goto error;
3512
3513 for (j = 0; j < npicks; j++, point++)
3514 {
3515 int *path, elt, vert, length;
3516 float *wts = (float *)(wPtr + 1);
3517
3518 if (! DXQueryPickPath(picks, i, j, &length, &path, &elt, &vert))
3519 goto error;
3520
3521 if (! PickTraverse(object, NULL, *point, path, length, elt,
3522 vert, picks, flag, wPtr->segment, wts))
3523 goto error;
3524
3525 wPtr = (PickWts *)(((char *)wPtr)+sizeof(PickWts)+wPtr->nweights*sizeof(float));
3526 }
3527 }
3528
3529 DXDelete((Object)wArray);
3530 return OK;
3531
3532 error:
3533 DXDelete((Object)wArray);
3534 return ERROR;
3535 }
3536
3537 #define INTERPOLATE_PICK(type, rnd) \
3538 { \
3539 int i, j; \
3540 type *_dst = (type *)dstD; \
3541 \
3542 for (i = 0; i < nItems; i++) \
3543 buf[i] = 0.0; \
3544 \
3545 for (i = 0; i < vPerE; i++) \
3546 { \
3547 type *_src = ((type *)DXGetArrayData(srcA)) + element[i]*nItems; \
3548 for (j = 0; j < nItems; j++) \
3549 buf[j] += wts[i]*_src[j]; \
3550 } \
3551 \
3552 for (i = 0; i < nItems; i++) \
3553 _dst[i] = (type)(buf[i] + rnd); \
3554 }
3555
3556 static Error
PickTraverse(Object object,Matrix * stack,Point xyz,int * path,int length,int eid,int vid,Field picks,int flag,int seg,float * wts)3557 PickTraverse(Object object, Matrix *stack, Point xyz,
3558 int *path, int length, int eid, int vid,
3559 Field picks, int flag, int seg, float *wts)
3560 {
3561 switch(DXGetObjectClass(object))
3562 {
3563 case CLASS_FIELD:
3564 {
3565 Field f = (Field)object;
3566 Type t;
3567 Category c;
3568 int r, s[32];
3569 Array srcA, dstA;
3570 Pointer *srcD, *dstD;
3571 int itemSize;
3572 int dstL;
3573 int srcI;
3574 char *name;
3575 int index;
3576 char *dstName;
3577 Object attr;
3578 Array eltsA, edgesA;
3579 int vPerE;
3580 int *element=NULL;
3581 int lineseg[2];
3582
3583 if (length != 0)
3584 {
3585 DXSetError(ERROR_INTERNAL,
3586 "path continues past a field object");
3587 goto error;
3588 }
3589
3590 if (flag == INTERPOLATE)
3591 {
3592 eltsA = (Array)DXGetComponentValue(f, "connections");
3593 if (eltsA)
3594 {
3595 DXGetArrayInfo(eltsA, NULL, NULL, NULL, NULL, &vPerE);
3596 element = ((int *)DXGetArrayData(eltsA)) + eid*vPerE;
3597 }
3598 else
3599 {
3600 eltsA = (Array)DXGetComponentValue(f, "polylines");
3601 if (eltsA)
3602 {
3603 int estart, eend, *polylines, *edges;
3604 int nP, nE;
3605
3606 edgesA = (Array)DXGetComponentValue(f, "edges");
3607
3608 polylines = (int *)DXGetArrayData(eltsA);
3609 edges = (int *)DXGetArrayData(edgesA);
3610
3611 DXGetArrayInfo(eltsA, &nP, NULL, NULL, NULL, NULL);
3612 DXGetArrayInfo(edgesA, &nE, NULL, NULL, NULL, NULL);
3613
3614 estart = polylines[eid];
3615 eend = (eid == nP-1) ? nE : polylines[eid+1];
3616
3617 lineseg[0] = edges[estart + seg];
3618 if (estart + seg + 1 == eend)
3619 lineseg[1] = edges[estart];
3620 else
3621 lineseg[1] = edges[estart + seg + 1];
3622
3623 element = lineseg;
3624 vPerE = 2;
3625 }
3626 else
3627 {
3628 flag = CLOSEST_VERTEX;
3629 }
3630 }
3631 }
3632
3633 for (index = 0;
3634 NULL != (srcA =
3635 (Array)DXGetEnumeratedComponentValue(f, index, &name));
3636 index ++)
3637 {
3638 char *dependency;
3639
3640 attr = DXGetAttribute((Object)srcA, "dep");
3641 if (! attr)
3642 continue;
3643
3644 dependency = DXGetString((String)attr);
3645
3646 if (! strcmp(name, "positions"))
3647 dstName = "closest vertex";
3648 else
3649 dstName = name;
3650
3651 DXGetArrayInfo(srcA, NULL, &t, &c, &r, s);
3652
3653 dstA = (Array)DXGetComponentValue(picks, dstName);
3654 if (! dstA)
3655 {
3656
3657 dstA = DXNewArrayV(t, c, r, s);
3658 if (! dstA)
3659 goto error;
3660
3661 if (! DXSetAttribute((Object)dstA, "dep",
3662 (Object)DXNewString("positions")))
3663 goto error;
3664
3665 if (! DXSetComponentValue(picks, dstName, (Object)dstA))
3666 goto error;
3667 }
3668 else
3669 if (! DXTypeCheckV(dstA, t, c, r, s))
3670 {
3671 DXSetError(ERROR_DATA_INVALID,
3672 "mismatched data components");
3673 goto error;
3674 }
3675
3676 DXGetArrayInfo(dstA, &dstL, NULL, NULL, NULL, NULL);
3677
3678 if (! DXAddArrayData(dstA, dstL, 1, NULL))
3679 goto error;
3680
3681 itemSize = DXGetItemSize(dstA);
3682
3683 dstD = (Pointer)((char *)DXGetArrayData(dstA)
3684 + dstL*itemSize);
3685
3686 if (flag == CLOSEST_VERTEX ||
3687 !strcmp(dependency, "connections") ||
3688 !strcmp(dependency, "faces") ||
3689 !strcmp(dependency, "polylines") ||
3690 !strcmp(dstName, "closest vertex"))
3691 {
3692 if (! strcmp(dependency, "connections") ||
3693 ! strcmp(dependency, "polylines") ||
3694 ! strcmp(dependency, "faces"))
3695 srcI = eid;
3696 else
3697 srcI = vid;
3698
3699 srcD = (Pointer)((char *)DXGetArrayData(srcA)
3700 + srcI*itemSize);
3701
3702 memcpy(dstD, srcD, itemSize);
3703 }
3704 else if (flag == INTERPOLATE)
3705 {
3706 int nItems = DXGetItemSize(dstA) / DXTypeSize(t);
3707 float *buf = (float *)DXAllocate(nItems*sizeof(float));
3708 if (! buf)
3709 goto error;
3710
3711 switch(t)
3712 {
3713 case TYPE_DOUBLE: INTERPOLATE_PICK(double,0.0); break;
3714 case TYPE_FLOAT: INTERPOLATE_PICK(float,0.0); break;
3715 case TYPE_INT: INTERPOLATE_PICK(int,0.5); break;
3716 case TYPE_UINT: INTERPOLATE_PICK(uint,0.5); break;
3717 case TYPE_SHORT: INTERPOLATE_PICK(short,0.5); break;
3718 case TYPE_USHORT: INTERPOLATE_PICK(ushort,0.5); break;
3719 case TYPE_BYTE: INTERPOLATE_PICK(byte,0.5); break;
3720 case TYPE_UBYTE: INTERPOLATE_PICK(ubyte,0.5); break;
3721 default: break;
3722 }
3723
3724 DXFree((Pointer)buf);
3725 }
3726 }
3727
3728
3729 return OK;
3730 }
3731
3732 case CLASS_GROUP:
3733 {
3734 Group g = (Group)object;
3735
3736 object = DXGetEnumeratedMember(g, *path, NULL);
3737 if (! object)
3738 {
3739 DXSetError(ERROR_DATA_INVALID,
3740 "pick path references non-existent group member");
3741 goto error;
3742 }
3743
3744 return PickTraverse(object, stack, xyz, path+1, length-1,
3745 eid, vid, picks, flag, seg, wts);
3746 }
3747
3748 case CLASS_XFORM:
3749 {
3750 Matrix m;
3751 Xform x = (Xform)object;
3752
3753 if (*path != 0)
3754 {
3755 DXSetError(ERROR_DATA_INVALID,
3756 "pick path references invalid xform child");
3757 goto error;
3758 }
3759
3760 DXGetXformInfo(x, &object, &m);
3761 if (stack)
3762 {
3763 Matrix p = DXConcatenate(m, *stack);
3764 return PickTraverse(object, &p, xyz, path+1, length-1,
3765 eid, vid, picks, flag, seg, wts);
3766 }
3767 else
3768 return PickTraverse(object, &m, xyz, path+1, length-1,
3769 eid, vid, picks, flag, seg, wts);
3770 }
3771
3772 case CLASS_CLIPPED:
3773 {
3774 Clipped c = (Clipped)object;
3775
3776 if (*path != 0)
3777 {
3778 DXSetError(ERROR_DATA_INVALID,
3779 "pick path references invalid Clipped child");
3780 goto error;
3781 }
3782
3783 DXGetClippedInfo(c, &object, NULL);
3784
3785 return PickTraverse(object, stack, xyz, path+1, length-1,
3786 eid, vid, picks, flag, seg, wts);
3787 }
3788
3789 case CLASS_SCREEN:
3790 {
3791 Screen s = (Screen)object;
3792
3793 if (*path != 0)
3794 {
3795 DXSetError(ERROR_DATA_INVALID,
3796 "pick path references invalid Screen child");
3797 goto error;
3798 }
3799
3800 DXGetScreenInfo(s, &object, NULL, NULL);
3801
3802 return PickTraverse(object, stack, xyz, path+1, length-1,
3803 eid, vid, picks, flag, seg, wts);
3804 }
3805
3806 default:
3807 {
3808 DXSetError(ERROR_BAD_CLASS,
3809 "invalid object encountered in traversal");
3810 goto error;
3811 }
3812 }
3813
3814 error:
3815 return ERROR;
3816 }
3817
3818
3819 #if 0
3820 static Error
3821 GetAAMatrix(Object o, Matrix *r)
3822 {
3823 Matrix p, m;
3824
3825 if (DXGetObjectClass(o) != CLASS_XFORM)
3826 goto error;
3827
3828 DXGetXformInfo((Xform)o, &o, &p);
3829
3830 if (DXGetObjectClass(o) != CLASS_XFORM)
3831 goto error;
3832
3833 DXGetXformInfo((Xform)o, &o, &m);
3834
3835 p = DXConcatenate(m, p);
3836
3837 if (DXGetObjectClass(o) != CLASS_GROUP ||
3838 DXGetGroupClass((Group)o) != CLASS_GROUP)
3839 goto error;
3840
3841 o = DXGetEnumeratedMember((Group)o, 1, NULL);
3842
3843 if (DXGetObjectClass(o) != CLASS_XFORM)
3844 goto error;
3845
3846 DXGetXformInfo((Xform)o, &o, &m);
3847
3848 *r = DXConcatenate(m, p);
3849
3850 return OK;
3851
3852 error:
3853 DXSetError(ERROR_DATA_INVALID,
3854 "unrecognized object in AutoAxes object header");
3855 return ERROR;
3856 }
3857 #endif
3858
3859 static Array
getXY(Array in)3860 getXY(Array in)
3861 {
3862 int i, nIn, nOut, *dataOut;
3863 DXEvents dataIn;
3864 Type t;
3865 Category c;
3866 int rank, nDim;
3867 Array out = NULL;
3868
3869 if (DXGetObjectClass((Object)in) != CLASS_ARRAY)
3870 {
3871 DXSetError(ERROR_DATA_INVALID, "pick list must be class ARRAY");
3872 return NULL;
3873 }
3874
3875 DXGetArrayInfo(in, &nIn, &t, &c, &rank, &nDim);
3876
3877 if (t != TYPE_INT || c != CATEGORY_REAL || rank != 1)
3878 {
3879 DXSetError(ERROR_DATA_INVALID,
3880 "pick list array of real integer vectors");
3881 return NULL;
3882 }
3883
3884 if (nDim == 2)
3885 return in;
3886
3887 dataIn = (DXEvents)DXGetArrayData(in);
3888 for (i = nOut = 0; i < nIn; i++)
3889 {
3890 int b = WHICH_BUTTON(&dataIn[i]);
3891 if (b != NO_BUTTON && dataIn[i].mouse.state == BUTTON_DOWN)
3892 nOut++;
3893 }
3894
3895 if (nOut == 0)
3896 return NULL;
3897
3898 out = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2);
3899 if (! out)
3900 return NULL;
3901
3902 if (! DXAddArrayData(out, 0, nOut, NULL))
3903 {
3904 DXDelete((Object)out);
3905 return NULL;
3906 }
3907
3908 dataIn = (DXEvents)DXGetArrayData(in);
3909 dataOut = (int *)DXGetArrayData(out);
3910 for (i = 0; i < nIn; i++)
3911 {
3912 int b = WHICH_BUTTON(&dataIn[i]);
3913 if (b != NO_BUTTON && dataIn[i].mouse.state == BUTTON_DOWN)
3914 {
3915 dataOut[0] = dataIn[i].mouse.x;
3916 dataOut[1] = dataIn[i].mouse.y;
3917 dataOut += 2;
3918 }
3919 }
3920
3921 return out;
3922 }
3923
3924