// polygons treatment private Polygons getPolygonsInRegion(int i, int j, double delta) { //converting the boundingbox of the region to a polygon Polygon clip = this.BoundingBoxToPolygon(this.ReagionsBoundingBoxes[i, j]); //initial polygons denote part of the subregions that are located within the region Polygons initialPolygons = new Polygons(); Clipper c = new Clipper(); //c.StrictlySimple = true; // jeremy c.AddPolygons(this.IntRoads, PolyType.ptSubject); c.AddPolygon(clip, PolyType.ptClip); c.Execute(ClipType.ctIntersection, initialPolygons, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); // negative Clip is the roads inside the region clipping the region Polygons negativeClip = new Polygons(); Clipper negative = new Clipper(); //negative.StrictlySimple = true; // jeremy negative.AddPolygons(initialPolygons, PolyType.ptClip); negative.AddPolygon(clip, PolyType.ptSubject); negative.Execute(ClipType.ctIntersection, negativeClip, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); //shrinking the negative clip to remove common edges Polygons negativeShrank = Clipper.OffsetPolygons(negativeClip, -1 * Math.Pow(10, this.Exponent - 1), ClipperLib.JoinType.jtMiter); // expanding the negative shrink the negative clip to remove common edges Polygons negativeShrankExpand = Clipper.OffsetPolygons(negativeShrank, Math.Pow(10, this.Exponent - 1) + 3, ClipperLib.JoinType.jtMiter); Polygons negativeShrankExpandNegative = new Polygons(); Clipper negativeAgain = new Clipper(); //negativeAgain.StrictlySimple = true; // jeremy negativeAgain.AddPolygons(negativeShrankExpand, PolyType.ptSubject); negativeAgain.AddPolygon(clip, PolyType.ptClip); negativeAgain.Execute(ClipType.ctIntersection, negativeShrankExpandNegative, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); return(negativeShrankExpandNegative); }
public List <IntPoint> AroundWall(Vector2 containPoint, float offset) { //将相邻的障碍物轮廓合并在一起 List <List <IntPoint> > unions = new List <List <IntPoint> >(); Clipper clipper = new Clipper(); for (int i = 0; i < m_walls.Count; i++) { clipper.AddPolygons(m_walls[i].m_polygons, PolyType.ptSubject); } if (!clipper.Execute(ClipType.ctUnion, unions)) { Debug.LogError("无法合并顶点"); return(null); } //过滤出特定的那个轮廓 List <IntPoint> contour = null; for (int i = 0; i < unions.Count; i++) { if (ClipperUtils.IsPointOnPolygonEdge(containPoint, unions[i])) { contour = unions[i]; break; } } if (contour == null) { Debug.LogError("没找到包含特定点的障碍轮廓"); return(null); } //对轮廓进行偏移 List <List <IntPoint> > result = new List <List <IntPoint> >() { contour }; result = Clipper.OffsetPolygons(result, offset * ClipperUtils.k_precision); if (result.Count > 1) { Debug.LogError("轮廓偏移后产生多个轮廓了?"); return(result[0]); } else if (result.Count == 0) { Debug.LogError("轮廓偏移后不产生轮廓了?"); return(null); } else { return(result[0]); } }
public Paths BuildOutlines(float growamt = 5 *3) { ClipperLib.Clipper cp = new ClipperLib.Clipper(); Path pp = new Path(); pp.AddRange(Vertices); Paths pps = new Paths(); pps.Add(pp); var Res = Clipper.OffsetPolygons(pps, growamt, JoinType.jtRound); return(Res); }
public void ShrinkFromShape(Path shape, float amt = 7 *3) { Path pp = new Path(); pp.AddRange(shape); Paths pps = new Paths(); pps.Add(pp); var Res = Clipper.OffsetPolygons(pps, -amt); if (Res.Count == 1) { Vertices.Clear(); Vertices.AddRange(Res[0]); } }
internal List <PolyLine> Offset(double margin, int v) { List <PolyLine> Res = new List <PolyLine>(); Polygons clips = new Polygons(); Polygon b = this.toPolygon(); clips.Add(b); Polygons clips2 = Clipper.OffsetPolygons(clips, margin * 100000.0f, JoinType.jtRound); foreach (var r in clips2) { PolyLine PLR = new PolyLine(v++); PLR.fromPolygon(r); Res.Add(PLR); } return(Res); }
public string MinimalDXFSave(string outputfile, double offset = 3.0, double holediameter = 3.2) { if (Directory.Exists(outputfile)) { outputfile = Path.Combine(outputfile, "SickOfBeige"); } PolyLine Biggest = null; double BiggestArea = 0; List <PointD> Holes = new List <PointD>(); var holeradius = holediameter / 2.0; double Circumference = 2 * Math.PI * holeradius; foreach (var a in PLSs.Where(x => x.Layer == BoardLayer.Outline)) { foreach (var b in a.OutlineShapes) { var A = b.toPolygon(); double LRatio = (b.OutlineLength() / Circumference); double Lperc = Math.Abs(LRatio - 1); if (Lperc < 0.1) { if (b.Vertices.Count > 5) { var C = b.GetCentroid(); bool round = true; foreach (var v in b.Vertices) { var L = (C - v).Length(); if (Math.Abs(L - holeradius) > 0.2) { // not very round! round = false; } } if (round) { Console.WriteLine("Hole detected in outline:{0} {1} {2} {3} {4} {5}", a.Layer, a.Side, C, LRatio, Lperc, b.Vertices.Count); Holes.Add(C); } } // might be hole! } var Area = Clipper.Area(A); if (Area > BiggestArea) { Biggest = b; BiggestArea = Area; } } } Polygons Offsetted = new Polygons(); List <String> Lines = new List <string>(); Lines.Add("0"); Lines.Add("SECTION"); Lines.Add("2 "); Lines.Add("ENTITIES"); if (Biggest != null) { Polygons clips = new Polygons(); clips.Add(Biggest.toPolygon()); Offsetted = Clipper.OffsetPolygons(clips, offset * 100000.0f, JoinType.jtRound); foreach (var poly in Offsetted) { PolyLine P = new PolyLine(PolyLine.PolyIDs.Temp); P.fromPolygon(poly); for (int i = 0; i < P.Vertices.Count; i++) { var V1 = P.Vertices[i]; var V2 = P.Vertices[(i + 1) % P.Vertices.Count]; Lines.Add("0"); Lines.Add("LINE"); Lines.Add("8"); Lines.Add("Outline"); Lines.Add("10"); Lines.Add(V1.X.ToString().Replace(',', '.')); Lines.Add("20"); Lines.Add(V1.Y.ToString().Replace(',', '.')); Lines.Add("11"); Lines.Add(V2.X.ToString().Replace(',', '.')); Lines.Add("21"); Lines.Add(V2.Y.ToString().Replace(',', '.')); } } } else { Errors.Add("No longest outline found - not generating offset curve"); } foreach (var a in Excellons) { foreach (var t in a.Tools) { var R = t.Value.Radius; if (Math.Abs(R * 2 - holediameter) < 0.05) { foreach (var h in t.Value.Drills) { Holes.Add(h); } } } } foreach (var a in Holes) { for (int i = 0; i < 40; i++) { double P = i * Math.PI * 2.0 / 40.0; double P2 = (i + 1) * Math.PI * 2.0 / 40.0; var C1 = Math.Cos(P) * holeradius; var C2 = Math.Cos(P2) * holeradius; var S1 = Math.Sin(P) * holeradius; var S2 = Math.Sin(P2) * holeradius; double x1 = a.X + C1; double y1 = a.Y + S1; double x2 = a.X + C2; double y2 = a.Y + S2; Lines.Add("0"); Lines.Add("LINE"); Lines.Add("8"); Lines.Add("Holes"); Lines.Add("10"); Lines.Add(x1.ToString().Replace(',', '.')); Lines.Add("20"); Lines.Add(y1.ToString().Replace(',', '.')); Lines.Add("11"); Lines.Add(x2.ToString().Replace(',', '.')); Lines.Add("21"); Lines.Add(y2.ToString().Replace(',', '.')); } } Lines.Add("0"); Lines.Add("ENDSEC"); Lines.Add("0"); Lines.Add("EOF"); File.WriteAllLines(outputfile + ".dxf", Lines); float scalefac = 10; Console.WriteLine("Report: {0} holes created in case ({1} spacers and {1} screws needed!)", Holes.Count, Holes.Count * 2); { var BB = new GerberLibrary.Bounds(); BB.AddPolygons(Offsetted); BB.AddPolyLine(Biggest); Bitmap B = new Bitmap((int)((BB.Width()) * scalefac) + 6, (int)((BB.Height()) * scalefac) + 6); Graphics G = Graphics.FromImage(B); G.Clear(Color.Transparent); G.Clear(Color.White); G.TranslateTransform(3, 3); G.ScaleTransform(scalefac, scalefac); G.TranslateTransform((float)-(BB.TopLeft.X), (float)-(BB.TopLeft.Y)); Pen pen = new Pen(Color.Black, 0.1f); Pen pen2 = new Pen(Color.FromArgb(160, 160, 160), 0.1f); pen2.DashPattern = new float[2] { 2, 2 }; GerberImageCreator.ApplyAASettings(G); RectangleF R = new RectangleF(0, 0, (float)holediameter, (float)holediameter); foreach (var a in Holes) { R.X = (float)a.X - (float)holeradius; R.Y = (float)a.Y - (float)holeradius; G.DrawEllipse(pen, R); } foreach (var poly in Offsetted) { PolyLine Pl = new PolyLine(PolyLine.PolyIDs.Temp); Pl.fromPolygon(poly); var Points = new List <PointF>(Pl.Vertices.Count); for (int i = 0; i < Pl.Vertices.Count; i++) { Points.Add(Pl.Vertices[i].ToF()); } Points.Add(Pl.Vertices[0].ToF()); G.DrawLines(pen, Points.ToArray()); } { PolyLine Pl = Biggest; var Points = new List <PointF>(Pl.Vertices.Count); for (int i = 0; i < Pl.Vertices.Count; i++) { Points.Add(Pl.Vertices[i].ToF()); } Points.Add(Pl.Vertices[0].ToF()); G.DrawLines(pen2, Points.ToArray()); } var ImagePNG = outputfile + ".png"; B.Save(ImagePNG); return(ImagePNG); } }
//--------------------------------------------------------------------------- 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.White); GraphicsPath path = new GraphicsPath(); if (rbNonZero.Checked) { path.FillMode = FillMode.Winding; } //draw subjects ... foreach (Polygon pg in subjects) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } Pen myPen = new Pen(Color.FromArgb(196, 0xC3, 0xC9, 0xCF), (float)0.6); SolidBrush myBrush = new SolidBrush(Color.FromArgb(127, 0xDD, 0xDD, 0xF0)); newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); path.Reset(); //draw clips ... 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.FromArgb(196, 0xF9, 0xBE, 0xA6); myBrush.Color = Color.FromArgb(127, 0xFF, 0xE0, 0xE0); newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //do the clipping ... if ((clips.Count > 0 || subjects.Count > 0) && !rbNone.Checked) { Polygons solution2 = new Polygons(); Clipper c = new Clipper(); c.AddPolygons(subjects, PolyType.ptSubject); c.AddPolygons(clips, PolyType.ptClip); exSolution.Clear(); solution.Clear(); bool succeeded = c.Execute(GetClipType(), solution, GetPolyFillType(), GetPolyFillType()); if (succeeded) { 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) { solution2 = Clipper.OffsetPolygons(solution, (double)nudOffset.Value * scale, JoinType.jtMiter); } else { solution2 = new Polygons(solution); } foreach (Polygon pg in solution2) { PointF[] pts = PolygonToPointFArray(pg, scale); if (pts.Count() > 2) { path.AddPolygon(pts); } pts = null; } myBrush.Color = Color.FromArgb(127, 0x66, 0xEF, 0x7F); myPen.Color = Color.FromArgb(255, 0, 0x33, 0); myPen.Width = 1.0f; newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //now do some fancy testing ... Font f = new Font("Arial", 8); SolidBrush b = new SolidBrush(Color.Navy); double subj_area = 0, clip_area = 0, int_area = 0, union_area = 0; c.Clear(); c.AddPolygons(subjects, PolyType.ptSubject); c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) { subj_area += Clipper.Area(pg); } c.Clear(); c.AddPolygons(clips, PolyType.ptClip); c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) { clip_area += Clipper.Area(pg); } c.AddPolygons(subjects, PolyType.ptSubject); c.Execute(ClipType.ctIntersection, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) { int_area += Clipper.Area(pg); } c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) { union_area += Clipper.Area(pg); } StringFormat lftStringFormat = new StringFormat(); lftStringFormat.Alignment = StringAlignment.Near; lftStringFormat.LineAlignment = StringAlignment.Near; StringFormat rtStringFormat = new StringFormat(); rtStringFormat.Alignment = StringAlignment.Far; rtStringFormat.LineAlignment = StringAlignment.Near; Rectangle rec = new Rectangle(pictureBox1.ClientSize.Width - 108, pictureBox1.ClientSize.Height - 116, 104, 106); newgraphic.FillRectangle(new SolidBrush(Color.FromArgb(196, Color.WhiteSmoke)), rec); newgraphic.DrawRectangle(myPen, rec); rec.Inflate(new Size(-2, 0)); newgraphic.DrawString("Areas", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 14)); newgraphic.DrawString("subj: ", f, b, rec, lftStringFormat); newgraphic.DrawString((subj_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("clip: ", f, b, rec, lftStringFormat); newgraphic.DrawString((clip_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("intersect: ", f, b, rec, lftStringFormat); newgraphic.DrawString((int_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("s + c - i: ", f, b, rec, lftStringFormat); newgraphic.DrawString(((subj_area + clip_area - int_area) / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("union: ", f, b, rec, lftStringFormat); newgraphic.DrawString((union_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); } //end if succeeded } //end if something to clip pictureBox1.Image = mybitmap; newgraphic.Dispose(); Cursor.Current = Cursors.Default; }
public void redraw() { canvas.Children.Clear(); if (rooms.Count == 0 && decoration.Count == 0) { return; } c.Clear(); Polygons outline = new Polygons(); c.AddPolygons(rooms, PolyType.ptSubject); c.AddPolygons(decoration, PolyType.ptSubject); c.Execute(ClipType.ctUnion, outline, PolyFillType.pftNonZero, PolyFillType.pftNonZero); outline = Clipper.OffsetPolygons(outline, 10, JoinType.jtMiter); // Bevel inside corners of the outline foreach (Polygon p in outline) { // Skip holes if (!Clipper.Orientation(p)) { continue; } // Find the inside corners List <bool> corners = new List <bool>(); for (int j = 0; j < p.Count; ++j) { int i = (j + p.Count - 1) % p.Count; int k = (j + 1) % p.Count; IntPoint e1 = new IntPoint(p[j].X - p[i].X, p[j].Y - p[i].Y); IntPoint e2 = new IntPoint(p[j].X - p[k].X, p[j].Y - p[k].Y); int a = (int)(e1.X * e2.Y - e2.X * e1.Y); corners.Add(a > 0); } // Bevel them to the midpoints of the original lines for (int j = 0; j < p.Count; ++j) { int i = (j + p.Count - 1) % p.Count; int k = (j + 1) % p.Count; if (corners[j]) { if (!corners[i]) { corners.Insert(j, true); p.Insert(j, new IntPoint((p[i].X + p[j].X) / 2, (p[i].Y + p[j].Y) / 2)); ++j; ++k; } p[j] = new IntPoint((p[j].X + p[k].X) / 2, (p[j].Y + p[k].Y) / 2); } } } foreach (Polygon p in rooms) { canvas.Children.Add(ToSystemPolygon(p)); } foreach (Polygon p in outline) { canvas.Children.Add(ToSystemPolygon(p, Brushes.Yellow)); } UpdateLayout(); }
private static unsafe bool ApplyFog(Bitmap fog, int delta, params FogUpdate[] fogUpdates) { if (fog == null || fogUpdates == null || !fogUpdates.Any()) { return(false); } var isInwards = (delta < 0); var anyComplete = false; // TODO: Look into a better way to handle multiple fog updates at the same time? foreach (var fogUpdate in fogUpdates) { var points = fogUpdate.Points; var isAddingFog = !fogUpdate.IsClearing; var pointPolygon = new List <IntPoint>(points.Select(x => new IntPoint(x.X, x.Y))); var pointPolygons = new List <List <IntPoint> >() { pointPolygon }; var offsetPolygons = Clipper.OffsetPolygons(pointPolygons, delta, JoinType.jtRound); // If our offset was simply too large to have an offset polygon, we'll change it (towards 0) // until we find one. If we never do, we'll just do direct drawing as the shape is too small for alpha fading. var retryDelta = delta; if (isInwards) { // Inwards means the delta is negative (to make the fog go inwards), so we'll add to it to get it to -1. while (offsetPolygons.Count == 0 && retryDelta != -1) { // The last iteration will end up with retryDelta set to 1, which will cause the smallest offset polygon to be generated. retryDelta = Math.Min(-1, retryDelta + DnDMapConstants.FogAlphaEffectRetryDelta); offsetPolygons = Clipper.OffsetPolygons(pointPolygons, retryDelta, JoinType.jtRound); } } // If we still don't have any offset polygon, then the size must just be too small so we'll draw it using the direct method instead. if (offsetPolygons.Count == 0) { anyComplete |= ApplyFogDirect(fog, fogUpdates); continue; } var offsetPoints = offsetPolygons[0].Select(x => new SimplePoint((int)x.X, (int)x.Y)).ToArray(); // When we're doing inwards delta, the offsetPoints shape is smaller than the points shape. // Therefore, we'll flip the variables to pretend that the user drew the smaller shape. if (isInwards) { var p = points; points = offsetPoints; offsetPoints = p; } var boundingBoxBuffered = GetBoundingBox(fog, offsetPoints, 4); var boundingBox = GetBoundingBox(fog, points, 0); var bmd = fog.LockBits(boundingBoxBuffered, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); int pixelSize = 4; Parallel.For(0, bmd.Height, (y) => { var row = (byte *)bmd.Scan0 + (y * bmd.Stride); for (var x = 0; x < bmd.Width; x++) { var offsetX = x + boundingBoxBuffered.X; var offsetY = y + boundingBoxBuffered.Y; if (isAddingFog) { // If the pixel is already opaque, then we'll skip it if (row[x * pixelSize + 3] == 255) { continue; } } else { // If the pixel is already transparent, then we'll hide it if (row[x * pixelSize + 3] == 0) { continue; } } // When going outwards, we reveal everything in the points (the actual drawn polygon) // we partially reveal anything in the offset polygons // When going inwards, we reveal anythign in the offset points (an inner polygon) // we partially reveal anything in the actual polygon // This is handled by flipping the points and offsetPoints variables above. if (IsPointInPolygon(points, offsetX, offsetY)) { row[x * pixelSize + 3] = (byte)(isAddingFog ? 255 : 0); } else if (IsPointInPolygon(offsetPoints, offsetX, offsetY)) { var testPoint = new SimplePoint(offsetX, offsetY); var dist = LineToPointDistance2D(points[0], points[1], testPoint); for (int i = 0, j = points.Length - 1; i < points.Length; j = i++) { var newDist = LineToPointDistance2D(points[j], points[i], testPoint); if (newDist < dist) { dist = newDist; } } var alpha = (255 - 5.5 * dist); alpha = Math.Max(Math.Floor(alpha), 0); if (isAddingFog) { alpha = Math.Min(alpha + row[x * pixelSize + 3], 255); } else { alpha = Math.Max(row[x * pixelSize + 3] - alpha, 0); } row[x * pixelSize + 3] = (byte)(alpha); } } }); fog.UnlockBits(bmd); anyComplete = true; } return(anyComplete); }