/* Takes a single contour and tries to render it * as a triangle fan. This handles convex polygons, as well as some * non-convex polygons if we get lucky. * * Returns TRUE if the polygon was successfully rendered. The rendering * output is provided as callbacks (see the api). */ public bool RenderCache() { Tesselator.VertexAndIndex[] vCache = this.simpleVertexCache; Tesselator.VertexAndIndex v0 = vCache[0]; double[] norm3 = new double[3]; int sign; if (this.cacheCount < 3) { /* Degenerate contour -- no output */ return(true); } norm3[0] = 0; norm3[1] = 0; norm3[2] = 1; sign = this.ComputeNormal(norm3); if (sign == SIGN_INCONSISTENT) { // Fan triangles did not have a consistent orientation return(false); } if (sign == 0) { // All triangles were degenerate return(true); } /* Make sure we do the right thing for each winding rule */ switch (this.windingRule) { case Tesselator.WindingRuleType.Odd: case Tesselator.WindingRuleType.NonZero: break; case Tesselator.WindingRuleType.Positive: if (sign < 0) { return(true); } break; case Tesselator.WindingRuleType.Negative: if (sign > 0) { return(true); } break; case Tesselator.WindingRuleType.ABS_GEQ_Two: return(true); } this.CallBegin(this.BoundaryOnly ? Tesselator.TriangleListType.LineLoop : (this.cacheCount > 3) ? Tesselator.TriangleListType.TriangleFan : Tesselator.TriangleListType.Triangles); this.CallVertex(v0.vertexIndex); if (sign > 0) { for (int vcIndex = 1; vcIndex < this.cacheCount; ++vcIndex) { this.CallVertex(vCache[vcIndex].vertexIndex); } } else { for (int vcIndex = this.cacheCount - 1; vcIndex > 0; --vcIndex) { this.CallVertex(vCache[vcIndex].vertexIndex); } } this.CallEnd(); return(true); }
private int ComputeNormal(double[] norm3) /* * Check that each triangle in the fan from v0 has a * consistent orientation with respect to norm3[]. If triangles are * consistently oriented CCW, return 1; if CW, return -1; if all triangles * are degenerate return 0; otherwise (no consistent orientation) return * SIGN_INCONSISTENT. */ { Tesselator.VertexAndIndex[] vCache = this.simpleVertexCache; Tesselator.VertexAndIndex v0 = vCache[0]; int vcIndex; double dot, xc, yc, xp, yp; double[] n = new double[3]; int sign = 0; /* Find the polygon normal. It is important to get a reasonable * normal even when the polygon is self-intersecting (eg. a bowtie). * Otherwise, the computed normal could be very tiny, but perpendicular * to the true plane of the polygon due to numerical noise. Then all * the triangles would appear to be degenerate and we would incorrectly * decompose the polygon as a fan (or simply not render it at all). * * We use a sum-of-triangles normal algorithm rather than the more * efficient sum-of-trapezoids method (used in CheckOrientation() * in normal.c). This lets us explicitly reverse the signed area * of some triangles to get a reasonable normal in the self-intersecting * case. */ vcIndex = 1; xc = vCache[vcIndex].x - v0.x; yc = vCache[vcIndex].y - v0.y; while (++vcIndex < this.cacheCount) { xp = xc; yp = yc; xc = vCache[vcIndex].x - v0.x; yc = vCache[vcIndex].y - v0.y; /* Compute (vp - v0) cross (vc - v0) */ n[0] = 0; n[1] = 0; n[2] = xp * yc - yp * xc; dot = n[0] * norm3[0] + n[1] * norm3[1] + n[2] * norm3[2]; if (dot != 0) { /* Check the new orientation for consistency with previous triangles */ if (dot > 0) { if (sign < 0) { return(SIGN_INCONSISTENT); } sign = 1; } else { if (sign > 0) { return(SIGN_INCONSISTENT); } sign = -1; } } } return(sign); }