bool Perp(Bez2D bez, out Param[] pars) { /* * MEANING: perpendicular to the parametric range * [-Infinity, Infinity] for NON-DEGENERATED, * NON-FLAT bezier */ pars = null; Param parM; if (bez.IsDegen) { throw new ExceptionGMath("VecD", "Perp", null); //return false; } if (bez.IsSeg(out parM) || bez.IsSelfInters(out parM)) { throw new ExceptionGMath("VecD", "Perp", null); //return false; } VecD[] pcf; bez.PowerCoeff(out pcf); double a = 2 * (pcf[2].Dot(pcf[2])); double b = 3 * (pcf[2].Dot(pcf[1])); double c = pcf[1].Dot(pcf[1]) + 2 * ((pcf[0] - (this)).Dot(pcf[2])); double d = (pcf[0] - (this)).Dot(pcf[1]); int numRootReal; double[] root; Equation.RootsReal(a, b, c, d, out numRootReal, out root); pars = new Param[root.Length]; for (int iRoot = 0; iRoot < root.Length; iRoot++) { pars[iRoot] = new Param(root[iRoot]); } return(true); }
// deg 4 public static void RootsReal(double a, double b, double c, double d, double e, out int numRootReal, out double[] root) { /* * Catch EXACT TANGENTS when they are not obvious * from the control points specification */ double rootToAdd = -1.0; // asign an invalid parametric value int numRootRealRed = -1; // roots after reduction double[] rootRed = null; if (Equation.Evaluate(0.0, a, b, c, d, e) == 0.0) { rootToAdd = 0.0; Equation.RootsReal(a, b, c, d, out numRootRealRed, out rootRed); } if (Equation.Evaluate(1.0, a, b, c, d, e) == 0.0) { rootToAdd = 1.0; Equation.RootsReal(a, a + b, a + b + c, a + b + c + d, out numRootRealRed, out rootRed); } if (rootToAdd != -1.0) { root = new double[numRootRealRed + 1]; numRootReal = numRootRealRed + 1; int indToInsert = 0; for (indToInsert = 0; indToInsert < numRootRealRed; indToInsert++) { if (rootToAdd <= rootRed[indToInsert]) { break; } } for (int iRoot = 0; iRoot < indToInsert; iRoot++) { root[iRoot] = rootRed[iRoot]; } root[indToInsert] = rootToAdd; for (int iRoot = indToInsert; iRoot < numRootRealRed; iRoot++) { root[iRoot + 1] = rootRed[iRoot]; } return; // end - catch EXACT TANGENT } if (Math.Abs(a) < MConsts.EPS_DEC) { Equation.RootsReal(b, c, d, e, out numRootReal, out root); } else { numRootReal = 0; root = null; double bb, cc, dd, ee, pp, qq, rr; bb = b / a; cc = c / a; dd = d / a; ee = e / a; // substitution: x = z - bb/4 pp = Equation.Evaluate(bb / 4.0, -6.0, 0, cc); qq = Equation.Evaluate(bb / 4.0, 8.0, 0, -2.0 * cc, dd); rr = Equation.Evaluate(bb / 4.0, -3.0, 0, cc, -dd, ee); // solve C(ubic) R(esolvent) equation (1, 2pp, pp^2-4rr, -q^2) int numRealRootCR, numRootCR; CNum[] rootCR; // the cubic equation is non-degenerated,=> numRootCR = 3 Equation.RootsAll(1.0, 2.0 * pp, pp * pp - 4.0 * rr, -qq * qq, out numRootCR, out numRealRootCR, out rootCR); if (numRootCR == Equation.NumRootInfinite) { throw new ExceptionGMath("Equation", "RootsReal", "Degree 4"); } if (numRealRootCR == 3) // 3 real (not necessarily different) roots of CR { if (rootCR[0].Re >= 0) // 3 real roots of CR; all roots are positive { numRootReal = 4; double sqrt0 = Math.Sqrt(rootCR[0].Re); double sqrt1 = Math.Sqrt(rootCR[1].Re); double sqrt2 = (Math.Sign(qq) != 0) ? Math.Sign(qq) * Math.Sqrt(rootCR[2].Re) : Math.Sqrt(rootCR[2].Re); ArrayList arr = new ArrayList(); arr.Add(-bb / 4.0 + 0.5 * (sqrt0 + sqrt1 - sqrt2)); arr.Add(-bb / 4.0 + 0.5 * (-sqrt0 + sqrt1 + sqrt2)); arr.Add(-bb / 4.0 + 0.5 * (sqrt0 - sqrt1 + sqrt2)); arr.Add(-bb / 4.0 + 0.5 * (-sqrt0 - sqrt1 - sqrt2)); arr.Sort(); root = new double[4]; for (int i = 0; i < 4; i++) { root[i] = (double)arr[i]; } } if ((rootCR[1].Re < 0) && (rootCR[2].Re >= 0)) // 3 real roots of CR; 1 root is positive { if (Math.Abs(rootCR[0].Re - rootCR[1].Re) < MConsts.EPS_DEC) { numRootReal = 2; // double-root root = new double[2]; root[0] = root[1] = -bb / 4.0 - 0.5 * Math.Sqrt(rootCR[2].Re) * Math.Sign(qq); } } } if ((numRealRootCR == 1) && (rootCR[0].Re >= 0)) // 1 real root of CR; the root is positive { numRootReal = 2; double sqrt0 = Math.Sign(qq) * Math.Sqrt(rootCR[0].Re); double sqrt1 = rootCR[1].PrimeRoot(2).Re; root = new double[2]; root[0] = -bb / 4.0 - 0.5 * sqrt0 - sqrt1; root[1] = -bb / 4.0 - 0.5 * sqrt0 + sqrt1; } } }
public static bool AuxIntersectBL(Bez2D bez, LCurve lrs, ListInfoInters linters) { // bezier is irreducable !!! if (linters == null) { throw new ExceptionGMath("Intersect", "AuxIntersectBL(bez,lrs)", "Null argument"); } if (lrs.IsDegen) { throw new ExceptionGMath("Intersect", "AuxIntersectBL(bez,lrs)", null); } Param parM; if (bez.IsSelfInters(out parM)) { if (parM.Val < 0) { Bez2D bezRev = bez.Reversed as Bez2D; int numIntersBefore = linters.Count; if (!Inters.AuxIntersectBL(bezRev, lrs, linters)) { return(false); } linters.ParamReverse(1, 0, numIntersBefore); return(true); } SegD support = bez.SupportFlat(); InfoInters intersSup; if (!Inters.IntersectLL(support, lrs, out intersSup)) { return(false); } if (intersSup == null) { return(true); } /* * convert parameters from support to Bezier */ // invalidate in case of D1 intersection if (intersSup.Dim == InfoInters.TypeDim.Dim1) { (intersSup as IntersD1).ParamInvalidateBezSI(); linters.Add(intersSup); return(true); } // write as 1 or 2 intersections with different parameters // in case of D0 intersections InfoInters[] intersBez; if (!bez.IntersFromSupport(intersSup, 0, out intersBez)) { return(false); } for (int iIntersBez = 0; iIntersBez < intersBez.Length; iIntersBez++) { linters.Add(intersBez[iIntersBez]); } return(true); } // bezier is NOT self/intersecting VecD[] cfLrs, cfBez; lrs.PowerCoeff(out cfLrs); bez.PowerCoeff(out cfBez); VecD norm = lrs.DirNorm; VecD tang = lrs.DirTang; double[] roots; int numRootBez; Equation.RootsReal(cfBez[2].Dot(norm), cfBez[1].Dot(norm), (cfBez[0] - cfLrs[0]).Dot(norm), out numRootBez, out roots); if (numRootBez == Equation.NumRootInfinite) { // bezier is irreducable,=> only D0 intersections are possible throw new ExceptionGMath("Intersect", "AuxIntersectBL(bez,lrs)", null); //return false; } for (int iRoot = 0; iRoot < numRootBez; iRoot++) { Param parBez = roots[iRoot]; if (bez.IsEvaluableStrict(parBez)) { Param parLrs = Equation.Evaluate(parBez.Val, cfBez[2].Dot(tang), cfBez[1].Dot(tang), (cfBez[0] - cfLrs[0]).Dot(tang)) / (cfLrs[1].Dot(tang)); if (lrs.IsEvaluableStrict(parLrs)) { IntersD0 inters = new IntersD0(parBez, parLrs, 0.5 * (lrs.Evaluate(parLrs.Val) + bez.Evaluate(parBez.Val)), false); linters.Add(inters); } } } return(true); }
public static bool AuxIntersectBB(Bez2D bezA, Bez2D bezB, InfoConnect icAB, InfoConnect icBA, ListInfoInters linters) { // bezA and bezB are irreducable !!! bool connectAB = ((icAB != null) && (icAB.IsConnect)); bool connectBA = ((icBA != null) && (icBA.IsConnect)); if ((connectBA) && (!connectAB)) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); } bool connect = connectAB || connectBA; Param parM; bool isSelfIntersA = bezA.IsSelfInters(out parM); bool isSelfIntersB = bezB.IsSelfInters(out parM); if (isSelfIntersA || isSelfIntersB) { BCurve curveA = bezA; if (isSelfIntersA) { curveA = bezA.SupportFlat(); } BCurve curveB = bezB; if (isSelfIntersB) { curveB = bezB.SupportFlat(); } int numIntersBefore = linters.Count; Inters.IntersectBB(curveA, curveB, null, null, linters); /* * CLEAN END-POINT if the curve does not return to it */ if ((connectAB) && (!connectBA)) { bool coversA1 = false; bool coversB0 = false; if (isSelfIntersA) { coversA1 = bezA.CoversEndPoint(false); } if (isSelfIntersB) { coversB0 = bezB.CoversEndPoint(true); } if ((!coversA1) && (!coversB0)) { linters.CleanEndPointBezSI(bezA.End, numIntersBefore); } } linters.ParamInvalidateBezSI(numIntersBefore); return(true); } // test for 1-dimensional intersection of supports bool isB0OnA, isB2OnA; Param paramAInvB0, paramAInvB2; if (!bezB.Cp(0).InverseOn(bezA, out isB0OnA, out paramAInvB0)) { return(false); } if (!bezB.Cp(2).InverseOn(bezA, out isB2OnA, out paramAInvB2)) { return(false); } if ((isB0OnA) && (isB2OnA)) { bool areCoincide = true; Param par; for (int i = 1; i <= 3; i++) { // evaluate bezB at paramaters 1/4, 1/2, 3/4 and check // whether the points lie on bezA [-Infinity,Infinity] VecD pnt = bezB.Evaluate(0.25 * i); if (!pnt.InverseOn(bezA, out areCoincide, out par)) { return(false); } if (!areCoincide) { break; } } if (areCoincide) { Param.TypeParam typeB0 = bezA.ParamClassify(paramAInvB0); Param.TypeParam typeB2 = bezA.ParamClassify(paramAInvB2); int mult = (int)typeB0 * (int)typeB2; if (mult == 4) { return(true); // no intersections } else if (mult == 1) { // bezB is degenerated throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } else if (mult == 2) { // 0-dimentional connection at the end point if ((typeB0 == Param.TypeParam.Start) && (typeB2 == Param.TypeParam.Before)) { if (connect) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } IntersD0 inters = new IntersD0(0, 0, bezB.Start, false); linters.Add(inters); return(true); } if ((typeB0 == Param.TypeParam.Before) && (typeB2 == Param.TypeParam.Start)) { if (connect) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } IntersD0 inters = new IntersD0(1, 0, bezB.End, false); linters.Add(inters); return(true); } if ((typeB0 == Param.TypeParam.End) && (typeB2 == Param.TypeParam.After)) { if (!connect) { IntersD0 inters = new IntersD0(0, 1, bezB.Start, false); linters.Add(inters); return(true); } return(true); } if ((typeB0 == Param.TypeParam.After) && (typeB2 == Param.TypeParam.End)) { if (connect) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } IntersD0 inters = new IntersD0(1, 1, bezB.End, false); linters.Add(inters); return(true); } } else if (mult <= 0) { InfoInters inters; Inters.RefineIntersBBD1(bezA, bezB, out inters); linters.Add(inters); return(true); } throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } } /* * INTERSECTION IS 0-DIMENTIONAL AT MOST */ VecD[] cfA, cfB; bezA.PowerCoeff(out cfA); bezB.PowerCoeff(out cfB); Param parA, parB; int numRootB; double[] rootsB; double kappa = cfA[2].Cross(cfA[1]); // bezA and bezB are non-degenerated and consequent if (connectAB) { if (bezA.End != bezB.Start) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (connectBA) { // both ends are connected if (bezA.Start != bezB.End) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (icAB.IsTangent || icBA.IsTangent) { // tangent connection - no additional intersections return(true); } double crossA2B2 = cfA[2].Cross(cfB[2]); double[] cfEqn = { kappa *(kappa + 2 * crossA2B2 + cfA[1].Cross(cfB[2])), -crossA2B2 * (2 * kappa + crossA2B2), crossA2B2 *crossA2B2 }; Equation.RootsReal(cfEqn[2], cfEqn[1], cfEqn[0], out numRootB, out rootsB); if (numRootB == Equation.NumRootInfinite) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (rootsB != null) { for (int iRoot = 0; iRoot < numRootB; iRoot++) { parB = rootsB[iRoot]; if (bezB.IsEvaluableStrict(parB)) { parA = 1.0 + parB.Val * (cfA[2].Cross(cfB[2]) * parB.Val + cfA[2].Cross(cfB[1])) / kappa; if (bezA.IsEvaluableStrict(parA) /*&& (parA!=1.)*/) { IntersD0 inters = new IntersD0(parA, parB, 0.5 * (bezA.Evaluate(parA) + bezB.Evaluate(parB)), false); linters.Add(inters); } } } } return(true); } // consequent Bezier with one connection if (icAB.IsTangent) { // tangent connection - at most 2 additional intersections double[] cfEqn = { kappa *(kappa - cfB[2].Cross(cfB[1])), 2 * cfA[2].Cross(cfB[2]) * kappa, cfA[2].Cross(cfB[2]) * cfA[2].Cross(cfB[2]) }; Equation.RootsReal(cfEqn[2], cfEqn[1], cfEqn[0], out numRootB, out rootsB); if (numRootB == Equation.NumRootInfinite) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (rootsB != null) { for (int iRoot = 0; iRoot < numRootB; iRoot++) { parB = rootsB[iRoot]; if (bezB.IsEvaluableStrict(parB)) { parA = 1 + parB.Val * (cfA[2].Cross(cfB[2]) * parB.Val + cfA[2].Cross(cfB[1])) / kappa; if (bezA.IsEvaluableStrict(parA) /*&&(parA!=1)*/) { IntersD0 inters = new IntersD0(parA, parB, 0.5 * (bezA.Evaluate(parA) + bezB.Evaluate(parB)), false); linters.Add(inters); } } } } return(true); } else { // non-tangent connection - at most 3 additional intersections double[] cfEqn = { kappa *(2 * cfA[2].Cross(cfB[1]) + cfA[1].Cross(cfB[1])), cfA[2].Cross(cfB[1]) * cfA[2].Cross(cfB[1]) + kappa * (2 * cfA[2].Cross(cfB[2]) + cfA[1].Cross(cfB[2])), 2 * cfA[2].Cross(cfB[2]) * cfA[2].Cross(cfB[1]), cfA[2].Cross(cfB[2]) * cfA[2].Cross(cfB[2]) }; Equation.RootsReal(cfEqn[3], cfEqn[2], cfEqn[1], cfEqn[0], out numRootB, out rootsB); if (numRootB == Equation.NumRootInfinite) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (rootsB != null) { for (int iRoot = 0; iRoot < numRootB; iRoot++) { parB = rootsB[iRoot]; if (bezB.IsEvaluableStrict(parB)) { parA = 1 + parB.Val * (cfA[2].Cross(cfB[2]) * parB + cfA[2].Cross(cfB[1])) / kappa; if (bezA.IsEvaluableStrict(parA) /*&&(parA!=1)*/) { IntersD0 inters = new IntersD0(parA, parB, 0.5 * (bezA.Evaluate(parA) + bezB.Evaluate(parB)), false); linters.Add(inters); } } } } return(true); } } // bezA and bezB are non-degenerated, non-consequent curves bool isSwappedAB = false; if (Math.Abs(cfA[2].Cross(cfA[1])) < Math.Abs(cfB[2].Cross(cfB[1]))) { kappa = cfB[2].Cross(cfB[1]); isSwappedAB = true; VecD tmp; for (int i = 0; i < 3; i++) { tmp = cfA[i]; cfA[i] = cfB[i]; cfB[i] = tmp; } } double[] e = { cfA[2].Cross(cfB[0] - cfA[0]), cfA[2].Cross(cfB[1]), cfA[2].Cross(cfB[2]) }; double[] f = { (cfB[0] - cfA[0]).Cross(cfA[1]), cfB[1].Cross(cfA[1]), cfB[2].Cross(cfA[1]) }; Equation.RootsReal(e[2] * e[2], 2 * e[2] * e[1], e[1] * e[1] + 2 * e[2] * e[0] - kappa * f[2], 2 * e[1] * e[0] - kappa * f[1], e[0] * e[0] - kappa * f[0], out numRootB, out rootsB); if (numRootB == Equation.NumRootInfinite) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(bez,bez)", null); //return false; } if (rootsB != null) { for (int iRoot = 0; iRoot < numRootB; iRoot++) { parB = rootsB[iRoot]; parA = Equation.Evaluate(parB.Val, e[2], e[1], e[0]) / kappa; if (isSwappedAB) { Param parTmp; parTmp = parA; parA = parB; parB = parTmp; } if (bezA.IsEvaluableStrict(parA) && bezB.IsEvaluableStrict(parB)) { IntersD0 inters = new IntersD0(parA, parB, 0.5 * (bezA.Evaluate(parA) + bezB.Evaluate(parB)), false); linters.Add(inters); } } } return(true); }
public static bool AuxIntersectBB(SegD seg, Bez2D bez, InfoConnect icAB, InfoConnect icBA, ListInfoInters linters) { // both seg & bez are irreducable !!! if (linters == null) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(seg,bez)", "Null argument"); } bool connectAB = ((icAB != null) && (icAB.IsConnect)); bool connectBA = ((icBA != null) && (icBA.IsConnect)); if ((connectBA) && (!connectAB)) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(seg,bez)", null); //return false; } bool connect = connectAB || connectBA; if (!connect) { int numIntersBefore = linters.Count; if (!Inters.AuxIntersectBL(bez, seg, linters)) { return(false); } linters.ParamSwap(numIntersBefore); return(true); } // bez and seg are connected, => connectAB=true Param parM; if (bez.IsSelfInters(out parM)) { if (connectBA) // both ends are connected { // parM!=Infinity - otherwise the seg is degenerated double valM = parM.Val; IntersD1 inters; if (valM > 1) { inters = new IntersD1(0, 1, 1, 1 / (2 * valM - 1), seg, true); } else { inters = new IntersD1(0, 1, 1, (2 * valM) / (2 * valM - 1), seg, true); } linters.Add(inters); return(true); } if (icAB.IsTangent) { return(true); // no additional intersections } else { SegD segSupp = bez.SupportFlat(); InfoInters inters; if (!Inters.IntersectLL(seg, segSupp, out inters)) { return(false); } if (inters == null) { return(true); } inters.ParamInvalidateBezSI(); int numIntersBefore = linters.Count; linters.Add(inters); /* * CLEAN END-POINT if the Bezier does not return to it */ bool coversBezStart = bez.CoversEndPoint(true); if (!coversBezStart) { linters.CleanEndPointBezSI(bez.Start, numIntersBefore); } return(true); } } // bezier is NOT self-intersecting if (connectBA) { return(true); // no additional intersections } if (icAB.IsTangent) { return(true); // no additional intersections } // seg & bez are connected and not-tangent,=> // at most one additional point of intersection VecD[] cfSeg, cfBez; seg.PowerCoeff(out cfSeg); bez.PowerCoeff(out cfBez); VecD tang = (seg as LCurve).DirTang; VecD norm = (seg as LCurve).DirNorm; // connected but not-tangent: one double[] rootsBez; int numRootBez; Equation.RootsReal(cfBez[2].Dot(norm), cfBez[1].Dot(norm), out numRootBez, out rootsBez); if (numRootBez == Equation.NumRootInfinite) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(seg,bez)", null); //return false; } if (rootsBez == null) { return(true); } Param parBez = rootsBez[0]; if (bez.IsEvaluableStrict(parBez)) { double valBez = parBez.Val; Param parSeg = 1 + valBez * (cfBez[2].Dot(tang) * valBez + cfBez[1].Dot(tang)) / cfSeg[1].Dot(tang); if (seg.IsEvaluableStrict(parSeg)) // ??? && (parSeg!=1) { IntersD0 inters = new IntersD0(parSeg, parBez, 0.5 * (seg.Evaluate(parSeg) + bez.Evaluate(parBez)), false); linters.Add(inters); } } return(true); }