/// error function for solver //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: virtual double error(double diangle) const public virtual double error(double diangle) { EllipsePosition tmp = new EllipsePosition(); tmp.setDiangle(diangle); return(error(tmp)); }
/// offset-ellipse Brent solver /// offfset-ellipse solver using Brent's method /// find the EllipsePosition that makes the offset-ellipse point be at p /// this is a zero of Ellipse::error() /// returns number of iterations /// /// called (only?) by BullCutter::singleEdgeDropCanonical() public int solver_brent() { int iters = 1; EllipsePosition apos = new EllipsePosition(); // Brent's method requires bracketing the root in [apos.diangle, bpos.diangle] EllipsePosition bpos = new EllipsePosition(); apos.setDiangle(0.0); Debug.Assert(apos.isValid()); bpos.setDiangle(3.0); Debug.Assert(bpos.isValid()); if (Math.Abs(error(apos)) < DefineConstants.OE_ERROR_TOLERANCE) { // if we are lucky apos is the solution EllipsePosition1.CopyFrom(apos); // and we do not need to search further. find_EllipsePosition2(); return(iters); } else if (Math.Abs(error(bpos)) < DefineConstants.OE_ERROR_TOLERANCE) { // or bpos might be the solution? EllipsePosition1.CopyFrom(bpos); find_EllipsePosition2(); return(iters); } // neither apos nor bpos is the solution // but root is now bracketed, so we can use brent_zero Debug.Assert(error(apos) * error(bpos) < 0.0); // this looks for the diangle that makes the offset-ellipse point y-coordinate zero double dia_sln = ocl.GlobalMembers.brent_zero(apos.diangle, bpos.diangle, 3E-16, DefineConstants.OE_ERROR_TOLERANCE, this); // brent_zero.hpp EllipsePosition1.setDiangle(dia_sln); Debug.Assert(EllipsePosition1.isValid()); // because we only work with the y-coordinate of the offset-ellipse-point, there are two symmetric solutions find_EllipsePosition2(); return(iters); }
/// error-function for the solver //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: double error(double diangle) const public new double error(double diangle) { EllipsePosition tmp = new EllipsePosition(); tmp.setDiangle(diangle); Point p = this.oePoint(tmp); Point errorVec = target - p; return(errorVec.dot(error_dir)); }
/// aligned offset-ellipse solver. callsn Numeric::brent_solver() // used by BullCutter pushcutter edge-test public bool aligned_solver(Fiber f) { error_dir.CopyFrom(f.dir.xyPerp()); // now calls to error(diangle) will give the right error Debug.Assert(error_dir.xyNorm() > 0.0); target.CopyFrom(f.p1); // target is either x or y-coord of f.p1 // find position(s) where ellipse tangent is parallel to fiber. Here error() will be minimized/maximized. // tangent at point is: -a t + b s = -a*major_dir*t + b*minor_dir*s // -at ma.y + bs mi.y = 0 for X-fiber // s = sqrt(1-t^2) // -a*ma.y * t + b*mi.y* sqrt(1-t^2) = 0 // => t^2 = b^2 / (a^2 + b^2) double t1 = 0.0; if (f.p1.y == f.p2.y) { t1 = Math.Sqrt(ocl.GlobalMembers.square(b * minor_dir.y) / (ocl.GlobalMembers.square(a * major_dir.y) + ocl.GlobalMembers.square(b * minor_dir.y))); } else if (f.p1.x == f.p2.x) { t1 = Math.Sqrt(ocl.GlobalMembers.square(b * minor_dir.x) / (ocl.GlobalMembers.square(a * major_dir.x) + ocl.GlobalMembers.square(b * minor_dir.x))); } else { Debug.Assert(false); } // bracket root EllipsePosition tmp = new EllipsePosition(); EllipsePosition apos = new EllipsePosition(); EllipsePosition bpos = new EllipsePosition(); double s1 = Math.Sqrt(1.0 - ocl.GlobalMembers.square(t1)); bool found_positive = false; bool found_negative = false; tmp.setDiangle(GlobalMembers.xyVectorToDiangle(s1, t1)); if (error(tmp.diangle) > 0) { found_positive = true; apos.CopyFrom(tmp); } else if (error(tmp.diangle) < 0) { found_negative = true; bpos.CopyFrom(tmp); } tmp.setDiangle(GlobalMembers.xyVectorToDiangle(s1, -t1)); if (error(tmp.diangle) > 0) { found_positive = true; apos.CopyFrom(tmp); } else if (error(tmp.diangle) < 0) { found_negative = true; bpos.CopyFrom(tmp); } tmp.setDiangle(GlobalMembers.xyVectorToDiangle(-s1, t1)); if (error(tmp.diangle) > 0) { found_positive = true; apos.CopyFrom(tmp); } else if (error(tmp.diangle) < 0) { found_negative = true; bpos.CopyFrom(tmp); } tmp.setDiangle(GlobalMembers.xyVectorToDiangle(-s1, -t1)); if (error(tmp.diangle) > 0) { found_positive = true; apos.CopyFrom(tmp); } else if (error(tmp.diangle) < 0) { found_negative = true; bpos.CopyFrom(tmp); } if (found_positive) { if (found_negative) { Debug.Assert(this.error(apos.diangle) * this.error(bpos.diangle) < 0.0); // root is now bracketed. double lolim = 0.0; double hilim = 0.0; if (apos.diangle > bpos.diangle) { lolim = bpos.diangle; hilim = apos.diangle; } else if (bpos.diangle > apos.diangle) { hilim = bpos.diangle; lolim = apos.diangle; } double dia_sln = ocl.GlobalMembers.brent_zero(lolim, hilim, 3E-16, DefineConstants.OE_ERROR_TOLERANCE, this); double dia_sln2 = ocl.GlobalMembers.brent_zero(hilim - 4.0, lolim, 3E-16, DefineConstants.OE_ERROR_TOLERANCE, this); EllipsePosition1.setDiangle(dia_sln); EllipsePosition2.setDiangle(dia_sln2); Debug.Assert(EllipsePosition1.isValid()); Debug.Assert(EllipsePosition2.isValid()); /* * // FIXME. This assert fails in some cases (30sphere.stl z=0, for example) * // FIXME. The allowed error should probably be in proportion to the difficulty of the case. * * if (!isZero_tol( error(EllipsePosition1.diangle) )) { * std::cout << "AlignedEllipse::aligned_solver() ERROR \n"; * std::cout << "error(EllipsePosition1.diangle)= "<< error(EllipsePosition1.diangle) << " (expected zero)\n"; * * } * assert( isZero_tol( error(EllipsePosition1.diangle) ) ); * assert( isZero_tol( error(EllipsePosition2.diangle) ) ); */ return(true); } } return(false); }