ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/lib/gprim/geom/pick.c

This is pick.c in view mode; [Download] [Up]

/* Copyright (c) 1992 The Geometry Center; University of Minnesota
   1300 South Second Street;  Minneapolis, MN  55454, USA;
   
This file is part of geomview/OOGL. geomview/OOGL is free software;
you can redistribute it and/or modify it only under the terms given in
the file COPYING, which you should have received along with this file.
This and other related software may be obtained via anonymous ftp from
geom.umn.edu; email: software@geom.umn.edu. */

/* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips, 
 * Celeste Fowler */

#include "geomclass.h"
#include "pickP.h"

#define PICK_POSSIBLE(pick, ap) \
(ap == NULL ? PW_VERT | PW_EDGE | PW_FACE : \
 ((((pick->want & PW_VERT) && \
    (ap->flag & (APF_FACEDRAW | APF_EDGEDRAW | APF_VECTDRAW))) \
   ? PW_VERT : 0) | \
  (((pick->want & PW_EDGE) && \
    (ap->flag & (APF_FACEDRAW | APF_EDGEDRAW | APF_VECTDRAW))) \
   ? PW_EDGE : 0) | \
  (((pick->want & PW_FACE) && \
    (ap->flag & APF_FACEDRAW)) ? PW_FACE : 0))) 

int PickFace(int n_verts, Point3 *verts, Pick *pick, Appearance *ap)
{
  Point3 got, ep;
  int v, e;

  if (PolyNearPosZInt(n_verts, verts, pick->thresh, &got, &v, &e, &ep) &&
	  got.z < pick->got.z && got.z >= -1)
    return PickFillIn(pick, n_verts, &got, v, e, ap);
  else return 0;

}

int PickFillIn(Pick *pick, int n_verts, Point3 *got, int vertex, 
	       int edge, Appearance *ap)
{
  int i, found = 0;

  pick->got = *got;

  vvcopy(&pick->gcur, &pick->gpath);

  found = 0;
  if ((PICK_POSSIBLE(pick, ap) & PW_VERT) && vertex != -1) {
    found |= PW_VERT;
    pick->vi = vertex;
  }
  if ((PICK_POSSIBLE(pick, ap) & PW_EDGE) && edge != -1 ) {
    found |= PW_EDGE;
    pick->ei[0] = edge;
    pick->ei[1] = (edge + 1) % n_verts;
  }
  if (PICK_POSSIBLE(pick, ap) & PW_FACE) {
    found |= PW_FACE;
    pick->fn = n_verts;
  }
  if (found) {
    pick->found = found;
    if (pick->f != NULL) OOGLFree(pick->f);
    pick->f = NULL;
  }

  return found;
}

Geom *
GeomMousePick(Geom *g, Pick *p, Appearance *ap,
	      Transform Tg, double x, double y)
{
    Pick *pick;
    Transform Txy, T;

    pick = p ? p : PickSet(NULL, PA_END);
    TmTranslate(Txy, -x, -y, 0.);
    TmConcat(Tg, Txy, T);
    g = GeomPick(g, pick, ap, T);
    if (g && p) {
      TmInvert(p->Tprim, p->Tmirp);
      TmInvert(T, p->Tw);
    }
    if(p == NULL)
	PickDelete(pick);
    return g;
}

/*
 * Simple generic Pick routine based on bounding-box intersection.
 * We succeed if the picked point lies within the screen projection of the
 * object, i.e. if the picked point lies within the smallest screen square
 * surrounding the object.  The depth is that of the midpoint of the
 * bounding box: average of min and max depth.
 */
static Geom *
GenericPick(Geom *g, Pick *p, Appearance *ap, Transform T)
{
    Geom *bbox;
    HPoint3 min, max;

    bbox = GeomBound(g, T);
    BBoxMinMax(bbox, &min, &max);
    if(min.x <= 0 && max.x >= 0 && min.y <= 0 && max.y >= 0 &&
					.5*(min.z + max.z) <= p->got.z) {
	p->got.x = p->got.y = 0;
	p->got.z = .5 * (min.z + max.z);
	p->gprim = g;
	TmCopy(T, p->Tprim);
	return g;
    }
    return NULL;
}

Geom *
GeomPick(Geom *g, Pick *p, Appearance *ap, Transform T)
{
   if(g == NULL)
	return;

   if(g->Class->pick == NULL) {
	/* OOGLError(1, "Note: using GenericPick for class %s",
				(*g->Class->name)()); */
	g->Class->pick = (GeomPickFunc *)GenericPick;
   }
   return (*g->Class->pick)(g, p, ap, T);
}

void
PickDelete(Pick *p)
{	/* Note we don't GeomDelete(p->gprim); it wasn't RefIncr'd */
  if(p) {
    if (p->f) OOGLFree(p->f);	/* free the face list, if any */
    vvfree(&p->gcur);
    vvfree(&p->gpath);
    OOGLFree(p);
  }
}

Pick *
PickSet(register Pick *p, int attr, ...)
{
    va_list al;
    int a;

    if(p == NULL) {
	/*
	 * Create new Pick structure
	 */
	p = OOGLNewE(Pick, "new Pick");
	p->got.x = 0;  p->got.y = 0;  p->got.z = 1;
	p->thresh = 0.02;
	p->want = 0;
	p->found = 0;
	VVINIT(p->gcur, int, 1);
	VVINIT(p->gpath, int, 1);
	p->gprim = NULL;
	HPt3From(&p->v, 0.0, 0.0, 0.0, 1.0);
	p->vi = -1;
	HPt3From(&p->e[0], 0.0, 0.0, 0.0, 1.0);
	HPt3From(&p->e[1], 0.0, 0.0, 0.0, 1.0);
	p->ei[0] = -1;
	p->ei[1] = -1;
	p->f = NULL;
	p->fn = 0;
	p->fi = -1;
    }
    va_start(al, attr);
    for(a = attr; a != PA_END; a = va_arg(al, int)) {
	switch(a) {
	case PA_WANT:	p->want = va_arg(al, int); break;
	case PA_THRESH:	p->thresh = va_arg(al, double); break;
	case PA_POINT:	p->got = *va_arg(al, Point3 *); break;
	case PA_DEPTH:	p->got.z = va_arg(al, double); break;
	case PA_GPRIM:	p->gprim = va_arg(al, Geom *); break;
	case PA_TPRIM:  TmCopy(*va_arg(al, Transform *), p->Tprim); break;
	case PA_VERT:	p->v = *va_arg(al, HPoint3 *); break;
	case PA_EDGE: { HPoint3 *e = va_arg(al, HPoint3 *);
			p->e[0] = e[0];
			p->e[1] = e[1];
		      }
	  break;
	case PA_FACE:	p->f = va_arg(al, HPoint3 *); break;
	case PA_FACEN:	p->fn = va_arg(al, int); break;
	default:
	    OOGLError(1, "PickSet: unknown attribute %d", a);
	    va_end(al);
	    return p;
	}
    }
    va_end(al);
    return p;
}

int
PickGet(register Pick *p, int attr, void *attrp)
{
    if(p == NULL)
	return -1;
    switch(attr) {
    case PA_WANT:   *(int *)attrp = p->want; return 1;
    case PA_THRESH: *(float *)attrp = p->thresh; return 1;
    case PA_POINT:  *(Point3 *)attrp = p->got; break;
    case PA_DEPTH:  *(float *)attrp = p->got.z; break;
    case PA_GPRIM:  *(Geom **)attrp = p->gprim; break;
    case PA_TPRIM:  TmCopy(p->Tprim, *(Transform *)attrp); break;
    case PA_VERT: *(HPoint3 *)attrp = p->v; break;
    case PA_EDGE:
      ((HPoint3 *)attrp)[0] = p->e[0];
      ((HPoint3 *)attrp)[1] = p->e[1];
      break;
    case PA_FACE: *(HPoint3 **)attrp = p->f; break;
    case PA_FACEN: *(int *)attrp = p->fn; break;
    default:
	return -1;
    }
    return p->found;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.