private static PathGeometryData MakeEmptyPathGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.MatrixToMilMatrix3x2D(Matrix.Identity); unsafe { int size = sizeof(MIL_PATHGEOMETRY); data.SerializedData = new byte[size]; fixed(byte *pbData = data.SerializedData) { MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY *)pbData; // implicitly set pPathGeometry->Flags = 0; pPathGeometry->FigureCount = 0; pPathGeometry->Size = (UInt32)size; } } return(data); }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return(Geometry.GetEmptyPathGeometryData()); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); Point[] points = GetPointList(); ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); // i == 0, 3, 6, 9 for (int i = 0; i < 12; i += 3) { ctx.BezierTo(points[i + 1], points[i + 2], points[i + 3], true /* is stroked */, true /* is smooth join */); } ctx.Close(); data.SerializedData = ctx.GetData(); return(data); }
/// <summary> /// Gets the bounds of this PathGeometry as an axis-aligned bounding box with pen and/or transform /// </summary> internal static Rect GetPathBounds( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { if (pathData.IsEmpty()) { return(Rect.Empty); } else { MilRectD bounds = PathGeometry.GetPathBoundsAsRB( pathData, pen, worldMatrix, tolerance, type, skipHollows); return(bounds.AsRect); } }
/// <summary> /// GetPathGeometryData - returns a struct which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); if (IsObviouslyEmpty()) { return(Geometry.GetEmptyPathGeometryData()); } ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); PathFigureCollection figures = Figures; int figureCount = figures == null ? 0 : figures.Count; for (int i = 0; i < figureCount; i++) { figures.Internal_GetItem(i).SerializeData(ctx); } ctx.Close(); data.SerializedData = ctx.GetData(); return(data); }
public void GetPointAtFractionLength( double progress, out Point point, out Point tangent) { if (IsEmpty()) { point = new Point(); tangent = new Point(); return; } unsafe { PathGeometryData pathData = GetPathGeometryData(); fixed(byte *pbPathData = pathData.SerializedData) { Debug.Assert(pbPathData != (byte *)0); HRESULT.Check(MilCoreApi.MilUtility_GetPointAtLengthFraction( &pathData.Matrix, pathData.FillRule, pbPathData, pathData.Size, progress, out point, out tangent)); } } }
private static PathGeometryData MakeEmptyGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Offset = Vector.Zero; return(data); }
public TechMapPath(Location p_startPoint, Location p_endPoint, byte p_groupIndex = 1) { this.startPoint = p_startPoint; this.endPoint = p_endPoint; this.groupIndex = p_groupIndex; QuadraticBezierSegmentData mapQuadraticBezierSegment = new QuadraticBezierSegmentData() { Point1 = this.middlePoint, Point2 = p_endPoint }; PathFigureData mapPathFigure = new PathFigureData() { StartPoint = p_startPoint, IsClosed = false }; mapPathFigure.Segments.Add(mapQuadraticBezierSegment); PathGeometryData mapPathGeometry = new PathGeometryData(); mapPathGeometry.Figures.Add(mapPathFigure); Brush stroke = Brushes.Transparent; this.Data = mapPathGeometry; switch (groupIndex) { case 1: { stroke = new SolidColorBrush(Colors.Red); break; } case 2: { stroke = new SolidColorBrush(Colors.Orange); break; } case 3: { stroke = new SolidColorBrush(Colors.Yellow); break; } case 4: { stroke = new SolidColorBrush(Colors.Green); break; } case 5: { stroke = new SolidColorBrush(Colors.LightBlue); break; } case 6: { stroke = new SolidColorBrush(Colors.Blue); break; } case 7: { stroke = new SolidColorBrush(Colors.Violet); break; } case 8: { stroke = new SolidColorBrush(Colors.Black); break; } } this.HighlightFill = new MapShapeFill() { Stroke = new SolidColorBrush(Colors.Green), StrokeThickness = 2 }; this.ShapeFill = new MapShapeFill() { Stroke = stroke, StrokeThickness = 10 }; this.SelectedFill = new MapShapeFill() { Stroke = Brushes.Black, StrokeThickness = 10 }; }
public virtual PathGeometry GetOutlinedPathGeometry(double tolerance, ToleranceType type) { ReadPreamble(); if (IsObviouslyEmpty()) { return(new PathGeometry()); } PathGeometryData pathData = GetPathGeometryData(); if (pathData.IsEmpty()) { return(new PathGeometry()); } PathGeometry resultGeometry = null; unsafe { fixed(byte *pbPathData = pathData.SerializedData) { Invariant.Assert(pbPathData != (byte *)0); FillRule fillRule = FillRule.Nonzero; PathGeometry.FigureList list = new PathGeometry.FigureList(); int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryOutline( &pathData.Matrix, pathData.FillRule, pbPathData, pathData.Size, tolerance, type == ToleranceType.Relative, new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), out fillRule); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we return an empty geometry. resultGeometry = new PathGeometry(); } else { HRESULT.Check(hr); resultGeometry = new PathGeometry(list.Figures, fillRule, null); } } } return(resultGeometry); }
private void ManualUpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) { // If we're told we can skip the channel check, then we must be on channel Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel)); if (skipOnChannelCheck || _duceResource.IsOnChannel(channel)) { checked { Transform vTransform = Transform; // Obtain handles for properties that implement DUCE.IResource DUCE.ResourceHandle hTransform; if (vTransform == null || Object.ReferenceEquals(vTransform, Transform.Identity) ) { hTransform = DUCE.ResourceHandle.Null; } else { hTransform = ((DUCE.IResource)vTransform).GetHandle(channel); } DUCE.MILCMD_PATHGEOMETRY data; data.Type = MILCMD.MilCmdPathGeometry; data.Handle = _duceResource.GetHandle(channel); data.hTransform = hTransform; data.FillRule = FillRule; PathGeometryData pathData = GetPathGeometryData(); data.FiguresSize = pathData.Size; unsafe { channel.BeginCommand( (byte *)&data, sizeof(DUCE.MILCMD_PATHGEOMETRY), (int)data.FiguresSize ); fixed(byte *pPathData = pathData.SerializedData) { channel.AppendCommandData(pPathData, (int)data.FiguresSize); } } channel.EndCommand(); } } }
internal static IntersectionDetail HitTestWithPathGeometry( Geometry geometry1, Geometry geometry2, double tolerance, ToleranceType type) { IntersectionDetail detail = IntersectionDetail.NotCalculated; unsafe { PathGeometryData data1 = geometry1.GetPathGeometryData(); PathGeometryData data2 = geometry2.GetPathGeometryData(); fixed(byte *pbPathData1 = data1.SerializedData) { Debug.Assert(pbPathData1 != (byte *)0); fixed(byte *pbPathData2 = data2.SerializedData) { Debug.Assert(pbPathData2 != (byte *)0); int hr = MilCoreApi.MilUtility_PathGeometryHitTestPathGeometry( &data1.Matrix, data1.FillRule, pbPathData1, data1.Size, &data2.Matrix, data2.FillRule, pbPathData2, data2.Size, tolerance, type == ToleranceType.Relative, &detail); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry is never hittable. detail = IntersectionDetail.Empty; } else { HRESULT.Check(hr); } } } } Debug.Assert(detail != IntersectionDetail.NotCalculated); return(detail); }
public virtual double GetArea(double tolerance, ToleranceType type) { ReadPreamble(); if (IsObviouslyEmpty()) { return(0); } PathGeometryData pathData = GetPathGeometryData(); if (pathData.IsEmpty()) { return(0); } double area; unsafe { // Call the core method on the path data fixed(byte *pbPathData = pathData.SerializedData) { Debug.Assert(pbPathData != (byte *)0); int hr = MilCoreApi.MilUtility_GeometryGetArea( pathData.FillRule, pbPathData, pathData.Size, &pathData.Matrix, tolerance, type == ToleranceType.Relative, &area); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry has 0 area. area = 0.0; } else { HRESULT.Check(hr); } } } return(area); }
/// <summary> /// GetPathGeometryData - returns a struct which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsEmpty()) { return(Geometry.GetEmptyPathGeometryData()); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); data.SerializedData = _data; return(data); }
/// <summary> /// Creates the path geometry. /// </summary> /// <param name="geometryData">The geometry data.</param> /// <returns></returns> public static PathGeometry CreatePathGeometry(PathGeometryData geometryData) { var figures = new List <PathFigure>(); foreach (var figureData in geometryData.Figures) { var segments = new List <PathSegment>(); foreach (var segmentData in figureData.Segments) { switch (segmentData.SegmentType) { case SegmentType.ArcSegment: throw new NotImplementedException("{FD35628A-FB82-491E-B042-ED2F893D342B}"); case SegmentType.BezierSegment: throw new NotImplementedException("{1B510116-A6D7-448B-99FF-D9F67210E8D3}"); case SegmentType.LineSegment: { segments.Add(new LineSegment(segmentData.Nodes[0].Point, segmentData.Nodes[0].IsStroked)); break; } case SegmentType.PolyBezierSegment: throw new NotImplementedException("{1EF8B9A9-BC3E-439C-A14E-3C56812D2002}"); case SegmentType.PolyLineSegment: { var points = new List <Point>(); foreach (var nodeData in segmentData.Nodes) { points.Add(nodeData.Point); } segments.Add(new PolyLineSegment(points, segmentData.Nodes[0].IsStroked)); break; } case SegmentType.PolyQuadraticBezierSegment: throw new NotImplementedException("{CD280F38-FC56-4838-A5D2-2BE04B5801C8}"); case SegmentType.QuadraticBezierSegment: throw new NotImplementedException("{7DE58DAC-9A43-4657-90A5-7B38F5748C4C}"); } } figures.Add(new PathFigure(figureData.StartPoint, segments, figureData.IsClosed)); } return(new PathGeometry(figures)); }
/// <summary> /// Returns the axis-aligned bounding rectangle when stroked with a pen, after applying /// the supplied transform (if non-null). /// </summary> internal virtual Rect GetBoundsInternal(Pen pen, Matrix matrix, double tolerance, ToleranceType type) { if (IsObviouslyEmpty()) { return(Rect.Empty); } PathGeometryData pathData = GetPathGeometryData(); return(PathGeometry.GetPathBounds( pathData, pen, matrix, tolerance, type, true)); /* skip hollows */ }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return(Geometry.GetEmptyPathGeometryData()); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); double radiusX = RadiusX; double radiusY = RadiusY; Rect rect = Rect; ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); if (IsRounded(radiusX, radiusY)) { Point[] points = GetPointList(rect, radiusX, radiusY); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); ctx.BezierTo(points[1], points[2], points[3], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[4], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[5], points[6], points[7], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[8], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[9], points[10], points[11], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[12], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[13], points[14], points[15], true /* is stroked */, false /* is smooth join */); } else { ctx.BeginFigure(rect.TopLeft, true /* is filled */, true /* is closed */); ctx.LineTo(Rect.TopRight, true /* is stroked */, false /* is smooth join */); ctx.LineTo(Rect.BottomRight, true /* is stroked */, false /* is smooth join */); ctx.LineTo(Rect.BottomLeft, true /* is stroked */, false /* is smooth join */); } ctx.Close(); data.SerializedData = ctx.GetData(); return(data); }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return(Geometry.GetEmptyPathGeometryData()); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); ctx.BeginFigure(StartPoint, true /* is filled */, false /* is closed */); ctx.LineTo(EndPoint, true /* is stroked */, false /* is smooth join */); ctx.Close(); data.SerializedData = ctx.GetData(); return(data); }
/// <summary> /// GetPathGeometryData - returns a struct which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsEmpty()) { return Geometry.GetEmptyPathGeometryData(); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); data.SerializedData = _data; return data; }
/// <summary> /// GetPathGeometryData - returns a struct which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); if (IsObviouslyEmpty()) { return Geometry.GetEmptyPathGeometryData(); } ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); PathFigureCollection figures = Figures; int figureCount = figures == null ? 0 : figures.Count; for (int i = 0; i < figureCount; i++) { figures.Internal_GetItem(i).SerializeData(ctx); } ctx.Close(); data.SerializedData = ctx.GetData(); return data; }
internal static MilRectD GetPathBoundsAsRB( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { // This method can't handle the empty geometry case, as it's impossible for us to // return Rect.Empty. Callers should do their own check. Debug.Assert(!pathData.IsEmpty()); unsafe { MIL_PEN_DATA penData; double[] dashArray = null; // If we have a pen, populate the CMD struct if (pen != null) { pen.GetBasicPenData(&penData, out dashArray); } MilMatrix3x2D worldMatrix3X2 = CompositionResourceManager.MatrixToMilMatrix3x2D(ref worldMatrix); fixed(byte *pbPathData = pathData.SerializedData) { MilRectD bounds; Debug.Assert(pbPathData != (byte *)0); fixed(double *pDashArray = dashArray) { int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryBounds( (pen == null) ? null : &penData, pDashArray, &worldMatrix3X2, pathData.FillRule, pbPathData, pathData.Size, &pathData.Matrix, tolerance, type == ToleranceType.Relative, skipHollows, &bounds ); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry has empty bounds // (NaN will get transformed into Rect.Empty higher up). bounds = MilRectD.NaN; } else { HRESULT.Check(hr); } } return(bounds); } } }
internal static void ParsePathGeometryData(PathGeometryData pathData, CapacityStreamGeometryContext ctx) { if (pathData.IsEmpty()) { return; } unsafe { int currentOffset = 0; fixed (byte* pbData = pathData.SerializedData) { // This assert is a logical correctness test Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_PATHGEOMETRY)); // ... while this assert tests "physical" correctness (i.e. are we running out of buffer). Invariant.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHGEOMETRY)); MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY*)pbData; // Move the current offset to after the Path's data currentOffset += sizeof(MIL_PATHGEOMETRY); // Are there any Figures to add? if (pPathGeometry->FigureCount > 0) { // Allocate the correct number of Figures up front ctx.SetFigureCount((int)pPathGeometry->FigureCount); // ... and iterate on the Figures. for (int i = 0; i < pPathGeometry->FigureCount; i++) { // We only expect well-formed data, but we should assert that we're not reading // too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHFIGURE)); MIL_PATHFIGURE *pPathFigure = (MIL_PATHFIGURE*)(pbData + currentOffset); // Move the current offset to the after of the Figure's data currentOffset += sizeof(MIL_PATHFIGURE); ctx.BeginFigure(pPathFigure->StartPoint, ((pPathFigure->Flags & MilPathFigureFlags.IsFillable) != 0), ((pPathFigure->Flags & MilPathFigureFlags.IsClosed) != 0)); if (pPathFigure->Count > 0) { // Allocate the correct number of Segments up front ctx.SetSegmentCount((int)pPathFigure->Count); // ... and iterate on the Segments. for (int j = 0; j < pPathFigure->Count; j++) { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT)); MIL_SEGMENT *pSegment = (MIL_SEGMENT*)(pbData + currentOffset); switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentLine: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_LINE)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_LINE)); MIL_SEGMENT_LINE *pSegmentLine = (MIL_SEGMENT_LINE*)(pbData + currentOffset); ctx.LineTo(pSegmentLine->Point, ((pSegmentLine->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentLine->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_LINE); } break; case MIL_SEGMENT_TYPE.MilSegmentBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); MIL_SEGMENT_BEZIER *pSegmentBezier = (MIL_SEGMENT_BEZIER*)(pbData + currentOffset); ctx.BezierTo(pSegmentBezier->Point1, pSegmentBezier->Point2, pSegmentBezier->Point3, ((pSegmentBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_BEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); MIL_SEGMENT_QUADRATICBEZIER *pSegmentQuadraticBezier = (MIL_SEGMENT_QUADRATICBEZIER*)(pbData + currentOffset); ctx.QuadraticBezierTo(pSegmentQuadraticBezier->Point1, pSegmentQuadraticBezier->Point2, ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_QUADRATICBEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentArc: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_ARC)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_ARC)); MIL_SEGMENT_ARC *pSegmentArc = (MIL_SEGMENT_ARC*)(pbData + currentOffset); ctx.ArcTo(pSegmentArc->Point, pSegmentArc->Size, pSegmentArc->XRotation, (pSegmentArc->LargeArc != 0), (pSegmentArc->Sweep == 0) ? SweepDirection.Counterclockwise : SweepDirection.Clockwise, ((pSegmentArc->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentArc->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_ARC); } break; case MIL_SEGMENT_TYPE.MilSegmentPolyLine: case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY)); MIL_SEGMENT_POLY *pSegmentPoly = (MIL_SEGMENT_POLY*)(pbData + currentOffset); Debug.Assert(pSegmentPoly->Count <= Int32.MaxValue); if (pSegmentPoly->Count > 0) { List<Point> points = new List<Point>((int)pSegmentPoly->Count); // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Point* pPoint = (Point*)(pbData + currentOffset + sizeof(MIL_SEGMENT_POLY)); for (uint k = 0; k < pSegmentPoly->Count; k++) { points.Add(*pPoint); pPoint++; } switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentPolyLine: ctx.PolyLineTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: ctx.PolyBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: ctx.PolyQuadraticBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; } } currentOffset += sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point); } break; #if DEBUG case MIL_SEGMENT_TYPE.MilSegmentNone: throw new System.InvalidOperationException(); default: throw new System.InvalidOperationException(); #endif } } } } } } } }
internal static PathGeometry InternalCombine( Geometry geometry1, Geometry geometry2, GeometryCombineMode mode, Transform transform, double tolerance, ToleranceType type) { PathGeometry resultGeometry = null; unsafe { MilMatrix3x2D matrix = CompositionResourceManager.TransformToMilMatrix3x2D(transform); PathGeometryData data1 = geometry1.GetPathGeometryData(); PathGeometryData data2 = geometry2.GetPathGeometryData(); fixed(byte *pPathData1 = data1.SerializedData) { Debug.Assert(pPathData1 != (byte *)0); fixed(byte *pPathData2 = data2.SerializedData) { Debug.Assert(pPathData2 != (byte *)0); FillRule fillRule = FillRule.Nonzero; FigureList list = new FigureList(); int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryCombine( &matrix, &data1.Matrix, data1.FillRule, pPathData1, data1.Size, &data2.Matrix, data2.FillRule, pPathData2, data2.Size, tolerance, type == ToleranceType.Relative, new AddFigureToListDelegate(list.AddFigureToList), mode, out fillRule); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we return an empty geometry. resultGeometry = new PathGeometry(); } else { HRESULT.Check(hr); resultGeometry = new PathGeometry(list.Figures, fillRule, null); } } } } return(resultGeometry); }
/// <summary> /// Gets the bounds of this PathGeometry as an axis-aligned bounding box with pen and/or transform /// </summary> internal static Rect GetPathBounds( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { if (pathData.IsEmpty()) { return Rect.Empty; } else { MilRectD bounds = PathGeometry.GetPathBoundsAsRB( pathData, pen, worldMatrix, tolerance, type, skipHollows); return bounds.AsRect; } }
public virtual PathGeometry GetWidenedPathGeometry(Pen pen, double tolerance, ToleranceType type) { ReadPreamble(); if (pen == null) { throw new System.ArgumentNullException("pen"); } if (IsObviouslyEmpty()) { return(new PathGeometry()); } PathGeometryData pathData = GetPathGeometryData(); if (pathData.IsEmpty()) { return(new PathGeometry()); } PathGeometry resultGeometry = null; unsafe { MIL_PEN_DATA penData; double[] dashArray = null; pen.GetBasicPenData(&penData, out dashArray); fixed(byte *pbPathData = pathData.SerializedData) { Debug.Assert(pbPathData != (byte *)0); FillRule fillRule = FillRule.Nonzero; PathGeometry.FigureList list = new PathGeometry.FigureList(); // The handle to the pDashArray, if we have one. // Since the dash array is optional, we may not need to Free it. GCHandle handle = new GCHandle(); // Pin the pDashArray, if we have one. if (dashArray != null) { handle = GCHandle.Alloc(dashArray, GCHandleType.Pinned); } try { int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryWiden( &penData, (dashArray == null) ? null : (double *)handle.AddrOfPinnedObject(), &pathData.Matrix, pathData.FillRule, pbPathData, pathData.Size, tolerance, type == ToleranceType.Relative, new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), out fillRule); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we return an empty geometry. resultGeometry = new PathGeometry(); } else { HRESULT.Check(hr); resultGeometry = new PathGeometry(list.Figures, fillRule, null); } } finally { if (handle.IsAllocated) { handle.Free(); } } } return(resultGeometry); } }
internal static MilRectD GetPathBoundsAsRB( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { // This method can't handle the empty geometry case, as it's impossible for us to // return Rect.Empty. Callers should do their own check. Debug.Assert(!pathData.IsEmpty()); unsafe { MIL_PEN_DATA penData; double[] dashArray = null; // If we have a pen, populate the CMD struct if (pen != null) { pen.GetBasicPenData(&penData, out dashArray); } MilMatrix3x2D worldMatrix3X2 = CompositionResourceManager.MatrixToMilMatrix3x2D(ref worldMatrix); fixed (byte *pbPathData = pathData.SerializedData) { MilRectD bounds; Debug.Assert(pbPathData != (byte*)0); fixed (double *pDashArray = dashArray) { int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryBounds( (pen == null) ? null : &penData, pDashArray, &worldMatrix3X2, pathData.FillRule, pbPathData, pathData.Size, &pathData.Matrix, tolerance, type == ToleranceType.Relative, skipHollows, &bounds ); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry has empty bounds // (NaN will get transformed into Rect.Empty higher up). bounds = MilRectD.NaN; } else { HRESULT.Check(hr); } } return bounds; } } }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return Geometry.GetEmptyPathGeometryData(); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); ctx.BeginFigure(StartPoint, true /* is filled */, false /* is closed */); ctx.LineTo(EndPoint, true /* is stroked */, false /* is smooth join */); ctx.Close(); data.SerializedData = ctx.GetData(); return data; }
/// <summary> Creates the path geometry data. /// </summary> /// <param name="nodes">The nodes.</param> /// <returns></returns> public static PathGeometryData CreatePathGeometryData(IEnumerable <PathNodeData> nodes) { PathGeometryData geometryData = new PathGeometryData(); PathFigureData figure = null; PathSegmentData segment = null; foreach (var node in nodes) { if (node.SegmentType == SegmentType.StartPoint) { figure = new PathFigureData { StartPoint = node.Point, IsClosed = node.IsClosed }; geometryData.Figures.Add(figure); } else { switch (node.SegmentType) { case SegmentType.ArcSegment: throw new NotImplementedException("{C3DB91D2-6511-4274-B60F-99DF3CADF0A3}"); case SegmentType.BezierSegment: throw new NotImplementedException("{D811AFE1-EB44-4671-9F27-E7609AEF8B5B}"); case SegmentType.LineSegment: { figure.Segments.Add(new PathSegmentData { Nodes = { node }, SegmentType = node.SegmentType }); break; } case SegmentType.PolyBezierSegment: throw new NotImplementedException("{3C01C459-4539-4D87-8206-DF1903491B63}"); case SegmentType.PolyLineSegment: { if (node.SegmentIndex == 0) { segment = new PathSegmentData { Nodes = { node }, SegmentType = node.SegmentType }; figure.Segments.Add(segment); } else { segment.Nodes.Add(node); } break; } case SegmentType.PolyQuadraticBezierSegment: throw new NotImplementedException("{61171A80-E52E-4C93-B7DE-DCF9C65B93F3}"); case SegmentType.QuadraticBezierSegment: throw new NotImplementedException("{64CA6FB1-A5B2-4F5E-BE48-5A2E85F6B6B9}"); default: throw new NotImplementedException("{E1D79545-F131-4196-B964-A74CBB99DBFD}"); } } } return(geometryData); }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return Geometry.GetEmptyPathGeometryData(); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); double radiusX = RadiusX; double radiusY = RadiusY; Rect rect = Rect; ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); if (IsRounded(radiusX, radiusY)) { Point[] points = GetPointList(rect, radiusX, radiusY); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); ctx.BezierTo(points[1], points[2], points[3], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[4], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[5], points[6], points[7], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[8], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[9], points[10], points[11], true /* is stroked */, false /* is smooth join */); ctx.LineTo(points[12], true /* is stroked */, false /* is smooth join */); ctx.BezierTo(points[13], points[14], points[15], true /* is stroked */, false /* is smooth join */); } else { ctx.BeginFigure(rect.TopLeft, true /* is filled */, true /* is closed */); ctx.LineTo(Rect.TopRight, true /* is stroked */, false /* is smooth join */); ctx.LineTo(Rect.BottomRight, true /* is stroked */, false /* is smooth join */); ctx.LineTo(Rect.BottomLeft, true /* is stroked */, false /* is smooth join */); } ctx.Close(); data.SerializedData = ctx.GetData(); return data; }
internal static void ParsePathGeometryData(PathGeometryData pathData, CapacityStreamGeometryContext ctx) { if (pathData.IsEmpty()) { return; } unsafe { int currentOffset = 0; fixed(byte *pbData = pathData.SerializedData) { // This assert is a logical correctness test Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_PATHGEOMETRY)); // ... while this assert tests "physical" correctness (i.e. are we running out of buffer). Invariant.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHGEOMETRY)); MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY *)pbData; // Move the current offset to after the Path's data currentOffset += sizeof(MIL_PATHGEOMETRY); // Are there any Figures to add? if (pPathGeometry->FigureCount > 0) { // Allocate the correct number of Figures up front ctx.SetFigureCount((int)pPathGeometry->FigureCount); // ... and iterate on the Figures. for (int i = 0; i < pPathGeometry->FigureCount; i++) { // We only expect well-formed data, but we should assert that we're not reading // too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHFIGURE)); MIL_PATHFIGURE *pPathFigure = (MIL_PATHFIGURE *)(pbData + currentOffset); // Move the current offset to the after of the Figure's data currentOffset += sizeof(MIL_PATHFIGURE); ctx.BeginFigure(pPathFigure->StartPoint, ((pPathFigure->Flags & MilPathFigureFlags.IsFillable) != 0), ((pPathFigure->Flags & MilPathFigureFlags.IsClosed) != 0)); if (pPathFigure->Count > 0) { // Allocate the correct number of Segments up front ctx.SetSegmentCount((int)pPathFigure->Count); // ... and iterate on the Segments. for (int j = 0; j < pPathFigure->Count; j++) { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT)); MIL_SEGMENT *pSegment = (MIL_SEGMENT *)(pbData + currentOffset); switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentLine: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_LINE)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_LINE)); MIL_SEGMENT_LINE *pSegmentLine = (MIL_SEGMENT_LINE *)(pbData + currentOffset); ctx.LineTo(pSegmentLine->Point, ((pSegmentLine->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentLine->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_LINE); } break; case MIL_SEGMENT_TYPE.MilSegmentBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); MIL_SEGMENT_BEZIER *pSegmentBezier = (MIL_SEGMENT_BEZIER *)(pbData + currentOffset); ctx.BezierTo(pSegmentBezier->Point1, pSegmentBezier->Point2, pSegmentBezier->Point3, ((pSegmentBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_BEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); MIL_SEGMENT_QUADRATICBEZIER *pSegmentQuadraticBezier = (MIL_SEGMENT_QUADRATICBEZIER *)(pbData + currentOffset); ctx.QuadraticBezierTo(pSegmentQuadraticBezier->Point1, pSegmentQuadraticBezier->Point2, ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_QUADRATICBEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentArc: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_ARC)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_ARC)); MIL_SEGMENT_ARC *pSegmentArc = (MIL_SEGMENT_ARC *)(pbData + currentOffset); ctx.ArcTo(pSegmentArc->Point, pSegmentArc->Size, pSegmentArc->XRotation, (pSegmentArc->LargeArc != 0), (pSegmentArc->Sweep == 0) ? SweepDirection.Counterclockwise : SweepDirection.Clockwise, ((pSegmentArc->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentArc->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_ARC); } break; case MIL_SEGMENT_TYPE.MilSegmentPolyLine: case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY)); MIL_SEGMENT_POLY *pSegmentPoly = (MIL_SEGMENT_POLY *)(pbData + currentOffset); Debug.Assert(pSegmentPoly->Count <= Int32.MaxValue); if (pSegmentPoly->Count > 0) { List <Point> points = new List <Point>((int)pSegmentPoly->Count); // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Point *pPoint = (Point *)(pbData + currentOffset + sizeof(MIL_SEGMENT_POLY)); for (uint k = 0; k < pSegmentPoly->Count; k++) { points.Add(*pPoint); pPoint++; } switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentPolyLine: ctx.PolyLineTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: ctx.PolyBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: ctx.PolyQuadraticBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; } } currentOffset += sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point); } break; #if DEBUG case MIL_SEGMENT_TYPE.MilSegmentNone: throw new System.InvalidOperationException(); default: throw new System.InvalidOperationException(); #endif } } } } } } } }
internal virtual bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type) { if (IsObviouslyEmpty()) { return(false); } PathGeometryData pathData = GetPathGeometryData(); if (pathData.IsEmpty()) { return(false); } bool contains = false; unsafe { MIL_PEN_DATA penData; double[] dashArray = null; // If we have a pen, populate the CMD struct if (pen != null) { pen.GetBasicPenData(&penData, out dashArray); } fixed(byte *pbPathData = pathData.SerializedData) { Debug.Assert(pbPathData != (byte *)0); fixed(double *dashArrayFixed = dashArray) { int hr = MilCoreApi.MilUtility_PathGeometryHitTest( &pathData.Matrix, (pen == null) ? null : &penData, dashArrayFixed, pathData.FillRule, pbPathData, pathData.Size, tolerance, type == ToleranceType.Relative, &hitPoint, out contains); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry is never hittable. contains = false; } else { HRESULT.Check(hr); } } } } return(contains); }
/// <summary> /// GetPathGeometryData - returns a byte[] which contains this Geometry represented /// as a path geometry's serialized format. /// </summary> internal override PathGeometryData GetPathGeometryData() { if (IsObviouslyEmpty()) { return Geometry.GetEmptyPathGeometryData(); } PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform); Point[] points = GetPointList(); ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); ctx.BeginFigure(points[0], true /* is filled */, true /* is closed */); // i == 0, 3, 6, 9 for (int i = 0; i < 12; i += 3) { ctx.BezierTo(points[i + 1], points[i + 2], points[i + 3], true /* is stroked */, true /* is smooth join */); } ctx.Close(); data.SerializedData = ctx.GetData(); return data; }
private static PathGeometryData MakeEmptyPathGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule.EvenOdd; data.Matrix = CompositionResourceManager.MatrixToMilMatrix3x2D(Matrix.Identity); unsafe { int size = sizeof(MIL_PATHGEOMETRY); data.SerializedData = new byte[size]; fixed (byte *pbData = data.SerializedData) { MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY*)pbData; // implicitly set pPathGeometry->Flags = 0; pPathGeometry->FigureCount = 0; pPathGeometry->Size = (UInt32)size; } } return data; }