private void getFirstDerivative(int index) { firstDerivative = new dPoint( (usedPoints[index + 1].X - usedPoints[index].X) / epszilon, (usedPoints[index + 1].Y - usedPoints[index].Y) / epszilon ); }
public void drawCircle(dPoint center, double radius) { Point centerPoint = drawCenterOfCurvature(center); int scaledRadius = (int)(scale * radius); graphics.DrawEllipse(new Pen(Color.Coral), centerPoint.X - scaledRadius, centerPoint.Y - scaledRadius, scaledRadius * 2, scaledRadius * 2); }
private void getSecondDerivative(int index) { secondDerivative = new dPoint( (usedPoints[index + 1].X - (2 * usedPoints[index].X) + usedPoints[index - 1].X) / Math.Pow(epszilon, 2), (usedPoints[index + 1].Y - (2 * usedPoints[index].Y) + usedPoints[index - 1].Y) / Math.Pow(epszilon, 2) ); }
private int closestPoint(Point p) { int resultIndex = 0; double deltaX = usedPoints.First().X - p.X; double deltaY = usedPoints.First().Y - p.Y; double minDistance = Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)); for (int i = 1; i < usedPoints.Count; i++) { deltaX = usedPoints.ElementAt(i).X - p.X; deltaY = usedPoints.ElementAt(i).Y - p.Y; double newDistance = Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)); if (newDistance < minDistance) { minDistance = newDistance; resultIndex = i; closest = new dPoint(usedPoints[i].X, usedPoints[i].Y); } } return(resultIndex); }
private void calcCentreOfCurvate(int index) { G_S_ortogonalization(); centerOfCurvature = new dPoint ( usedPoints[index].X + radiusOfCurvature * ortogonalizedSecondDerivative.X, usedPoints[index].Y + radiusOfCurvature * ortogonalizedSecondDerivative.Y ); Console.WriteLine("Görbületi középpont: (" + centerOfCurvature.X + "," + centerOfCurvature.Y + ")"); }
public Point drawCenterOfCurvature(dPoint centerOfCurvature) { Point centerPoint = new Point ( origo.X + (int)(scale * centerOfCurvature.X), origo.Y - (int)(scale * centerOfCurvature.Y) ); graphics.DrawEllipse(new Pen(Color.Black), centerPoint.X - 1, centerPoint.Y - 1, 4, 4); return(centerPoint); }
public void drawCircle(dPoint center, double radius, Image img, Boolean b, Boolean centerOnly) { if (!b) { refresh(img); } Point centerPoint = drawCenterOfCurvature(center); int scaledRadius = (int)(scale * radius); if (!centerOnly) { graphics.DrawEllipse(new Pen(Color.Coral), centerPoint.X - scaledRadius, centerPoint.Y - scaledRadius, scaledRadius * 2, scaledRadius * 2); } }
public static dPoint GetAvg(dPoint[] points) { dPoint sum = new dPoint(0, 0); if (points == null || points.Length == 0) { return(sum); } for (int i = 0; i < points.Length; i++) { sum += points[i]; } sum /= points.Length; return(sum); }
static bool GetCurrentDirection(Contour c2) { double s1 = 0; double s2 = 0; int index = 0; while (s1 == 0 || s2 == 0) { if (index + 2 >= c2.point.Length) { break; } dPoint p1 = new dPoint((double)c2.point[index + 0].x, (double)c2.point[index + 0].y); dPoint p2 = new dPoint((double)c2.point[index + 1].x, (double)c2.point[index + 1].y); dPoint p3 = new dPoint((double)c2.point[index + 2].x, (double)c2.point[index + 2].y); s1 = MathUtil.Slope(p1, p2); s2 = MathUtil.Slope(p2, p3); //If σ < τ, the orientation is counterclockwise (left turn) //If σ = τ, the orientation is collinear //If σ > τ, the orientation is clockwise (right turn) if (s1 == 0 || s2 == 0) { index = index + 1; continue; } if (s1 < s2) { return(false); } if (s1 == s2) { index = index + 1; continue; } return(true); } return(true); }
private void G_S_ortogonalization() { double c = secondDerivative.scalar(firstDerivative) / firstDerivative.scalar(firstDerivative); dPoint secondDerivateS = new dPoint ( secondDerivative.X - c * firstDerivative.X, secondDerivative.Y - c * firstDerivative.Y ); double multiplier = 1 / secondDerivateS.euclideanNorm(); ortogonalizedSecondDerivative = new dPoint ( multiplier * secondDerivateS.X, multiplier * secondDerivateS.Y ); }
private void calcCurvature() { normalVector = new dPoint(-firstDerivative.Y, firstDerivative.X); curvature = ((secondDerivative.scalar(normalVector)) / Math.Pow(firstDerivative.euclideanNorm(), 2)); Console.WriteLine("Görbület: " + curvature); if (curvature > 0.0000000000001 || curvature < -0.0000000000001) { radiusOfCurvature = 1 / Math.Abs(curvature); } else { radiusOfCurvature = 0; } Console.WriteLine("Görbületi sugár: " + radiusOfCurvature); }
private void getPoints() { usedPoints.Clear(); string codeX = textBoxX.Text; string codeY = textBoxY.Text; string[] interval = textBoxInt.Text.Split(','); if ((textBoxPoint.Text != ",")) { pont = new Point( int.Parse(textBoxPoint.Text.Split(',')[0]), int.Parse(textBoxPoint.Text.Split(',')[1]) ); } if (interval.Length != 2) { throw new ArgumentException(); } double from = double.Parse(interval[0]); double to = double.Parse(interval[1]); dPoint bufferPoint = new dPoint(stringToFunction(codeX, from), stringToFunction(codeY, from)); usedPoints.Add(bufferPoint); for (double i = from + 0.1; i < to; i += epszilon) { dPoint nextPoint = new dPoint((stringToFunction(codeX, i)), (stringToFunction(codeY, i))); usedPoints.Add(nextPoint); bufferPoint = nextPoint; } }
public static double GetDist(dPoint a, dPoint b) { return(Math.Sqrt((a.Y - b.Y) * (a.Y - b.Y) + (a.X - b.X) * (a.X - b.X))); }
} // @ public void GotoXYZ(dPoint x, dPoint y, dPoint z, bool KeepRunning) /// <summary> /// Will move the player to the passed destination or stop within a specified time. /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="y">Function returning Y coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> /// <param name="timeOut">Time out in milliseconds</param> public void Goto(dPoint x, dPoint y, dPoint z, bool KeepRunning, int timeOut) { float X = x(); float Y = y(); float Z = z(); // if passed values are all 0's we won't even bother. // because a target we're running to shouldn't be the player WHILE HE'S ZONING if (X == 0.0f && Y == 0.0f && Z == 0.0f) { return; } double Heading = 0.0f; // = HeadingTo(X, Y, Z, HeadingType.Degrees); double PlayerHeading = 0.0f; // = GetPlayerPosHInDegrees(); double Herror = 0.0f; // = HeadingError(PlayerHeading, Heading); DateTime Start = DateTime.Now; // while we're not within our distance tolerance // and // either timeOut is <= 0 (unlimited) or timeOut > 0 and Time since Goto called < timeOut while ((DistanceTo(X, Y, Z) > DistanceTolerance) && ((timeOut <= 0) || ((timeOut > 0) && ((DateTime.Now - Start).TotalMilliseconds) < timeOut))) { // Update X, Y, and Z values X = x(); Y = y(); Z = z(); // if ANY of the values are NOT zero, then we aren't zoning, do something if (X != 0.0f || Y != 0.0f || Z != 0.0f) { if (UseNewMovement) { FFACE.StartRunning(_InstanceID, X, Z); } else { // Force ViewMode to first person otherwise this doesn't make sense SetViewMode(ViewMode.FirstPerson); // Check Heading Error Heading = HeadingTo(X, Y, Z, HeadingType.Degrees); PlayerHeading = GetPlayerPosHInDegrees(); Herror = HeadingError(PlayerHeading, Heading); // if we're out of our heading tolerance if (Math.Abs(Herror) > HeadingTolerance) { // Face proper direction FaceHeading(X, Y, Z); } else if (UseArrowKeysForTurning && (Herror < -(HeadingTolerance / 2.0f))) { _FFACE.Windower.SendKeyPress(KeyCode.NP_Number4); } else if (UseArrowKeysForTurning && (Herror > (HeadingTolerance / 2.0f))) { _FFACE.Windower.SendKeyPress(KeyCode.NP_Number6); } // Moved StartRunning to AFTER the Distance check // to avoid tap-tap-tapping when we're already within distance if (!IsRunning()) { StartRunning(); } } } // Sleep(GotoDelay) milliseconds before next loop System.Threading.Thread.Sleep(GotoDelay); } // @ while (DistanceToPosXZ(X, Z) > DistanceTolerance) if (!KeepRunning) { StopRunning(); } } // @ public void GotoXYZ(dPoint x, dPoint y, dPoint z, bool KeepRunning, int timeOut)
} // @ public void GotoXZ(dPoint x, dPoint z, bool KeepRunning) /// <summary> /// Will move the player to the passed destination or stop within a specified time. /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> /// <param name="timeOut">Time out in milliseconds</param> public void Goto(dPoint x, dPoint z, bool KeepRunning, int timeOut) { Goto(x, () => _FFACE.Player.PosY, z, KeepRunning, timeOut); } // @ public void GotoXZ(dPoint x, dPoint z, bool KeepRunning, int timeOut)
/// <summary> /// Will move the player to the passed destination (will not stop trying) /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="y">Function returning Y coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> public void Goto(dPoint x, dPoint y, dPoint z, bool KeepRunning) { Goto(x, y, z, KeepRunning, -1); }
/// <summary> /// Will move the player to the passed destination (will not stop trying) /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> public void Goto(dPoint x, dPoint z, bool KeepRunning) { Goto(x, () => _FFACE.Player.PosY, z, KeepRunning, -1); }
/* 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 iPoint dorth_infty(dPoint p0, dPoint p2) { iPoint r; r.y = sign(p2.x - p0.x); r.x = -sign(p2.y - p0.y); return r; }
/* 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) { iPoint r = dorth_infty(p0, p2); return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y); }
/* 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; }
/* 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; res.x = a.x + lambda * (b.x - a.x); res.y = a.y + lambda * (b.y - a.y); return res; }
public static Point ToPoint(this dPoint p) { return(new Point(p.x, p.y)); }
public double scalar(dPoint y) { return((X * y.X) + (Y * y.Y)); }
public static double GetK(dPoint a, dPoint b) { return((a.Y - b.Y) / (a.X - b.X)); }
/* 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; /* 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; }
/* 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; }
/* 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 pp, int i, int j, ref dPoint ctr, ref dPoint dir) { /* assume i<j */ int n = pp.pt.Length; SumStruct[] sums = pp.Sums; double x, y, x2, xy, y2; double k; double a, b, c, lambda2, l; 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 - (double)x * x / k) / k; b = (xy - (double)x * y / k) / k; c = (y2 - (double)y * y / k) / k; lambda2 = (a + c + Math.Sqrt((a - c) * (a - c) + 4 * b * b)) / 2; /* larger e.value */ /* now find e.vector for lambda2 */ 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 */ } }
/* 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)); }
public void drawPoint(dPoint point, Color color) { graphics.DrawEllipse(new Pen(color), point.toPoint().X - 3, point.toPoint().Y - 3, 6, 6); }
/* 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 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; } }
/// <summary> /// Will move the player to the passed destination or stop within a specified time. /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> /// <param name="timeOut">Time out in milliseconds</param> public void Goto(dPoint x, dPoint z, bool KeepRunning, int timeOut) { Goto(x, () => _FFACE.Player.PosY, z, KeepRunning, timeOut); }
static void AddCurve(ArrayList Curves, dPoint A, dPoint ControlPointA, dPoint ControlPointB, dPoint B) { // Curves.Add(new Curve(CurveKind.Bezier, A, ControlPointA, ControlPointB, B)); // return; CurveKind Kind; if ((Math.Abs(xprod(new dPoint(ControlPointA.x - A.x, ControlPointA.y - A.y), new dPoint(B.x - A.x, B.y - A.y))) < 0.01) && (Math.Abs(xprod(new dPoint(ControlPointB.x - B.x, ControlPointB.y - B.y), new dPoint(B.x - A.x, B.y - A.y))) < 0.01)) Kind = CurveKind.Line; else Kind = CurveKind.Bezier; /* Curves.Add(new Curve(Kind,A,ControlPointA,ControlPointB,B)); return;*/ if ((Kind == CurveKind.Line)) { if ((Curves.Count > 0) && (((Curve)Curves[Curves.Count - 1]).Kind == CurveKind.Line)) { Curve C = (Curve)Curves[Curves.Count - 1]; if ((Math.Abs(xprod(new dPoint(C.B.x - C.A.x, C.B.y - C.A.y), new dPoint(B.x - A.x, B.y - A.y))) < 0.01) && (iprod(C.B, C.A, B) < 0)) Curves[Curves.Count - 1] = new Curve(Kind, C.A, C.A, C.A, B); else Curves.Add(new Curve(CurveKind.Line, A, ControlPointA, ControlPointB, B)); } else Curves.Add(new Curve(CurveKind.Line, A, ControlPointA, ControlPointB, B)); } else Curves.Add(new Curve(CurveKind.Bezier, A, ControlPointA, ControlPointB, B)); }
/// <summary> /// Will move the player to the passed destination or stop within a specified time. /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="y">Function returning Y coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> /// <param name="timeOut">Time out in milliseconds</param> public void Goto(dPoint x, dPoint y, dPoint z, bool KeepRunning, int timeOut) { float X = x(); float Y = y(); float Z = z(); // if passed values are all 0's we won't even bother. // because a target we're running to shouldn't be the player WHILE HE'S ZONING if (X == 0.0f && Y == 0.0f && Z == 0.0f) { return; } double Heading = 0.0f; // = HeadingTo(X, Y, Z, HeadingType.Degrees); double PlayerHeading = 0.0f; // = GetPlayerPosHInDegrees(); double Herror = 0.0f; // = HeadingError(PlayerHeading, Heading); DateTime Start = DateTime.Now; // while we're not within our distance tolerance // and // either timeOut is <= 0 (unlimited) or timeOut > 0 and Time since Goto called < timeOut while (( DistanceTo(X, Y, Z) > DistanceTolerance ) && ( ( timeOut <= 0 ) || ( ( timeOut > 0 ) && ( ( DateTime.Now - Start ).TotalMilliseconds ) < timeOut ) )) { // Update X, Y, and Z values X = x(); Y = y(); Z = z(); // if ANY of the values are NOT zero, then we aren't zoning, do something if (X != 0.0f || Y != 0.0f || Z != 0.0f) { // Force ViewMode to first person otherwise this doesn't make sense SetViewMode(ViewMode.FirstPerson); // Check Heading Error Heading = HeadingTo(X, Y, Z, HeadingType.Degrees); PlayerHeading = GetPlayerPosHInDegrees(); Herror = HeadingError(PlayerHeading, Heading); // if we're out of our heading tolerance if (Math.Abs(Herror) > HeadingTolerance) { // Face proper direction FaceHeading(X, Y, Z); } else if (UseArrowKeysForTurning && ( Herror < -( HeadingTolerance / 2.0f ) )) { _FFACE.Windower.SendKeyPress(KeyCode.NP_Number4); } else if (UseArrowKeysForTurning && ( Herror > ( HeadingTolerance / 2.0f ) )) { _FFACE.Windower.SendKeyPress(KeyCode.NP_Number6); } // Moved StartRunning to AFTER the Distance check // to avoid tap-tap-tapping when we're already within distance if (!IsRunning()) StartRunning(); } // Sleep(GotoDelay) milliseconds before next loop System.Threading.Thread.Sleep(GotoDelay); } // @ while (DistanceToPosXZ(X, Z) > DistanceTolerance) if (!KeepRunning) StopRunning(); }
/* calculate p1 x p2 */ static double xprod(dPoint p1, dPoint p2) { return p1.x * p2.y - p1.y * p2.x; }
} // @ public void GotoXZ(dPoint x, dPoint z, bool KeepRunning, int timeOut) /// <summary> /// Will move the player to the passed destination (will not stop trying) /// </summary> /// <param name="x">Function returning X coordinate of the destination</param> /// <param name="y">Function returning Y coordinate of the destination</param> /// <param name="z">Function returning Z coordinate of the destination</param> /// <param name="KeepRunning">Whether to keep moving after reaching the destination</param> public void Goto(dPoint x, dPoint y, dPoint z, bool KeepRunning) { Goto(x, y, z, KeepRunning, -1); } // @ public void GotoXYZ(dPoint x, dPoint y, dPoint z, bool KeepRunning)
/// <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; this.B = B; }
/* Apply quadratic form Q to vector w = (w.x,w.y) */ static double quadform(double[,] Q, dPoint w) { double[] v = { w.x, w.y, 1 }; int i, j; double sum = 0; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { sum += v[i] * Q[i, j] * v[j]; } } return sum; }
/* 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 adjust_vertices(Path pp) { int m = pp.po.Length; int[] po = pp.po; iPoint[] pt = pp.pt; int n = pt.Length; int x0 = pt[0].x; int y0 = pt[0].y; dPoint[] ctr = new dPoint[m]; /* ctr[m] */ dPoint[] dir = new dPoint[m]; /* dir[m] */ //quadform_t *q = NULL; /* q[m] */ double[, ,] q = new double[m, 3, 3]; double[] v = new double[3]; double d; int i, j, k, l; dPoint s; pp.Curves = 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]; pointslope(pp, po[i], j, ref ctr[i], ref 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++) { 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, j, 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, l, k] = v[l] * v[k] / d; } } } } /* 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++) { double[,] Q = new double[3, 3]; dPoint w; double dx, dy; double det; double min, cand; /* minimum and candidate for minimum of quad. form */ double xmin, ymin; /* coordinates of minimum */ int z; /* 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[l, k] = q[j, l, k] + q[i, l, k]; } } while (true) { /* minimize the quadratic form Q on the unit square */ /* find intersection */ det = Q[0, 0] * Q[1, 1] - Q[0, 1] * Q[1, 0]; if (det != 0.0) { w.x = (-Q[0, 2] * Q[1, 1] + Q[1, 2] * Q[0, 1]) / det; w.y = (Q[0, 2] * Q[1, 0] - Q[1, 2] * Q[0, 0]) / det; break; } /* matrix is singular - lines are parallel. Add another, orthogonal axis, through the center of the unit square */ if (Q[0, 0] > Q[1, 1]) { v[0] = -Q[0, 1]; v[1] = Q[0, 0]; } else if (Q[1, 1] != 0) // nur if (Q[1,1]) { v[0] = -Q[1, 1]; v[1] = Q[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[l, k] += v[l] * v[k] / d; } } } dx = Math.Abs(w.x - s.x); dy = Math.Abs(w.y - s.y); if (dx <= .5 && dy <= .5) { // - 1 because we have a additional border set to the bitmap pp.Curves.vertex[i].x = w.x + x0; pp.Curves.vertex[i].y = 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[0, 0] == 0.0) { goto fixx; } for (z = 0; z < 2; z++) { /* value of the y-coordinate */ w.y = s.y - 0.5 + z; w.x = -(Q[0, 1] * w.y + Q[0, 2]) / Q[0, 0]; dx = Math.Abs(w.x - s.x); cand = quadform(Q, w); if (dx <= .5 && cand < min) { min = cand; xmin = w.x; ymin = w.y; } } fixx: if (Q[1, 1] == 0.0) { goto corners; } for (z = 0; z < 2; z++) { /* value of the x-coordinate */ w.x = s.x - 0.5 + z; w.y = -(Q[1, 0] * w.x + Q[1, 2]) / Q[1, 1]; dy = Math.Abs(w.y - s.y); cand = quadform(Q, w); if (dy <= .5 && cand < min) { min = cand; xmin = w.x; ymin = w.y; } } corners: /* 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; } } } // - 1 because we have a additional border set to the bitmap pp.Curves.vertex[i].x = xmin + x0 - 1; pp.Curves.vertex[i].y = ymin + y0 - 1; continue; } }