/***************************************************************************** * A facility to convert line segments into triangles. * ****************************************************************************** * (C) Gershon Elber, Technion, Israel Institute of Technology * ****************************************************************************** * Written by: David Shafrir & Alex Reicher Ver 0.3, Sep. 2003 * *****************************************************************************/ #include "polyline.h" #include /***************************************************************************** * DESCRIPTION: M * Initialize the segment structure, using the PolylineOptions. M * Should be called when object is created. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * PolyOptions: IN, the polyline options structure. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentInit, Initialize Options M *****************************************************************************/ void LineSegmentInit(LineSegmentStruct *Seg, PolylineOptionsStruct *PolyOptions) { Seg -> TriVertex[2] = IPAllocVertex2(NULL); Seg -> TriVertex[1] = IPAllocVertex2(Seg -> TriVertex[2]); Seg -> TriVertex[0] = IPAllocVertex2(Seg -> TriVertex[1]); Seg -> Tri = IPAllocPolygon(0, Seg -> TriVertex[0], NULL); Seg -> Tri -> Plane[X_AXIS] = 0.0; Seg -> Tri -> Plane[Y_AXIS] = 0.0; Seg -> Tri -> Plane[Z_AXIS] = -1.0; Seg -> Tri -> Plane[W_AXIS] = 0.0; IPUpdateVrtxNrml(Seg -> Tri, Seg -> Tri -> Plane); Seg -> TrianglesNum = 0; if (PolyOptions) LineSegmentSetOptions(Seg, PolyOptions); else { Seg -> k = 0; Seg -> PolyOptions.MaxWidth = Seg -> PolyOptions.MinWidth = 0.01; Seg -> PolyOptions.ZNear = Seg -> PolyOptions.ZFar = 0; } } /***************************************************************************** * DESCRIPTION: M * Changes the PolyOptions. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * PolyOptions: IN, the polyline options structure. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentSetOptions,Initialize Options M *****************************************************************************/ void LineSegmentSetOptions(LineSegmentStruct *Seg, PolylineOptionsStruct *PolyOptions) { if (!PolyOptions) return; memcpy(&Seg -> PolyOptions, PolyOptions, sizeof(PolylineOptionsStruct)); Seg -> k = APX_EQ(PolyOptions -> ZNear, PolyOptions -> ZFar) ? 0 : (PolyOptions -> MaxWidth - PolyOptions -> MinWidth) / (PolyOptions -> ZNear - PolyOptions -> ZFar); } /***************************************************************************** * DESCRIPTION: M * Frees the memory allocated by the object. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentRelease, Release free Options M *****************************************************************************/ void LineSegmentRelease(LineSegmentStruct *Seg) { IPFreePolygon(Seg -> Tri); } /***************************************************************************** * DESCRIPTION: M * Begins a new line. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentStart, begin start M *****************************************************************************/ void LineSegmentStart(LineSegmentStruct *Seg) { Seg -> NumVertex = -1; Seg -> SharpBend = FALSE; } /***************************************************************************** * DESCRIPTION: M * Sets the next point for the line. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * Vertex: IN, the new point. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentSet, add point line-to M *****************************************************************************/ void LineSegmentSet(LineSegmentStruct *Seg, PointType4 Vertex) { RealType Width, Length; PointType d; PointType4 LastPoint; Seg -> NumVertex++; if (Seg -> NumVertex == 0) { PT_COPY4(Seg -> LastPoint, Vertex); Seg -> TrianglesNum = 0; return; } PT2D_SUB(d, Vertex, Seg -> LastPoint); Length = sqrt(SQR(d[X_AXIS]) + SQR(d[Y_AXIS])); PT2D_SCALE(d, 1 / Length); if (APX_EQ(Length, 0)) { Seg -> TrianglesNum = 0; return; /* Segment has zero length. */ } if (Seg -> NumVertex == 1) { PT_COPY4(LastPoint, Seg -> LastPoint); Width = (LastPoint[Z_AXIS] - Seg -> PolyOptions.ZFar) * Seg -> k + Seg -> PolyOptions.MinWidth; PT_COPY4(Seg -> Vertex[2], LastPoint); Seg -> Vertex[2][X_AXIS] -= Width * d[Y_AXIS]; Seg -> Vertex[2][Y_AXIS] += Width * d[X_AXIS]; Seg -> Normal[2][X_AXIS] = -d[Y_AXIS]; Seg -> Normal[2][Y_AXIS] = d[X_AXIS]; Seg -> Normal[2][Z_AXIS] = -0.5; PT_COPY4(Seg -> Vertex[3], LastPoint); Seg -> Vertex[3][X_AXIS] += Width * d[Y_AXIS]; Seg -> Vertex[3][Y_AXIS] -= Width * d[X_AXIS]; Seg -> Normal[3][X_AXIS] = d[Y_AXIS]; Seg -> Normal[3][Y_AXIS] = -d[X_AXIS]; Seg -> Normal[3][Z_AXIS] = -0.5; Seg -> TrianglesNum = 0; /* Don't return triangle. */ } else { VectorType Dir; PT_COPY4(LastPoint, Seg -> LastPoint); if (Seg -> SharpBend) { Seg -> SharpBend = FALSE; PT_COPY4(Seg -> Vertex[0], Seg -> Vertex[3]); PT_COPY4(Seg -> Vertex[1], Seg -> Vertex[2]); VEC_COPY(Seg -> Normal[0], Seg -> Normal[3]); VEC_COPY(Seg -> Normal[1], Seg -> Normal[2]); } else { PT_COPY4(Seg -> Vertex[0], Seg -> Vertex[2]); PT_COPY4(Seg -> Vertex[1], Seg -> Vertex[3]); VEC_COPY(Seg -> Normal[0], Seg -> Normal[2]); VEC_COPY(Seg -> Normal[1], Seg -> Normal[3]); } Width = (LastPoint[Z_AXIS] - Seg -> PolyOptions.ZFar) * Seg -> k + Seg -> PolyOptions.MinWidth; if (DOT_PROD_2D(Seg -> LastDelta, d) > 0.0) { VEC2D_ADD(Dir, Seg -> LastDelta, d); } else { Seg -> SharpBend = TRUE; VEC2D_SUB(Dir, Seg -> LastDelta, d); } VEC2D_NORMALIZE(Dir); PT_COPY4(Seg -> Vertex[2], LastPoint); Seg -> Vertex[2][X_AXIS] -= Width * Dir[Y_AXIS]; Seg -> Vertex[2][Y_AXIS] += Width * Dir[X_AXIS]; PT_COPY4(Seg -> Vertex[3], LastPoint); Seg -> Vertex[3][X_AXIS] += Width * Dir[Y_AXIS]; Seg -> Vertex[3][Y_AXIS] -= Width * Dir[X_AXIS]; VEC_RESET(Seg -> Normal[2]); Seg -> Normal[2][X_AXIS] -= Dir[Y_AXIS]; Seg -> Normal[2][Y_AXIS] += Dir[X_AXIS]; Seg -> Normal[2][Z_AXIS] = -0.5; VEC_RESET(Seg -> Normal[3]); Seg -> Normal[3][X_AXIS] += Dir[Y_AXIS]; Seg -> Normal[3][Y_AXIS] -= Dir[X_AXIS]; Seg -> Normal[3][Z_AXIS] = -0.5; /* Two new triangles can be returned. */ Seg -> TrianglesNum = 2; } PT_COPY4(Seg -> LastPoint, Vertex); PT_COPY(Seg -> LastDelta, d); } /***************************************************************************** * DESCRIPTION: M * Ends a line. Should be called when after the last point was added. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * LineSegmentEnd, line termination M *****************************************************************************/ void LineSegmentEnd(LineSegmentStruct *Seg) { /* We simulate as if there is a new vertex in the tangent direction. */ PointType4 Pt; PT_COPY4(Pt, Seg -> LastPoint); Pt[0] += Seg -> LastDelta[0]; Pt[1] += Seg -> LastDelta[1]; LineSegmentSet(Seg, Pt); } /***************************************************************************** * DESCRIPTION: M * Retrieves the triangles compromising the current segment. M * * * PARAMETERS: M * Seg: IN, OUT, pointer to the line segment. M * NumTri: IN, the number of triangle, shold be < TrianglesNum. M * * * RETURN VALUE: M * IPPolygonStruct *: The triangle. M * * * KEYWORDS: M * LineSegmentGetTri, triangulation M *****************************************************************************/ IPPolygonStruct *LineSegmentGetTri(LineSegmentStruct *Seg, int NumTri) { int Map[3], i; if (NumTri >= Seg -> TrianglesNum) { return NULL; } if (NumTri < 2) { Map[0] = 0; Map[1] = NumTri == 0 ? 1 : 3; Map[2] = NumTri == 0 ? 3 : 2; } for (i = 0; i < 3; i++) { PT_COPY(Seg -> TriVertex[i] -> Coord, Seg -> Vertex[Map[i]]); VEC_COPY(Seg -> TriVertex[i] -> Normal, Seg -> Normal[Map[i]]); VEC_NORMALIZE(Seg -> TriVertex[i] -> Normal); AttrSetRealAttrib(&Seg -> TriVertex[i] -> Attr, "_1/W", Seg -> Vertex[Map[i]][3]); } return Seg -> Tri; }