public Point2d[] Perpendicular(Point2d from) { double i, j; //i,j is from-point in standard space Transform2d tr = ToStandardPosition; tr.Apply(from.X, from.Y, out i, out j, true); //cubic coefficients gotten from langarnge multiplier minimizing distance from i,j to curve double[] xs = RealPolynomial.SolveCubic2(-1, 0.0, j - 0.25, 0.25 * i); if (xs == null) { return(null); } Point2d[] res = new Point2d[xs.Length]; tr = tr.Inversed; int respos = 0; foreach (double x in xs) { tr.Apply(x, x * x, out i, out j, true); res[respos++] = new Point2d(i, j); } return(res); }
public static Point2d[] ConicConic(GeneralConic2d tcon1, GeneralConic2d tcon2) { // uses the beautiful solution to find the multiplier λ, so that Conic11+λ*Conic2 is // a degenerate conic, that is a conic of lines (the 'pencil'). The lines in this conic // intersects each of the conics in their common intersection points, thus the problem // has been reduced to a Conic-Line intersection problem. // This technique is described in book Graphics Gems V, of which we are inspired although // this code differs a somewhat from the one in the book. // work in standard space for conic 1, gives a more stable computation and speeds up // the multiple line-conic intersections later on. GeneralConic2d con1 = new GeneralConic2d(tcon1); GeneralConic2d con2 = new GeneralConic2d(tcon2); //TODO: does not work properly, probably because line extractor does not work correctly in some cases //convert conic coefficients to their matrix form double a = con1.A, b = con1.B * 0.5, c = con1.C, d = con1.D * 0.5, e = con1.E * 0.5, f = con1.F; double A = con2.A, B = con2.B * 0.5, C = con2.C, D = con2.D * 0.5, E = con2.E * 0.5, F = con2.F; //TODO: since conic 1 is in standard position, thoose can be simplified: b,d,e terms are always zero double c3 = (A * C - B * B) * F - A * E * E + 2 * B * D * E - C * D * D; double c2 = (a * C - 2 * b * B + c * A) * F - a * E * E + (2 * b * D + 2 * d * B - 2 * e * A) * E - c * D * D + (2 * e * B - 2 * d * C) * D + f * A * C - f * B * B; double c1 = (a * c - b * b) * F + (2 * b * d - 2 * a * e) * E + (2 * b * e - 2 * c * d) * D + (a * f - d * d) * C + (2 * d * e - 2 * b * f) * B + (c * f - e * e) * A; double c0 = (a * c - b * b) * f - a * e * e + 2 * b * d * e - c * d * d; double[] lambdas2 = RealPolynomial.SolveCubic2(c3, c2, c1, c0); //up to three coefficients that will turn conic sum to degenerate lines double[] lambdas = GetRealRoots(c3, c2, c1, c0); if (lambdas == null) { return(null); //this can never happen on a 3d degree equation but we check it anyway } Point2dSet res = new Point2dSet(); foreach (double lambda in lambdas) { GeneralConic2d pencil = new GeneralConic2d( a + lambda * A, (b + lambda * B) * 2, c + lambda * C, (d + lambda * D) * 2, (e + lambda * E) * 2, f + lambda * F); Line2d[] lines = pencil.ToLines(); if (lines != null) { foreach (Line2d lin in lines) { //max 2 lines Point2d[] intpts = ConicLine(con1, lin); if (intpts == null) { continue; } //validate each point satisfying the conic equations (they can be out of range for finite conics such as ellipses) foreach (Point2d pt in intpts) { double x = pt.X; double y = pt.Y; double err1 = con1.A * x * x + con1.B * x * y + con1.C * y * y + con1.D * x + con1.E * y + con1.F; if (MathUtil.IsZero(err1, 5.0)) { double err2 = con2.A * x * x + con2.B * x * y + con2.C * y * y + con2.D * x + con2.E * y + con2.F; if (MathUtil.IsZero(err2, 5.0)) { res.Add(pt); } } } } } } //res.Transform(tr.Inversed); return(res.ToArray()); }