This is hinge.c in view mode; [Download] [Up]
#include <stdio.h> #include <signal.h> #include <math.h> #include "geom.h" #include "polylistP.h" #include "3d.h" #include "ooglutil.h" #include "hinge.h" #include "hui.h" /* pl is the polyhedron we're dealing with. int pl->n_verts: total number of vertices in the polyhedron HPoint3 pl->vl[]: array containing vertices int pl->n_polys: total number of faces in the polyhedron Poly pl->p[]: array containing the faces int pl->p[i].n_vertices: number of vertices in i-th face HPoint3 pl->p[i].v[j]->pt: j-th vertex of i-th face */ PolyList *pl; Transform *TT[MAXTHINGS]; float epsilon = .005; /* pipes to and from geomview */ FILE *togv, *fromgv; char hingedatastring[] = #include "hingedata.h" ; /* the space we're in */ int space = HYPERBOLIC; /* whether a rotation axis is currently defined */ int haveaxis = 0; /* the angle to rotate through */ float angle = 90; /* increments by which to rotate */ float hingeincr = 5.0; /* whether to kill geomview when we exit or die */ int killgv = 0; Point currentedge[2]; Point base = {0, 0, 0, 1}; Point tip = {0, 0, 1, 1}; Point axis = {0, 0, 1, 1}; Transform BaseT; int mainpos[2]; int helppos[2]; int infopos[2]; int filepos[2]; char *file = NULL; static void space_alignZ(Point *a, Point *b, Transform T); #define NEXTARG ++argv; --argc usage() { fprintf(stderr, "hinge [OPTIONS] [FILE]\n\ OPTIONS:\n\ -space {euclidean|hyperbolic}\n\ -angle a (set angle initially to a degrees)\n\ -incr a (hinge through increments of a degrees)\n\ -killgv (kill geomview upon exit)\n\ -mpos x y (position of main panel)\n\ -hpos x y (position of help panel)\n\ -ipos x y (position of info panel)\n\ -fpos x y (position of file panel)\n"); exit(-1); } void die(int sig, int code, struct sigcontext *sc) { QuitProc(NULL,0); } main(argc, argv) int argc; char *argv[]; { signal(SIGHUP, die); signal(SIGINT, die); signal(SIGQUIT, die); signal(SIGILL, die); signal(SIGTRAP, die); signal(SIGABRT, die); signal(SIGBUS, die); signal(SIGSEGV, die); signal(SIGPIPE, die); signal(SIGTERM, die); NEXTARG; while (argc) { if (!strcmp(argv[0],"-killgv")) { killgv = 1; } else if (!strcmp(argv[0],"-space")) { NEXTARG; if (!argc) usage(); if (!strcmp(argv[0],"hyperbolic")) { space = HYPERBOLIC; } else if (!strcmp(argv[0],"spherical")) { space = SPHERICAL; } else {; space = EUCLIDEAN; } } else if (!strcmp(argv[0], "-incr")) { NEXTARG; if (!argc) usage(); hingeincr = atof(argv[0]); } else if (!strcmp(argv[0], "-angle")) { NEXTARG; if (!argc) usage(); angle = atof(argv[0]); } else if (!strcmp(argv[0], "-mpos")) { NEXTARG; if (argc<2) usage(); mainplacement = FL_PLACE_POSITION; mainpos[0] = atoi(argv[0]); mainpos[1] = atoi(argv[1]); NEXTARG; } else if (!strcmp(argv[0], "-fpos")) { NEXTARG; if (argc<2) usage(); fileplacement = FL_PLACE_POSITION; filepos[0] = atoi(argv[0]); filepos[1] = atoi(argv[1]); NEXTARG; } else if (!strcmp(argv[0], "-ipos")) { NEXTARG; if (argc<2) usage(); infoplacement = FL_PLACE_POSITION; infopos[0] = atoi(argv[0]); infopos[1] = atoi(argv[1]); NEXTARG; } else if (!strcmp(argv[0], "-hpos")) { NEXTARG; if (argc<2) usage(); helpplacement = FL_PLACE_POSITION; helppos[0] = atoi(argv[0]); helppos[1] = atoi(argv[1]); NEXTARG; } else { file = argv[0]; if (argc>1) { fprintf(stderr, "hinge: ignoring arguments after %s\n", file); break; } } NEXTARG; } hui_init(); Initialize(); hui_main_loop(); } Initialize() { int i; LangInit(); for (i=0; i<MAXTHINGS; ++i) TT[i] = NULL; togv = stdout; fromgv = stdin; TmCopy(TM_IDENTITY, BaseT); NewInst(0.0); fprintf(togv, "(progn\n\ (normalization allgeoms none)\n\ (lines-closer allcams 1)\n\ (merge-baseap appearance { +edge })\n\ )\n"); HingeSpace(space); if (file == NULL) { switch (space) { case HYPERBOLIC: file = "HingeDodec"; break; default: case EUCLIDEAN: file = "HingeCube"; break; } } if (file != NULL) { HingeLoad(file); } { Geom *g = NULL; FILE *fp = fopen("hingedata", "r"); if (fp == NULL) fp = fstropen(hingedatastring, sizeof(hingedatastring), "r"); if (fp == NULL) { OOGLError(0,"can't find the file \"hingedata\"; it must be\n\ in the current directory. This will be fixed soon. [mbp]"); exit(-1); } if (fp != NULL) { g = GeomFLoad(fp, "hinge data"); fclose(fp); } if (g != NULL) { DefinePick(g); } else { OOGLError(1,"can't read hinge data\n"); exit(-1); } } fprintf(togv, "(interest (pick world))\n"); fflush(togv); } int WhichFace(HPoint3 *p, Transform T, PolyList *pl) { int i; for (i=0; i<pl->n_polys; ++i) { if (CoPlanar(p, T, &(pl->p[i]))) return i; } return -1; } /*----------------------------------------------------------------------- * Function: CoPlanar * Description: test whether a point is coplanar with the image * of a polygon * Args: *p: the point * T: transform to apply to poly before test * *poly: the polygon * Returns: 1 if yes, 0 if no * Author: mbp * Date: Thu Oct 1 10:06:39 1992 * Notes: Uses global variable "epsilon" for test. * The plane of the polygon is assumed to be * that determined by its first 3 vertices. This * assumes that those vertices are not collinear. * If they are collinear, this test may falsely * return 1. * */ int CoPlanar(HPoint3 *p, Transform T, Poly *poly) { register HPoint3 v0; register HPoint3 v1; register HPoint3 v2; float det; int ans; HPt3Transform(T, &(poly->v[0]->pt), &v0); HPt3Transform(T, &(poly->v[1]->pt), &v1); HPt3Transform(T, &(poly->v[2]->pt), &v2); /* the following is the determinant of the 4x4 matrix whose 1st 3 rows are the homog coords of the polygon's 1st 3 vertices, and whose last row is the homog coords of p */ det = p->x * ( v2.w*v1.y*v0.z - v1.w*v2.y*v0.z - v2.w*v0.y*v1.z + v0.w*v2.y*v1.z + v1.w*v0.y*v2.z - v0.w*v1.y*v2.z ) + p->y * (- v2.w*v1.x*v0.z + v1.w*v2.x*v0.z + v2.w*v0.x*v1.z - v0.w*v2.x*v1.z - v1.w*v0.x*v2.z + v0.w*v1.x*v2.z ) + p->z * ( v2.w*v1.x*v0.y - v1.w*v2.x*v0.y - v2.w*v0.x*v1.y + v0.w*v2.x*v1.y + v1.w*v0.x*v2.y - v0.w*v1.x*v2.y ) + p->w * (- v2.x*v1.y*v0.z + v1.x*v2.y*v0.z + v2.x*v0.y*v1.z - v0.x*v2.y*v1.z - v1.x*v0.y*v2.z + v0.x*v1.y*v2.z ); ans = fabs(det) <= epsilon; return ans; } float HPt3EucDistance( HPoint3 *a, HPoint3 *b ) { Point3 aa, ab; float dist; HPt3ToPt3(a, &aa); HPt3ToPt3(b, &ab); dist = Pt3Distance( &aa, &ab ); return dist; } int pt4equal(HPoint3 *a, HPoint3 *b) { float dist; int ans; dist = HPt3EucDistance( a, b ); ans = dist <= epsilon; return ans; } #if 0 /* commented out until spherical mode can be added; don't need this now */ float space_distance(HPoint3 *a, HPoint3 *b) { float dist; Point3 aa, bb; switch (space) { default: case EUCLIDEAN: dist = HPt3EucDistance( a, b ); return dist; break; case HYPERBOLIC: dist = HPt3HypDistance( a, b ); return dist; break; } } float HPt3HypDistance( HPoint3 *a, HPoint3 *b ) { float ab, aa, bb, dist, p, s; extern double acosh(double); ab = MinkDot(a,b); aa = MinkDot(a,a); bb = MinkDot(b,b); p = ab*ab / (aa * bb); if (p < 1) return 0; s = sqrt(p); dist = 2 * acosh( (double)s ); return dist; } float MinkDot( HPoint3 *a, HPoint3 *b ) { return a->x*b->x + a->y*b->y + a->z*b->z - a->w*b->w; } #endif /*----------------------------------------------------------------------- * Function: PolyContainsEdge * Description: test whether the image of a polygon contain an edge * Args: e[]: array of two points --- the endpoints of the edge * T: transform to apply to the polygon * *poly: the polygon * Returns: -1, 0, or 1 (see below) * Author: mbp * Date: Thu Oct 1 12:28:36 1992 * Notes: returns 1 if the polygon contains the edge with the vertices * in the same order, -1 if opposite order, 0 if polygon doesn't * contain the edge at all. */ int PolyContainsEdge(Point e[], Transform T, Poly *poly) { int i,ans; HPoint3 v; ans = 0; for (i=0; i<poly->n_vertices; ++i) { HPt3Transform(T, &(poly->v[i]->pt), &v); if (pt4equal(&e[0], &v)) { HPt3Transform(T, &(poly->v[(i+1)%poly->n_vertices]->pt), &v); if (pt4equal(&e[1], &v)) { ans = 1; goto done; } HPt3Transform(T, &(poly->v[(i-1+poly->n_vertices)%poly->n_vertices]->pt), &v); if (pt4equal(&e[1], &v)) { ans = -1; goto done; } } } done: return ans; } /* for debugging, just to make sure we understand what we have... */ void WritePolyListInfo(PolyList *pl) { int i,j; FILE *fp = fopen("hinge.out", "w"); fprintf(fp, "%1d vertices\n\n", pl->n_verts); for (i=0; i<pl->n_verts; ++i) { fprintf(fp, "vert[%2d] = (%6f, %6f, %6f, %6f)\n", i, pl->vl[i].pt.x, pl->vl[i].pt.y, pl->vl[i].pt.z, pl->vl[i].pt.w); } fprintf(fp, "\n"); fprintf(fp, "%1d faces\n\n", pl->n_polys); for (i=0; i<pl->n_polys; ++i) { fprintf(fp, "face %1d has %1d vertices:\n", i, pl->p[i].n_vertices); for (j=0; j<pl->p[i].n_vertices; ++j) { fprintf(fp, "\t(%6f, %6f, %6f, %6f)\n", pl->p[i].v[j]->pt.x, pl->p[i].v[j]->pt.y, pl->p[i].v[j]->pt.z, pl->p[i].v[j]->pt.w); } } fclose(fp); } int HingeLoad(char *file) { FILE *f; Geom *g; if (strlen(file)<=0) return 0; /* The following kludge uses geomview to get the data; we tell geomview to load it, then dump it back to us, then delete it. */ fprintf(togv,"(progn\n\ (geometry thing { < %s })\n\ (echo \"{\")\n\ (write geometry - thing self)\n\ (echo \"}\")\n\ (delete thing)\n\ )\n", file); fflush(togv); /* * We now read the object we just told geomview to give us. */ g = GeomFLoad(fromgv, "Hinge: pipe from geomview"); if (g == NULL) { fprintf(stderr, "Hinge: error reading geometry from file %s\n", file); } else { char buf[80]; DefineThing(g); sprintf(buf,"%s",file); hui_message(buf); haveaxis = 0; ShowAxis(); } pl = (PolyList *)g; return g != NULL; } int NewInst(float ang) { int n = NewTTindex(); fprintf(togv, "(progn (read geometry { define T%1d { LIST } } )\n\ (geometry \"geom%1d\" { INST tlist { LIST { :T%1d } } geom :thing } ) )\n", n, n, n); fflush(togv); Inst(n, 0.0); return n; } void ComputeTransform(Transform T, Transform BaseT, float ang) { if (ang == 0) { TmCopy(BaseT, T); } else { Rotation(T, ¤tedge[0], ¤tedge[1], RADIANS(ang)); TmConcat(BaseT, T, T); } } int NewTTindex() { int i; for (i=0; i<MAXTHINGS && TT[i]!=NULL; ++i); if (i==MAXTHINGS) return -1; /* TT[i] = (TmCoord *(*)[4])malloc(sizeof(Transform)); */ TT[i] = (void*)malloc(sizeof(Transform)); TmCopy(TM_IDENTITY, TT[i]); return i; } void DefineAxis(Point *a, Point *b) { haveaxis = 1; currentedge[0] = *a; currentedge[1] = *b; base = *a; tip = *b; HPt3Sub(b, a, &axis); } void Rotation(Transform T, Point *a, Point *b, float angle) { Transform A; space_alignZ(a, b, A); TmInvert(A,A); TmRotateZ(T, angle); TmConjugate(T, A, T); } void DefineThing(Geom *g) { fprintf(togv,"(read geometry { define thing {\n"); GeomFSave(g, togv, "hinge output pipe (define thing...)"); fprintf(togv, "} } )\n"); fflush(togv); } void DefinePick(Geom *g) { fprintf(togv, "(geometry \"pick\" { INST tlist { LIST { :edgeT } } geom { \n"); GeomFSave(g, togv, "hinge output pipe (geometry pick...)"); fprintf(togv, " } } )\n"); fflush(togv); } void Inst(int n, float ang) { ComputeTransform(*(TT[n]), BaseT, ang); fprintf(togv,"(read geometry { define T%1d TLIST\n",n); fputtransform(togv, 1, (float*)(TT[n]), 0); fprintf(togv," } )\n"); fflush(togv); } void Undo() { int i; for (i=0; i<MAXTHINGS && TT[i]!=NULL; ++i); if (i==MAXTHINGS || i<=1) return; --i; /* OOGLFree(TT[i]); */ free(TT[i]); TT[i] = NULL; fprintf(togv,"(delete \"geom%1d\")\n", i); fflush(togv); } void Reset() { int i; fprintf(togv,"(progn\n"); for (i=1; i<MAXTHINGS && TT[i]!=NULL; ++i) { /* OOGLFree(TT[i]); */ free(TT[i]); TT[i] = NULL; fprintf(togv,"(delete \"geom%1d\")\n", i); } haveaxis = 0; ShowAxis(); fprintf(togv,")\n"); fflush(togv); } void ShowAxis() { Transform Ta, TaInv, R, Tloc, Tsize, Tnet; Point3 a, b, b1; float b1halflen, radius; if (haveaxis) { space_alignZ(¤tedge[0], ¤tedge[1], Tloc); HPt3TransPt3(Tloc, ¤tedge[1], &b1); TmInvert(Tloc, Tloc); b1halflen = .5 * Pt3Length(&b1); TmTranslate( Tsize, (float)0, (float)0, b1halflen ); radius = .05 * b1halflen; CtmScale( Tsize, radius, radius, b1halflen ); TmConcat(Tsize, Tloc, Tnet); fprintf(togv,"(read geometry { define edgeT TLIST\n"); fputtransform(togv, 1, (float*)Tnet, 0); fprintf(togv," } )\n"); } else { fprintf(togv,"(read geometry { define edgeT { LIST } })\n"); } fflush(togv); } void space_translate_origin(Point *pt, Transform T) { switch(space) { case HYPERBOLIC: TmHypTranslateOrigin(T, pt); break; case SPHERICAL: TmSphTranslateOrigin(T, pt); break; default: case EUCLIDEAN: TmTranslateOrigin(T, pt); break; } } void HingeSpace(int s) { switch (s) { case HYPERBOLIC: space = HYPERBOLIC; fprintf(togv, "\ (progn\n\ (space hyperbolic)\n\ (camera-reset allcams)\n\ (merge-baseap appearance { +edge shading constant })\n\ )\n"); fflush(togv); break; case SPHERICAL: space = SPHERICAL; fprintf(togv, "\ (progn\n\ (space spherical)\n\ (camera-reset allcams)\n\ (merge-baseap appearance { +edge shading constant })\n\ )\n"); fflush(togv); break; case EUCLIDEAN: default: space = EUCLIDEAN; fprintf(togv, "\ (progn\n\ (space euclidean)\n\ (merge-baseap appearance { +edge shading flat })\n\ )\n"); fflush(togv); break; } } /* returns T = transform taking a to 0 and b to a point on the +Z axis */ static void space_alignZ(Point *a, Point *b, Transform T) { Transform Ta, R; Point b1; /* Ta = transform taking a to origin */ space_translate_origin(a, Ta); TmInvert(Ta,Ta); /* b1 = image of b under Ta */ HPt3Transform(Ta, b, &b1); /* R = transform rotating b1 to +Z axis */ TmRotateTowardZ(R, &b1); /* answer T is Ta * R */ TmConcat(Ta, R, T); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.