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