/// \brief drop cutter at (cl.x, cl.y) against facet of Triangle t
        /// calls xy_normal_length(), normal_length(), and center_height() on the subclass.
        /// if cl.z is too low, updates cl.z so that cutter does not cut the facet.
        /// CompositeCutter may be the only sub-class that needs to reimplement this function.

        // general purpose facet-drop which calls xy_normal_length(), normal_length(),
        // and center_height() on the subclass
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: virtual bool facetDrop(CLPoint &cl, const Triangle &t) const
        public virtual bool facetDrop(CLPoint cl, Triangle t)
        {                                           // Drop cutter at (cl.x, cl.y) against facet of Triangle t
            Point normal = t.upNormal();            // facet surface normal

            if (GlobalMembers.isZero_tol(normal.z)) // vertical surface
            {
                return(false);                      //can't drop against vertical surface
            }
            Debug.Assert(GlobalMembers.isPositive(normal.z));

            if ((GlobalMembers.isZero_tol(normal.x)) && (GlobalMembers.isZero_tol(normal.y)))
            {             // horizontal plane special case
                CCPoint cc_tmp = new CCPoint(cl.x, cl.y, t.p[0].z, CCType.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 = new Point(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       = new CCPoint(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 = CCType.FACET;
                double tip_z = cc_tmp.z + radiusvector.z - this.center_height;
                return(cl.liftZ_if_inFacet(tip_z, cc_tmp, t));
            }
        }
示例#2
0
        // drop-cutter: vertex and facet are handled in base-class

        // drop-cutter: Toroidal cutter edge-test handled here
        // called from MillingCutter::singleEdgeDrop()
        //
        // the canonical geometry is one where (cl.x, cl.y) = (0,0)
        // and the edge is rotated to lie along the x-axis.
        // since the u1-u2 edge is along the x-axis, the points u1 u2 have the same y-coordinate.
        //
        // when a radius2 cylinder around the edge is sliced by an XY plane this
        // results in an ellipse with a shorter axis of radius2, and a longer axis of radius2/sin(theta)
        // where theta is the slope of the edge in the XZ plane
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: System.Tuple< double, double > singleEdgeDropCanonical(const Point& u1, const Point& u2) const
        protected new Tuple <double, double> singleEdgeDropCanonical(Point u1, Point u2)
        {
            if (GlobalMembers.isZero_tol(u1.z - u2.z))
            {             // horizontal edge special case
                return(new Tuple <double, double>(0, u1.z - height(u1.y)));
            }
            else
            {                                                                        // the general offset-ellipse case
                double  b_axis    = radius2;                                         // short axis of ellipse = radius2
                double  theta     = Math.Atan((u2.z - u1.z) / (u2.x - u1.x));        // theta is the slope of the line
                double  a_axis    = Math.Abs(radius2 / Math.Sin(theta));             // long axis of ellipse = radius2/sin(theta)
                Point   ellcenter = new Point(0, u1.y, 0);
                Ellipse e         = new Ellipse(ellcenter, a_axis, b_axis, radius1); // radius1 is the ellipse-offset
                int     iters     = e.solver_brent();                                // numerical solver that searches for a point on the ellipse
                // such that a radius1-length normal-vector from this ellipse-point
                // is at the CL point (0,0)
                if (iters > 200)
                {
                    Console.Write("WARNING: BullCutter::singleEdgeDropCanonical() iters>200 !!\n");
                }
                Debug.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=(0,0) system
                Point ell_ccp = e.ePointHi();
                Debug.Assert(Math.Abs(ell_ccp.xyNorm() - radius1) < 1E-5);     // ell_ccp should be on the cylinder-circle
                Point cc_tmp_u = ell_ccp.closestPoint(u1, u2);                 // find cc-point on u1-u2 edge
                return(new Tuple <double, double>(cc_tmp_u.x, e.getCenterZ() - radius2));
            }
        }
示例#3
0
        /*
         *      /// 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);
        }
示例#4
0
        /// return true if vector parallel to y-axis
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool yParallel() const
        public bool yParallel()
        {
            if (GlobalMembers.isZero_tol(x) && GlobalMembers.isZero_tol(z))
            {
                return(true);
            }
            return(false);
        }
示例#5
0
        // test for intersection with the fiber and a tip-tang line
        // if there is an intersection in tip-tang, calculate the cc-point and update the interval
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool cone_CC(const Point& tang, const Point& tip, const Point& base, const Point& p1, const Point& p2, const Fiber& f, Interval& i) const
        protected bool cone_CC(Point tang, Point tip, Point @base, Point p1, Point p2, Fiber f, Interval i)
        {
            double u = 0;
            double t = 0;

            if (GlobalMembers.xy_line_line_intersection(f.p1, f.p2, ref u, tang, tip, ref t))
            {
                if ((t >= 0.0) && (t <= 1.0))
                {
                    CCPoint cc_tmp = new CCPoint(@base + t * (tip - @base));
                    cc_tmp.z_projectOntoEdge(p1, p2);
                    cc_tmp.type = CCType.EDGE_CONE;
                    return(i.update_ifCCinEdgeAndTrue(u, cc_tmp, p1, p2, (true)));
                }
            }
            return(false);
        }
        /// return true if (s,t) is valid, i.e. lies on the unit circle
        /// checks s^2 + t^2 == 1  (to within tolerance)

        // check that s and t values are OK
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool isValid() const
        public bool isValid()
        {
            if (GlobalMembers.isZero_tol(ocl.GlobalMembers.square(s) + ocl.GlobalMembers.square(t) - 1.0))
            {
                return(true);
            }
            else
            {
                Console.Write(" EllipsePosition=");
                Console.Write(this);
                Console.Write("\n");
                Console.Write(" square(s) + square(t) - 1.0 = ");
                Console.Write(ocl.GlobalMembers.square(s) + ocl.GlobalMembers.square(t) - 1.0);
                Console.Write(" !!\n");
                return(false);
            }
        }
        /// push-cutter horizontal edge case
        /// horizontal are much simpler than the general case.
        /// we can consider the cutter circular with an effective radius of this->width(h)

        // this is the horizontal edge case
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool horizEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const
        protected bool horizEdgePush(Fiber f, Interval i, Point p1, Point p2)
        {
            bool   result = false;
            double h      = p1.z - f.p1.z;        // height of edge above fiber

            if ((h > 0.0))
            {
                if (GlobalMembers.isZero_tol(p2.z - p1.z))
                {                                      // this is the horizontal-edge special case
                    double eff_radius = this.width(h); // the cutter acts as a cylinder with eff_radius
                    // contact this cylinder/circle against edge in xy-plane
                    double qt = 0;                     // fiber is f.p1 + qt*(f.p2-f.p1)
                    double qv = 0;                     // line  is p1 + qv*(p2-p1)
                    if (GlobalMembers.xy_line_line_intersection(p1, p2, ref qv, f.p1, f.p2, ref qt))
                    {
                        Point q = p1 + qv * (p2 - p1);                         // the intersection point
                        // from q, go v-units along tangent, then eff_r*normal, and end up on fiber:
                        // q + ccv*tangent + r*normal = p1 + clt*(p2-p1)
                        double ccv     = 0;
                        double clt     = 0;
                        Point  xy_tang = p2 - p1;
                        xy_tang.z = 0;
                        xy_tang.xyNormalize();
                        Point xy_normal = xy_tang.xyPerp();
                        Point q1        = q + eff_radius * xy_normal;
                        Point q2        = q1 + (p2 - p1);
                        if (GlobalMembers.xy_line_line_intersection(q1, q2, ref ccv, f.p1, f.p2, ref clt))
                        {
                            double t_cl1 = clt;
                            double t_cl2 = qt + (qt - clt);
                            if (calcCCandUpdateInterval(t_cl1, ccv, q, p1, p2, f, i, f.p1.z, CCType.EDGE_HORIZ))
                            {
                                result = true;
                            }
                            if (calcCCandUpdateInterval(t_cl2, -ccv, q, p1, p2, f, i, f.p1.z, CCType.EDGE_HORIZ))
                            {
                                result = true;
                            }
                        }
                    }
                }
            }
            //std::cout << " horizEdgePush = " << result << "\n";
            return(result);
        }
示例#8
0
        /// Cone facet-drop is special, since we can make contact with either the tip or the circular rim

        // 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
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool facetDrop(CLPoint &cl, const Triangle &t) const
        public new bool facetDrop(CLPoint cl, Triangle t)
        {
            bool  result = false;
            Point normal = t.upNormal();            // facet surface normal

            if (GlobalMembers.isZero_tol(normal.z)) // vertical surface
            {
                return(false);                      //can't drop against vertical surface
            }

            if ((GlobalMembers.isZero_tol(normal.x)) && (GlobalMembers.isZero_tol(normal.y)))
            {                                                                         // horizontal plane special case
                CCPoint cc_tmp = new CCPoint(cl.x, cl.y, t.p[0].z, CCType.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 = new CCPoint(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 = CCType.FACET_CYL;

                // tip contact with facet
                CCPoint tip_cc_tmp = new CCPoint(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 = CCType.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);
            }
        }
        /// push-cutter cylindrical shaft case.
        /// This is called when the contact is above the sphere/toroid/cone shaped lower part of the cutter

        // this is used for the cylindrical shaft of Cyl, Ball, Bull, Cone
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool shaftEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const
        protected bool shaftEdgePush(Fiber f, Interval i, Point p1, Point p2)
        {
            // push cutter along Fiber f in contact with edge p1-p2
            // contact with cylindrical cutter shaft
            double u      = 0;
            double v      = 0;
            bool   result = false;

            if (GlobalMembers.xy_line_line_intersection(p1, p2, ref u, f.p1, f.p2, ref v))
            {                                 // find XY-intersection btw fiber and edge
                Point q = p1 + u * (p2 - p1); // edge/fiber intersection point, on edge
                // Point q = f.p1 + v*(f.p2-f.p1); // q on fiber
                // from q, go v_cc*xy_tangent, then r*xy_normal, and end up on fiber:
                // q + v_cc*tangent + r*xy_normal = p1 + t_cl*(p2-p1)
                Point xy_tang = p2 - p1;
                xy_tang.z = 0;
                xy_tang.xyNormalize();
                Point  xy_normal = xy_tang.xyPerp();
                Point  q1        = q + radius * xy_normal;
                Point  q2        = q1 + (p2 - p1);
                double u_cc      = 0;
                double t_cl      = 0;
                if (GlobalMembers.xy_line_line_intersection(q1, q2, ref u_cc, f.p1, f.p2, ref t_cl))
                {
                    double t_cl1 = t_cl;                     // cc_tmp1 = q +/- u_cc*(p2-p1);
                    double t_cl2 = v + (v - t_cl);
                    if (calcCCandUpdateInterval(t_cl1, u_cc, q, p1, p2, f, i, f.p1.z + center_height, CCType.EDGE_SHAFT))
                    {
                        result = true;
                    }
                    if (calcCCandUpdateInterval(t_cl2, -u_cc, q, p1, p2, f, i, f.p1.z + center_height, CCType.EDGE_SHAFT))
                    {
                        result = true;
                    }
                }
            }
            //std::cout << " shaftEdgePush = " << result << "\n";
            return(result);
        }
示例#10
0
        /// return closest Point to line through p1 and p2. Works in the XY plane.

        /// return Point on p1-p2 line which is closest in XY-plane to this
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: Point xyClosestPoint(const Point &p1, const Point &p2) const
        public Point xyClosestPoint(Point p1, Point p2)
        {
            // one explanation is here
            // http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/
            Point pt1 = new Point(p1);             // this required because of "const" arguments above.
            Point pt2 = new Point(p2);
            Point v   = pt2 - pt1;

            if (GlobalMembers.isZero_tol(v.xyNorm()))
            {             // if p1 and p2 do not make a line in the xy-plane
                Console.Write("point.cpp: xyClosestPoint ERROR!: can't calculate closest point from \n");
                Console.Write("point.cpp: xyClosestPoint ERROR!: *this =");
                Console.Write(this);
                Console.Write(" to line through\n");
                Console.Write("point.cpp: xyClosestPoint ERROR!: p1=");
                Console.Write(p1);
                Console.Write(" and \n");
                Console.Write("point.cpp: xyClosestPoint ERROR!: p2=");
                Console.Write(p2);
                Console.Write("\n");
                Console.Write("point.cpp: xyClosestPoint ERROR!: in the xy-plane\n");
                Debug.Assert(false);
                return(new Point(0, 0, 0));
            }

            double u;

            // vector notation:
            // u = (p3-p1) dot v / (v dot v)
            u = (this.x - p1.x) * (v.x) + (this.y - p1.y) * (v.y);
            u = u / (v.x * v.x + v.y * v.y);
            // coordinates for closest point
            double x = p1.x + u * v.x;
            double y = p1.y + u * v.y;

            return(new Point(x, y, 0));
        }
示例#11
0
        /// \brief drop cutter at (cl.x, cl.y) against the three edges of input Triangle t.
        /// calls the sub-class MillingCutter::singleEdgeDrop on each edge
        /// if cl.z is too low, updates cl.z so that cutter does not cut any edge.

        // edge-drop function which calls the sub-class MillingCutter::singleEdgeDrop on each
        // edge of the input Triangle t.
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: virtual bool edgeDrop(CLPoint &cl, const Triangle &t) const
        public virtual bool edgeDrop(CLPoint cl, Triangle t)
        {
            bool result = false;

            for (int n = 0; n < 3; n++)
            {                              // loop through all three edges
                int   start = n;           // index of the start-point of the edge
                int   end   = (n + 1) % 3; // index of the end-point of the edge
                Point p1    = t.p[start];
                Point p2    = t.p[end];
                if (!GlobalMembers.isZero_tol(p1.x - p2.x) || !GlobalMembers.isZero_tol(p1.y - p2.y))
                {
                    double d = cl.xyDistanceToLine(p1, p2);
                    if (d <= radius)                     // potential contact with edge
                    {
                        if (this.singleEdgeDrop(cl, p1, p2, d))
                        {
                            result = true;
                        }
                    }
                }
            }
            return(result);
        }
示例#12
0
        // 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);
        }
示例#13
0
        /// string repr
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: string str() const;
//C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:
//		string str();

        /// build and return a KDNode containing list *tris at depth dep.
        protected KDNode <Triangle> build_node(LinkedList <Triangle> tris, int dep, KDNode <Triangle> par)
        {         // parent node
            //std::cout << "KDNode::build_node list.size()=" << tris->size() << "\n";

            if (tris.Count == 0)
            {             //this is a fatal error.
                Console.Write("ERROR: KDTree::build_node() called with tris->size()==0 !");
                Debug.Assert(false);
                return(null);
            }
            Spread spr      = calc_spread(tris);        // calculate spread in order to know how to cut
            double cutvalue = spr.start + spr.val / 2;  // cut in the middle

            //std::cout << " cutvalue= " << cutvalue << "\n";
            if ((tris.Count <= bucketSize) || GlobalMembers.isZero_tol(spr.val))
            {                             // then return a bucket/leaf node
                //std::cout << "KDNode::build_node BUCKET list.size()=" << tris->size() << "\n";
                KDNode <Triangle> bucket; //  dim   cutv   parent   hi    lo   triangles depth
                bucket = new KDNode <Triangle>(spr.d, cutvalue, par, null, null, tris, dep);
                Debug.Assert(bucket.isLeaf);
                spr = null;
                return(bucket);                // this is the leaf/end of the recursion-tree
            }
            // build lists of triangles for hi and lo child nodes
            LinkedList <Triangle> lolist = new LinkedList <Triangle>();
            LinkedList <Triangle> hilist = new LinkedList <Triangle>();

            foreach (Triangle t in tris)
            {             // loop through each triangle and put it in either lolist or hilist
                if (t.bb[spr.d] > cutvalue)
                {
                    hilist.AddLast(t);
                }
                else
                {
                    lolist.AddLast(t);
                }
            }

            /*
             * if (hilist->empty() || lolist->empty()) {// an error ??
             *  std::cout << "kdtree: hilist.size()==0! or lolist.size()==0! \n";
             *  std::cout << "kdtree: tris->size()= " << tris->size()<< "\n";
             *  std::cout << "kdtree: hilist.size()= " << hilist->size()<< "\n";
             *  std::cout << "kdtree: lolist.size()= " << lolist->size()<< "\n";
             *  BOOST_FOREACH(Triangle t, *tris) {
             *      std::cout << t << "\n";
             *      std::cout << t.bb << "\n";
             *  }
             *  std::cout << "kdtree: spr->d= " << spr->d << "\n";
             *  std::cout << "kdtree: cutvalue= " << cutvalue << "\n";
             *  assert(0);
             * }*/


            // create the current node  dim     value    parent  hi   lo   trilist  depth
            KDNode <Triangle> node = new KDNode <Triangle>(spr.d, cutvalue, par, null, null, null, dep);

            // create the child-nodes through recursion
            //                    list    depth   parent
            if (hilist.Count > 0)
            {
                node.hi = build_node(hilist, dep + 1, node);
            }
            //else
            //std::cout << "hilist empty!\n";

            if (lolist.Count > 0)
            {
                node.lo = build_node(lolist, dep + 1, node);
            }
            else
            {
                //std::cout << "lolist empty!\n";
            }

            lolist.Clear();
            hilist.Clear();
            spr    = null;
            lolist = null;
            hilist = null;

            return(node);            // return a new node
        }
示例#14
0
        /// 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);
        }
示例#15
0
        // push-cutter: vertex and facet handled in base-class
//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 - p1).xyNorm()))
            {             // this would be a vertical edge
                return(result);
            }

            Point ufp1 = f.p1 + new Point(0, 0, radius);             // take a fiber which is raised up by radius
            Point ufp2 = f.p2 + new Point(0, 0, radius);             // and intersect it with a cylinder around the edge p1-p2
            // Ray : P(t) = O + t*V    from point O, in direction V
            // Cylinder [A, B, r]   from point A to point B, radius r
            // Point P on infinite cylinder if ((P - A) x (B - A))^2 = r^2 * (B - A)^2
            // expand : ((O - A) x (B - A) + t * (V x (B - A)))^2 = r^2 * (B - A)^2
            // equation in the form (X + t * Y)^2 = d , where:
            //  X = (O - A) x (B - A)
            //  Y = V x (B - A)
            //  d = r^2 * (B - A)^2
            // expand the equation :
            // t^2 * (Y . Y) + t * (2 * (X . Y)) + (X . X) - d = 0
            // => second order equation in the form : a*t^2 + b*t + c = 0 where
            // a = (Y . Y)
            // b = 2 * (X . Y)
            // c = (X . X) - d
            Point  ab      = p2 - p1;                   // axis of the cylinder
            Point  ao      = (ufp1 - p1);               // cyl start to ray start
            Point  ao_x_ab = ao.cross(ab);              // cross product
            Point  v_x_ab  = (ufp2 - ufp1).cross(ab);   // cross product
            double ab2     = ab.dot(ab);                // dot product
            double a       = v_x_ab.dot(v_x_ab);        // dot product
            double b       = 2 * (v_x_ab.dot(ao_x_ab)); // dot product
            double c       = ao_x_ab.dot(ao_x_ab) - (radius * radius * ab2);
            // solve second order equation : a*t^2 + b*t + c = 0
            // t = (-b +/- sqrt( b^2 - 4ac ) )   / 2a
            double discr = b * b - 4 * a * c;
            double t1;
            double t2;

            if (GlobalMembers.isZero_tol(discr))
            {             // tangent case, only one root
                t1 = -b / (2 * a);
                if (calcCCandUpdateInterval(t1, p1, p2, f, i))
                {
                    result = true;
                }
            }
            else if (discr > 0.0)
            {             // two roots
                t1 = (-b + Math.Sqrt(discr)) / (2 * a);
                t2 = (-b - Math.Sqrt(discr)) / (2 * a);
                if (calcCCandUpdateInterval(t1, p1, p2, f, i))
                {
                    result = true;
                }
                if (calcCCandUpdateInterval(t2, p1, p2, f, i))
                {
                    result = true;
                }
            }
            return(result);
        }
示例#16
0
        /// push cutter with given normal/center/xy_length into contact with Triangle facet

        // general purpose facetPush
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:
//ORIGINAL LINE: bool generalFacetPush(double normal_length, double center_height, double xy_normal_length, const Fiber& fib, Interval& i, const Triangle& t) const
        protected bool generalFacetPush(double normal_length, double center_height, double xy_normal_length, Fiber fib, Interval i, Triangle t)
        {
            bool  result = false;
            Point normal = t.upNormal();       // facet surface normal, pointing up

            if (normal.zParallel())            // normal points in z-dir
            {
                return(result);                //can't push against horizontal plane, stop here.
            }
            normal.normalize();
            Point xy_normal = new Point(normal);

            xy_normal.z = 0;
            xy_normal.xyNormalize();

            //   find a point on the plane from which radius2*normal+radius1*xy_normal lands on the fiber+radius2*Point(0,0,1)
            //   (u,v) locates a point on the triangle facet    v0+ u*(v1-v0)+v*(v2-v0)    u,v in [0,1]
            //   t locates a point along the fiber:             p1 + t*(p2-p1)             t in [0,1]
            //
            //   facet-point + r2 * n + r1* xy_n = fiber-point + r2*Point(0,0,1)
            //   =>
            //   v0+ u*(v1-v0)+v*(v2-v0) + r2 * n + r1* xy_n  = p1 + t*(p2-p1) + r2*Point(0,0,1)
            //
            //   v0x + u*(v1x-v0x) + v*(v2x-v0x) + r2*nx + r1*xy_n.x  = p1x + t*(p2x-p1x)          p2x-p1x==0 for Y-fiber
            //   v0y + u*(v1y-v0y) + v*(v2y-v0y) + r2*ny + r1*xy_n.y  = p1y + t*(p2y-p1y)          p2y-p1y==0 for X-fiber
            //   v0z + u*(v1z-v0z) + v*(v2z-v0z) + r2*nz              = p1z + t*(p2z-p1z) + r2    (p2z-p1z)==0 for XY-fibers!!
            //   X-fiber:
            //   v0x + u*(v1x-v0x) + v*(v2x-v0x) + r2*nx + r1*xy_n.x  = p1x + t*(p2x-p1x)
            //   v0y + u*(v1y-v0y) + v*(v2y-v0y) + r2*ny + r1*xy_n.y  = p1y                    solve these  two for (u,v)
            //   v0z + u*(v1z-v0z) + v*(v2z-v0z) + r2*nz              = p1z + r2               and substitute above for t
            //   or
            //   [ (v1y-v0y)    (v2y-v0y) ] [ u ] = [ -v0y - r2*ny - r1*xy_n.y + p1y     ]
            //   [ (v1z-v0z)    (v2z-v0z) ] [ v ] = [ -v0z - r2*nz + p1z + r2            ]
            //
            //   Y-fiber:
            //   [ (v1x-v0x)    (v2x-v0x) ] [ u ] = [ -v0x - r2*nx - r1*xy_n.x + p1x     ]

            double a;
            double b;
            double c = t.p[1].z - t.p[0].z;
            double d = t.p[2].z - t.p[0].z;
            double e;
            double f = -t.p[0].z - normal_length * normal.z + fib.p1.z + center_height;
            // note: the xy_normal does not have a z-component, so omitted here.

            double u = 0;           // u and v are coordinates of the cc-point within the triangle facet
            double v = 0;

            // a,b,e depend on the fiber:
            if (fib.p1.y == fib.p2.y)
            {             // XFIBER
                a = t.p[1].y - t.p[0].y;
                b = t.p[2].y - t.p[0].y;
                e = -t.p[0].y - normal_length * normal.y - xy_normal_length * xy_normal.y + fib.p1.y;
                if (!GlobalMembers.two_by_two_solver(a, b, c, d, e, f, ref u, ref v))
                {
                    return(result);
                }
                CCPoint cc = new CCPoint(t.p[0] + u * (t.p[1] - t.p[0]) + v * (t.p[2] - t.p[0]));
                cc.type = CCType.FACET;
                if (!cc.isInside(t))
                {
                    return(result);
                }
                // v0x + u*(v1x-v0x) + v*(v2x-v0x) + r2*nx + r1*xy_n.x = p1x + t*(p2x-p1x)
                // =>
                // t = 1/(p2x-p1x) * ( v0x + r2*nx + r1*xy_n.x - p1x +  u*(v1x-v0x) + v*(v2x-v0x)       )
                Debug.Assert(!GlobalMembers.isZero_tol(fib.p2.x - fib.p1.x));                 // guard against division by zero
                double tval = (1.0 / (fib.p2.x - fib.p1.x)) * (t.p[0].x + normal_length * normal.x + xy_normal_length * xy_normal.x - fib.p1.x + u * (t.p[1].x - t.p[0].x) + v * (t.p[2].x - t.p[0].x));
                if (tval < 0.0 || tval > 1.0)
                {
                    Console.Write("MillingCutter::facetPush() tval= ");
                    Console.Write(tval);
                    Console.Write(" error!?\n");
                    //std::cout << " cutter: " << *this << "\n";
                    Console.Write(" triangle: ");
                    Console.Write(t);
                    Console.Write("\n");
                    Console.Write(" fiber: ");
                    Console.Write(fib);
                    Console.Write("\n");
                }
                Debug.Assert(tval > 0.0 && tval < 1.0);
                i.update(tval, cc);
                result = true;
            }
            else if (fib.p1.x == fib.p2.x)
            {             // YFIBER
                a = t.p[1].x - t.p[0].x;
                b = t.p[2].x - t.p[0].x;
                e = -t.p[0].x - normal_length * normal.x - xy_normal_length * xy_normal.x + fib.p1.x;
                if (!GlobalMembers.two_by_two_solver(a, b, c, d, e, f, ref u, ref v))
                {
                    return(result);
                }
                CCPoint cc = new CCPoint(t.p[0] + u * (t.p[1] - t.p[0]) + v * (t.p[2] - t.p[0]));
                cc.type = CCType.FACET;
                if (!cc.isInside(t))
                {
                    return(result);
                }
                Debug.Assert(!GlobalMembers.isZero_tol(fib.p2.y - fib.p1.y));
                double tval = (1.0 / (fib.p2.y - fib.p1.y)) * (t.p[0].y + normal_length * normal.y + xy_normal_length * xy_normal.y - fib.p1.y + u * (t.p[1].y - t.p[0].y) + v * (t.p[2].y - t.p[0].y));
                if (tval < 0.0 || tval > 1.0)
                {
                    Console.Write("MillingCutter::facetPush() tval= ");
                    Console.Write(tval);
                    Console.Write(" error!?\n");
                    Console.Write(" (most probably a user error, the fiber is too short compared to the STL model?)\n");
                }
                Debug.Assert(tval > 0.0 && tval < 1.0);
                i.update(tval, cc);
                result = true;
            }
            else
            {
                Debug.Assert(false);
            }

            return(result);
        }