public DoublePoint(DoublePoint dp) { this.X = dp.X; this.Y = dp.Y; }
public IntPoint(DoublePoint dp) { this.X = (cInt)dp.X; this.Y = (cInt)dp.Y; this.Z = 0; }
//------------------------------------------------------------------------------ public PolyOffsetBuilder(Paths pts, out Paths solution, double delta, JoinType jointype, EndType endtype, double limit = 0) { //precondition: solution != pts solution = new Paths(); if (ClipperBase.near_zero(delta)) {solution = pts; return; } m_p = pts; if (endtype != EndType.etClosed && delta < 0) delta = -delta; m_delta = delta; if (jointype == JoinType.jtMiter) { //m_miterVal: see offset_triginometry.svg in the documentation folder ... if (limit > 2) m_miterLim = 2 / (limit * limit); else m_miterLim = 0.5; if (endtype == EndType.etRound) limit = 0.25; } if (jointype == JoinType.jtRound || endtype == EndType.etRound) { if (limit <= 0) limit = 0.25; else if (limit > Math.Abs(delta)*0.25) limit = Math.Abs(delta)*0.25; //m_roundVal: see offset_triginometry2.svg in the documentation folder ... m_Steps360 = Math.PI / Math.Acos(1 - limit / Math.Abs(delta)); m_sin = Math.Sin(2 * Math.PI / m_Steps360); m_cos = Math.Cos(2 * Math.PI / m_Steps360); m_Steps360 /= Math.PI * 2; if (delta < 0) m_sin = -m_sin; } double deltaSq = delta * delta; solution.Capacity = pts.Count; for (m_i = 0; m_i < pts.Count; m_i++) { int len = pts[m_i].Count; if (len == 0 || (len < 3 && delta <= 0)) continue; if (len == 1) { if (jointype == JoinType.jtRound) { double X = 1.0, Y = 0.0; for (cInt j = 1; j <= Round(m_Steps360 * 2 * Math.PI); j++) { AddPoint(new IntPoint( Round(m_p[m_i][0].X + X * delta), Round(m_p[m_i][0].Y + Y * delta))); double X2 = X; X = X * m_cos - m_sin * Y; Y = X2 * m_sin + Y * m_cos; } } else { double X = -1.0, Y = -1.0; for (int j = 0; j < 4; ++j) { AddPoint(new IntPoint(Round(m_p[m_i][0].X + X * delta), Round(m_p[m_i][0].Y + Y * delta))); if (X < 0) X = 1; else if (Y < 0) Y = 1; else X = -1; } } continue; } //build normals ... normals.Clear(); normals.Capacity = len; for (int j = 0; j < len -1; ++j) normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j+1])); if (endtype == EndType.etClosed) normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0])); else normals.Add(new DoublePoint(normals[len - 2])); currentPoly = new Path(); if (endtype == EndType.etClosed) { m_k = len - 1; for (m_j = 0; m_j < len; ++m_j) OffsetPoint(jointype); solution.Add(currentPoly); } else { m_k = 0; for (m_j = 1; m_j < len - 1; ++m_j) OffsetPoint(jointype); IntPoint pt1; if (endtype == EndType.etButt) { m_j = len - 1; pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X + normals[m_j].X * delta), (cInt)Round(pts[m_i][m_j].Y + normals[m_j].Y * delta)); AddPoint(pt1); pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X - normals[m_j].X * delta), (cInt)Round(pts[m_i][m_j].Y - normals[m_j].Y * delta)); AddPoint(pt1); } else { m_j = len - 1; m_k = len - 2; m_sinA = 0; normals[m_j] = new DoublePoint(-normals[m_j].X, -normals[m_j].Y); if (endtype == EndType.etSquare) DoSquare(); else DoRound(); } //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); m_k = len - 1; for (m_j = m_k - 1; m_j > 0; --m_j) OffsetPoint(jointype); if (endtype == EndType.etButt) { pt1 = new IntPoint((cInt)Round(pts[m_i][0].X - normals[0].X * delta), (cInt)Round(pts[m_i][0].Y - normals[0].Y * delta)); AddPoint(pt1); pt1 = new IntPoint((cInt)Round(pts[m_i][0].X + normals[0].X * delta), (cInt)Round(pts[m_i][0].Y + normals[0].Y * delta)); AddPoint(pt1); } else { m_k = 1; m_sinA = 0; if (endtype == EndType.etSquare) DoSquare(); else DoRound(); } solution.Add(currentPoly); } } //finally, clean up untidy corners ... Clipper clpr = new Clipper(); clpr.AddPaths(solution, PolyType.ptSubject, true); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = clpr.GetBounds(); Path outer = new Path(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPath(outer, PolyType.ptSubject, true); clpr.ReverseSolution = true; clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) solution.RemoveAt(0); } }
//------------------------------------------------------------------------------ private void DoOffset(double delta) { m_destPolys = new List<List<IntPoint>>(); m_delta = delta; //if Zero offset, just copy any CLOSED polygons to m_p and return ... if (ClipperBase.near_zero(delta)) { m_destPolys.Capacity = m_polyNodes.ChildCount; for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode node = m_polyNodes.Childs[i]; if (node.m_endtype == EndType.etClosedPolygon) m_destPolys.Add(node.m_polygon); } return; } //see offset_triginometry3.svg in the documentation folder ... if (MiterLimit > 2) m_miterLim = 2 / (MiterLimit * MiterLimit); else m_miterLim = 0.5; double y; if (ArcTolerance <= 0.0) y = def_arc_tolerance; else if (ArcTolerance > Math.Abs(delta) * def_arc_tolerance) y = Math.Abs(delta) * def_arc_tolerance; else y = ArcTolerance; //see offset_triginometry2.svg in the documentation folder ... double steps = Math.PI / Math.Acos(1 - y / Math.Abs(delta)); m_sin = Math.Sin(two_pi / steps); m_cos = Math.Cos(two_pi / steps); m_StepsPerRad = steps / two_pi; if (delta < 0.0) m_sin = -m_sin; m_destPolys.Capacity = m_polyNodes.ChildCount * 2; for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode node = m_polyNodes.Childs[i]; m_srcPoly = node.m_polygon; int len = m_srcPoly.Count; if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != EndType.etClosedPolygon))) continue; m_destPoly = new List<IntPoint>(); if (len == 1) { if (node.m_jointype == JoinType.jtRound) { double X = 1.0, Y = 0.0; for (int j = 1; j <= steps; j++) { m_destPoly.Add(new IntPoint( Round(m_srcPoly[0].X + X * delta), Round(m_srcPoly[0].Y + Y * delta))); double X2 = X; X = X * m_cos - m_sin * Y; Y = X2 * m_sin + Y * m_cos; } } else { double X = -1.0, Y = -1.0; for (int j = 0; j < 4; ++j) { m_destPoly.Add(new IntPoint( Round(m_srcPoly[0].X + X * delta), Round(m_srcPoly[0].Y + Y * delta))); if (X < 0) X = 1; else if (Y < 0) Y = 1; else X = -1; } } m_destPolys.Add(m_destPoly); continue; } //build m_normals ... m_normals.Clear(); m_normals.Capacity = len; for (int j = 0; j < len - 1; j++) m_normals.Add(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); if (node.m_endtype == EndType.etClosedLine || node.m_endtype == EndType.etClosedPolygon) m_normals.Add(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); else m_normals.Add(new DoublePoint(m_normals[len - 2])); if (node.m_endtype == EndType.etClosedPolygon) { int k = len - 1; for (int j = 0; j < len; j++) OffsetPoint(j, ref k, node.m_jointype); m_destPolys.Add(m_destPoly); } else if (node.m_endtype == EndType.etClosedLine) { int k = len - 1; for (int j = 0; j < len; j++) OffsetPoint(j, ref k, node.m_jointype); m_destPolys.Add(m_destPoly); m_destPoly = new List<IntPoint>(); //re-build m_normals ... DoublePoint n = m_normals[len - 1]; for (int j = len - 1; j > 0; j--) m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); m_normals[0] = new DoublePoint(-n.X, -n.Y); k = 0; for (int j = len - 1; j >= 0; j--) OffsetPoint(j, ref k, node.m_jointype); m_destPolys.Add(m_destPoly); } else { int k = 0; for (int j = 1; j < len - 1; ++j) OffsetPoint(j, ref k, node.m_jointype); IntPoint pt1; if (node.m_endtype == EndType.etOpenButt) { int j = len - 1; pt1 = new IntPoint((int)Round(m_srcPoly[j].X + m_normals[j].X * delta), (int)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); m_destPoly.Add(pt1); pt1 = new IntPoint((int)Round(m_srcPoly[j].X - m_normals[j].X * delta), (int)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); m_destPoly.Add(pt1); } else { int j = len - 1; k = len - 2; m_sinA = 0; m_normals[j] = new DoublePoint(-m_normals[j].X, -m_normals[j].Y); if (node.m_endtype == EndType.etOpenSquare) DoSquare(j, k); else DoRound(j, k); } //re-build m_normals ... for (int j = len - 1; j > 0; j--) m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); m_normals[0] = new DoublePoint(-m_normals[1].X, -m_normals[1].Y); k = len - 1; for (int j = k - 1; j > 0; --j) OffsetPoint(j, ref k, node.m_jointype); if (node.m_endtype == EndType.etOpenButt) { pt1 = new IntPoint((int)Round(m_srcPoly[0].X - m_normals[0].X * delta), (int)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); m_destPoly.Add(pt1); pt1 = new IntPoint((int)Round(m_srcPoly[0].X + m_normals[0].X * delta), (int)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); m_destPoly.Add(pt1); } else { k = 1; m_sinA = 0; if (node.m_endtype == EndType.etOpenSquare) DoSquare(0, 1); else DoRound(0, 1); } m_destPolys.Add(m_destPoly); } } }
private void OffsetPoint(int j, ref int k, JoinType jointype) { DoublePoint doublePoint = m_normals[k]; double x = doublePoint.X; DoublePoint doublePoint2 = m_normals[j]; double num = x * doublePoint2.Y; DoublePoint doublePoint3 = m_normals[j]; double x2 = doublePoint3.X; DoublePoint doublePoint4 = m_normals[k]; m_sinA = num - x2 * doublePoint4.Y; if (Math.Abs(m_sinA * m_delta) < 1.0) { DoublePoint doublePoint5 = m_normals[k]; double x3 = doublePoint5.X; DoublePoint doublePoint6 = m_normals[j]; double num2 = x3 * doublePoint6.X; DoublePoint doublePoint7 = m_normals[j]; double y = doublePoint7.Y; DoublePoint doublePoint8 = m_normals[k]; double num3 = num2 + y * doublePoint8.Y; if (num3 > 0.0) { List <IntPoint> destPoly = m_destPoly; IntPoint intPoint = m_srcPoly[j]; double num4 = (double)intPoint.X; DoublePoint doublePoint9 = m_normals[k]; long x4 = Round(num4 + doublePoint9.X * m_delta); IntPoint intPoint2 = m_srcPoly[j]; double num5 = (double)intPoint2.Y; DoublePoint doublePoint10 = m_normals[k]; destPoly.Add(new IntPoint(x4, Round(num5 + doublePoint10.Y * m_delta))); return; } } else if (m_sinA > 1.0) { m_sinA = 1.0; } else if (m_sinA < -1.0) { m_sinA = -1.0; } if (!(m_sinA * m_delta < 0.0)) { switch (jointype) { case JoinType.jtMiter: { DoublePoint doublePoint11 = m_normals[j]; double x5 = doublePoint11.X; DoublePoint doublePoint12 = m_normals[k]; double num6 = x5 * doublePoint12.X; DoublePoint doublePoint13 = m_normals[j]; double y2 = doublePoint13.Y; DoublePoint doublePoint14 = m_normals[k]; double num7 = 1.0 + (num6 + y2 * doublePoint14.Y); if (num7 >= m_miterLim) { DoMiter(j, k, num7); } else { DoSquare(j, k); } break; } case JoinType.jtSquare: DoSquare(j, k); break; case JoinType.jtRound: DoRound(j, k); break; } } else { List <IntPoint> destPoly2 = m_destPoly; IntPoint intPoint3 = m_srcPoly[j]; double num8 = (double)intPoint3.X; DoublePoint doublePoint15 = m_normals[k]; long x6 = Round(num8 + doublePoint15.X * m_delta); IntPoint intPoint4 = m_srcPoly[j]; double num9 = (double)intPoint4.Y; DoublePoint doublePoint16 = m_normals[k]; destPoly2.Add(new IntPoint(x6, Round(num9 + doublePoint16.Y * m_delta))); m_destPoly.Add(m_srcPoly[j]); List <IntPoint> destPoly3 = m_destPoly; IntPoint intPoint5 = m_srcPoly[j]; double num10 = (double)intPoint5.X; DoublePoint doublePoint17 = m_normals[j]; long x7 = Round(num10 + doublePoint17.X * m_delta); IntPoint intPoint6 = m_srcPoly[j]; double num11 = (double)intPoint6.Y; DoublePoint doublePoint18 = m_normals[j]; destPoly3.Add(new IntPoint(x7, Round(num11 + doublePoint18.Y * m_delta))); } k = j; }
private void DoOffset(double delta) { m_destPolys = new List <List <IntPoint> >(); m_delta = delta; if (ClipperBase.near_zero(delta)) { m_destPolys.Capacity = m_polyNodes.ChildCount; for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode polyNode = m_polyNodes.Childs[i]; if (polyNode.m_endtype == EndType.etClosedPolygon) { m_destPolys.Add(polyNode.m_polygon); } } } else { if (MiterLimit > 2.0) { m_miterLim = 2.0 / (MiterLimit * MiterLimit); } else { m_miterLim = 0.5; } double num = (ArcTolerance <= 0.0) ? 0.25 : ((!(ArcTolerance > Math.Abs(delta) * 0.25)) ? ArcTolerance : (Math.Abs(delta) * 0.25)); double num2 = 3.1415926535897931 / Math.Acos(1.0 - num / Math.Abs(delta)); m_sin = Math.Sin(6.2831853071795862 / num2); m_cos = Math.Cos(6.2831853071795862 / num2); m_StepsPerRad = num2 / 6.2831853071795862; if (delta < 0.0) { m_sin = 0.0 - m_sin; } m_destPolys.Capacity = m_polyNodes.ChildCount * 2; for (int j = 0; j < m_polyNodes.ChildCount; j++) { PolyNode polyNode2 = m_polyNodes.Childs[j]; m_srcPoly = polyNode2.m_polygon; int count = m_srcPoly.Count; if (count != 0 && (!(delta <= 0.0) || (count >= 3 && polyNode2.m_endtype == EndType.etClosedPolygon))) { m_destPoly = new List <IntPoint>(); if (count == 1) { if (polyNode2.m_jointype == JoinType.jtRound) { double num3 = 1.0; double num4 = 0.0; for (int k = 1; (double)k <= num2; k++) { List <IntPoint> destPoly = m_destPoly; IntPoint intPoint = m_srcPoly[0]; long x = Round((double)intPoint.X + num3 * delta); IntPoint intPoint2 = m_srcPoly[0]; destPoly.Add(new IntPoint(x, Round((double)intPoint2.Y + num4 * delta))); double num5 = num3; num3 = num3 * m_cos - m_sin * num4; num4 = num5 * m_sin + num4 * m_cos; } } else { double num6 = -1.0; double num7 = -1.0; for (int l = 0; l < 4; l++) { List <IntPoint> destPoly2 = m_destPoly; IntPoint intPoint3 = m_srcPoly[0]; long x2 = Round((double)intPoint3.X + num6 * delta); IntPoint intPoint4 = m_srcPoly[0]; destPoly2.Add(new IntPoint(x2, Round((double)intPoint4.Y + num7 * delta))); if (num6 < 0.0) { num6 = 1.0; } else if (num7 < 0.0) { num7 = 1.0; } else { num6 = -1.0; } } } m_destPolys.Add(m_destPoly); } else { m_normals.Clear(); m_normals.Capacity = count; for (int m = 0; m < count - 1; m++) { m_normals.Add(GetUnitNormal(m_srcPoly[m], m_srcPoly[m + 1])); } if (polyNode2.m_endtype == EndType.etClosedLine || polyNode2.m_endtype == EndType.etClosedPolygon) { m_normals.Add(GetUnitNormal(m_srcPoly[count - 1], m_srcPoly[0])); } else { m_normals.Add(new DoublePoint(m_normals[count - 2])); } if (polyNode2.m_endtype == EndType.etClosedPolygon) { int k2 = count - 1; for (int n = 0; n < count; n++) { OffsetPoint(n, ref k2, polyNode2.m_jointype); } m_destPolys.Add(m_destPoly); } else if (polyNode2.m_endtype == EndType.etClosedLine) { int k3 = count - 1; for (int num8 = 0; num8 < count; num8++) { OffsetPoint(num8, ref k3, polyNode2.m_jointype); } m_destPolys.Add(m_destPoly); m_destPoly = new List <IntPoint>(); DoublePoint doublePoint = m_normals[count - 1]; for (int num9 = count - 1; num9 > 0; num9--) { List <DoublePoint> normals = m_normals; int index = num9; DoublePoint doublePoint2 = m_normals[num9 - 1]; double x3 = 0.0 - doublePoint2.X; DoublePoint doublePoint3 = m_normals[num9 - 1]; normals[index] = new DoublePoint(x3, 0.0 - doublePoint3.Y); } m_normals[0] = new DoublePoint(0.0 - doublePoint.X, 0.0 - doublePoint.Y); k3 = 0; for (int num10 = count - 1; num10 >= 0; num10--) { OffsetPoint(num10, ref k3, polyNode2.m_jointype); } m_destPolys.Add(m_destPoly); } else { int k4 = 0; for (int num11 = 1; num11 < count - 1; num11++) { OffsetPoint(num11, ref k4, polyNode2.m_jointype); } IntPoint item = default(IntPoint); if (polyNode2.m_endtype == EndType.etOpenButt) { int index2 = count - 1; IntPoint intPoint5 = m_srcPoly[index2]; double num12 = (double)intPoint5.X; DoublePoint doublePoint4 = m_normals[index2]; long x4 = Round(num12 + doublePoint4.X * delta); IntPoint intPoint6 = m_srcPoly[index2]; double num13 = (double)intPoint6.Y; DoublePoint doublePoint5 = m_normals[index2]; item = new IntPoint(x4, Round(num13 + doublePoint5.Y * delta)); m_destPoly.Add(item); IntPoint intPoint7 = m_srcPoly[index2]; double num14 = (double)intPoint7.X; DoublePoint doublePoint6 = m_normals[index2]; long x5 = Round(num14 - doublePoint6.X * delta); IntPoint intPoint8 = m_srcPoly[index2]; double num15 = (double)intPoint8.Y; DoublePoint doublePoint7 = m_normals[index2]; item = new IntPoint(x5, Round(num15 - doublePoint7.Y * delta)); m_destPoly.Add(item); } else { int num16 = count - 1; k4 = count - 2; m_sinA = 0.0; List <DoublePoint> normals2 = m_normals; int index3 = num16; DoublePoint doublePoint8 = m_normals[num16]; double x6 = 0.0 - doublePoint8.X; DoublePoint doublePoint9 = m_normals[num16]; normals2[index3] = new DoublePoint(x6, 0.0 - doublePoint9.Y); if (polyNode2.m_endtype == EndType.etOpenSquare) { DoSquare(num16, k4); } else { DoRound(num16, k4); } } for (int num17 = count - 1; num17 > 0; num17--) { List <DoublePoint> normals3 = m_normals; int index4 = num17; DoublePoint doublePoint10 = m_normals[num17 - 1]; double x7 = 0.0 - doublePoint10.X; DoublePoint doublePoint11 = m_normals[num17 - 1]; normals3[index4] = new DoublePoint(x7, 0.0 - doublePoint11.Y); } List <DoublePoint> normals4 = m_normals; DoublePoint doublePoint12 = m_normals[1]; double x8 = 0.0 - doublePoint12.X; DoublePoint doublePoint13 = m_normals[1]; normals4[0] = new DoublePoint(x8, 0.0 - doublePoint13.Y); k4 = count - 1; for (int num18 = k4 - 1; num18 > 0; num18--) { OffsetPoint(num18, ref k4, polyNode2.m_jointype); } if (polyNode2.m_endtype == EndType.etOpenButt) { IntPoint intPoint9 = m_srcPoly[0]; double num19 = (double)intPoint9.X; DoublePoint doublePoint14 = m_normals[0]; long x9 = Round(num19 - doublePoint14.X * delta); IntPoint intPoint10 = m_srcPoly[0]; double num20 = (double)intPoint10.Y; DoublePoint doublePoint15 = m_normals[0]; item = new IntPoint(x9, Round(num20 - doublePoint15.Y * delta)); m_destPoly.Add(item); IntPoint intPoint11 = m_srcPoly[0]; double num21 = (double)intPoint11.X; DoublePoint doublePoint16 = m_normals[0]; long x10 = Round(num21 + doublePoint16.X * delta); IntPoint intPoint12 = m_srcPoly[0]; double num22 = (double)intPoint12.Y; DoublePoint doublePoint17 = m_normals[0]; item = new IntPoint(x10, Round(num22 + doublePoint17.Y * delta)); m_destPoly.Add(item); } else { k4 = 1; m_sinA = 0.0; if (polyNode2.m_endtype == EndType.etOpenSquare) { DoSquare(0, 1); } else { DoRound(0, 1); } } m_destPolys.Add(m_destPoly); } } } } } }