// cone sliced with vertical plane results in a hyperbola as the intersection curve // find point where hyperbola and line slopes match CC_CLZ_Pair ConeCutter::singleEdgeDropCanonical( const Point& u1, const Point& u2) const { double d = u1.y; double m = (u2.z-u1.z) / (u2.x-u1.x); // slope of edge // the outermost point on the cutter is at xu = sqrt( R^2 - d^2 ) double xu = sqrt( square(radius) - square(u1.y) ); assert( xu <= radius ); // max slope at xu is mu = (L/(R-R2)) * xu /(sqrt( xu^2 + d^2 )) double mu = (center_height/radius ) * xu / sqrt( square(xu) + square(d) ) ; bool hyperbola_case = (fabs(m) <= fabs(mu)); // find contact point where slopes match, there are two cases: // 1) if abs(m) <= abs(mu) we contact the curve at xp = sign(m) * sqrt( R^2 m^2 d^2 / (h^2 - R^2 m^2) ) // 2) if abs(m) > abs(mu) there is contact with the circular edge at +/- xu double ccu; if ( hyperbola_case ) { ccu = sign(m) * sqrt( square(radius)*square(m)*square(d) / (square(length) -square(radius)*square(m) ) ); } else { ccu = sign(m)*xu; } Point cc_tmp( ccu, d, 0.0); // cc-point in the XY plane cc_tmp.z_projectOntoEdge(u1,u2); double cl_z; if ( hyperbola_case ) { // 1) zc = zp - Lc + (R - sqrt(xp^2 + d^2)) / tan(beta2) cl_z = cc_tmp.z - center_height + (radius-sqrt(square(ccu) + square(d)))/ tan(angle); } else { // 2) zc = zp - Lc cl_z = cc_tmp.z - center_height; // case where we hit the edge of the cone } return CC_CLZ_Pair( ccu , cl_z); }
// drop-cutter: Toroidal cutter edge-test CC_CLZ_Pair BullCutter::singleEdgeDropCanonical( const Point& u1, const Point& u2 ) const { if ( isZero_tol( u1.z - u2.z ) ) { // horizontal edge special case return CC_CLZ_Pair( 0 , u1.z - height(u1.y) ); } else { // the general offset-ellipse case double b_axis = radius2; // short axis of ellipse = radius2 double theta = atan( (u2.z - u1.z) / (u2.x-u1.x) ); // theta is the slope of the line double a_axis = fabs( radius2/sin(theta) ); // long axis of ellipse = radius2/sin(theta) Point ellcenter(0,u1.y,0); Ellipse e = Ellipse( ellcenter, a_axis, b_axis, radius1); int iters = e.solver_brent(); assert( iters < 200 ); e.setEllipsePositionHi(u1,u2); // this selects either EllipsePosition1 or EllipsePosition2 and sets it to EllipsePosition_hi // pseudo cc-point on the ellipse/cylinder, in the CL=origo system Point ell_ccp = e.ePointHi(); assert( fabs( ell_ccp.xyNorm() - radius1 ) < 1E-5); // ell_ccp should be on the cylinder-circle Point cc_tmp_u = ell_ccp.closestPoint(u1,u2); // find real cc-point return CC_CLZ_Pair( cc_tmp_u.x , e.getCenterZ()-radius2); } }
CC_CLZ_Pair CylCutter::singleEdgeDropCanonical(const Point& u1, const Point& u2) const { // along the x-axis the cc-point is at x-coord s: double s = sqrt( square( radius ) - square( u1.y ) ); Point cc1( s, u1.y, 0); Point cc2( -s, u1.y, 0); cc1.z_projectOntoEdge(u1,u2); cc2.z_projectOntoEdge(u1,u2); // pick the higher one double cc_u; double cl_z; if (cc1.z > cc2.z) { cc_u = cc1.x; cl_z = cc1.z; } else { cc_u = cc2.x; cl_z = cc2.z; } return CC_CLZ_Pair( cc_u, cl_z); }