// 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); }
void Tell::tellCmd(const QString& from, const QStringList& list) { octAssert(list.count() == 2); QStringList tmp = list[0].split(",",QString::SkipEmptyParts); QStringList dest, ok, ko; for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) dest << manager()->databasePlugin()->canonicalName(*it); QString cc = dest.join(",") + ","; for(QStringList::Iterator it = dest.begin(); it != dest.end(); ++it) { QString cc_tmp(cc); cc_tmp.replace(*it + ",",""); cc_tmp = cc_tmp.left(cc_tmp.length() - 1); QString txt1(from + " tells you" + (dest.count() > 1 ? ("(CC: " + cc_tmp + ")") : "") + ": " + list[1]); if(manager()->connectionPlugin()->serverSend(*it,txt1)) ok << *it; else ko << *it; } if(ok.count()){ QString txt2("You tell " + (ok.join(",")) + ": " + list[1]); manager()->connectionPlugin()->serverSend(from,txt2); } if(ko.count()) { QString txt2((ko.join(",")) + (ko.count() > 1 ? " are" : " is") + " not connected!"); manager()->connectionPlugin()->serverSend(from,txt2); } }
// general purpose facet-drop which calls xy_normal_length(), normal_length(), // and center_height() on the subclass bool MillingCutter::facetDrop(CLPoint &cl, const Triangle &t) const { // Drop cutter at (cl.x, cl.y) against facet of Triangle t Point normal = t.upNormal(); // facet surface normal if ( isZero_tol( normal.z ) ) // vertical surface return false; //can't drop against vertical surface assert( isPositive( normal.z ) ); if ( ( isZero_tol(normal.x) ) && ( isZero_tol(normal.y) ) ) { // horizontal plane special case CCPoint cc_tmp( cl.x, cl.y, t.p[0].z, FACET); return cl.liftZ_if_inFacet(cc_tmp.z, cc_tmp, t); } else { // general case // plane containing facet: a*x + b*y + c*z + d = 0, so // d = -a*x - b*y - c*z, where (a,b,c) = surface normal double d = - normal.dot(t.p[0]); normal.normalize(); // make length of normal == 1.0 Point xyNormal( normal.x, normal.y, 0.0); xyNormal.xyNormalize(); // define the radiusvector which points from the cc-point to the cutter-center Point radiusvector = this->xy_normal_length*xyNormal + this->normal_length*normal; CCPoint cc_tmp = cl - radiusvector; // NOTE xy-coords right, z-coord is not. cc_tmp.z = (1.0/normal.z)*(-d-normal.x*cc_tmp.x-normal.y*cc_tmp.y); // cc-point lies in the plane. cc_tmp.type = FACET; double tip_z = cc_tmp.z + radiusvector.z - this->center_height; return cl.liftZ_if_inFacet(tip_z, cc_tmp, t); } }
// general purpose vertex-drop which delegates to this->height(r) of subclass bool MillingCutter::vertexDrop(CLPoint &cl, const Triangle &t) const { bool result = false; BOOST_FOREACH( const Point& p, t.p) { // test each vertex of triangle double q = cl.xyDistance(p); // distance in XY-plane from cl to p if ( q <= radius ) { // p is inside the cutter CCPoint cc_tmp(p, VERTEX); if ( cl.liftZ( p.z - this->height(q), cc_tmp ) ) result = true; } } return result; }
// "dual" edge-drop problems // cylinder: zero diam edge/ellipse, r-radius cylinder, find r-offset == cl (ITO surface XY-slice is a circle) // sphere: zero diam cylinder. ellipse around edge, find offset == cl (ITO surface slice is ellipse) (?) // toroid: radius2 diam edge, radius1 cylinder, find radius1-offset-ellipse=cl (ITO surf slice is offset ellipse) (this is the offset-ellipse problem) // cone: ??? (how is this an ellipse??) bool MillingCutter::singleEdgeDrop(CLPoint& cl, const Point& p1, const Point& p2, double d) const { Point v = p2 - p1; // vector along edge, from p1 -> p2 Point vxy( v.x, v.y, 0.0); vxy.xyNormalize(); // normalized XY edge vector // figure out u-coordinates of p1 and p2 (i.e. x-coord in the rotated system) Point sc = cl.xyClosestPoint( p1, p2 ); assert( ( (cl-sc).xyNorm() - d ) < 1E-6 ); // edge endpoints in the new coordinate system, in these coordinates, CL is at origo Point up1( (p1-sc).dot(vxy) , d, p1.z); // d, distance to line, is the y-coord in the rotated system Point up2( (p2-sc).dot(vxy) , d, p2.z); CC_CLZ_Pair contact = this->singleEdgeDropCanonical( up1, up2 ); // the subclass handles this CCPoint cc_tmp( sc + contact.first * vxy, EDGE); // translate back into original coord-system cc_tmp.z_projectOntoEdge(p1,p2); return cl.liftZ_if_InsidePoints( contact.second , cc_tmp , p1, p2); }
bool MillingCutter::singleVertexPush(const Fiber& f, Interval& i, const Point& p, CCType cctyp) const { 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; assert( h>= 0.0); double cwidth = this->width( h ); if ( q <= cwidth ) { // we are going to hit the vertex p double ofs = sqrt( square( cwidth ) - square(q) ); // distance along fiber Point start = pq - ofs*f.dir; Point stop = pq + ofs*f.dir; CCPoint cc_tmp( p, cctyp ); i.updateUpper( f.tval(stop) , cc_tmp ); i.updateLower( f.tval(start) , cc_tmp ); result = true; } } return result; }
// because this checks for contact with both the tip and the circular edge it is hard to move to the base-class // we either hit the tip, when the slope of the plane is smaller than angle // or when the slope is steep, the circular edge between the cone and the cylindrical shaft bool ConeCutter::facetDrop(CLPoint &cl, const Triangle &t) const { bool result = false; Point normal = t.upNormal(); // facet surface normal if ( isZero_tol( normal.z ) ) // vertical surface return false; //can't drop against vertical surface if ( (isZero_tol(normal.x)) && (isZero_tol(normal.y)) ) { // horizontal plane special case CCPoint cc_tmp( cl.x, cl.y, t.p[0].z, FACET_TIP ); // so any vertex is at the correct height return cl.liftZ_if_inFacet(cc_tmp.z, cc_tmp, t); } else { // define plane containing facet // a*x + b*y + c*z + d = 0, so // d = -a*x - b*y - c*z, where (a,b,c) = surface normal double a = normal.x; double b = normal.y; double c = normal.z; double d = - normal.dot(t.p[0]); normal.xyNormalize(); // make xy length of normal == 1.0 // cylindrical contact point case // find the xy-coordinates of the cc-point CCPoint cyl_cc_tmp = cl - radius*normal; cyl_cc_tmp.z = (1.0/c)*(-d-a*cyl_cc_tmp.x-b*cyl_cc_tmp.y); double cyl_cl_z = cyl_cc_tmp.z - length; // tip positioned here cyl_cc_tmp.type = FACET_CYL; // tip contact with facet CCPoint tip_cc_tmp(cl.x,cl.y,0.0); tip_cc_tmp.z = (1.0/c)*(-d-a*tip_cc_tmp.x-b*tip_cc_tmp.y); double tip_cl_z = tip_cc_tmp.z; tip_cc_tmp.type = FACET_TIP; result = result || cl.liftZ_if_inFacet( tip_cl_z, tip_cc_tmp, t); result = result || cl.liftZ_if_inFacet( cyl_cl_z, cyl_cc_tmp, t); return result; } }