public Bez2D(Bez2D bez) : this() { this.cp[0] = new VecD(bez.Cp(0)); this.cp[1] = new VecD(bez.Cp(1)); this.cp[2] = new VecD(bez.Cp(2)); }
public Bez2D(Bez2D bez) : this() { this.cp[0]=new VecD(bez.Cp(0)); this.cp[1]=new VecD(bez.Cp(1)); this.cp[2]=new VecD(bez.Cp(2)); }
public BCurve SubCurve(Param parA, Param parB) { if ((!this.IsEvaluableStrict(parA)) || (!this.IsEvaluableStrict(parB))) { return(null); } Bez2D bezWork = new Bez2D(this); double valA = parA.Val; double valB = parB.Val; if (valA > valB) { bezWork.Reverse(); valA = 1 - valA; valB = 1 - valB; } /* * if ((valS==0)&&(valE==1)) * return new Bez2D(bezWork); * CurveD curveS, curveE; * if (valS==0) * { * bezWork.Subdivide(valB,out curveS, out curveE); * return curveS; * } * if (valE==1) * { * bezWork.Subdivide(valA,out curveS, out curveE); * return curveE; * } */ VecD a01, a12, b01, b12; a01 = (1 - valA) * bezWork.Cp(0) + valA * bezWork.Cp(1); a12 = (1 - valA) * bezWork.Cp(1) + valA * bezWork.Cp(2); b01 = (1 - valB) * bezWork.Cp(0) + valB * bezWork.Cp(1); b12 = (1 - valB) * bezWork.Cp(1) + valB * bezWork.Cp(2); VecD start, mid, end; start = (1 - valA) * a01 + valA * a12; end = (1 - valB) * b01 + valB * b12; mid = (1 - valB) * a01 + valB * a12; // mid=(1-valA)*(1-valB)*bezWork.Cp(0)+valA*valB*bezWork.Cp(2)+ // ((1-valB)*valA+(1-valA)*valB))*bezWork.Cp(1); return(new Bez2D(start, mid, end)); }
public BCurve SubCurve(Param parA, Param parB) { if ((!this.IsEvaluableStrict(parA))||(!this.IsEvaluableStrict(parB))) return null; Bez2D bezWork=new Bez2D(this); double valA=parA.Val; double valB=parB.Val; if (valA>valB) { bezWork.Reverse(); valA=1-valA; valB=1-valB; } /* if ((valS==0)&&(valE==1)) return new Bez2D(bezWork); CurveD curveS, curveE; if (valS==0) { bezWork.Subdivide(valB,out curveS, out curveE); return curveS; } if (valE==1) { bezWork.Subdivide(valA,out curveS, out curveE); return curveE; } */ VecD a01,a12,b01,b12; a01=(1-valA)*bezWork.Cp(0)+valA*bezWork.Cp(1); a12=(1-valA)*bezWork.Cp(1)+valA*bezWork.Cp(2); b01=(1-valB)*bezWork.Cp(0)+valB*bezWork.Cp(1); b12=(1-valB)*bezWork.Cp(1)+valB*bezWork.Cp(2); VecD start, mid, end; start=(1-valA)*a01+valA*a12; end=(1-valB)*b01+valB*b12; mid=(1-valB)*a01+valB*a12; // mid=(1-valA)*(1-valB)*bezWork.Cp(0)+valA*valB*bezWork.Cp(2)+ // ((1-valB)*valA+(1-valA)*valB))*bezWork.Cp(1); return new Bez2D(start,mid,end); }
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(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; }