/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include "clippedClass.h" #include "internals.h" /* * New..., DXDelete... */ Clipped _NewClipped(Object render, Object clipping, struct clipped_class *class) { Clipped c = (Clipped) _dxf_NewObject((struct object_class *)class); if (!c) return NULL; c->render = DXReference(render); c->clipping = DXReference(clipping); return c; } Clipped DXNewClipped(Object render, Object clipping) { return _NewClipped(render, clipping, &_dxdclipped_class); } Clipped DXGetClippedInfo(Clipped c, Object *render, Object *clipping) { CHECK(c, CLASS_CLIPPED); if (render) *render = c->render; if (clipping) *clipping = c->clipping; return c; } Clipped DXSetClippedObjects(Clipped c, Object render, Object clipping) { CHECK(c, CLASS_CLIPPED); if (render) { DXReference(render); DXDelete(c->render); c->render = render; } if (clipping) { DXReference(clipping); DXDelete(c->clipping); c->clipping = clipping; } return c; } int _dxfClipped_Delete(Clipped c) { DXDelete(c->render); DXDelete(c->clipping); return OK; } /* * DXCopy */ Object _dxfClipped_Copy(Clipped old, enum copy copy) { Clipped new; Object render, clipping; /* * Do recursive copy? * NB - no difference between COPY_HEADER and COPY_ATTRIBUTES * here, because we can't create a clipped object w/o subparts */ if (copy==COPY_HEADER || copy==COPY_ATTRIBUTES) { render = old->render; clipping = old->clipping; } else { render = DXCopy(old->render, copy); if (!render) return NULL; clipping = DXCopy(old->clipping, copy); if (!clipping) { DXDelete(render); return NULL; } } /* make new object */ new = DXNewClipped(render, clipping); if (!new) { DXDelete(render); DXDelete(clipping); return NULL; } /* copy superclass parts */ return _dxf_CopyObject((Object)new, (Object)old, copy); } /* * */ static void facenormals(Field f) { Array a; Point *points; RGBColor *colors; Vector *normals; Triangle *tris; int i, n; /* triangles */ a = (Array) DXGetComponentValue(f, "connections"); DXGetArrayInfo(a, &n, NULL, NULL, NULL, NULL); tris = (Triangle *) DXGetArrayData(a); /* points */ a = (Array) DXGetComponentValue(f, "positions"); points = (Point *) DXGetArrayData(a); /* colors */ a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); DXAddArrayData(a, 0, n, NULL); colors = (RGBColor *) DXGetArrayData(a); for (i=0; i=0) { \ if (debug) \ DXAddLine(clip, elements++, DXLn(last,n)); \ else if (first>=0) \ DXAddTriangle(clip, elements++, DXTri(first,last,n)); \ } else \ first = n; \ last = n; \ DXDebug("C", " POINT %d",n); \ } #define END { \ if (debug && first>=0) \ DXAddLine(clip, elements++, DXLn(last,first)); \ } /* * This macro checks edge #e, going from point a to point b, * to see if it crosses the plane; if so, it adds a new point * and records in the crossings array the point number for * that edge crossing. Note that the point number are specified * assuming a nearPlane point of 0, thus we must xor the specified point * numbers a and b with nearPlane. */ #define CROSSING(e,a,b) { /* edge e, endpoints a and b */ \ Point pa, pb; \ float da, db, t, r; \ pa = points[nearPlane^a]; /* point a, relative to nearPlane */ \ pb = points[nearPlane^b]; /* point b, relative to nearPlane */ \ da = DXDot(pa, n); /* projection of a on normal */ \ db = DXDot(pb, n); /* projection of b on normal */ \ if (db!=da) { /* XXX ABS((d-da)/(db-da))d) \ POINT(a) \ else \ DXDebug("C", " (skipping %d: %.2g<=%.2g)",a,DXDot(points[a],n),d); \ #define EDGE(e) if (crossings[e]>=0) POINT(crossings[e]) #define FACE(start,x,y,e) { \ BEGIN; \ CORNER(nearPlane^start); \ EDGE((e)%12); \ CORNER(nearPlane^start^x); \ EDGE((e+1)%12); \ CORNER(nearPlane^start^x^y); \ EDGE((e+3)%12); \ CORNER(nearPlane^start^y); \ EDGE((e+4)%12); \ END; \ } static Vector perp(Vector *d, Vector *a, Vector *b) { float x = d->x; float y = d->y; float z = d->z; if (x!=0) x*=.02,d->x=x, a->x=0,a->y=x,a->z=0, b->x=0,b->y=0,b->z=x; else if (y!=0) y*=.02,d->y=y, a->x=0,a->y=0,a->z=y, b->x=y,b->y=0,b->z=0; else if (z!=0) z*=.02,d->z=z, a->x=z,a->y=0,a->z=0, b->x=0,b->y=z,b->z=0; } Object DXClipPlane(Object o, Point p, Vector n) { Field clip; /* resulting clipping solid */ Point points[20]; /* up to 14: 8 original + 6 crossings */ int npoints; /* actual number of points */ int crossings[12]; /* point num for each of 12 edge crossings */ int first, last; /* first, last point num on current face */ int elements = 0; /* number of triangles so far */ int nearPlane; /* maximal box corner in direction of n */ Vector v1, v2, v4; Vector c1, c2, c4; float max, d, l1, l2, l4; int i, debug; ConstantArray array; /* change the sense of the normal */ n = DXNeg(n); /* check the debug flag */ debug = DXGetAttribute(o, "debug clipping")? 1 : 0; /* get 8 points of box */ if (!DXBoundingBox(o, points)) { if (DXGetError()==ERROR_NONE) return o; else { DXAddMessage("bad input object"); return NULL; } } npoints = 8; /* * Expand box slightly to avoid problems w/ planes on face of box, * taking account of the possibility of a zero-length side. * XXX - there must be a better way */ v1 = DXSub(points[1],points[0]); v2 = DXSub(points[2],points[0]); v4 = DXSub(points[4],points[0]); d = DXLength(DXSub(points[7], points[0])) * .02; l1 = DXLength(v1); l2 = DXLength(v2); l4 = DXLength(v4); if (l2==0 && l4==0) perp(&v1, &v2, &v4); else if (l1==0 && l4==0) perp(&v2, &v4, &v1); else if (l1==0 && l2==0) perp(&v4, &v1, &v2); else { v1 = DXMul(DXNormalize(l1>0 ? v1 : DXCross(v2,v4)), d); v2 = DXMul(DXNormalize(l2>0 ? v2 : DXCross(v4,v1)), d); v4 = DXMul(DXNormalize(l4>0 ? v4 : DXCross(v1,v2)), d); } for (i=0; i<8; i++) { points[i] = i&1? DXAdd(points[i], v1) : DXSub(points[i], v1); points[i] = i&2? DXAdd(points[i], v2) : DXSub(points[i], v2); points[i] = i&4? DXAdd(points[i], v4) : DXSub(points[i], v4); } #if 0 /* expand box slightly to avoid problems w/ planes on face of box */ for (i=0; i<8; i++) { Point a, b; a = points[i]; b = points[i^7]; points[i] = DXAdd(a, DXMul(DXSub(a,b),.05)); } #endif /* find maximal point in direction of normal to plane */ for (i=0, max= -DXD_MAX_FLOAT; i<8; i++) { float l = DXDot(n, points[i]); if (l>max) { max = l; nearPlane = i; } } DXDebug("C", "nearPlane %d", nearPlane); /* field to hold result */ clip = DXNewField(); if (!clip) return NULL; /* start out with no crossings */ for (i=0; i<12; i++) crossings[i] = -1; /* used by CROSSING macro */ d = DXDot(p, n); /* check 12 edges for crossings, constructing face as we go */ BEGIN; CROSSING( 0, 0,1); CROSSING( 1, 1,3); CROSSING( 2, 7,3); CROSSING( 3, 3,2); CROSSING( 4, 0,2); CROSSING( 5, 2,6); CROSSING( 6, 7,6); CROSSING( 7, 6,4); CROSSING( 8, 0,4); CROSSING( 9, 4,5); CROSSING(10, 7,5); CROSSING(11, 5,1); END; /* six faces */ FACE(0,X,Y, 0); FACE(0,Y,Z, 4); FACE(0,Z,X, 8); FACE(7,Z,X, 2); FACE(7,X,Y, 6); FACE(7,Y,Z, 10); /* we're done now */ DXAddPoints(clip, 0, npoints, points); if (debug) for (i=0; i