public bool Project(Bez2D bez, out Param par, out VecD pnt) { /* * MEANING: the NEAREST point in the RANGE [0,1] * ASSUMPTION: - bezier can be non-reduced * - bezier is NOT self-intersecting */ par = null; pnt = null; Param parM; if (bez.IsSelfInters(out parM)) { throw new ExceptionGMath("VecD", "Project(bez)", null); //return false; } if (bez.IsDegen) { par = new Param(Param.Degen); pnt = bez.Middle; return(true); } if (bez.IsSeg(out parM)) { SegD seg = bez.Reduced as SegD; this.Project(seg, out par, out pnt); bez.ParamFromSeg(par); return(true); } // case of non-flat Bezier Param[] parsPerp; if (!this.Perp(bez, out parsPerp)) { return(false); } double distS = this.Dist(bez.Start); double distE = this.Dist(bez.End); double distMin = Math.Min(distS, distE); double parMin = (distS <= distE)? 0.0: 1.0; if (parsPerp != null) { for (int iPerp = 0; iPerp < parsPerp.Length; iPerp++) { if (bez.IsEvaluableStrict(parsPerp[iPerp])) { double distPerp = this.Dist(bez.Evaluate(parsPerp[iPerp])); if (distPerp < distMin) { distMin = distPerp; parMin = parsPerp[iPerp]; } } } } par = parMin; pnt = bez.Evaluate(parMin); return(true); }
public bool Inverse(Bez2D bez, out Param par) { /* * MEANING: * - Parameter of the nearest point in range * [-Infinity, Infinity] * ASSUMPTIONS: * - Bezier is REDUCED * - Works for any bezier if the nearest point belongs * to support * - Works for non S/I bezier if the nearest point lies * without the support */ par = null; Param parM; if (!bez.IsSelfInters(out parM)) { Param[] parsPerp; if (!this.Perp(bez, out parsPerp)) { return(false); } double distMin = MConsts.Infinity; for (int iPar = 0; iPar < parsPerp.Length; iPar++) { double distCur = this.Dist(bez.Evaluate(parsPerp[iPar])); if (distCur < distMin) { distMin = distCur; par = parsPerp[iPar]; } } return(true); } // bezier is s/i Param[] parsProj; VecD pnt; if (!this.ProjectGeneral(bez, out parsProj, out pnt)) { return(false); } if (this.Dist(pnt) > MConsts.EPS_DEC) { throw new ExceptionGMath("VecD", "Inverse(bez)", null); //return false; } par = parsProj[0]; return(true); }
public static bool AuxIntersectBB(DegenD degen, Bez2D bez, InfoConnect icAB, InfoConnect icBA, ListInfoInters linters) { if (linters == null) { throw new ExceptionGMath("Intersect", "AuxIntersectBB(degen,bez)", "Null argument"); } // no reduction !! bool connectAB = ((icAB != null) && (icAB.IsConnect)); bool connectBA = ((icBA != null) && (icBA.IsConnect)); bool connect = connectAB || connectBA; if (connect) { return(true); } // bbox check if (!bez.BBox.Contains(degen.Cp)) { return(true); } Param[] pars; VecD pnt; if (!degen.Cp.ProjectGeneral(bez, out pars, out pnt)) { return(false); } if (degen.Cp.Dist(pnt) < MConsts.EPS_DEC) { Param parM; bool isSelfInters = bez.IsSelfInters(out parM); for (int iPar = 0; iPar < pars.Length; iPar++) { IntersD0 inters = new IntersD0(Param.Degen, pars[iPar], pnt, isSelfInters); linters.Add(inters); } } return(true); }
bool InverseOn(Bez2D bez, out bool isOn, out Param par) { /* * MEANING: inverse point which is known to lie on the * bezier in range [-Infinity, Infinity] * * ASSUMPTIONS: bez is IRREDUCABLE && NOT S/I * */ isOn = false; par = null; Param parM; if ((bez.IsDegen) || (bez.IsSeg(out parM)) || (bez.IsSelfInters(out parM))) { throw new ExceptionGMath("VecD", "InverseOn(bez)", null); //return false; } VecD[] cfBez; bez.PowerCoeff(out cfBez); double dev = (cfBez[2].Cross(this - cfBez[0])) * (cfBez[2].Cross(this - cfBez[0])) - (cfBez[2].Cross(cfBez[1])) * ((this - cfBez[0]).Cross(cfBez[1])); if (Math.Abs(dev) < MConsts.EPS_DEC) { isOn = true; par = (cfBez[2].Cross(this - cfBez[0])) / (cfBez[2].Cross(cfBez[1])); } return(true); }
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); }
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); }
public bool Inverse(Bez2D bez, out Param par) { /* * MEANING: * - Parameter of the nearest point in range * [-Infinity, Infinity] * ASSUMPTIONS: * - Bezier is REDUCED * - Works for any bezier if the nearest point belongs * to support * - Works for non S/I bezier if the nearest point lies * without the support */ par=null; Param parM; if (!bez.IsSelfInters(out parM)) { Param[] parsPerp; if (!this.Perp(bez, out parsPerp)) return false; double distMin=MConsts.Infinity; for (int iPar=0; iPar<parsPerp.Length; iPar++) { double distCur=this.Dist(bez.Evaluate(parsPerp[iPar])); if (distCur<distMin) { distMin=distCur; par=parsPerp[iPar]; } } return true; } // bezier is s/i Param[] parsProj; VecD pnt; if (!this.ProjectGeneral(bez, out parsProj, out pnt)) return false; if (this.Dist(pnt)>MConsts.EPS_DEC) { throw new ExceptionGMath("VecD","Inverse(bez)",null); //return false; } par=parsProj[0]; return true; }
bool InverseOn(Bez2D bez, out bool isOn, out Param par) { /* * MEANING: inverse point which is known to lie on the * bezier in range [-Infinity, Infinity] * * ASSUMPTIONS: bez is IRREDUCABLE && NOT S/I * */ isOn=false; par=null; Param parM; if ((bez.IsDegen)||(bez.IsSeg(out parM))||(bez.IsSelfInters(out parM))) { throw new ExceptionGMath("VecD","InverseOn(bez)",null); //return false; } VecD[] cfBez; bez.PowerCoeff(out cfBez); double dev=(cfBez[2].Cross(this-cfBez[0]))* (cfBez[2].Cross(this-cfBez[0]))- (cfBez[2].Cross(cfBez[1]))* ((this-cfBez[0]).Cross(cfBez[1])); if (Math.Abs(dev)<MConsts.EPS_DEC) { isOn=true; par=(cfBez[2].Cross(this-cfBez[0]))/(cfBez[2].Cross(cfBez[1])); } return true; }
public bool Project(Bez2D bez, out Param par, out VecD pnt) { /* * MEANING: the NEAREST point in the RANGE [0,1] * ASSUMPTION: - bezier can be non-reduced * - bezier is NOT self-intersecting */ par=null; pnt=null; Param parM; if (bez.IsSelfInters(out parM)) { throw new ExceptionGMath("VecD","Project(bez)",null); //return false; } if (bez.IsDegen) { par=new Param(Param.Degen); pnt=bez.Middle; return true; } if (bez.IsSeg(out parM)) { SegD seg=bez.Reduced as SegD; this.Project(seg,out par,out pnt); bez.ParamFromSeg(par); return true; } // case of non-flat Bezier Param[] parsPerp; if (!this.Perp(bez, out parsPerp)) return false; double distS=this.Dist(bez.Start); double distE=this.Dist(bez.End); double distMin=Math.Min(distS,distE); double parMin=(distS<=distE)? 0.0: 1.0; if (parsPerp!=null) { for (int iPerp=0; iPerp<parsPerp.Length; iPerp++) { if (bez.IsEvaluableStrict(parsPerp[iPerp])) { double distPerp=this.Dist(bez.Evaluate(parsPerp[iPerp])); if (distPerp<distMin) { distMin=distPerp; parMin=parsPerp[iPerp]; } } } } par=parMin; pnt=bez.Evaluate(parMin); return true; }
public bool ProjectGeneral(Bez2D bez, out Param[] pars, out VecD pnt) { /* * MEANING: parameter (or parameters) of the nearest point * in range [0,1] * * ASSUMPTIONS: bezier can be non-reduced * bezier can be self-intersecting * */ pars=null; pnt=null; Param parM; if (!bez.IsSelfInters(out parM)) { Param par; if (!this.Project(bez,out par,out pnt)) return false; if (par!=null) { pars=new Param[1]; pars[0]=par; } return true; } double valM=parM.Val; if (parM<0) { Bez2D bezRev=new Bez2D(bez); bezRev.Reverse(); if (!this.ProjectGeneral(bezRev,out pars,out pnt)) return false; if (pars!=null) { for (int iPar=0; iPar<pars.Length; iPar++) { pars[iPar].Reverse(1); } } return true; } SegD support=bez.SupportFlat(); Param parSupport; if (!this.Project(support,out parSupport, out pnt)) return false; if (!bez.ParamFromSupport(parSupport,out pars)) return false; 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 bool ProjectGeneral(Bez2D bez, out Param[] pars, out VecD pnt) { /* * MEANING: parameter (or parameters) of the nearest point * in range [0,1] * * ASSUMPTIONS: bezier can be non-reduced * bezier can be self-intersecting * */ pars = null; pnt = null; Param parM; if (!bez.IsSelfInters(out parM)) { Param par; if (!this.Project(bez, out par, out pnt)) { return(false); } if (par != null) { pars = new Param[1]; pars[0] = par; } return(true); } double valM = parM.Val; if (parM < 0) { Bez2D bezRev = new Bez2D(bez); bezRev.Reverse(); if (!this.ProjectGeneral(bezRev, out pars, out pnt)) { return(false); } if (pars != null) { for (int iPar = 0; iPar < pars.Length; iPar++) { pars[iPar].Reverse(1); } } return(true); } SegD support = bez.SupportFlat(); Param parSupport; if (!this.Project(support, out parSupport, out pnt)) { return(false); } if (!bez.ParamFromSupport(parSupport, out pars)) { return(false); } return(true); }
public static bool AuxIntersectBB(DegenD degen, Bez2D bez, InfoConnect icAB, InfoConnect icBA, ListInfoInters linters) { if (linters==null) { throw new ExceptionGMath("Intersect","AuxIntersectBB(degen,bez)","Null argument"); } // no reduction !! bool connectAB = ((icAB!=null)&&(icAB.IsConnect)); bool connectBA = ((icBA!=null)&&(icBA.IsConnect)); bool connect=connectAB||connectBA; if (connect) { return true; } // bbox check if (!bez.BBox.Contains(degen.Cp)) return true; Param[] pars; VecD pnt; if (!degen.Cp.ProjectGeneral(bez,out pars, out pnt)) return false; if (degen.Cp.Dist(pnt)<MConsts.EPS_DEC) { Param parM; bool isSelfInters=bez.IsSelfInters(out parM); for (int iPar=0; iPar<pars.Length; iPar++) { IntersD0 inters=new IntersD0(Param.Degen,pars[iPar],pnt,isSelfInters); linters.Add(inters); } } return true; }
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; }
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; }
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(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; }