1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 *
4 * This file is part of Geomview.
5 *
6 * Geomview is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Geomview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Geomview; see the file COPYING. If not, write
18 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19 * USA, or visit http://www.gnu.org.
20 */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30
31
32 /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips,
33 * Celeste Fowler */
34
35 #include "geomclass.h"
36 #include "pickP.h"
37 #include "bbox.h"
38
39 #define PICK_WANTED(pick, ap) \
40 (pick->want & (!(pick->want & PW_VISIBLE) \
41 || ap == NULL || (ap->flag & APF_FACEDRAW) \
42 ? PW_VERT | PW_EDGE | PW_FACE : \
43 (ap->flag & (APF_EDGEDRAW|APF_VECTDRAW)) \
44 ? PW_VERT|PW_EDGE : 0))
45
PickFace(int n_verts,Point3 * verts,Pick * pick,Appearance * ap)46 int PickFace(int n_verts, Point3 *verts, Pick *pick, Appearance *ap)
47 {
48 Point3 got, ep;
49 int v, e;
50
51 if (PolyNearPosZInt(n_verts, verts, pick->thresh, &got, &v, &e, &ep,
52 PICK_WANTED(pick, ap), pick->got.z))
53 return PickFillIn(pick, n_verts, &got, v, e, ap);
54 else return 0;
55
56 }
57
PickFillIn(Pick * pick,int n_verts,Point3 * got,int vertex,int edge,Appearance * ap)58 int PickFillIn(Pick *pick, int n_verts, Point3 *got, int vertex, int edge, Appearance *ap)
59 {
60 int found = 0;
61
62 (void)ap;
63
64 pick->got = *got;
65
66 vvcopy(&pick->gcur, &pick->gpath);
67
68 found = 0;
69 if (vertex != -1) {
70 found |= PW_VERT;
71 pick->vi = vertex;
72 }
73 if (edge != -1) {
74 found |= PW_EDGE;
75 pick->ei[0] = edge;
76 pick->ei[1] = (edge + 1) % n_verts;
77 }
78 if (pick->want & PW_FACE) {
79 found |= PW_FACE;
80 pick->fn = n_verts;
81 }
82 if (found) {
83 pick->found = found;
84 if (pick->f != NULL) OOGLFree(pick->f);
85 pick->f = NULL;
86 }
87
88 return found;
89 }
90
91 Geom *
GeomMousePick(Geom * g,Pick * p,Appearance * ap,Transform Tg,TransformN * TgN,int * axes,double x,double y)92 GeomMousePick(Geom *g, Pick *p, Appearance *ap,
93 Transform Tg, TransformN *TgN, int *axes,
94 double x, double y)
95 {
96 Pick *pick = NULL;
97 Transform Txy, T;
98 TransformN *TN = NULL;
99
100 if (!p)
101 pick = p = PickSet(NULL, PA_END);
102 p->x0 = x;
103 p->y0 = y;
104 if (TgN) {
105 HPointN *tmp = HPtNCreate(TgN->odim, NULL);
106
107 tmp->v[axes[0]] = -x;
108 tmp->v[axes[1]] = -y;
109
110 TN = TmNTranslateOrigin(NULL, tmp);
111 HPtNDelete(tmp);
112 TmNConcat(TgN, TN, TN);
113 } else {
114 TmTranslate(Txy, -x, -y, 0.);
115 TmConcat(Tg, Txy, T);
116 }
117 g = GeomPick(g, p, ap, T, TN, axes);
118 if (g && !pick) {
119 /* Only bother if the caller will get to see these */
120 if (TN) {
121 p->TmirpN = TmNInvert(p->TprimN, p->TmirpN);
122 p->TwN = TmNInvert(TN, p->TwN);
123 } else {
124 TmInvert(p->Tprim, p->Tmirp);
125 TmInvert(T, p->Tw);
126 }
127 }
128 if (pick)
129 PickDelete(pick);
130 if (TN)
131 TmNDelete(TN);
132 return g;
133 }
134
135 /*
136 * Simple generic Pick routine based on bounding-box intersection.
137 * We succeed if the picked point lies within the screen projection of the
138 * object, i.e. if the picked point lies within the smallest screen square
139 * surrounding the object. The depth is that of the midpoint of the
140 * bounding box: average of min and max depth.
141 */
142 static Geom *
GenericPick(Geom * g,Pick * p,Appearance * ap,Transform T,TransformN * TN,int axes[4])143 GenericPick(Geom *g, Pick *p, Appearance *ap,
144 Transform T, TransformN *TN, int axes[4])
145 {
146 Geom *bbox;
147 HPoint3 min, max;
148
149 (void)ap;
150
151 if (TN) {
152 TransformN *proj;
153 int i;
154
155 proj = TmNCreate(TN->idim, 4, NULL);
156 for (i = 0; i < TN->idim; i++) {
157 proj->a[i*4+0] = TN->a[i*TN->odim+axes[3]];
158 proj->a[i*4+1] = TN->a[i*TN->odim+axes[0]];
159 proj->a[i*4+2] = TN->a[i*TN->odim+axes[1]];
160 proj->a[i*4+3] = TN->a[i*TN->odim+axes[2]];
161 }
162 bbox = GeomBound(g, NULL, proj);
163 TmNDelete(proj);
164 } else {
165 bbox = GeomBound(g, T, NULL);
166 }
167 BBoxMinMax((BBox*)bbox, &min, &max);
168 if (min.x <= 0 && max.x >= 0 && min.y <= 0 && max.y >= 0
169 && .5*(min.z + max.z) <= p->got.z) {
170 p->got.x = p->got.y = 0;
171 p->got.z = .5 * (min.z + max.z);
172 p->gprim = g;
173 if (TN) {
174 p->TprimN = TmNCopy(TN, p->TprimN);
175 memcpy(p->axes, axes, sizeof(p->axes));
176 } else {
177 TmCopy(T, p->Tprim);
178 }
179 return g;
180 }
181 return NULL;
182 }
183
184 Geom *
GeomPick(Geom * g,Pick * p,Appearance * ap,Transform T,TransformN * TN,int * axes)185 GeomPick(Geom *g, Pick *p, Appearance *ap,
186 Transform T, TransformN *TN, int *axes)
187 {
188 Appearance *nap = ap;
189 Geom *result;
190
191 if(g == NULL)
192 return NULL;
193
194 if(g->Class->pick == NULL) {
195 /* OOGLError(1, "Note: using GenericPick for class %s",
196 (*g->Class->name)()); */
197 g->Class->pick = (GeomPickFunc *)GenericPick;
198 }
199 if(g->ap && (p->want & PW_VISIBLE))
200 nap = ApMerge( g->ap, ap, 0 );
201 result = (*g->Class->pick)(g, p, nap, T, TN, axes);
202 if(ap != nap)
203 ApDelete(nap);
204 return result;
205 }
206
207 void
PickDelete(Pick * p)208 PickDelete(Pick *p)
209 { /* Note we don't GeomDelete(p->gprim); it wasn't RefIncr'd */
210 if(p) {
211 if (p->f)
212 OOGLFree(p->f); /* free the face list, if any */
213 if (p->TprimN)
214 TmNDelete(p->TprimN);
215 if (p->TmirpN)
216 TmNDelete(p->TmirpN);
217 if (p->TwN)
218 TmNDelete(p->TwN);
219 if (p->TselfN)
220 TmNDelete(p->TselfN);
221 vvfree(&p->gcur);
222 vvfree(&p->gpath);
223 OOGLFree(p);
224 }
225 }
226
227 Pick *
PickSet(Pick * p,int attr,...)228 PickSet(Pick *p, int attr, ...)
229 {
230 va_list al;
231 int a;
232
233 if(p == NULL) {
234 /*
235 * Create new Pick structure
236 */
237 p = OOGLNewE(Pick, "new Pick");
238 p->got.x = 0; p->got.y = 0; p->got.z = 1;
239 p->thresh = 0.02;
240 p->want = 0;
241 p->found = 0;
242 VVINIT(p->gcur, int, 1);
243 VVINIT(p->gpath, int, 1);
244 p->gprim = NULL;
245 p->TprimN = NULL;
246 p->TmirpN = NULL;
247 p->TwN = NULL;
248 p->TselfN = NULL;
249 HPt3From(&p->v, 0.0, 0.0, 0.0, 1.0);
250 p->vi = -1;
251 HPt3From(&p->e[0], 0.0, 0.0, 0.0, 1.0);
252 HPt3From(&p->e[1], 0.0, 0.0, 0.0, 1.0);
253 p->ei[0] = -1;
254 p->ei[1] = -1;
255 p->f = NULL;
256 p->fn = 0;
257 p->fi = -1;
258 TmIdentity(p->Tw2n);
259 TmIdentity(p->Tc2n);
260 TmIdentity(p->Ts2n);
261 TmIdentity(p->Tprim);
262 TmIdentity(p->Tmirp);
263 TmIdentity(p->Tw);
264 TmIdentity(p->Tself);
265 }
266 va_start(al, attr);
267 for(a = attr; a != PA_END; a = va_arg(al, int)) {
268 switch(a) {
269 case PA_WANT: p->want = va_arg(al, int); break;
270 case PA_THRESH: p->thresh = va_arg(al, double); break;
271 case PA_POINT: p->got = *va_arg(al, Point3 *); break;
272 case PA_DEPTH: p->got.z = va_arg(al, double); break;
273 case PA_GPRIM: p->gprim = va_arg(al, Geom *); break;
274 case PA_TPRIM: TmCopy(*va_arg(al, Transform *), p->Tprim); break;
275 case PA_TPRIMN:
276 p->TprimN = TmNCopy(*va_arg(al, TransformN **), p->TprimN); break;
277 case PA_VERT: p->v = *va_arg(al, HPoint3 *); break;
278 case PA_EDGE: { HPoint3 *e = va_arg(al, HPoint3 *);
279 p->e[0] = e[0];
280 p->e[1] = e[1];
281 }
282 break;
283 case PA_FACE: p->f = va_arg(al, HPoint3 *); break;
284 case PA_FACEN: p->fn = va_arg(al, int); break;
285
286 case PA_TW2N: TmCopy(*va_arg(al, Transform *), p->Tw2n); break;
287 case PA_TC2N: TmCopy(*va_arg(al, Transform *), p->Tc2n); break;
288 case PA_TS2N: TmCopy(*va_arg(al, Transform *), p->Ts2n); break;
289
290 default:
291 OOGLError(1, "PickSet: unknown attribute %d", a);
292 va_end(al);
293 return p;
294 }
295 }
296 va_end(al);
297 return p;
298 }
299
300 int
PickGet(Pick * p,int attr,void * attrp)301 PickGet(Pick *p, int attr, void *attrp)
302 {
303 if(p == NULL)
304 return -1;
305 switch(attr) {
306 case PA_WANT: *(int *)attrp = p->want; return 1;
307 case PA_THRESH: *(float *)attrp = p->thresh; return 1;
308 case PA_POINT: *(Point3 *)attrp = p->got; break;
309 case PA_DEPTH: *(float *)attrp = p->got.z; break;
310 case PA_GPRIM: *(Geom **)attrp = p->gprim; break;
311 case PA_TPRIM: TmCopy(p->Tprim, *(Transform *)attrp); break;
312 case PA_TPRIMN:
313 *((TransformN **)attrp) = TmNCopy(p->TprimN, *((TransformN **)attrp));
314 break;
315 case PA_TWORLD: TmCopy(p->Tw, *(Transform *)attrp); break;
316 case PA_VERT: *(HPoint3 *)attrp = p->v; break;
317 case PA_EDGE:
318 ((HPoint3 *)attrp)[0] = p->e[0];
319 ((HPoint3 *)attrp)[1] = p->e[1];
320 break;
321 case PA_FACE: *(HPoint3 **)attrp = p->f; break;
322 case PA_FACEN: *(int *)attrp = p->fn; break;
323 default:
324 return -1;
325 }
326 return p->found;
327 }
328
329 /*
330 * Local Variables: ***
331 * c-basic-offset: 4 ***
332 * End: ***
333 */
334