Example #1
0
		//------------------------------------------------------------------------------
		
		public static Paths SimplifyPolygons(Paths polys,
		                                     PolyFillType fillType = PolyFillType.pftEvenOdd)
		{
			Paths result = new Paths();
			Clipper c = new Clipper();
			c.StrictlySimple = true;
			c.AddPaths(polys, PolyType.ptSubject, true);
			c.Execute(ClipType.ctUnion, result, fillType, fillType);
			return result;
		}
Example #2
0
		//------------------------------------------------------------------------------
		
		internal static Paths Minkowki(Path poly, Path path, bool IsSum, bool IsClosed)
		{
			int delta = (IsClosed ? 1 : 0);
			int polyCnt = poly.Count;
			int pathCnt = path.Count;
			Paths result = new Paths(pathCnt);
			if (IsSum)
				for (int i = 0; i < pathCnt; i++)
			{
				Path p = new Path(polyCnt);
				foreach (IntPoint ip in poly)
					p.Add(new IntPoint(path[i].X + ip.X, path[i].Y + ip.Y));
				result.Add(p);
			}
			else
				for (int i = 0; i < pathCnt; i++)
			{
				Path p = new Path(polyCnt);
				foreach (IntPoint ip in poly)
					p.Add(new IntPoint(path[i].X - ip.X, path[i].Y - ip.Y));
				result.Add(p);
			}
			
			Paths quads = new Paths((pathCnt + delta) * (polyCnt + 1));
			for (int i = 0; i <= pathCnt - 2 + delta; i++)
				for (int j = 0; j <= polyCnt - 1; j++)
			{
				Path quad = new Path(4);
				quad.Add(result[i % pathCnt][j % polyCnt]);
				quad.Add(result[(i + 1) % pathCnt][j % polyCnt]);
				quad.Add(result[(i + 1) % pathCnt][(j + 1) % polyCnt]);
				quad.Add(result[i % pathCnt][(j + 1) % polyCnt]);
				if (!Orientation(quad)) quad.Reverse();
				quads.Add(quad);
			}
			
			Clipper c = new Clipper();
			c.AddPaths(quads, PolyType.ptSubject, true);
			c.Execute(ClipType.ctUnion, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
			return result;
		}
Example #3
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;
				}
				
				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);
				}
			}