// Copyright (c) 1999 Philip A. Hardin (pahardin@cs.utexas.edu) // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License v2 or later. #include #include // to get INT_MAX #include "region3d.h" /*=========================================================================*/ region3d::region3d(coord *srcPts, int *srcPanels, coord scale) { #ifdef __GNUC__ // cout << "srcPts=" << srcPts << " *=" << *srcPts << " srcPanels=" << srcPanels << " *=" << *srcPanels << " scale=" << scale << endl; #endif while (*srcPts != COORD_MAX) pts.Add(pt3d(srcPts)*scale); InitPanelsEtc(srcPanels,pt3d(scale,scale,scale)); } region3d::region3d(coord *srcPts, int *srcPanels, const pt3d& scale) { while (*srcPts != COORD_MAX) pts.Add(pt3d(srcPts)*scale); InitPanelsEtc(srcPanels,scale); } region3d::region3d(pt3d *srcPts, int *srcPanels, const pt3d& scale) { while (srcPts->x != COORD_MAX) pts.Add(pt3d(srcPts)*scale); InitPanelsEtc(srcPanels,scale); } /* wantEdges = true -> fill the edgeTable with the edges from the polygons in tree false-> don't add anything to the edgeTable (which saves time if the edgeTable isn't needed) This funny little routine allows initialization of some of a region3d's fields, from an external list of panels. Assumes that this->pts is already defined. */ region3d::region3d(const panelList& otherPanels, bool wantEdges) { panelList::const_iterator p; if (wantEdges) for(p= otherPanels.begin(); p != otherPanels.end(); p++) edges.AddPanel(*p); box.MakeBoundingBox(pts.table(),farthestDist); } /*-------------------------------------------------------------------------*/ // In: viewPos = viewer's eye position, in world coords // frustumNormals = four normals of planes bounding the view frustum; // where normals point _into_ the viewable space. // Note that to get the plane equations, // viewPos must be added to these normals. // worldPos = model-to-world transform for this region3d // Returns true if any part of this region3d may be viewable in the // view frustum. bool region3d::InFrustum(const pt3d& viewPos, const pt3d frustumNormals[], const tmtrx& worldPos) const { // vector from eye pos to center of this region3d, in world coords pt3d eyeToThis= (Box().Center() >> worldPos) - viewPos; forii(4) { coord distInsideFrustum= eyeToThis.Dot(frustumNormals[i]); if (distInsideFrustum +FarthestDist() <0) return false; } return true; } /*-------------------------------------------------------------------------*/ /* Adds an xpanel3d to this region3d. Assumes that the panel's point numbers refer to points that already exist in this->pts. No panel is added if the xpanel3d is empty (i.e. xpanel3d.ptNums.Num()==0) Returns the panel number of the added panel, or -1 if the panel wasn't added. */ int region3d::Add(const xpanel3d& p) { if (p.ptNums.Num() >0) { edges.AddPanel(p); box.MakeBoundingBox(pts.table(), farthestDist); return panels.Add(p); } else return -1; } /*-------------------------------------------------------------------------*/ /* Adds a src region3d to this region3d. Nothing is added if the src region3d is empty (i.e. rgn.panels.Num()==0). The src region3d is (1) scaled, (2) rotated, and (3) offset, in that order, before being added to the this region3d. */ void region3d::Add(const region3d &rgn, const pt3d& offset, const ang3d &ang, const pt3d& scale) { forii(rgn.panels.Num()) Add(xpanel3d(rgn.panels[i],rgn.pts.Array(),pts,offset,ang,scale)); } /*-------------------------------------------------------------------------*/ /* In: srcPanelData = an array of integers which define the panels of this region3d; terminated by INT_MAX scale = needed only to ensure that the panels' normals point in the correct direction */ void region3d::InitPanelsEtc(int *srcPanelData, const pt3d& sc) { bool shouldReverse= false; // reverse the directions that the panels face if (sc.x <0) shouldReverse= ! shouldReverse; if (sc.y <0) shouldReverse= ! shouldReverse; if (sc.z <0) shouldReverse= ! shouldReverse; // So... reverse the directions already! how? -PAH while (*srcPanelData != INT_MAX) { panels.Add(xpanel3d(srcPanelData,&pts[0])); // updates srcPanelData ptr //panels[panels.Num()-1].normal *= normalDir; edges.AddPanel(panels[panels.Num()-1]); } box.MakeBoundingBox(pts.table(),farthestDist); } /*-------------------------------------------------------------------------*/ // Should this function go in pt3d.C? // Writes into the array 'pts' a sequence of 'numSides' points which form // a regular polygon; dist = distance from poly center to each side's center // Returns a pointer just past the end of the last point written pt3d* RegularPolygon(int numSides, pt3d::coord dist, pt3d *pts) { double innerAng= M_PI_2 - M_PI/numSides; pt3d::coord distToCorner= dist/sin(innerAng); /* Using this code, instead of the code below, elicits a compiler bug in g++ 2.7.2.1 when optimizing with -O2 -funroll-loops on a Pentium. forii(numSides) { double ang= -M_PI_2 +(2*M_PI/numSides)/2 +(i * 2*M_PI)/numSides; *tempPts = pt3d(distToCorner,0,0) >> ang; tempPts++; } */ pt3d *tempPts= pts; pt3d *ptsEnd= pts +numSides; while (tempPts != ptsEnd) { double ang= -M_PI_2 +(2*M_PI/numSides)/2 +((tempPts-pts) * 2*M_PI)/numSides; *tempPts = pt3d(distToCorner,0,0) >> ang; tempPts++; } return tempPts; } /*-------------------------------------------------------------------------*/ ostream& operator<< (ostream& out, const region3d& r) { return out << "panels:" << r.panels.Num() << " edges:" << r.edges.Num() << "\n" << r.pts; }