public override GeneralConic2d ToGeneralConic() { Transform2d tr = Transform2d.Scale(MajorRadius) * Transform2d.Rotate(Rotation) * Transform2d.Translate(center.X, center.Y); GeneralConic2d elcon = new GeneralConic2d(1, 0, 1.0 / (sigratio * sigratio), 0, 0, -1); //x^2+(1/b)^2-1=0 => unit ellipse elcon.Transform(tr); //transform conic to position of ellipse return(elcon); //TODO: optimize this function }
public override GeneralConic2d ToGeneralConic() { Transform2d tr = Transform2d.Rotate(rotation) * Transform2d.Translate(vertex.X, vertex.Y); GeneralConic2d res = new GeneralConic2d(a, 0, 0, 0, -1, 0); //y=ax^2 res.Transform(tr); return(res); //TODO: optimize this function }
public GeneralConic2d(GeneralConic2d tocopy) { a = tocopy.a; b = tocopy.b; c = tocopy.c; d = tocopy.d; e = tocopy.e; f = tocopy.f; }
public override GeneralConic2d ToGeneralConic() { //TODO: test this function Transform2d tr = Transform2d.Scale(majoraxis.Length) * Transform2d.Rotate(Rotation) * Transform2d.Translate(center.X, center.Y); GeneralConic2d hypcon = new GeneralConic2d(1, 0, -1.0 / (ratio * ratio), 0, 0, -1); //x^2-(y/b)^2-1=0 => unit hypcon.Transform(tr); return(hypcon); //TODO: optimize this function }
public static Point2d[] ParabolaHyperbola(Parabola2d pab, Hyperbola2d hyp) //tested ok { Transform2d tr = pab.ToStandardPosition; //y=x^2 hyp = new Hyperbola2d(hyp); //copy for transformation hyp.Transform(tr); //to standard space of parabola for stabillity GeneralConic2d gencon = hyp.ToGeneralConic(); var ptset = StandardPosParabolaGeneralConic(gencon); ptset.Transform(tr.Inversed); return(ptset.ToArray()); }
/*private static Point2d[] ConicStandardPosLine(GeneralConic2d con, Line2d lin) * { * return LineParamsToPoints(ConicStandardPosLineParametric(con, lin), lin, double.NegativeInfinity, double.PositiveInfinity); * }*/ public static Point2d[] ConicLine(GeneralConic2d con, Line2d lin) { return(LineParamsToPoints(ConicLineParametric(con, lin), lin, double.NegativeInfinity, double.PositiveInfinity)); /* * Transform2d tr = con.ToStandardPosition; * * GeneralConic2d stdcon=new GeneralConic2d(con); * Line2d stdlin=new Line2d(lin); * stdcon.Transform(tr); * stdlin.Transform(tr); * * double[] ts=ConicStandardPosLineParametric(stdcon,stdlin); * * return LineParamsToPoints(ts, lin, double.NegativeInfinity, double.PositiveInfinity);*/ }
/// <summary> /// Intersects a general conic with the curve y=x^2, returning a point set (possibly empty). /// This function is used as a helper function for parabola dominant intersection functions. /// </summary> private static Point2dSet StandardPosParabolaGeneralConic(GeneralConic2d con) //tested ok //c*x^4+b*x^3+(e+a)*x^2+d*x+f { Point2dSet res = new Point2dSet(); double[] xs = GetRealRoots(con.C, con.B, con.E + con.A, con.D, con.F); if (xs == null) { return(res); //no solutions } foreach (double x in xs) { double tx = x; double ty = x * x; res.Add(new Point2d(tx, ty)); } return(res); }
public static Point2d[] HyperbolaEllipse(Hyperbola2d hyp, Ellipse2d elp) { //TODO: this is probably more stable intersecting hyperbola with unitcircle. Rewrite. Transform2d tr = hyp.ToStandardPosition; hyp = new Hyperbola2d(hyp); elp = new Ellipse2d(elp); hyp.Transform(tr); elp.Transform(tr); GeneralConic2d hcon = new GeneralConic2d(1, 0.0, -1 / (hyp.B * hyp.B), 0.0, 0.0, -1); Point2dSet pset = new Point2dSet(); pset.AddRange(ConicConic(hcon, elp.ToGeneralConic())); pset.Transform(tr.Inversed); return(pset.ToArray()); }
public static Point2d[] EllipseEllipse2(Ellipse2d elp1, Ellipse2d elp2) { //TODO: check if this is better than EllipseEllipse in stabillity and replace it or remove this function Transform2d tr = elp1.ToStandardPosition; elp2 = new Ellipse2d(elp2); //dont alter the original ellipse elp2.Transform(tr); elp1 = new Ellipse2d(elp1); elp1.Transform(tr); GeneralConic2d con1 = new GeneralConic2d(1.0, 0.0, 1 / (elp1.Ratio * elp1.Ratio), 0.0, 0.0, -1.0); GeneralConic2d con2 = elp2.ToGeneralConic(); // GeneralConic2d.FromEllipse(elp2); Point2dSet pset = new Point2dSet(); pset.AddRange(ConicConic(con1, con2)); pset.Transform(tr.Inversed); return(pset.ToArray()); }
/// <summary> /// Intersect a hyperbola in standard position (a=1.0) with a general conic. /// Helper function for other hyperbola intersection functions. /// </summary> /// <param name="hyp1_b"></param> /// <param name="hyp2"></param> private static Point2dSet StdHyperbolaConic(double b1, Conic2d con) { double R = 1.0 / (b1 * b1); Point2dSet res = new Point2dSet(); GeneralConic2d gc = con.ToGeneralConic(); double A = gc.A, B = gc.B, C = gc.C, D = gc.D, E = gc.E, F = gc.F; double y4 = A * A * R * R + (2 * A * C - B * B) * R + C * C; double y3 = (2 * A * E - 2 * B * D) * R + 2 * C * E; double y2 = (-D * D + 2 * A * A + 2 * F * A) * R + E * E + (2 * A + 2 * F) * C - B * B; double y1 = (2 * A + 2 * F) * E - 2 * B * D; double y0 = A * A + 2 * F * A + F * F - D * D; double[] ys = GetRealRoots(y4, y3, y2, y1, y0); if (ys == null) { return(null); } foreach (double y in ys) { //two possible x for each y. Try to find the correct one: double x = Math.Sqrt(y * y * R + 1); double nx = -x; double err = A * x * x + B * x * y + C * y * y + D * x + E * y + F; double nerr = A * nx * nx + B * nx * y + C * y * y + D * nx + E * y + F; if (Math.Abs(err) < Math.Abs(nerr)) { res.Add(new Point2d(x, y)); } else { res.Add(new Point2d(nx, y)); } } return(res); }
/// <summary> /// Intersects a line with a conic that is in standard position, that is, not rotated and /// centered at 0,0 /// </summary> /// <param name="con"></param> /// <param name="lin"></param> /// <returns>A list of parameters on line that is intersection points, or null if no intersections</returns> private static double[] ConicLineParametric(GeneralConic2d con, Line2d lin) { //We construct a matrix so that: conic is unrotated (B term=0) and line starts at origo and has length=1.0 //This is to improve stabillity of the equation double invlen = 1.0 / lin.Length; if (double.IsInfinity(invlen)) { return(null); //zero length line does not intersect } Transform2d tr = Transform2d.Translate(-lin.X1, -lin.Y1) * Transform2d.Rotate(-con.Rotation) * Transform2d.Scale(invlen); GeneralConic2d c = new GeneralConic2d(con); //copy for modification double x1 = lin.X2, y1 = lin.Y2; c.Transform(tr); tr.Apply(x1, y1, out x1, out y1, true); //transformed line end double t2 = y1 * y1 * c.C + x1 * x1 * c.A; double t1 = y1 * c.E + x1 * c.D; double t0 = c.F; double[] ts = RealPolynomial.SolveQuadric(t2, t1, t0); return(ts); /*double dx=lin.DX; * double dy=lin.DY; * double x0=lin.X1; * double y0=lin.Y1; * * double t2=con.C*dy*dy+con.A*dx*dx; * double t1=2*con.C*dy*y0+2*con.A*dx*x0+dy*con.E+con.D*dx; * double t0=con.C*y0*y0+con.E*y0+con.A*x0*x0+con.D*x0+con.F; * * return RealPolynomial.SolveQuadric(t2, t1, t0, 1e-9);*/ }
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()); }
/// <summary> /// Gets the line geometries, one or two lines. The type of the conic has to be /// Intersecting lines (2 results), Paralell lines (2 results) or Coincident lienes (1 result), /// otherwise the result is null. /// </summary> /// <returns></returns> public Line2d[] ToLines() { // Inspired by line extraction conmat.c from book Graphics Gems V double xx, yy; ConicType type = Type; Line2d tmplin; Transform2d tr; GeneralConic2d cpy; List <Line2d> res = null; double de = B * B * 0.25 - A * C; if (MathUtil.IsZero(A) && MathUtil.IsZero(B) && MathUtil.IsZero(C)) { //single line // compute endpoints of the line, avoiding division by zero res = new List <Line2d>(); if (Math.Abs(d) > Math.Abs(e)) { res.Add(new Line2d(-f / (d), 0.0, -(e + f) / (d), 1.0)); } else { res.Add(new Line2d(0.0, -f / (e), 1.0, -(d + f) / (e))); } } else { // two lines cpy = new GeneralConic2d(this); double a = cpy.a, b = cpy.b * 0.5, c = cpy.c, d = cpy.d * 0.5, e = cpy.e * 0.5, f = cpy.f; //get matrix coefficient // use the expression for phi that takes atan of the smallest argument double phi = (Math.Abs(b + b) < Math.Abs(a - c) ? Math.Atan((b + b) / (a - c)) : MathUtil.Deg360 - Math.Atan((a - c) / (b + b))) / 2.0; //phi = cpy.Rotation; if (MathUtil.IsZero(de)) { //parallel lines tr = Transform2d.Rotate(-phi); cpy.Transform(tr); a = cpy.A; b = cpy.B * 0.5; c = cpy.c; d = cpy.d * 0.5; e = cpy.e * 0.5; f = cpy.f; //get matrix coefficient if (Math.Abs(c) < Math.Abs(a)) // vertical { double[] xs = RealPolynomial.SolveQuadric(a, d, f); if (xs != null) { res = new List <Line2d>(); foreach (double x in xs) { tmplin = new Line2d(x, -1, x, 1); tmplin.Transform(tr.Inversed); //back to original spacxe res.Add(tmplin); } } } else //horizontal { double[] ys = RealPolynomial.SolveQuadric(c, e, f, 0.0); if (ys != null) { res = new List <Line2d>(); foreach (double y in ys) { tmplin = new Line2d(-1, y, 1, y); tmplin.Transform(tr.Inversed); res.Add(tmplin); } } } } //end parallel lines case else { //crossing lines Point2d center = Center; double rot = this.Rotation; tr = Transform2d.Translate(-center.X, -center.Y) * Transform2d.Rotate(-rot); cpy.Transform(tr); a = cpy.A; b = cpy.B * 0.5; c = cpy.c; d = cpy.c * 0.5; e = cpy.e * 0.5; f = cpy.f; res = new List <Line2d>(); xx = Math.Sqrt(Math.Abs(1.0 / a)); yy = Math.Sqrt(Math.Abs(1.0 / c)); tr = tr.Inversed; tmplin = new Line2d(-xx, -yy, xx, yy); tmplin.Transform(tr); res.Add(tmplin); tmplin = new Line2d(new Line2d(-xx, yy, xx, -yy)); tmplin.Transform(tr); res.Add(tmplin); } //end crossing lines case } //end two lines if (res == null || res.Count == 0) { return(null); } return(res.ToArray()); }