public static bool Contains(PolygonPath subject, PolygonPath clip) { // The subjectPath polygon path contains the clipPath polygon path if: // 1. The union operation must result in one polygon result // 2. The area of the union equals subjectPath area. // 3. The area of the clipPath must be <= than the area of subjectPath. var solution = new PolygonPath(); var clipper = new Clipper(); if (!clipper.Execute(ClipOperation.Union, subject, clip, solution)) { return(false); } if (solution.Count != 1) { return(false); } if (!GeometryHelper.NearZero(subject.Area - solution.Area)) { return(false); } return(clip.Area <= subject.Area); }
internal static DoublePoint GetUnitNormal(IntPoint pt1, IntPoint pt2) { double dx = pt2.X - pt1.X; double dy = pt2.Y - pt1.Y; if (GeometryHelper.NearZero(dx) && GeometryHelper.NearZero(dy)) { return(new DoublePoint()); } var f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy); dx *= f; dy *= f; return(new DoublePoint(dy, -dx)); }
private void DoOffset(double delta) { _destinationPolygons = new PolygonPath(); _delta = delta; //if Zero offset, just copy any CLOSED polygons to m_p and return ... if (GeometryHelper.NearZero(delta)) { _destinationPolygons.Capacity = _polygonNodes.Children.Count; foreach (var node in _polygonNodes.Children) { if (node.EndType == EndType.ClosedPolygon) { _destinationPolygons.Add(node.Polygon); } } return; } // see offset_triginometry3.svg in the documentation folder ... if (MiterLimit > 2) { _miterLim = 2 / (MiterLimit * MiterLimit); } else { _miterLim = 0.5; } double y; if (ArcTolerance <= 0.0) { y = DefaulArcTolerance; } else if (ArcTolerance > Math.Abs(delta) * DefaulArcTolerance) { y = Math.Abs(delta) * DefaulArcTolerance; } else { y = ArcTolerance; } // see offset_triginometry2.svg in the documentation folder ... var steps = Math.PI / Math.Acos(1 - y / Math.Abs(delta)); _sin = Math.Sin(TwpPi / steps); _cos = Math.Cos(TwpPi / steps); _stepsPerRad = steps / TwpPi; if (delta < 0.0) { _sin = -_sin; } _destinationPolygons.Capacity = _polygonNodes.Children.Count * 2; foreach (var node in _polygonNodes.Children) { _sourcePolygon = node.Polygon; var len = _sourcePolygon.Count; if (len == 0 || delta <= 0 && (len < 3 || node.EndType != EndType.ClosedPolygon)) { continue; } _destinationPolygon = new Polygon(); if (len == 1) { if (node.JoinType == JoinType.Round) { var x = 1.0; var Y = 0.0; for (var j = 1; j <= steps; j++) { _destinationPolygon.Add(new IntPoint( (_sourcePolygon[0].X + x * delta).RoundToLong(), (_sourcePolygon[0].Y + Y * delta).RoundToLong())); var x2 = x; x = x * _cos - _sin * Y; Y = x2 * _sin + Y * _cos; } } else { var x = -1.0; var Y = -1.0; for (var j = 0; j < 4; ++j) { _destinationPolygon.Add(new IntPoint( (_sourcePolygon[0].X + x * delta).RoundToLong(), (_sourcePolygon[0].Y + Y * delta).RoundToLong())); if (x < 0) { x = 1; } else if (Y < 0) { Y = 1; } else { x = -1; } } } _destinationPolygons.Add(_destinationPolygon); continue; } //build _normals ... _normals.Clear(); _normals.Capacity = len; for (int j = 0; j < len - 1; j++) { _normals.Add(GetUnitNormal(_sourcePolygon[j], _sourcePolygon[j + 1])); } if (node.EndType == EndType.ClosedLine || node.EndType == EndType.ClosedPolygon) { _normals.Add(GetUnitNormal(_sourcePolygon[len - 1], _sourcePolygon[0])); } else { _normals.Add(new DoublePoint(_normals[len - 2])); } if (node.EndType == EndType.ClosedPolygon) { int k = len - 1; for (int j = 0; j < len; j++) { OffsetPoint(j, ref k, node.JoinType); } _destinationPolygons.Add(_destinationPolygon); } else if (node.EndType == EndType.ClosedLine) { int k = len - 1; for (int j = 0; j < len; j++) { OffsetPoint(j, ref k, node.JoinType); } _destinationPolygons.Add(_destinationPolygon); _destinationPolygon = new Polygon(); //re-build _normals ... DoublePoint n = _normals[len - 1]; for (int j = len - 1; j > 0; j--) { _normals[j] = new DoublePoint(-_normals[j - 1].X, -_normals[j - 1].Y); } _normals[0] = new DoublePoint(-n.X, -n.Y); k = 0; for (int j = len - 1; j >= 0; j--) { OffsetPoint(j, ref k, node.JoinType); } _destinationPolygons.Add(_destinationPolygon); } else { var k = 0; for (var j = 1; j < len - 1; ++j) { OffsetPoint(j, ref k, node.JoinType); } IntPoint pt1; if (node.EndType == EndType.OpenButt) { var j = len - 1; pt1 = new IntPoint( (_sourcePolygon[j].X + _normals[j].X * delta).RoundToLong(), (_sourcePolygon[j].Y + _normals[j].Y * delta).RoundToLong()); _destinationPolygon.Add(pt1); pt1 = new IntPoint( (_sourcePolygon[j].X - _normals[j].X * delta).RoundToLong(), (_sourcePolygon[j].Y - _normals[j].Y * delta).RoundToLong()); _destinationPolygon.Add(pt1); } else { var j = len - 1; k = len - 2; _sinA = 0; _normals[j] = new DoublePoint(-_normals[j].X, -_normals[j].Y); if (node.EndType == EndType.OpenSquare) { DoSquare(j, k); } else { DoRound(j, k); } } //re-build _normals ... for (int j = len - 1; j > 0; j--) { _normals[j] = new DoublePoint(-_normals[j - 1].X, -_normals[j - 1].Y); } _normals[0] = new DoublePoint(-_normals[1].X, -_normals[1].Y); k = len - 1; for (int j = k - 1; j > 0; --j) { OffsetPoint(j, ref k, node.JoinType); } if (node.EndType == EndType.OpenButt) { pt1 = new IntPoint( (_sourcePolygon[0].X - _normals[0].X * delta).RoundToLong(), (_sourcePolygon[0].Y - _normals[0].Y * delta).RoundToLong()); _destinationPolygon.Add(pt1); pt1 = new IntPoint( (_sourcePolygon[0].X + _normals[0].X * delta).RoundToLong(), (_sourcePolygon[0].Y + _normals[0].Y * delta).RoundToLong()); _destinationPolygon.Add(pt1); } else { _sinA = 0; if (node.EndType == EndType.OpenSquare) { DoSquare(0, 1); } else { DoRound(0, 1); } } _destinationPolygons.Add(_destinationPolygon); } } }