/* * /// string repr * public static std::ostream operator << (std::ostream stream, BullCutter c) * { * stream << "BullCutter(d=" << c.diameter << ", r1=" << c.radius1 << " r2=" << c.radius2 << ", L=" << c.length << ")"; * return stream; * } * * //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: * //ORIGINAL LINE: string str() const * public new string str() * { * std::ostringstream o = new std::ostringstream(); * o << this; * return o.str(); * } */ // push-cutter: vertex and facet handled by base-class // edge handled here //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: bool generalEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const protected new bool generalEdgePush(Fiber f, Interval i, Point p1, Point p2) { //std::cout << " BullCutter::generalEdgePush() \n"; bool result = false; if (GlobalMembers.isZero_tol((p2 - p1).xyNorm())) { // this would be a vertical edge return(result); } if (GlobalMembers.isZero_tol(p2.z - p1.z)) // this would be a horizontal edge { return(result); } Debug.Assert(Math.Abs(p2.z - p1.z) > 0.0); // no horiz edges allowed hereafter // p1+t*(p2-p1) = f.p1.z+radius2 => double tplane = (f.p1.z + radius2 - p1.z) / (p2.z - p1.z); // intersect edge with plane at z = ufp1.z Point ell_center = p1 + tplane * (p2 - p1); Debug.Assert(GlobalMembers.isZero_tol(Math.Abs(ell_center.z - (f.p1.z + radius2)))); Point major_dir = (p2 - p1); Debug.Assert(major_dir.xyNorm() > 0.0); major_dir.z = 0; major_dir.xyNormalize(); Point minor_dir = major_dir.xyPerp(); double theta = Math.Atan((p2.z - p1.z) / (p2 - p1).xyNorm()); double major_length = Math.Abs(radius2 / Math.Sin(theta)); double minor_length = radius2; AlignedEllipse e = new AlignedEllipse(ell_center, major_length, minor_length, radius1, major_dir, minor_dir); if (e.aligned_solver(f)) { // now we want the offset-ellipse point to lie on the fiber Point pseudo_cc = e.ePoint1(); // pseudo cc-point on ellipse and cylinder Point pseudo_cc2 = e.ePoint2(); CCPoint cc = new CCPoint(pseudo_cc.closestPoint(p1, p2)); CCPoint cc2 = new CCPoint(pseudo_cc2.closestPoint(p1, p2)); cc.type = CCType.EDGE_POS; cc2.type = CCType.EDGE_POS; Point cl = e.oePoint1() - new Point(0, 0, center_height); Debug.Assert(GlobalMembers.isZero_tol(Math.Abs(cl.z - f.p1.z))); Point cl2 = e.oePoint2() - new Point(0, 0, center_height); Debug.Assert(GlobalMembers.isZero_tol(Math.Abs(cl2.z - f.p1.z))); double cl_t = f.tval(cl); double cl_t2 = f.tval(cl2); if (i.update_ifCCinEdgeAndTrue(cl_t, cc, p1, p2, true)) { result = true; } if (i.update_ifCCinEdgeAndTrue(cl_t2, cc2, p1, p2, true)) { result = true; } } //std::cout << " BullCutter::generalEdgePush() DONE result= " << result << "\n"; return(result); }
/// push cutter against a single vertex p //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: bool singleVertexPush(const Fiber& f, Interval& i, const Point& p, CCType cctyp) const protected bool singleVertexPush(Fiber f, Interval i, Point p, CCType cctyp) { bool result = false; if ((p.z >= f.p1.z) && (p.z <= (f.p1.z + this.getLength()))) { // p.z is within cutter Point pq = p.xyClosestPoint(f.p1, f.p2); // closest point on fiber double q = (p - pq).xyNorm(); // distance in XY-plane from fiber to p double h = p.z - f.p1.z; Debug.Assert(h >= 0.0); double cwidth = this.width(h); if (q <= cwidth) { // we are going to hit the vertex p double ofs = Math.Sqrt(ocl.GlobalMembers.square(cwidth) - ocl.GlobalMembers.square(q)); // distance along fiber Point start = pq - ofs * f.dir; Point stop = pq + ofs * f.dir; CCPoint cc_tmp = new CCPoint(p, cctyp); i.updateUpper(f.tval(stop), cc_tmp); i.updateLower(f.tval(start), cc_tmp); result = true; } } return(result); }
// cone is pushed along Fiber f into contact with edge p1-p2 //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: bool generalEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const protected new bool generalEdgePush(Fiber f, Interval i, Point p1, Point p2) { bool result = false; if (GlobalMembers.isZero_tol(p2.z - p1.z)) // guard against horizontal edge { return(result); } Debug.Assert((p2.z - p1.z) != 0.0); // idea: as the ITO-cone slides along the edge it will pierce a z-plane at the height of the fiber // the shaped of the pierced area is either a circle if the edge is steep // or a 'half-circle' + cone shape if the edge is shallow (ice-cream cone...) // we can now intersect this 2D shape with the fiber and get the CL-points. // this is where the ITO cone pierces the z-plane of the fiber // edge-line: p1+t*(p2-p1) = zheight // => t = (zheight - p1)/ (p2-p1) double t_tip = (f.p1.z - p1.z) / (p2.z - p1.z); Point p_tip = p1 + t_tip * (p2 - p1); Debug.Assert(GlobalMembers.isZero_tol(Math.Abs(p_tip.z - f.p1.z))); // p_tip should be in plane of fiber // this is where the ITO cone base exits the plane double t_base = (f.p1.z + center_height - p1.z) / (p2.z - p1.z); Point p_base = p1 + t_base * (p2 - p1); p_base.z = f.p1.z; // project to plane of fiber double L = (p_base - p_tip).xyNorm(); //if ( L <= radius ){ // this is where the ITO-slice is a circle // find intersection points, if any, between the fiber and the circle // fiber is f.p1 - f.p2 // circle is centered at p_base double d = p_base.xyDistanceToLine(f.p1, f.p2); if (d <= radius) { // we know there is an intersection point. // http://mathworld.wolfram.com/Circle-LineIntersection.html // subtract circle center, math is for circle centered at (0,0) double dx = f.p2.x - f.p1.x; double dy = f.p2.y - f.p1.y; double dr = Math.Sqrt(ocl.GlobalMembers.square(dx) + ocl.GlobalMembers.square(dy)); double det = (f.p1.x - p_base.x) * (f.p2.y - p_base.y) - (f.p2.x - p_base.x) * (f.p1.y - p_base.y); // intersection given by: // x = det*dy +/- sign(dy) * dx * sqrt( r^2 dr^2 - det^2 ) / dr^2 // y = -det*dx +/- abs(dy) * sqrt( r^2 dr^2 - det^2 ) / dr^2 double discr = ocl.GlobalMembers.square(radius) * ocl.GlobalMembers.square(dr) - ocl.GlobalMembers.square(det); if (discr >= 0.0) { if (discr == 0.0) { // tangent case double x_tang = (det * dy) / ocl.GlobalMembers.square(dr); double y_tang = -(det * dx) / ocl.GlobalMembers.square(dr); Point p_tang = new Point(x_tang + p_base.x, y_tang + p_base.y); // translate back from (0,0) system! double t_tang = f.tval(p_tang); if (circle_CC(t_tang, p1, p2, f, i)) { result = true; } } else { // two intersection points with the base-circle double x_pos = (det * dy + Math.Sign(dy) * dx * Math.Sqrt(discr)) / ocl.GlobalMembers.square(dr); double y_pos = (-det * dx + Math.Abs(dy) * Math.Sqrt(discr)) / ocl.GlobalMembers.square(dr); Point cl_pos = new Point(x_pos + p_base.x, y_pos + p_base.y); double t_pos = f.tval(cl_pos); // the same with "-" sign: double x_neg = (det * dy - Math.Sign(dy) * dx * Math.Sqrt(discr)) / ocl.GlobalMembers.square(dr); double y_neg = (-det * dx - Math.Abs(dy) * Math.Sqrt(discr)) / ocl.GlobalMembers.square(dr); Point cl_neg = new Point(x_neg + p_base.x, y_neg + p_base.y); double t_neg = f.tval(cl_neg); if (circle_CC(t_pos, p1, p2, f, i)) { result = true; } if (circle_CC(t_neg, p1, p2, f, i)) { result = true; } } } } //} // circle-case if (L > radius) { // ITO-slice is cone + "half-circle" // lines from p_tip to tangent points of the base-circle // this page has an analytic solution: // http://mathworld.wolfram.com/CircleTangentLine.html // this page has a geometric construction: // http://www.mathopenref.com/consttangents.html // circle p_base, radius // top p_tip // tangent point at intersection of base-circle with this circle: Point p_mid = 0.5 * (p_base + p_tip); p_mid.z = f.p1.z; double r_tang = L / 2; // circle-circle intersection to find tangent-points // three cases: no intersection point // one intersection point // two intersection points //d is the distance between the circle centers Point pd = p_mid - p_base; pd.z = 0; double dist = pd.xyNorm(); //distance between the circles //Check for special cases which do not lead to solutions we want bool case1 = (GlobalMembers.isZero_tol(dist) && GlobalMembers.isZero_tol(Math.Abs(radius - r_tang))); bool case2 = (dist > (radius + r_tang)); //no solution. circles do not intersect bool case3 = (dist < Math.Abs(radius - r_tang)); //no solution. one circle is contained in the other bool case4 = (GlobalMembers.isZero_tol(dist - (radius + r_tang))); // tangent case if (case1 || case2 || case3 || case4) { } else { // here we know we have two solutions. //Determine the distance from point 0 to point 2 // law of cosines (http://en.wikipedia.org/wiki/Law_of_cosines) // rt^2 = d^2 + r^2 -2*d*r*cos(gamma) // so cos(gamma) = (rt^2-d^2-r^2)/ -(2*d*r) // and the sought distance is // a = r*cos(gamma) = (-rt^2+d^2+r^2)/ (2*d) double a = (-ocl.GlobalMembers.square(r_tang) + ocl.GlobalMembers.square(radius) + ocl.GlobalMembers.square(dist)) / (2.0 * dist); Debug.Assert(a >= 0.0); Point v2 = p_base + (a / dist) * pd; // v2 is the point where the line through the circle intersection points crosses the line between the circle centers. //Determine the distance from v2 to either of the intersection points double h = Math.Sqrt(ocl.GlobalMembers.square(radius) - ocl.GlobalMembers.square(a)); //Now determine the offsets of the intersection points from point 2 Point ofs = new Point(-pd.y * (h / dist), pd.x * (h / dist)); // now we know the tangent-points Point tang1 = v2 + ofs; Point tang2 = v2 - ofs; if (cone_CC(tang1, p_tip, p_base, p1, p2, f, i)) { result = true; } if (cone_CC(tang2, p_tip, p_base, p1, p2, f, i)) { result = true; } } } // end circle+cone case return(result); }