//--------------------------------------------------------------------- private void DrawBitmap(bool justClip = false) { if (!justClip) { if (rbTest2.Checked) GenerateAustPlusRandomEllipses((int)nudCount.Value); else GenerateRandomPolygon((int)nudCount.Value); } Cursor.Current = Cursors.WaitCursor; Graphics newgraphic; newgraphic = Graphics.FromImage(mybitmap); newgraphic.SmoothingMode = SmoothingMode.AntiAlias; newgraphic.Clear(Color.WhiteSmoke); Pen myPen = new Pen(Color.LightSlateGray, (float)1.5); SolidBrush myBrush = new SolidBrush(Color.FromArgb(16, Color.Blue)); GraphicsPath path = new GraphicsPath(); if (rbNonZero.Checked) path.FillMode = FillMode.Winding; foreach (Polygon pg in subjects) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); path.Reset(); if (rbNonZero.Checked) path.FillMode = FillMode.Winding; foreach (Polygon pg in clips) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } myPen.Color = Color.LightSalmon; myBrush.Color = Color.FromArgb(16, Color.Red); newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //do the clipping ... if ((clips.Count > 0 || subjects.Count > 0) && !rbNone.Checked) { Polygons solution = new Polygons(); //Stopwatch sw = new Stopwatch(); //sw.Start(); clipper.Clipper c = new clipper.Clipper(); c.AddPolygons(subjects, PolyType.ptSubject); c.AddPolygons(clips, PolyType.ptClip); if (!c.Execute(GeClipType(), solution, GePolyFillType(), GePolyFillType())) { Console.Beep(1250, 250); } //sw.Stop(); //TimeSpan ts = sw.Elapsed; //this.Text = Convert.ToString(ts.TotalMilliseconds); myBrush.Color = Color.Black; path.Reset(); //It really shouldn't matter what FillMode is used for solution //polygons because none of the solution polygons overlap. //However, FillMode.Winding will show any orientation errors where //holes will be stroked (outlined) correctly but filled incorrectly ... path.FillMode = FillMode.Winding; //or for something fancy ... if (nudOffset.Value != 0) solution = clipper.Clipper.OffsetPolygons(solution, (double)nudOffset.Value * scale); foreach (Polygon pg in solution) { PointF[] pts = PolygonToPointFArray(pg, scale); if (pts.Count() > 2) path.AddPolygon(pts); pts = null; } myBrush.Color = Color.FromArgb(128, Color.Yellow); myPen.Color = Color.Black; newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); foreach (Polygon pg in solution) { PointF[] pts = PolygonToPointFArray(pg, scale); path.Reset(); path.AddPolygon(pts); } } pictureBox1.Image = mybitmap; newgraphic.Dispose(); Cursor.Current = Cursors.Default; }
//--------------------------------------------------------------------- private void DrawBitmap(bool justClip = false) { if (!justClip) { if (rbTest2.Checked) { GenerateAustPlusRandomEllipses((int)nudCount.Value); } else { GenerateRandomPolygon((int)nudCount.Value); } } Cursor.Current = Cursors.WaitCursor; Graphics newgraphic; newgraphic = Graphics.FromImage(mybitmap); newgraphic.SmoothingMode = SmoothingMode.AntiAlias; newgraphic.Clear(Color.WhiteSmoke); Pen myPen = new Pen(Color.LightSlateGray, (float)1.5); SolidBrush myBrush = new SolidBrush(Color.FromArgb(16, Color.Blue)); GraphicsPath path = new GraphicsPath(); if (rbNonZero.Checked) { path.FillMode = FillMode.Winding; } foreach (Polygon pg in subjects) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); path.Reset(); if (rbNonZero.Checked) { path.FillMode = FillMode.Winding; } foreach (Polygon pg in clips) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } myPen.Color = Color.LightSalmon; myBrush.Color = Color.FromArgb(16, Color.Red); newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //do the clipping ... if ((clips.Count > 0 || subjects.Count > 0) && !rbNone.Checked) { Polygons solution = new Polygons(); //Stopwatch sw = new Stopwatch(); //sw.Start(); clipper.Clipper c = new clipper.Clipper(); c.AddPolygons(subjects, PolyType.ptSubject); c.AddPolygons(clips, PolyType.ptClip); if (!c.Execute(GeClipType(), solution, GePolyFillType(), GePolyFillType())) { Console.Beep(1250, 250); } //sw.Stop(); //TimeSpan ts = sw.Elapsed; //this.Text = Convert.ToString(ts.TotalMilliseconds); myBrush.Color = Color.Black; path.Reset(); //It really shouldn't matter what FillMode is used for solution //polygons because none of the solution polygons overlap. //However, FillMode.Winding will show any orientation errors where //holes will be stroked (outlined) correctly but filled incorrectly ... path.FillMode = FillMode.Winding; //or for something fancy ... if (nudOffset.Value != 0) { solution = clipper.Clipper.OffsetPolygons(solution, (double)nudOffset.Value * scale); } foreach (Polygon pg in solution) { PointF[] pts = PolygonToPointFArray(pg, scale); if (pts.Count() > 2) { path.AddPolygon(pts); } pts = null; } myBrush.Color = Color.FromArgb(128, Color.Yellow); myPen.Color = Color.Black; newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); foreach (Polygon pg in solution) { PointF[] pts = PolygonToPointFArray(pg, scale); path.Reset(); path.AddPolygon(pts); } } pictureBox1.Image = mybitmap; newgraphic.Dispose(); Cursor.Current = Cursors.Default; }
//------------------------------------------------------------------------------ public static Polygons OffsetPolygons(Polygons pts, double delta) { double deltaSq = delta*delta; Polygons result = new Polygons(pts.Count); for (int j = 0; j < pts.Count; ++j) { int highI = pts[j].Count -1; //to minimize artefacts, strip out those polygons where //it's shrinking and where its area < Sqr(delta) ... double a1 = Area(pts[j]); if (delta < 0) { if (a1 > 0 && a1 < deltaSq) highI = 0;} else if (a1 < 0 && -a1 < deltaSq) highI = 0; //nb: a hole if area < 0 Polygon pg = new Polygon(highI*2+2); if (highI < 2) { result.Add(pg); continue; } List<DoublePoint> normals = new List<DoublePoint>(highI+1); normals.Add(GetUnitNormal(pts[j][highI], pts[j][0])); for (int i = 1; i <= highI; ++i) normals.Add(GetUnitNormal(pts[j][i-1], pts[j][i])); for (int i = 0; i < highI; ++i) { pg.Add(new IntPoint(Round(pts[j][i].X + delta *normals[i].X), (int)(pts[j][i].Y + delta *normals[i].Y))); pg.Add(new IntPoint(Round(pts[j][i].X + delta * normals[i + 1].X), (int)(pts[j][i].Y + delta *normals[i+1].Y))); } pg.Add(new IntPoint(Round(pts[j][highI].X + delta * normals[highI].X), (int)(pts[j][highI].Y + delta *normals[highI].Y))); pg.Add(new IntPoint(Round(pts[j][highI].X + delta * normals[0].X), (int)(pts[j][highI].Y + delta *normals[0].Y))); //round off reflex angles (ie > 180 deg) unless it's almost flat (ie < 10deg angle) ... //cross product normals < 0 . reflex angle; dot product normals == 1 . no angle if ((normals[highI].X *normals[0].Y - normals[0].X *normals[highI].Y) *delta > 0 && (normals[0].X *normals[highI].X + normals[0].Y *normals[highI].Y) < 0.985) { double at1 = Math.Atan2(normals[highI].Y, normals[highI].X); double at2 = Math.Atan2(normals[0].Y, normals[0].X); if (delta > 0 && at2 < at1) at2 = at2 + Math.PI*2; else if (delta < 0 && at2 > at1) at2 = at2 - Math.PI*2; Polygon arc = BuildArc(pts[j][highI], at1, at2, delta); pg.InsertRange(highI * 2 + 1, arc); } for (int i = highI; i > 0; --i) if ((normals[i-1].X*normals[i].Y - normals[i].X*normals[i-1].Y) *delta > 0 && (normals[i].X*normals[i-1].X + normals[i].Y*normals[i-1].Y) < 0.985) { double at1 = Math.Atan2(normals[i-1].Y, normals[i-1].X); double at2 = Math.Atan2(normals[i].Y, normals[i].X); if (delta > 0 && at2 < at1) at2 = at2 + Math.PI*2; else if (delta < 0 && at2 > at1) at2 = at2 - Math.PI*2; Polygon arc = BuildArc(pts[j][i-1], at1, at2, delta); pg.InsertRange((i - 1) * 2 + 1, arc); } result.Add(pg); } //finally, clean up untidy corners ... Clipper clpr = new Clipper(); clpr.AddPolygons(result, PolyType.ptSubject); if (delta > 0){ if(!clpr.Execute(ClipType.ctUnion, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero)) result.Clear(); } else { IntRect r = clpr.GetBounds(); Polygon outer = new Polygon(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.AddPolygon(outer, PolyType.ptSubject); if (clpr.Execute(ClipType.ctUnion, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero)) result.RemoveAt(0); else result.Clear(); } return result; }