void tracetoList(List <List <Curve> > ListOfPathes) { if (ListOfPathes == null) { return; } for (int i = 0; i < pathlist.Count; i++) { Path P = pathlist[i]; List <Curve> CurveList = new List <Curve>(); ListOfPathes.Add(CurveList); dPoint L = P.curve.c[(P.curve.n - 1) * 3 + 2]; for (int j = 0; j < P.curve.n; j++) { dPoint A = P.curve.c[j * 3 + 1]; dPoint B = P.curve.c[j * 3 + 2]; if (P.curve.tag[j] == POTRACE_CORNER) { CurveList.Add(new Curve(CurveKind.Line, L, L, A, A)); CurveList.Add(new Curve(CurveKind.Line, A, A, B, B)); } else { dPoint CP = P.curve.c[j * 3]; CurveList.Add(new Curve(CurveKind.Bezier, L, CP, A, B)); } L = B; } } }
/* range over the straight line segment [a,b] when lambda ranges over [0,1] */ static dPoint interval(double lambda, dPoint a, dPoint b) { dPoint res = new dPoint(); res.X = a.X + lambda * (b.X - a.X); res.Y = a.Y + lambda * (b.Y - a.Y); return(res); }
/// <summary> /// Creates a curve /// </summary> /// <param name="Kind"></param> /// <param name="A">Startpoint</param> /// <param name="ControlPointA">Controlpoint</param> /// <param name="ControlPointB">Controlpoint</param> /// <param name="B">Endpoint</param> public Curve(CurveKind Kind, dPoint A, dPoint ControlPointA, dPoint ControlPointB, dPoint B) { this.Kind = Kind; this.A = A; this.B = B; this.ControlPointA = ControlPointA; this.ControlPointB = ControlPointB; }
/* return a direction that is 90 degrees counterclockwise from p2-p0, * but then restricted to one of the major wind directions (n, nw, w, etc) */ static dPoint dorth_infty(dPoint p0, dPoint p2) { dPoint r = new dPoint(); r.Y = sign(p2.X - p0.X); r.X = -sign(p2.Y - p0.Y); return(r); }
/* calculate (p1-p0)*(p3-p2) */ static double iprod1(dPoint p0, dPoint p1, dPoint p2, dPoint p3) { double x1, y1, x2, y2; x1 = p1.X - p0.X; y1 = p1.Y - p0.Y; x2 = p3.X - p2.X; y2 = p3.Y - p2.Y; return(x1 * x2 + y1 * y2); }
/* calculate (p1-p0)x(p3-p2) */ static double cprod(dPoint p0, dPoint p1, dPoint p2, dPoint p3) { double x1, y1, x2, y2; x1 = p1.X - p0.X; y1 = p1.Y - p0.Y; x2 = p3.X - p2.X; y2 = p3.Y - p2.Y; return(x1 * y2 - x2 * y1); }
/* return (p1-p0)x(p2-p0), the area of the parallelogram */ static double dpara(dPoint p0, dPoint p1, dPoint p2) { double x1, y1, x2, y2; x1 = p1.X - p0.X; y1 = p1.Y - p0.Y; x2 = p2.X - p0.X; y2 = p2.Y - p0.Y; return(x1 * y2 - x2 * y1); }
/* calculate point of a bezier curve */ static dPoint bezier(double t, dPoint p0, dPoint p1, dPoint p2, dPoint p3) { double s = 1 - t; dPoint res = new dPoint(); /* Note: a good optimizing compiler (such as gcc-3) reduces the * following to 16 multiplications, using common subexpression * elimination. */ res.X = s * s * s * p0.X + 3 * (s * s * t) * p1.X + 3 * (t * t * s) * p2.X + t * t * t * p3.X; res.Y = s * s * s * p0.Y + 3 * (s * s * t) * p1.Y + 3 * (t * t * s) * p2.Y + t * t * t * p3.Y; return(res); }
internal static List <List <Curve> > BuildFilling(List <List <Curve> > plist, double spacing, double w, double h, LaserGRBL.RasterConverter.ImageProcessor.Direction dir) { if (dir == LaserGRBL.RasterConverter.ImageProcessor.Direction.NewInsetFilling) { return(BuildInsetFilling(plist, spacing)); } List <List <Curve> > flist = new List <List <Curve> >(); Clipper c = new Clipper(); AddGridSubject(c, spacing, w, h, dir); AddGridClip(plist, c); long t1 = Tools.HiResTimer.TotalMilliseconds; PolyTree solution = new PolyTree(); bool succeeded = c.Execute(ClipType.ctIntersection, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); long t2 = Tools.HiResTimer.TotalMilliseconds; System.Diagnostics.Debug.WriteLine($"ClipperExecute: {t2 - t1}ms"); //GraphicsPath result = new GraphicsPath(); List <List <IntPoint> > ll = Clipper.OpenPathsFromPolyTree(solution); foreach (List <IntPoint> pg in ll) { PointF[] pts = PolygonToPointFArray(pg, resolution); if (pts.Count() > 2) { ; // result.AddPolygon(pts); } else { dPoint a = new dPoint(pts[0].X, pts[0].Y); dPoint b = new dPoint(pts[1].X, pts[1].Y); flist.Add(new List <Curve>() { new Curve(CurveKind.Line, a, a, b, b) }); } //result.AddLine(pts[0], pts[1]); } flist.Reverse(); return(flist); }
/* Apply quadratic form Q to vector w = (w.x,w.y) */ static double quadform(Quad Q, dPoint w) { double sum = 0; double[] v = new double[3]; v[0] = w.X; v[1] = w.Y; v[2] = 1; sum = 0.0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { sum += v[i] * Q.at(i, j) * v[j]; } } return(sum); }
/* calculate the point t in [0..1] on the (convex) bezier curve * (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no * solution in [0..1]. */ static double tangent(dPoint p0, dPoint p1, dPoint p2, dPoint p3, dPoint q0, dPoint q1) { double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */ double a, b, c; /* a t^2 + b t + c = 0 */ double d, s, r1, r2; A = cprod(p0, p1, q0, q1); B = cprod(p1, p2, q0, q1); C = cprod(p2, p3, q0, q1); a = A - 2 * B + C; b = -2 * A + 2 * B; c = A; d = b * b - 4 * a * c; if (a == 0 || d < 0) { return(-1.0); } s = Math.Sqrt(d); r1 = (-b + s) / (2 * a); r2 = (-b - s) / (2 * a); if (r1 >= 0 && r1 <= 1) { return(r1); } else if (r2 >= 0 && r2 <= 1) { return(r2); } else { return(-1.0); } }
private static List <List <Curve> > ToPotraceList(List <List <IntPoint> > ll, bool close) { List <List <Curve> > flist = new List <List <Curve> >(); foreach (List <IntPoint> pg in ll) { if (pg.Count == 2) { dPoint a = new dPoint(pg[0].X / resolution, pg[0].Y / resolution); dPoint b = new dPoint(pg[1].X / resolution, pg[1].Y / resolution); flist.Add(new List <Curve>() { new Curve(CurveKind.Line, a, a, b, b) }); } else { List <Curve> potcurve = new List <Curve>(); for (int i = 0; i < pg.Count - 1; i++) { dPoint a = new dPoint(pg[i].X / resolution, pg[i].Y / resolution); dPoint b = new dPoint(pg[i + 1].X / resolution, pg[i + 1].Y / resolution); potcurve.Add(new Curve(CurveKind.Line, a, a, b, b)); } if (close) { dPoint a = new dPoint(pg[pg.Count - 1].X / resolution, pg[pg.Count - 1].Y / resolution); dPoint b = new dPoint(pg[0].X / resolution, pg[0].Y / resolution); potcurve.Add(new Curve(CurveKind.Line, a, a, b, b)); } flist.Add(potcurve); } } //flist.Reverse(); return(flist); }
/* ddenom/dpara have the property that the square of radius 1 centered * at p1 intersects the line p0p2 iff |dpara(p0,p1,p2)| <= ddenom(p0,p2) */ static double ddenom(dPoint p0, dPoint p2) { dPoint r = dorth_infty(p0, p2); return(r.Y * (p2.X - p0.X) - r.X * (p2.Y - p0.Y)); }
public static Rg.Point3d ToRhPoint(this Pt.dPoint input, double height) { return(new Rg.Point3d(input.x, height - input.y, 0)); }
/* Stage 3: vertex adjustment (Sec. 2.3.1). */ /* Adjust vertices of optimal polygon: calculate the intersection of * the two "optimal" line segments, then move it into the unit square * if it lies outside. Return 1 with errno set on error; 0 on * success. */ /* calculate "optimal" point-slope representation for each line segment */ static void adjustVertices(Path path) { int m = path.m; int[] po = path.po; int n = path.len; List <Point> pt = path.pt; double x0 = path.x0; double y0 = path.y0; dPoint[] ctr = new dPoint[m]; dPoint[] dir = new dPoint[m]; Quad[] q = new Quad[m]; int i, j, k, l; double[] v = new double[3]; dPoint s = new dPoint(); double d; path.curve = new privcurve(m); /* calculate "optimal" point-slope representation for each line * segment */ for (i = 0; i < m; i++) { j = po[mod(i + 1, m)]; j = mod(j - po[i], n) + po[i]; ctr[i] = new dPoint(); dir[i] = new dPoint(); pointslope(path, po[i], j, ctr[i], dir[i]); } /* represent each line segment as a singular quadratic form; the * distance of a point (x,y) from the line segment will be * (x,y,1)Q(x,y,1)^t, where Q=q[i]. */ for (i = 0; i < m; i++) { q[i] = new Quad(); d = dir[i].X * dir[i].X + dir[i].Y * dir[i].Y; if (d == 0.0) { for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++) { q[i].data[j * 3 + k] = 0; } } } else { v[0] = dir[i].Y; v[1] = -dir[i].X; v[2] = -v[1] * ctr[i].Y - v[0] * ctr[i].X; for (l = 0; l < 3; l++) { for (k = 0; k < 3; k++) { q[i].data[l * 3 + k] = v[l] * v[k] / d; } } } } double dx, dy, det; int z; double xmin, ymin; /* coordinates of minimum */ double min, cand; /* minimum and candidate for minimum of quad. form */ /* now calculate the "intersections" of consecutive segments. * Instead of using the actual intersection, we find the point * within a given unit square which minimizes the square distance to * the two lines. */ for (i = 0; i < m; i++) { Quad Q = new Quad(); dPoint w = new dPoint(); /* let s be the vertex, in coordinates relative to x0/y0 */ s.X = pt[po[i]].X - x0; s.Y = pt[po[i]].Y - y0; /* intersect segments i-1 and i */ j = mod(i - 1, m); /* add quadratic forms */ for (l = 0; l < 3; l++) { for (k = 0; k < 3; k++) { Q.data[l * 3 + k] = q[j].at(l, k) + q[i].at(l, k); } } while (true) { /* minimize the quadratic form Q on the unit square */ /* find intersection */ det = Q.at(0, 0) * Q.at(1, 1) - Q.at(0, 1) * Q.at(1, 0); if (det != 0.0) { w.X = (-Q.at(0, 2) * Q.at(1, 1) + Q.at(1, 2) * Q.at(0, 1)) / det; w.Y = (Q.at(0, 2) * Q.at(1, 0) - Q.at(1, 2) * Q.at(0, 0)) / det; break; } /* matrix is singular - lines are parallel. Add another, * orthogonal axis, through the center of the unit square */ if (Q.at(0, 0) > Q.at(1, 1)) { v[0] = -Q.at(0, 1); v[1] = Q.at(0, 0); } else if (Q.at(1, 1) != 0.0) { v[0] = -Q.at(1, 1); v[1] = Q.at(1, 0); } else { v[0] = 1; v[1] = 0; } d = v[0] * v[0] + v[1] * v[1]; v[2] = -v[1] * s.Y - v[0] * s.X; for (l = 0; l < 3; l++) { for (k = 0; k < 3; k++) { Q.data[l * 3 + k] += v[l] * v[k] / d; } } } dx = Math.Abs(w.X - s.X); dy = Math.Abs(w.Y - s.Y); if (dx <= 0.5 && dy <= 0.5) { path.curve.vertex[i] = new dPoint(w.X + x0, w.Y + y0); continue; } /* the minimum was not in the unit square; now minimize quadratic * on boundary of square */ min = quadform(Q, s); xmin = s.X; ymin = s.Y; if (Q.at(0, 0) != 0.0) { for (z = 0; z < 2; z++) { /* value of the y-coordinate */ w.Y = s.Y - 0.5 + z; w.X = -(Q.at(0, 1) * w.Y + Q.at(0, 2)) / Q.at(0, 0); dx = Math.Abs(w.X - s.X); cand = quadform(Q, w); if (dx <= 0.5 && cand < min) { min = cand; xmin = w.X; ymin = w.Y; } } } if (Q.at(1, 1) != 0.0) { for (z = 0; z < 2; z++) { /* value of the x-coordinate */ w.X = s.X - 0.5 + z; w.Y = -(Q.at(1, 0) * w.X + Q.at(1, 2)) / Q.at(1, 1); dy = Math.Abs(w.Y - s.Y); cand = quadform(Q, w); if (dy <= 0.5 && cand < min) { min = cand; xmin = w.X; ymin = w.Y; } } } /* check four corners */ for (l = 0; l < 2; l++) { for (k = 0; k < 2; k++) { w.X = s.X - 0.5 + l; w.Y = s.Y - 0.5 + k; cand = quadform(Q, w); if (cand < min) { min = cand; xmin = w.X; ymin = w.Y; } } } path.curve.vertex[i] = new dPoint(xmin + x0, ymin + y0); } }
/* calculate p1 x p2 */ static double xprod(dPoint p1, dPoint p2) { return(p1.X * p2.Y - p1.Y * p2.X); }
/* calculate distance between two points */ static double ddist(dPoint p, dPoint q) { return(Math.Sqrt((p.X - q.X) * (p.X - q.X) + (p.Y - q.Y) * (p.Y - q.Y))); }
/* determine the center and slope of the line i..j. Assume i<j. Needs * "sum" components of p to be set. */ static void pointslope(Path path, int i, int j, dPoint ctr, dPoint dir) { int n = path.len; List <Sum> sums = path.sums; double x, y, x2, xy, y2; double a, b, c, lambda2, l; int k = 0; /* assume i<j */ int r = 0; /* rotations from i to j */ while (j >= n) { j -= n; r += 1; } while (i >= n) { i -= n; r -= 1; } while (j < 0) { j += n; r -= 1; } while (i < 0) { i += n; r += 1; } x = sums[j + 1].x - sums[i].x + r * sums[n].x; y = sums[j + 1].y - sums[i].y + r * sums[n].y; x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2; xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy; y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2; k = j + 1 - i + r * n; ctr.X = x / k; ctr.Y = y / k; a = (x2 - x * x / k) / k; b = (xy - x * y / k) / k; c = (y2 - y * y / k) / k; lambda2 = (a + c + Math.Sqrt((a - c) * (a - c) + 4 * b * b)) / 2; /* larger e.value */ a -= lambda2; c -= lambda2; if (Math.Abs(a) >= Math.Abs(c)) { l = Math.Sqrt(a * a + b * b); if (l != 0) { dir.X = -b / l; dir.Y = a / l; } } else { l = Math.Sqrt(c * c + b * b); if (l != 0) { dir.X = -c / l; dir.Y = b / l; } } if (l == 0) { dir.X = dir.Y = 0; /* sometimes this can happen when k=4: * the two eigenvalues coincide */ } }
private static List <List <Curve> > BuildInsetFilling(List <List <Curve> > plist, double spacing) { int loop = 1; bool empty = false; List <List <Curve> > flist = new List <List <Curve> >(); ClipperOffset c = new ClipperOffset(); foreach (List <Curve> LC in plist) { GraphicsPath Current = new GraphicsPath(); for (int j = 0; j < LC.Count; j++) { Curve C = LC[j]; if (C.Kind == CurveKind.Line) { Current.AddLine(new PointF((float)C.A.X, (float)C.A.Y), new PointF((float)C.B.X, (float)C.B.Y)); } else { PointF A = new PointF((float)C.A.X, (float)C.A.Y); Current.AddBezier(new PointF((float)C.A.X, (float)C.A.Y), new PointF((float)C.ControlPointA.X, (float)C.ControlPointA.Y), new PointF((float)C.ControlPointB.X, (float)C.ControlPointB.Y), new PointF((float)C.B.X, (float)C.B.Y)); } } AddClip(c, Current); } while (!empty) { long t1 = Tools.HiResTimer.TotalMilliseconds; List <List <IntPoint> > solution = new List <List <IntPoint> >(); c.Execute(ref solution, -spacing * loop * resolution); loop++; long t2 = Tools.HiResTimer.TotalMilliseconds; System.Diagnostics.Debug.WriteLine($"ClipperExecute: {t2 - t1}ms"); //GraphicsPath result = new GraphicsPath(); if (solution.Count == 0) { empty = true; } foreach (List <IntPoint> pg in solution) { PointF[] pts = PolygonToPointFArray(pg, resolution); if (pts.Count() > 2) { List <Curve> curve = new List <Curve>(); for (int i = 0; i < pts.Length - 1; i++) { dPoint a = new dPoint(pts[i].X, pts[i].Y); dPoint b = new dPoint(pts[i + 1].X, pts[i + 1].Y); curve.Add(new Curve(CurveKind.Line, a, a, b, b)); } //chiudi la figura dPoint a1 = new dPoint(pts[pts.Length - 1].X, pts[pts.Length - 1].Y); dPoint b1 = new dPoint(pts[0].X, pts[0].Y); curve.Add(new Curve(CurveKind.Line, a1, a1, b1, b1)); flist.Add(curve); } else { dPoint a = new dPoint(pts[0].X, pts[0].Y); dPoint b = new dPoint(pts[1].X, pts[1].Y); flist.Add(new List <Curve>() { new Curve(CurveKind.Line, a, a, b, b) }); } //result.AddLine(pts[0], pts[1]); } } return(flist); }
public static Sw.Point ToPoint(this Pt.dPoint input) { return(new Sw.Point(input.x, input.y)); }