/************************************************************************* * InsertCircleCmd - do a rational NURB. There are at least three ways to do * this: * 2 are found on page 374, Mathematical Elements for Computer Graphics, * 2nd ed. David F. Rogers and J Alan Adams. McGraw Hill, 1990. * One of which is the triangle method, using 7 control points at the corners * and middles of an equilateral triangle, with knot vector * [ 0, 0, 0, 1, 1, 2, 2, 3, 3, 3 ] and weights ( or H or W values ) * [ 1.0, 0.5, 1.0, 0.5, 1.0, 0.5, 1.0] * * The second is a square, with control points at the corners and midpoints. * X (knots) = [0,0,0,1,1,2,2,3,3,4,4,4] * W = [1.0, 0.707, 1.0, 0.707, 1.0, 0.707, 1.0] * 0.707 = sqrt(2)/2.0 * * A third is a square, but only two of the sides have midpoint controls. * X [ 0,0,0, 0.25, 0.5, 0.5, 0.75, 1,1,1] * W [1, 0.5, 0.5, 1, 0.5, 0.5, 1] * from Piegl, Les. On NURBS: A Survey. IEEE CG&A, January 1991. * * We are going to use the triangle. * * we have two points, center of circle & triangle & p1 == p7. * distance to p2, & p6 is RADICAL3 * distance from p1 to center. * distance from p1 to p4 ( top of triangle ) is 3 * distance to center. * just make p3 & p5 midpoints. * * We must have a third point to construct the plane. * */ void InsertCircleCmd( nPoints, points, select ) int nPoints; PEXCoord *points; int select; { int order = 3; float knots[10]; PEXCoord4D p4[7]; PEXArrayOfCoord p; double distance; PEXVector A, B, C; if (nPoints != 3) {printf("not enough points\n"); return;} if (theNewStrux == 0) { theNewStrux = InitStrux(); } else if ( theSelectedElement != -1 ) { ClearSelection(); } A.x = points[0].x - points[1].x; A.y = points[0].y - points[1].y; A.z = points[0].z - points[1].z; B.x = points[2].x - points[1].x; B.y = points[2].y - points[1].y; B.z = points[2].z - points[1].z; Cross3D( &A, &B, &C ); Cross3D( &A, &C, &B ); PEXNormalizeVectors( 1, &B, &B ); /* * B now contains a unit vector perpedicular to A in the plane * defined by the three input points. After we get the distance * we can define all of the points of the equilateral triangle. */ distance = sqrt(A.x*A.x + A.y*A.y + A.z*A.z); #define RADICAL3 1.732 p4[0].x =points[0].x; p4[0].y =points[0].y; p4[0].z =points[0].z; p4[0].w = 1.0; p4[6] = p4[0]; /* * rational NURB control points are given as x*w, y*w, z*w, w * p1 & p7 are the midpoint of the base. * p2 & p6 are the corners of base. */ p4[1].w = 0.5; p4[1].x = (points[0].x + RADICAL3 * distance * B.x) * p4[1].w; p4[1].y = (points[0].y + RADICAL3 * distance * B.y) * p4[1].w; p4[1].z = (points[0].z + RADICAL3 * distance * B.z) * p4[1].w; p4[5].w = 0.5; p4[5].x = (points[0].x - RADICAL3 * distance * B.x) * p4[1].w; p4[5].y = (points[0].y - RADICAL3 * distance * B.y) * p4[1].w; p4[5].z = (points[0].z - RADICAL3 * distance * B.z) * p4[1].w; /* the top of the triangle is 3X past the center */ p4[3].w = 0.5; p4[3].x = (points[0].x - 3 * A.x) * p4[1].w; p4[3].y = (points[0].y - 3 * A.y) * p4[1].w; p4[3].z = (points[0].z - 3 * A.z) * p4[1].w; /* now get the midpoints, special case of weights = 0.5 !!! */ p4[2].w = p4[1].w + p4[3].w; p4[2].x = p4[1].x + p4[3].x; p4[2].y = p4[1].y + p4[3].y; p4[2].z = p4[1].z + p4[3].z; p4[4].w = p4[5].w + p4[3].w; p4[4].x = p4[5].x + p4[3].x; p4[4].y = p4[5].y + p4[3].y; p4[4].z = p4[5].z + p4[3].z; p.point_4d = p4; /* * generate a knot vector for a uniform B-splines * [ 0, 0, 0, 1, 1, 2, 2, 3, 3, 3 ] */ knots[0] = 0; knots[1] = 0; knots[2] = 0; knots[3] = 1; knots[4] = 1; knots[5] = 2; knots[6] = 2; knots[7] = 3; knots[8] = 3; knots[9] = 3; PEXSetElementPtr( theDisplay, theNewStrux, PEXEnd, 0 ); PEXSetLineColorIndex( theDisplay, theNewStrux, PEXOCStore, 1); PEXNURBCurve(theDisplay, theNewStrux, PEXOCStore, PEXRational, order, knots, (unsigned int)7, p, (double)0.0, (double)3.0); if (select) { PEXStructureInfo info; if (PEXGetStructureInfo(theDisplay, theNewStrux, theFF, PEXElementPtr, &info )) { SelectSomething( theNewStrux, info.element_pointer ); } else { printf("PEXGetStructureInfo failed\n");} } }