private void CompileOpenPath(IList <Vector2> points, IList <float> accumLengths, int offset, int count, Pen outlinePen) { if (_strokeType != StrokeType.Outline) { InitializeBuffers(count); } IList <float> lengths = accumLengths ?? _zeroList; Buffer <Vector2> insetBuffer = null; Buffer <Vector2> outsetBuffer = null; if (outlinePen != null && _strokeType != StrokeType.Fill) { insetBuffer = Pools <Buffer <Vector2> > .Obtain(); outsetBuffer = Pools <Buffer <Vector2> > .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(Vector2.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 <Vector2> mergedBuffer = Pools <Buffer <Vector2> > .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 <Vector2> > .Release(mergedBuffer); Pools <Buffer <Vector2> > .Release(insetBuffer); Pools <Buffer <Vector2> > .Release(outsetBuffer); } }
private void CompileClosedPath(IList <Vector2> 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 <Vector2> insetBuffer = null; Buffer <Vector2> outsetBuffer = null; if (outlinePen != null && _strokeType != StrokeType.Fill) { insetBuffer = Pools <Buffer <Vector2> > .Obtain(); outsetBuffer = Pools <Buffer <Vector2> > .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 <Vector2> > .Release(insetBuffer); Pools <Buffer <Vector2> > .Release(outsetBuffer); } }
internal void ComputeStartPoint(CCVector2 a, CCVector2 b, PenWorkspace ws) { StartCapInfo.Calculate(a, b - a, ws, Alignment, true); }
//internal InsetOutsetCount ComputeBevel (CCVector2 a, CCVector2 b, CCVector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeBevel(ref JoinSample js, PenWorkspace ws) { CCVector2 a = js.PointA; CCVector2 b = js.PointB; CCVector2 c = js.PointC; CCVector2 edgeBA = new CCVector2(a.X - b.X, a.Y - b.Y); CCVector2 edgeBC = new CCVector2(c.X - b.X, c.Y - b.Y); double dot = CCVector2.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)); } } CCVector2 edgeAB = new CCVector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); CCVector2 edgeABt = new CCVector2(-edgeAB.Y, edgeAB.X); edgeBC.Normalize(); CCVector2 edgeBCt = new CCVector2(-edgeBC.Y, edgeBC.X); CCVector2 pointA = a; CCVector2 pointC = c; short vertexCount = 0; if (Cross2D(edgeAB, edgeBC) > 0) { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new CCVector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); pointC = new CCVector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); ws.XYInsetBuffer[0] = new CCVector2(b.X + w2 * edgeABt.X, b.Y + w2 * edgeABt.Y); ws.XYInsetBuffer[1] = new CCVector2(b.X + w2 * edgeBCt.X, b.Y + w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: ws.XYInsetBuffer[0] = new CCVector2(b.X + Width * edgeABt.X, b.Y + Width * edgeABt.Y); ws.XYInsetBuffer[1] = new CCVector2(b.X + Width * edgeBCt.X, b.Y + Width * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Outset: pointA = new CCVector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); pointC = new CCVector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); ws.XYInsetBuffer[0] = b; vertexCount = 1; break; } CCVector2 point5; float tdiv = CCVector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point5 = new CCVector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset35 = CCVector2.Dot(edgeBCt, pointC); float t5 = (offset35 - CCVector2.Dot(edgeBCt, pointA)) / tdiv; point5 = new CCVector2(pointA.X + t5 * edgeAB.X, pointA.Y + t5 * edgeAB.Y); } ws.XYOutsetBuffer[0] = point5; ws.UVOutsetBuffer[0] = new CCVector2(1, js.LengthB); for (int i = 0; i < vertexCount; i++) { ws.UVInsetBuffer[i] = new CCVector2(0, js.LengthB); } return(new InsetOutsetCount(vertexCount, 1, false)); } else { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new CCVector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); pointC = new CCVector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); ws.XYOutsetBuffer[0] = new CCVector2(b.X - w2 * edgeABt.X, b.Y - w2 * edgeABt.Y); ws.XYOutsetBuffer[1] = new CCVector2(b.X - w2 * edgeBCt.X, b.Y - w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: pointA = new CCVector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); pointC = new CCVector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); ws.XYOutsetBuffer[0] = b; vertexCount = 1; break; case PenAlignment.Outset: ws.XYOutsetBuffer[0] = new CCVector2(b.X - Width * edgeABt.X, b.Y - Width * edgeABt.Y); ws.XYOutsetBuffer[1] = new CCVector2(b.X - Width * edgeBCt.X, b.Y - Width * edgeBCt.Y); vertexCount = 2; break; } CCVector2 point0; float tdiv = CCVector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point0 = new CCVector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset01 = CCVector2.Dot(edgeBCt, pointC); float t0 = (offset01 - CCVector2.Dot(edgeBCt, pointA)) / tdiv; point0 = new CCVector2(pointA.X + t0 * edgeAB.X, pointA.Y + t0 * edgeAB.Y); } ws.XYInsetBuffer[0] = point0; ws.UVInsetBuffer[0] = new CCVector2(0, js.LengthB); for (int i = 0; i < vertexCount; i++) { ws.UVOutsetBuffer[i] = new CCVector2(1, js.LengthB); } return(new InsetOutsetCount(1, vertexCount, true)); } }
//internal InsetOutsetCount ComputeMiter (CCVector2 a, CCVector2 b, CCVector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeMiter(ref JoinSample js, PenWorkspace ws) { CCVector2 a = js.PointA; CCVector2 b = js.PointB; CCVector2 c = js.PointC; CCVector2 edgeAB = new CCVector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); CCVector2 edgeABt = new CCVector2(-edgeAB.Y, edgeAB.X); CCVector2 edgeBC = new CCVector2(c.X - b.X, c.Y - b.Y); edgeBC.Normalize(); CCVector2 edgeBCt = new CCVector2(-edgeBC.Y, edgeBC.X); CCVector2 point1, point2, point3, point4; switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; point2 = new CCVector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); point4 = new CCVector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); point1 = new CCVector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); point3 = new CCVector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); break; case PenAlignment.Inset: point2 = new CCVector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); point4 = a; point1 = new CCVector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); point3 = c; break; case PenAlignment.Outset: point2 = a; point4 = new CCVector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); point1 = c; point3 = new CCVector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); break; default: point2 = CCVector2.Zero; point4 = CCVector2.Zero; point1 = CCVector2.Zero; point3 = CCVector2.Zero; break; } CCVector2 point0, point5; float tdiv = CCVector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < .0005f) { point0 = new CCVector2((point2.X + point1.X) / 2, (point2.Y + point1.Y) / 2); point5 = new CCVector2((point4.X + point3.X) / 2, (point4.Y + point3.Y) / 2); } else { float offset01 = CCVector2.Dot(edgeBCt, point1); float t0 = (offset01 - CCVector2.Dot(edgeBCt, point2)) / tdiv; float offset35 = CCVector2.Dot(edgeBCt, point3); float t5 = (offset35 - CCVector2.Dot(edgeBCt, point4)) / tdiv; point0 = new CCVector2(point2.X + t0 * edgeAB.X, point2.Y + t0 * edgeAB.Y); point5 = new CCVector2(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 CCVector2(0, js.LengthB); ws.UVOutsetBuffer[0] = new CCVector2(1, js.LengthB); return(new InsetOutsetCount(1, 1)); }
private int AddJoint(int pointIndex, InsetOutsetCount vioCount, PenWorkspace ws) { int vIndex = _vertexBufferIndex; _vertexBufferIndex += vioCount.InsetCount + vioCount.OutsetCount; if (!vioCount.CCW) { _jointCCW[pointIndex] = false; _positionData[vIndex + 0] = ws.XYOutsetBuffer[0]; for (int i = 0; i < vioCount.InsetCount; i++) { _positionData[vIndex + 1 + i] = ws.XYInsetBuffer[i]; } for (int i = 0; i < vioCount.InsetCount - 1; i++) { _indexData[_indexBufferIndex++] = (short)(vIndex); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 2); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 1); } } else { _jointCCW[pointIndex] = true; _positionData[vIndex + 0] = ws.XYInsetBuffer[0]; for (int i = 0; i < vioCount.OutsetCount; i++) { _positionData[vIndex + 1 + i] = ws.XYOutsetBuffer[i]; } for (int i = 0; i < vioCount.OutsetCount - 1; i++) { _indexData[_indexBufferIndex++] = (short)(vIndex); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 1); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 2); } } if (_colorData != null) { if (!vioCount.CCW) { _colorData[vIndex] = _pen.ColorAt(ws.UVOutsetBuffer[0], ws.PathLengthScale); for (int i = 0; i < vioCount.InsetCount; i++) { _colorData[vIndex + 1 + i] = _pen.ColorAt(ws.UVInsetBuffer[i], ws.PathLengthScale); } } else { _colorData[vIndex] = _pen.ColorAt(ws.UVInsetBuffer[0], ws.PathLengthScale); for (int i = 0; i < vioCount.OutsetCount; i++) { _colorData[vIndex + 1 + i] = _pen.ColorAt(ws.UVOutsetBuffer[i], ws.PathLengthScale); } } } if (_textureData != null) { int texWidth = _pen.Brush.Texture.Width; int texHeight = _pen.Brush.Texture.Height; for (int i = vIndex; i < _vertexBufferIndex; i++) { Vector2 pos = _positionData[i]; _textureData[i] = new Vector2(pos.X / texWidth, pos.Y / texHeight); } } return(_vertexBufferIndex - vIndex); }
public void Calculate(Vector2 p, Vector2 edgeAB, PenWorkspace ws, PenAlignment alignment, bool start) { edgeAB.Normalize(); // [ eAB.X -eAB.Y ] // [ eAB.Y eAB.X ] float tC = edgeAB.X * _width; float tS = edgeAB.Y * _width; float tX = p.X; float tY = p.Y; switch (alignment) { case PenAlignment.Center: break; case PenAlignment.Inset: if (start) { tX = p.X + (-.5f * tS); tY = p.Y - (-.5f * tC); } else { tX = p.X - (-.5f * tS); tY = p.Y + (-.5f * tC); } break; case PenAlignment.Outset: if (start) { tX = p.X + (.5f * tS); tY = p.Y - (.5f * tC); } else { tX = p.X - (.5f * tS); tY = p.Y + (.5f * tC); } break; } for (int i = 0; i < _xyBuffer.Length; i++) { ws.XYBuffer[i] = new Vector2(_xyBuffer[i].X * tC - _xyBuffer[i].Y * tS + tX, _xyBuffer[i].X * tS + _xyBuffer[i].Y * tC + tY); } for (int i = 0; i < _uvBuffer.Length; i++) { ws.UVBuffer[i] = _uvBuffer[i]; } for (int i = 0; i < _indexBuffer.Length; i++) { ws.IndexBuffer[i] = _indexBuffer[i]; } for (int i = 0; i < _outlineBuffer.Length; i++) { ws.OutlineIndexBuffer[i] = _outlineBuffer[i]; } ws.XYBuffer.Index = _xyBuffer.Length; ws.UVBuffer.Index = _uvBuffer.Length; ws.IndexBuffer.Index = _indexBuffer.Length; ws.OutlineIndexBuffer.Index = _outlineBuffer.Length; }