private int AddJoint(int pointIndex, ref JoinSample joinSample, PenWorkspace ws, Buffer <CCVector2> insetBuffer, Buffer <CCVector2> outsetBuffer) { InsetOutsetCount vioCount = new InsetOutsetCount(); switch (_pen.LineJoin) { case LineJoin.Miter: vioCount = _pen.ComputeMiter(ref joinSample, ws); break; case LineJoin.Bevel: vioCount = _pen.ComputeBevel(ref joinSample, ws); break; } if (insetBuffer != null) { for (int i = 0; i < vioCount.InsetCount; i++) { insetBuffer.SetNext(ws.XYInsetBuffer[i]); } } if (outsetBuffer != null) { for (int i = 0; i < vioCount.OutsetCount; i++) { outsetBuffer.SetNext(ws.XYOutsetBuffer[i]); } } return((_strokeType != StrokeType.Outline) ? AddJoint(pointIndex, vioCount, ws) : 0); }
//internal InsetOutsetCount ComputeBevel (Vector2 a, Vector2 b, Vector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeBevel(ref JoinSample js, PenWorkspace ws) { Vector2 a = js.PointA; Vector2 b = js.PointB; Vector2 c = js.PointC; Vector2 edgeBA = new Vector2(a.X - b.X, a.Y - b.Y); Vector2 edgeBC = new Vector2(c.X - b.X, c.Y - b.Y); double dot = Vector2.Dot(edgeBA, edgeBC); if (dot < 0) { double den = edgeBA.LengthSquared() * edgeBC.LengthSquared(); double cos2 = (dot * dot) / den; if (cos2 > _joinLimitCos2) { return(ComputeMiter(ref js, ws)); } } Vector2 edgeAB = new Vector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); Vector2 edgeABt = new Vector2(-edgeAB.Y, edgeAB.X); edgeBC.Normalize(); Vector2 edgeBCt = new Vector2(-edgeBC.Y, edgeBC.X); Vector2 pointA = a; Vector2 pointC = c; short vertexCount = 0; if (Cross2D(edgeAB, edgeBC) > 0) { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new Vector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); pointC = new Vector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); ws.XYInsetBuffer[0] = new Vector2(b.X + w2 * edgeABt.X, b.Y + w2 * edgeABt.Y); ws.XYInsetBuffer[1] = new Vector2(b.X + w2 * edgeBCt.X, b.Y + w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: ws.XYInsetBuffer[0] = new Vector2(b.X + Width * edgeABt.X, b.Y + Width * edgeABt.Y); ws.XYInsetBuffer[1] = new Vector2(b.X + Width * edgeBCt.X, b.Y + Width * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Outset: pointA = new Vector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); pointC = new Vector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); ws.XYInsetBuffer[0] = b; vertexCount = 1; break; } Vector2 point5; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point5 = new Vector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset35 = Vector2.Dot(edgeBCt, pointC); float t5 = (offset35 - Vector2.Dot(edgeBCt, pointA)) / tdiv; point5 = new Vector2(pointA.X + t5 * edgeAB.X, pointA.Y + t5 * edgeAB.Y); } ws.XYOutsetBuffer[0] = point5; ws.UVOutsetBuffer[0] = new Vector2(1, js.LengthB); for (int i = 0; i < vertexCount; i++) { ws.UVInsetBuffer[i] = new Vector2(0, js.LengthB); } return(new InsetOutsetCount(vertexCount, 1, false)); } else { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new Vector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); pointC = new Vector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); ws.XYOutsetBuffer[0] = new Vector2(b.X - w2 * edgeABt.X, b.Y - w2 * edgeABt.Y); ws.XYOutsetBuffer[1] = new Vector2(b.X - w2 * edgeBCt.X, b.Y - w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: pointA = new Vector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); pointC = new Vector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); ws.XYOutsetBuffer[0] = b; vertexCount = 1; break; case PenAlignment.Outset: ws.XYOutsetBuffer[0] = new Vector2(b.X - Width * edgeABt.X, b.Y - Width * edgeABt.Y); ws.XYOutsetBuffer[1] = new Vector2(b.X - Width * edgeBCt.X, b.Y - Width * edgeBCt.Y); vertexCount = 2; break; } Vector2 point0; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point0 = new Vector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset01 = Vector2.Dot(edgeBCt, pointC); float t0 = (offset01 - Vector2.Dot(edgeBCt, pointA)) / tdiv; point0 = new Vector2(pointA.X + t0 * edgeAB.X, pointA.Y + t0 * edgeAB.Y); } ws.XYInsetBuffer[0] = point0; ws.UVInsetBuffer[0] = new Vector2(0, js.LengthB); for (int i = 0; i < vertexCount; i++) { ws.UVOutsetBuffer[i] = new Vector2(1, js.LengthB); } return(new InsetOutsetCount(1, vertexCount, true)); } }
//internal InsetOutsetCount ComputeMiter (Vector2 a, Vector2 b, Vector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeMiter(ref JoinSample js, PenWorkspace ws) { Vector2 a = js.PointA; Vector2 b = js.PointB; Vector2 c = js.PointC; Vector2 edgeAB = new Vector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); Vector2 edgeABt = new Vector2(-edgeAB.Y, edgeAB.X); Vector2 edgeBC = new Vector2(c.X - b.X, c.Y - b.Y); edgeBC.Normalize(); Vector2 edgeBCt = new Vector2(-edgeBC.Y, edgeBC.X); Vector2 point1, point2, point3, point4; switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; point2 = new Vector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); point4 = new Vector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); point1 = new Vector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); point3 = new Vector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); break; case PenAlignment.Inset: point2 = new Vector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); point4 = a; point1 = new Vector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); point3 = c; break; case PenAlignment.Outset: point2 = a; point4 = new Vector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); point1 = c; point3 = new Vector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); break; default: point2 = Vector2.Zero; point4 = Vector2.Zero; point1 = Vector2.Zero; point3 = Vector2.Zero; break; } Vector2 point0, point5; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < .0005f) { point0 = new Vector2((point2.X + point1.X) / 2, (point2.Y + point1.Y) / 2); point5 = new Vector2((point4.X + point3.X) / 2, (point4.Y + point3.Y) / 2); } else { float offset01 = Vector2.Dot(edgeBCt, point1); float t0 = (offset01 - Vector2.Dot(edgeBCt, point2)) / tdiv; float offset35 = Vector2.Dot(edgeBCt, point3); float t5 = (offset35 - Vector2.Dot(edgeBCt, point4)) / tdiv; point0 = new Vector2(point2.X + t0 * edgeAB.X, point2.Y + t0 * edgeAB.Y); point5 = new Vector2(point4.X + t5 * edgeAB.X, point4.Y + t5 * edgeAB.Y); } double miterLimit = MiterLimit * Width; if ((point0 - point5).LengthSquared() > miterLimit * miterLimit) { return(ComputeBevel(ref js, ws)); } ws.XYInsetBuffer[0] = point0; ws.XYOutsetBuffer[0] = point5; ws.UVInsetBuffer[0] = new Vector2(0, js.LengthB); ws.UVOutsetBuffer[0] = new Vector2(1, js.LengthB); return(new InsetOutsetCount(1, 1)); }
private void CompileClosedPath(IList <CCVector2> points, IList <float> accumLengths, int offset, int count, Pen outlinePen) { if (_strokeType != StrokeType.Outline) { InitializeBuffers(count + 1); } if (IsClose(points[offset], points[offset + count - 1])) { count--; } IList <float> lengths = accumLengths ?? _zeroList; Buffer <CCVector2> insetBuffer = null; Buffer <CCVector2> outsetBuffer = null; if (outlinePen != null && _strokeType != StrokeType.Fill) { insetBuffer = Pools <Buffer <CCVector2> > .Obtain(); outsetBuffer = Pools <Buffer <CCVector2> > .Obtain(); int vCount = _positionData != null ? _positionData.Length : _pen.MaximumVertexCount(count); insetBuffer.EnsureCapacity(vCount); outsetBuffer.EnsureCapacity(vCount); } PenWorkspace ws = Pools <PenWorkspace> .Obtain(); ws.ResetWorkspace(_pen); JoinSample joinSample = new JoinSample(points[offset + count - 1], points[offset + 0], points[offset + 1], 0, lengths[offset + 0], lengths[offset + 1]); int vBaseIndex = _vertexBufferIndex; int vBaseCount = AddJoint(0, ref joinSample, ws, insetBuffer, outsetBuffer); int vPrevCount = 0; int vNextCount = vBaseCount; for (int i = 0; i < count - 2; i++) { joinSample.Advance(points[offset + i + 2], lengths[offset + i + 2]); vPrevCount = vNextCount; vNextCount = AddJoint(i + 1, ref joinSample, ws, insetBuffer, outsetBuffer); if (_strokeType != StrokeType.Outline) { AddSegment(_vertexBufferIndex - vNextCount - vPrevCount, vPrevCount, _jointCCW[i], _vertexBufferIndex - vNextCount, vNextCount, _jointCCW[i + 1]); } } joinSample.Advance(points[offset + 0], lengths[offset + 0]); vPrevCount = vNextCount; vNextCount = AddJoint(count - 1, ref joinSample, ws, insetBuffer, outsetBuffer); if (_strokeType != StrokeType.Outline) { AddSegment(_vertexBufferIndex - vNextCount - vPrevCount, vPrevCount, _jointCCW[count - 2], _vertexBufferIndex - vNextCount, vNextCount, _jointCCW[count - 1]); AddSegment(_vertexBufferIndex - vNextCount, vNextCount, _jointCCW[count - 1], vBaseIndex, vBaseCount, _jointCCW[0]); } Pools <PenWorkspace> .Release(ws); if (outlinePen != null && _strokeType != StrokeType.Fill) { Array.Reverse(insetBuffer.Data, 0, insetBuffer.Index); _outlinePaths = new GraphicsPath[] { new GraphicsPath(outlinePen, insetBuffer.Data, PathType.Closed, 0, insetBuffer.Index), new GraphicsPath(outlinePen, outsetBuffer.Data, PathType.Closed, 0, outsetBuffer.Index), }; Pools <Buffer <CCVector2> > .Release(insetBuffer); Pools <Buffer <CCVector2> > .Release(outsetBuffer); } }
private void CompileOpenPath(IList <CCVector2> points, IList <float> accumLengths, int offset, int count, Pen outlinePen) { if (_strokeType != StrokeType.Outline) { InitializeBuffers(count); } IList <float> lengths = accumLengths ?? _zeroList; Buffer <CCVector2> insetBuffer = null; Buffer <CCVector2> outsetBuffer = null; if (outlinePen != null && _strokeType != StrokeType.Fill) { insetBuffer = Pools <Buffer <CCVector2> > .Obtain(); outsetBuffer = Pools <Buffer <CCVector2> > .Obtain(); int vCount = _positionData != null ? _positionData.Length : _pen.MaximumVertexCount(count); insetBuffer.EnsureCapacity(vCount); outsetBuffer.EnsureCapacity(vCount); } PenWorkspace ws = Pools <PenWorkspace> .Obtain(); ws.ResetWorkspace(_pen); ws.PathLength = lengths[offset + count - 1]; int vPrevCount = 0; int vNextCount = AddStartPoint(0, points[offset + 0], points[offset + 1], ws, insetBuffer); if (insetBuffer != null) { Array.Reverse(insetBuffer.Data, 0, insetBuffer.Index); } JoinSample joinSample = new JoinSample(CCVector2.Zero, points[offset + 0], points[offset + 1], 0, lengths[offset + 0], lengths[offset + 1]); for (int i = 0; i < count - 2; i++) { joinSample.Advance(points[offset + i + 2], lengths[offset + i + 2]); vPrevCount = vNextCount; vNextCount = AddJoint(i + 1, ref joinSample, ws, insetBuffer, outsetBuffer); if (_strokeType != StrokeType.Outline) { AddSegment(_vertexBufferIndex - vNextCount - vPrevCount, vPrevCount, _jointCCW[i], _vertexBufferIndex - vNextCount, vNextCount, _jointCCW[i + 1]); } } /*for (int i = 0; i < count - 2; i++) { * int i0 = offset + i; * int i1 = i0 + 1; * int i2 = i0 + 2; * * vPrevCount = vNextCount; * vNextCount = AddJoint(i + 1, points[i0], points[i1], points[i2], lengths[i0], lengths[i1], lengths[i2], ws, insetBuffer, outsetBuffer); * if (_strokeType != StrokeType.Outline) * AddSegment(_vertexBufferIndex - vNextCount - vPrevCount, vPrevCount, _jointCCW[i], _vertexBufferIndex - vNextCount, vNextCount, _jointCCW[i + 1]); * }*/ vPrevCount = vNextCount; vNextCount = AddEndPoint(count - 1, points[offset + count - 2], points[offset + count - 1], ws, insetBuffer); if (_strokeType != StrokeType.Outline) { AddSegment(_vertexBufferIndex - vNextCount - vPrevCount, vPrevCount, _jointCCW[count - 2], _vertexBufferIndex - vNextCount, vNextCount, _jointCCW[count - 1]); } if (insetBuffer != null) { Array.Reverse(insetBuffer.Data, 0, insetBuffer.Index); } Pools <PenWorkspace> .Release(ws); if (outlinePen != null && _strokeType != StrokeType.Fill) { Buffer <CCVector2> mergedBuffer = Pools <Buffer <CCVector2> > .Obtain(); mergedBuffer.EnsureCapacity(insetBuffer.Index + outsetBuffer.Index); Array.Copy(insetBuffer.Data, 0, mergedBuffer.Data, 0, insetBuffer.Index); Array.Copy(outsetBuffer.Data, 0, mergedBuffer.Data, insetBuffer.Index, outsetBuffer.Index); _outlinePaths = new GraphicsPath[] { new GraphicsPath(outlinePen, mergedBuffer.Data, PathType.Closed, 0, insetBuffer.Index + outsetBuffer.Index), }; Pools <Buffer <CCVector2> > .Release(mergedBuffer); Pools <Buffer <CCVector2> > .Release(insetBuffer); Pools <Buffer <CCVector2> > .Release(outsetBuffer); } }