/******************************Module*Header*******************************\ * Module Name: xc.cxx * * Cross-section (xc) object stuff * * Copyright (c) 1995 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "sscommon.h" #include "sspipes.h" #include "eval.h" #include "xc.h" /**************************************************************************\ * XC::CalcArcACValues90 * * Calculate arc control points for a 90 degree rotation of an xc * * Arc is a quarter-circle * - 90 degree is much easier, so we special case it * - radius is distance from xc-origin to hinge of turn * * History * July 28, 95 : [marcfo] * - Wrote it * \**************************************************************************/ void XC::CalcArcACValues90( int dir, float radius, float *acPts ) { int i; float sign; int offset; float *ppts = (float *) pts; // 1) calc 'r' values for each point (4 turn possibilities/point). From // this can determine ac, which is extrusion of point from xc face switch( dir ) { case PLUS_X: offset = 0; sign = -1.0f; break; case MINUS_X: offset = 0; sign = 1.0f; break; case PLUS_Y: offset = 1; sign = -1.0f; break; case MINUS_Y: offset = 1; sign = 1.0f; break; } for( i = 0; i < numPts; i++, ppts+=2, acPts++ ) { *acPts = EVAL_CIRC_ARC_CONTROL * (radius + (sign * ppts[offset])); } // replicate ! *acPts = *(acPts - numPts); } /**************************************************************************\ * XC::CalcArcACValuesByDistance * * Use the distance of each xc point from the xc origin, as the radius for * an arc control value. * * History * July 29, 95 : [marcfo] * - Wrote it * \**************************************************************************/ void XC::CalcArcACValuesByDistance( float *acPts ) { int i; float r; POINT2D *ppts = pts; for( i = 0; i < numPts; i++, ppts++ ) { r = (float) sqrt( ppts->x*ppts->x + ppts->y*ppts->y ); *acPts++ = EVAL_CIRC_ARC_CONTROL * r; } // replicate ! *acPts = *(acPts - numPts); } /**************************************************************************\ * ELLIPTICAL_XC::SetControlPoints * * Set the 12 control points for a circle at origin in z=0 plane * * Points go CCW from +x * * History * July 24, 95 : [marcfo] * - Wrote it * - 10/18/95 [marcfo] : Convert to C++ * \**************************************************************************/ void ELLIPTICAL_XC::SetControlPoints( GLfloat r1, GLfloat r2 ) { GLfloat ac1, ac2; ac1 = EVAL_CIRC_ARC_CONTROL * r2; ac2 = EVAL_CIRC_ARC_CONTROL * r1; // create 12-pt. set CCW from +x // last 2 points of right triplet pts[0].x = r1; pts[0].y = 0.0f; pts[1].x = r1; pts[1].y = ac1; // top triplet pts[2].x = ac2; pts[2].y = r2; pts[3].x = 0.0f; pts[3].y = r2; pts[4].x = -ac2; pts[4].y = r2; // left triplet pts[5].x = -r1; pts[5].y = ac1; pts[6].x = -r1; pts[6].y = 0.0f; pts[7].x = -r1; pts[7].y = -ac1; // bottom triplet pts[8].x = -ac2; pts[8].y = -r2; pts[9].x = 0.0f; pts[9].y = -r2; pts[10].x = ac2; pts[10].y = -r2; // first point of first triplet pts[11].x = r1; pts[11].y = -ac1; } /**************************************************************************\ * RANDOM4ARC_XC::SetControlPoints * * Set random control points for xc * Points go CCW from +x * * History * July 30, 95 : [marcfo] * - Wrote it * - 10/18/95 [marcfo] : Convert to C++ * \**************************************************************************/ void RANDOM4ARC_XC::SetControlPoints( float radius ) { int i; GLfloat r[4]; float rMin = 0.5f * radius; float distx, disty; // figure the radius of each side first for( i = 0; i < 4; i ++ ) r[i] = ss_fRand( rMin, radius ); // The 4 r's now describe a box around the origin - this restricts stuff // Now need to select a point along each edge of the box as the joining // points for each arc (join points are at indices 0,3,6,9) pts[0].x = r[RIGHT]; pts[3].y = r[TOP]; pts[6].x = -r[LEFT]; pts[9].y = -r[BOTTOM]; // quarter of distance between edges disty = (r[TOP] - -r[BOTTOM]) / 4.0f; distx = (r[RIGHT] - -r[LEFT]) / 4.0f; // uh, put'em somwhere in the middle half of each side pts[0].y = ss_fRand( -r[BOTTOM] + disty, r[TOP] - disty ); pts[6].y = ss_fRand( -r[BOTTOM] + disty, r[TOP] - disty ); pts[3].x = ss_fRand( -r[LEFT] + distx, r[RIGHT] - distx ); pts[9].x = ss_fRand( -r[LEFT] + distx, r[RIGHT] - distx ); // now can calc ac's // easy part first: pts[1].x = pts[11].x = pts[0].x; pts[2].y = pts[4].y = pts[3].y; pts[5].x = pts[7].x = pts[6].x; pts[8].y = pts[10].y = pts[9].y; // right side ac's disty = (r[TOP] - pts[0].y) / 4.0f; pts[1].y = ss_fRand( pts[0].y + disty, r[TOP] ); disty = (pts[0].y - -r[BOTTOM]) / 4.0f; pts[11].y = ss_fRand( -r[BOTTOM], pts[0].y - disty ); // left side ac's disty = (r[TOP] - pts[6].y) / 4.0f; pts[5].y = ss_fRand( pts[6].y + disty, r[TOP]); disty = (pts[6].y - -r[BOTTOM]) / 4.0f; pts[7].y = ss_fRand( -r[BOTTOM], pts[6].y - disty ); // top ac's distx = (r[RIGHT] - pts[3].x) / 4.0f; pts[2].x = ss_fRand( pts[3].x + distx, r[RIGHT] ); distx = (pts[3].x - -r[LEFT]) / 4.0f; pts[4].x = ss_fRand( -r[LEFT], pts[3].x - distx ); // bottom ac's distx = (r[RIGHT] - pts[9].x) / 4.0f; pts[10].x = ss_fRand( pts[9].x + distx, r[RIGHT] ); distx = (pts[9].x - -r[LEFT]) / 4.0f; pts[8].x = ss_fRand( -r[LEFT], pts[9].x - distx ); } /**************************************************************************\ * ConvertPtsZ * * Convert the 2D pts in an xc, to 3D pts in point buffer, with z. * * Also replicate the last point. * * July 28, 95 : [marcfo] * - Wrote it * \**************************************************************************/ void XC::ConvertPtsZ( POINT3D *newpts, float z ) { int i; POINT2D *xcPts = pts; for( i = 0; i < numPts; i++, newpts++ ) { *( (POINT2D *) newpts ) = *xcPts++; newpts->z = z; } *newpts = *(newpts - numPts); } /**************************************************************************\ * XC::CalcBoundingBox * * Calculate bounding box in x/y plane for xc * * July 28, 95 : [marcfo] * - Wrote it * \**************************************************************************/ void XC::CalcBoundingBox( ) { POINT2D *ppts = pts; int i; float xMin, xMax, yMax, yMin; // initialize to really insane numbers xMax = yMax = -FLT_MAX; xMin = yMin = FLT_MAX; // compare with rest of points for( i = 0; i < numPts; i ++, ppts++ ) { if( ppts->x < xMin ) xMin = ppts->x; else if( ppts->x > xMax ) xMax = ppts->x; if( ppts->y < yMin ) yMin = ppts->y; else if( ppts->y > yMax ) yMax = ppts->y; } xLeft = xMin; xRight = xMax; yBottom = yMin; yTop = yMax; } /**************************************************************************\ * * MinTurnRadius * * Get minimum radius for the xc to turn in given direction. * * If the turn radius is less than this minimum, then primitive will 'fold' * over itself at the inside of the turn, creating ugliness. * * History * July 27, 95 : [marcfo] * - Wrote it * \**************************************************************************/ float XC::MinTurnRadius( int relDir ) { //mf: for now, assume xRight, yTop positive, xLeft, yBottom negative // otherwise, might want to consider 'negative'radius switch( relDir ) { case PLUS_X: return( xRight ); case MINUS_X: return( - xLeft ); case PLUS_Y: return( yTop ); case MINUS_Y: return( - yBottom ); default: return(0.0f); } } /**************************************************************************\ * * XC::MaxExtent * * Get maximum extent of the xc in x and y * * History * Aug. 1, 95 : [marcfo] * - Wrote it * \**************************************************************************/ float XC::MaxExtent( ) { float max; max = xRight; if( yTop > max ) max = yTop; if( -xLeft > max ) max = -xLeft; if( -yBottom > max ) max = -yBottom; return max; } /**************************************************************************\ * * XC::Scale * * Scale an XC's points and extents by supplied scale value * \**************************************************************************/ void XC::Scale( float scale ) { int i; POINT2D *ppts = pts; for( i = 0; i < numPts; i ++, ppts++ ) { ppts->x *= scale; ppts->y *= scale; } xLeft *= scale; xRight *= scale; yBottom *= scale; yTop *= scale; } /**************************************************************************\ * ~XC::XC * * Destructor * \**************************************************************************/ XC::~XC() { if( pts ) LocalFree( pts ); } /**************************************************************************\ * XC::XC * * Constructor * * - Allocates point buffer for the xc * \**************************************************************************/ XC::XC( int nPts ) { numPts = nPts; pts = (POINT2D *) LocalAlloc( LMEM_FIXED, numPts * sizeof(POINT2D) ); SS_ASSERT( pts != 0, "XC constructor\n" ); } #if 0 /**************************************************************************\ * XC::XC * * Constructor * * - Copies data from another XC * \**************************************************************************/ //mf: couldn't get calling this to work (compile time) XC::XC( const XC& xc ) { numPts = xc.numPts; pts = (POINT2D *) LocalAlloc( LMEM_FIXED, numPts * sizeof(POINT2D) ); SS_ASSERT( pts != 0, "XC constructor\n" ); RtlCopyMemory( pts, xc.pts, numPts * sizeof(POINT2D) ); xLeft = xc.xLeft; xRight = xc.xRight; yBottom = xc.yBottom; yTop = xc.yTop; } #endif XC::XC( XC *xc ) { numPts = xc->numPts; pts = (POINT2D *) LocalAlloc( LMEM_FIXED, numPts * sizeof(POINT2D) ); SS_ASSERT( pts != 0, "XC constructor\n" ); RtlCopyMemory( pts, xc->pts, numPts * sizeof(POINT2D) ); xLeft = xc->xLeft; xRight = xc->xRight; yBottom = xc->yBottom; yTop = xc->yTop; } /**************************************************************************\ * * ELLIPTICAL_XC::ELLIPTICALXC * * Elliptical XC constructor * These have 4 sections of 4 pts each, with pts shared between sections. * \**************************************************************************/ ELLIPTICAL_XC::ELLIPTICAL_XC( float r1, float r2 ) // initialize base XC with numPts : XC( (int) EVAL_XC_CIRC_SECTION_COUNT * (EVAL_ARC_ORDER - 1)) { SetControlPoints( r1, r2 ); CalcBoundingBox( ); } /**************************************************************************\ * * RANDOM4ARC_XC::RANDOM4ARC_XC * * Random 4-arc XC constructor * The bounding box is 2*r each side * These have 4 sections of 4 pts each, with pts shared between sections. * \**************************************************************************/ RANDOM4ARC_XC::RANDOM4ARC_XC( float r ) // initialize base XC with numPts : XC( (int) EVAL_XC_CIRC_SECTION_COUNT * (EVAL_ARC_ORDER - 1)) { SetControlPoints( r ); CalcBoundingBox( ); }