Example #1
0
        public static double? VertexTest(Cutter c,Geo.Point e, Geo.Point p)
       {
           // c.R and c.r define the cutter
           // e.x and e.y is the xy-position of the cutter (e.z is ignored)
           // p is the vertex tested against

           // q is the distance along xy-plane from e to vertex
           double q = Math.Sqrt(Math.Pow(e.x - p.x, 2) + Math.Pow((e.y - p.y), 2));

           if (q > c.R)
           { 
               // vertex is outside cutter. no need to do anything!
               return null;
           }
           else if (q <= (c.R - c.r))
           { 
                // vertex is in the cylindical/flat part of the cutter
               return p.z;
           }
           else if ((q > (c.R - c.r)) && (q <= c.R))
           {
               // vertex is in the toroidal part of the cutter
               double h2 = Math.Sqrt(Math.Pow(c.r, 2) - Math.Pow((q - (c.R - c.r)), 2));
               double h1 = c.r - h2;
               return p.z - h1;
           }
           else
           {
               // SERIOUS ERROR, we should not be here!
               System.Console.WriteLine("DropCutter: VertexTest: ERROR!");
               return null;
           }

       } // end VertexTest
Example #2
0
        public static void search_kdtree(List<Tri> tlist, Point p, Cutter c, kd_node node)
        {
            ns+=1;

            if (node.tris != null)
            {
                if (node.tris.Count > 0)
                {   // add all triangles of a bucket node
                    foreach (Tri t in node.tris)
                    {
                        // check that t belongs
                        if ((p.x + c.R) < t.bb.minx)
                            return;
                        else if ((p.x - c.R) > t.bb.maxx)
                            return;
                        else if ((p.y + c.R) < t.bb.miny)
                            return;
                        else if ((p.y - c.R) > t.bb.maxy)
                            return;
                        else
                            tlist.Add(t);
                    }
                    return;
                }
            }

            switch (node.dim)
            {
                case 0: // cut along xplus
                    if (node.cutval <= p.x - c.R)
                        search_kdtree(tlist, p, c, node.hi);
                    else
                    {
                        search_kdtree(tlist, p, c, node.hi);
                        search_kdtree(tlist, p, c, node.lo);
                    }
                    break;
                case 1: // cut along xminus
                    if (node.cutval >= p.x + c.R)
                        search_kdtree(tlist, p, c, node.lo);
                    else
                    {
                        search_kdtree(tlist, p, c, node.hi);
                        search_kdtree(tlist, p, c, node.lo);
                    }
                    break;
                case 2: // cut along yplus
                    if (node.cutval <= p.y - c.R)
                        search_kdtree(tlist, p, c, node.hi);
                    else
                    {
                        search_kdtree(tlist, p, c, node.hi);
                        search_kdtree(tlist, p, c, node.lo);
                    }
                    break;
                case 3: // cut along yminus
                    if (node.cutval >= p.y + c.R)
                        search_kdtree(tlist, p, c, node.lo);
                    {
                        search_kdtree(tlist, p, c, node.hi);
                        search_kdtree(tlist, p, c, node.lo);
                    }
                    break;
            }
            return;
        }
Example #3
0
        public static void stlmachine(GLWindow g, STLSurf s)
        {
            List<Geo.Point> pointlist=new List<Geo.Point>();

            // seems to work...
            // foreach (Geo.Tri t in s.tris)
            //    System.Console.WriteLine("loop1 triangles " + t);
            // System.Console.ReadKey();

            // recalculate normal data
            // create bounding box data
            foreach (Geo.Tri t in s.tris)
            {
                t.recalc_normals(); // FIXME why don't new values stick??
                t.calc_bbox(); // FIXME: why doen't bb-data 'stick' ??
            }

            /*
            // FIXME: if we check bb-data here it is gone!!(??)
            foreach (Geo.Tri t in s.tris)
            {
                System.Console.WriteLine("loop2 triangles " + t);
                System.Console.WriteLine("loop2 direct maxx" + t.bb.maxx + " minx:" + t.bb.minx);
            }
            System.Console.ReadKey();
            */

            // find bounding box (this should probably be done in the STLSurf class?)
            double minx = 0, maxx = 10, miny = 0, maxy = 10;

            // generate XY pattern (a general zigzag-strategy, needed also for pocketing)
            double Nx=50;
            double Ny=50;
            double dx=(maxx-minx)/(double)(Nx-1);
            double dy = (maxy - miny) / (double)(Ny-1);
            double x = minx;
            for (int n = 0; n < Nx; n++)
            {
                if (n%2==0)
                {
                    double y = miny;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Geo.Point(x,y,5));
                        // System.Console.WriteLine("x:"+x+" y:"+y);
                        y += dy;
                        // System.Console.ReadKey();
                    }
                }
                else
                {
                    double y = maxy;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Geo.Point(x,y,5));
                        //System.Console.WriteLine("x:" + x + " y:" + y);
                        y -= dy;
                        //System.Console.ReadKey();
                    }
                }
                x += dx;
            }

            // drop cutter (i.e. add z-data)
            double R=1,r=0.2;
            Cutter cu = new Cutter(R,r);
            List<Geo.Point> drop_points = new List<Geo.Point>();
            double redundant = 0;
            double checks = 0;
            foreach (Geo.Point p in pointlist)
            {

                double? v1 = null,v2=null,v3=null,z_new=null,f=null,e1=null,e2=null,e3=null;
                List<double> zlist = new List<double>();

                foreach (Geo.Tri t in s.tris)
                {
                    checks++;
                    t.calc_bbox(); // why do we have to re-calculate bb-data here??

                    //System.Console.WriteLine("testing triangle" + t);
                    if (t.bb.minx > (p.x + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    else if (t.bb.maxx < (p.x - cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.miny > (p.y + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.maxy < (p.y - cu.R))
                    {
                        redundant++;
                        continue;
                    }

                    v1 = DropCutter.VertexTest(cu, p, t.p[0]);
                    v2 = DropCutter.VertexTest(cu, p, t.p[1]);
                    v3 = DropCutter.VertexTest(cu, p, t.p[2]);
                    if (v2 != null)
                    {
                        zlist.Add((double)v2);
                    }
                    if (v1 != null)
                    {
                        zlist.Add((double)v1);
                    }
                    if (v3 != null)
                    {
                        zlist.Add((double)v3);
                    }

                    f = DropCutter.FacetTest(cu, p, t);
                    if (f != null)
                    {
                        zlist.Add((double)f);
                    }

                    e1 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[1]);
                    e2 = DropCutter.EdgeTest(cu, p, t.p[1], t.p[2]);
                    e3 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[2]);

                    if (e1 != null)
                        zlist.Add((double)e1);
                    if (e2 != null)
                        zlist.Add((double)e2);
                    if (e3 != null)
                        zlist.Add((double)e3);

                    /*
                    if (zlist.Count > 1)
                    {
                        System.Console.Write("Before: ");
                        foreach (double d in zlist)
                            System.Console.Write(d.ToString() + " ");
                        System.Console.Write("\n");
                    }
                     */

                    zlist.Sort();
                    /*
                    if (zlist.Count > 2)
                    {
                        System.Console.Write("After: ");
                        foreach (double d in zlist)
                            System.Console.Write(d.ToString() + " ");
                        System.Console.Write("\n");
                    }
                     */
                    // System.Console.Write("Sorted: ");
                    // foreach (double d in zlist)
                    //    System.Console.Write(d.ToString() + " ");
                    // System.Console.Write("\n");

                    if (zlist.Count > 0)
                        z_new = zlist[zlist.Count-1];
                    /*
                     if (zlist.Count > 1)
                        System.Console.WriteLine("chosen: " + z_new);
                     */
                    // System.Console.ReadKey();

                } // end triangle loop

                if (z_new != null)
                {
                    drop_points.Add(new Geo.Point(p.x, p.y, (double)z_new));
                }

            } // end point-list loop

            System.Console.WriteLine("checked: "+ checks + " redundant: " + redundant);
            System.Console.WriteLine("relevant: "+(checks-redundant) + "  ("+100*(double)(checks-redundant)/(double)checks+"%)");

            // check to see that STL has not changed

            // display drop-points
            int i = 1;
            Geo.Point p0=new Geo.Point();
            foreach (Geo.Point p in drop_points)
            {

                if (i == 1) // first move
                {
                    p0 = new Geo.Point(p.x, p.y, 10);
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Yellow;
                    g.addGeom(l);
                    p0 = p;
                }
                else  // don't do anything for last move
                {
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Magenta;
                    g.addGeom(l);
                    p0 = p;
                }
                i++;

                /*
                GeoPoint pg = new GeoPoint(p);
                pg.color = System.Drawing.Color.Aqua;
                g.addGeom(pg);
                 */

            }

            // display zigzag and points
            /*
            i = 1;
            foreach (Geo.Point p in pointlist)
            {
                if (i == 1)
                {
                    p0 = new Geo.Point(p.x, p.y, 10);
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Yellow;
                    g.addGeom(l);
                    p0 = p;
                }
                else
                {
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Cyan;
                    g.addGeom(l);
                    p0 = p;
                }
                i++;
            }
            */

            // dummy test:
            /*
            foreach (Geo.Tri t in s.tris)
            {
                GeoPoint p = new GeoPoint(t.p[0].x, t.p[0].y, t.p[0].z);
                pointlist.Add(p);
            }
            */
        }
Example #4
0
        public static void stlmachine(STLSurf s, GeoCollection g)
        {
            List <Point> pointlist = new List <Point>();

            // seems to work...
            // foreach (Geo.Tri t in s.tris)
            //    System.Console.WriteLine("loop1 triangles " + t);
            // System.Console.ReadKey();

            // recalculate normal data
            // create bounding box data
            foreach (Tri t in s.tris)
            {
                t.recalc_normals();  // FIXME why don't new values stick??
                t.calc_bbox();       // FIXME: why doen't bb-data 'stick' ??
            }

            /*
             * // FIXME: if we check bb-data here it is gone!!(??)
             * foreach (Geo.Tri t in s.tris)
             * {
             *  System.Console.WriteLine("loop2 triangles " + t);
             *  System.Console.WriteLine("loop2 direct maxx" + t.bb.maxx + " minx:" + t.bb.minx);
             * }
             * System.Console.ReadKey();
             */

            // find bounding box (this should probably be done in the STLSurf class?)
            double minx = 0, maxx = 10, miny = 0, maxy = 10;

            // generate XY pattern (a general zigzag-strategy, needed also for pocketing)
            // store in a list called pointlist
            double Nx = 30;
            double Ny = 40;
            double dx = (maxx - minx) / (double)(Nx - 1);
            double dy = (maxy - miny) / (double)(Ny - 1);
            double x  = minx;

            for (int n = 0; n < Nx; n++)
            {
                if (n % 2 == 0)
                {
                    double y = miny;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Point(x, y, 5));
                        // System.Console.WriteLine("x:"+x+" y:"+y);
                        y += dy; // go forward in the y-axis direction
                        // System.Console.ReadKey();
                    }
                }
                else
                {
                    double y = maxy;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Point(x, y, 5));
                        //System.Console.WriteLine("x:" + x + " y:" + y);
                        y -= dy; // go backward in the y-axis direction
                        //System.Console.ReadKey();
                    }
                }
                x += dx;
            }


            // drop cutter (i.e. add z-data)

            double R = 1, r = 0.2; // this is the cutter definition
            Cutter cu = new Cutter(R, r);

            List <Point> drop_points = new List <Point>();
            double       redundant   = 0; // number of unneccesary calls to drop-cutter
            double       checks      = 0; // number of relevant calls

            // build the kd-tree
            Stopwatch st = new Stopwatch();

            Console.WriteLine("Building kd-tree. Stopwatch start");
            st.Start();
            kd_node root;

            root = kdtree.build_kdtree(s.tris);
            st.Stop();
            Console.WriteLine("Elapsed = {0}", st.Elapsed.ToString());



            // FIXME: these calls to drop-cutter are independent of each other
            // thus the points could/should be divided into many subsets
            // and each subset is processed by a seprarate thread
            // this should give a substantial speedup on multi-core cpus
            Console.WriteLine("Running drop-cutter. Stopwatch start");
            st.Start();
            foreach (Point p in pointlist) // loop through each point
            {
                double?v1 = null, v2 = null, v3 = null, z_new = null, f = null, e1 = null, e2 = null, e3 = null;

                // store the possible z-values in this list
                // the highest one of these should be chosen in the end
                List <double> zlist = new List <double>();

                // find triangles under cutter using kd-tree


                int        mode           = 1;
                List <Tri> tris_to_search = new List <Tri>();

                if (mode == 0)
                {
                    tris_to_search = s.tris;
                }
                else if (mode == 1)
                {
                    kdtree.search_kdtree(tris_to_search, p, cu, root);
                }
                //Console.WriteLine("searching {0} tris",tris_to_search.Count);
                //Console.ReadKey();



                // loop through each triangle
                foreach (Tri t in tris_to_search)
                {
                    checks++;
                    t.calc_bbox(); // FIXME: why do we have to re-calculate bb-data here??

                    //System.Console.WriteLine("testing triangle" + t);

                    // here are four ways the triangle bounding box can be
                    // outside the cutter bounding box
                    // redundant could be used to test the performance of bucketing/kd-tree
                    if (t.bb.minx > (p.x + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    else if (t.bb.maxx < (p.x - cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.miny > (p.y + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.maxy < (p.y - cu.R))
                    {
                        redundant++;
                        continue;
                    }

                    // test cutter against each vertex
                    v1 = DropCutter.VertexTest(cu, p, t.p[0]);
                    v2 = DropCutter.VertexTest(cu, p, t.p[1]);
                    v3 = DropCutter.VertexTest(cu, p, t.p[2]);
                    if (v2 != null)
                    {
                        zlist.Add((double)v2);
                    }
                    if (v1 != null)
                    {
                        zlist.Add((double)v1);
                    }
                    if (v3 != null)
                    {
                        zlist.Add((double)v3);
                    }



                    // test cutter against facet
                    f = DropCutter.FacetTest(cu, p, t);
                    if (f != null)
                    {
                        zlist.Add((double)f);
                    }


                    // test cutter against each edge
                    e1 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[1]);
                    e2 = DropCutter.EdgeTest(cu, p, t.p[1], t.p[2]);
                    e3 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[2]);
                    if (e1 != null)
                    {
                        zlist.Add((double)e1);
                    }
                    if (e2 != null)
                    {
                        zlist.Add((double)e2);
                    }
                    if (e3 != null)
                    {
                        zlist.Add((double)e3);
                    }

                    // now we have some suggestions for z in zlist
                    // by sorting it we get the highest one at the end of the list
                    zlist.Sort();

                    // if there's anything in the list, return the last element
                    if (zlist.Count > 0)
                    {
                        z_new = zlist[zlist.Count - 1];
                    }
                } // end triangle loop

                // we've gone through all triangles for this XY-location
                // if we found a z-value, let's add the valid cutter location
                // to a list drop_points
                if (z_new != null)
                {
                    drop_points.Add(new Point(p.x, p.y, (double)z_new));
                }
            } // end point-list loop
            st.Stop();
            Console.WriteLine("Elapsed = {0}", st.Elapsed.ToString());

            // print some statistics:
            System.Console.WriteLine("checked: " + checks + " redundant: " + redundant);
            double fraction = (100 * (double)(checks - redundant) / (double)checks);

            System.Console.WriteLine("relevant: " + (checks - redundant) + "  (" + fraction.ToString("N3") + "%)");



            // FIXME: now a toolpath object should be created
            // that has rapids/feeds according to the points calculated above
            int   i  = 1;
            Point p0 = new Point();

            // this is needed so we get decimal points, not commas
            System.Globalization.CultureInfo glob = new System.Globalization.CultureInfo("en-GB");
            Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-GB");

            foreach (Point p in drop_points)
            {
                if (i == 1) // first move
                {
                    p0 = new Point(p.x, p.y, 12);

                    camtest.outfile.WriteLine("Cylinder");
                    camtest.outfile.WriteLine("{0},{1},{2}", p0.x.ToString("0.000", glob), p0.y.ToString("0.000", glob), p0.z.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0}", 0.01.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0},{1},{2}", p.x.ToString("0.000", glob), p.y.ToString("0.000", glob), p.z.ToString("0.000", glob));
                    Line l = new Line(p0, p);
                    g.add(l); //  ADD geometry to toolpath

                    p0 = p;
                }
                else
                {
                    camtest.outfile.WriteLine("Cylinder");
                    camtest.outfile.WriteLine("{0},{1},{2}", p0.x.ToString("0.000", glob), p0.y.ToString("0.000", glob), p0.z.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0}", 0.01.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0},{1},{2}", p.x.ToString("0.000", glob), p.y.ToString("0.000", glob), p.z.ToString("0.000", glob));
                    Line l = new Line(p0, p);
                    g.add(l);  // ADD geometry to toolpath
                    p0 = p;
                }
                i++;
            }
        }
Example #5
0
        public static double? EdgeTest(Cutter cu, Point e, Point p1, Point p2)
        {
            // contact cutter against edge from p1 to p2

            // translate segment so that cutter is at (0,0)
            Point start = new Point(p1.x - e.x, p1.y - e.y, p1.z);
            Point end = new Point(p2.x - e.x, p2.y - e.y, p2.z);

            // find angle btw. segment and X-axis
            double dx = end.x - start.x;
            double dy = end.y - start.y;
            double alfa;
            if (dx != 0)
                alfa = Math.Atan(dy / dx);
            else
                alfa = Math.PI / 2;

            //alfa = -alfa;
            // rotation matrix for rotation around z-axis:
            // should probably implement a matrix class later

            // rotate by angle alfa
            // need copy of data that does not change as we go through each line:
            double sx = start.x, sy = start.y, ex = end.x, ey = end.y;
            start.x = sx * Math.Cos(alfa) + sy * Math.Sin(alfa);
            start.y = -sx * Math.Sin(alfa) + sy * Math.Cos(alfa);
            end.x = ex * Math.Cos(alfa) + ey * Math.Sin(alfa);
            end.y = -ex * Math.Sin(alfa) + ey * Math.Cos(alfa);

            // check if segment is below cutter

            if (start.y > 0)
            {
                alfa = alfa+Math.PI;
                start.x = sx * Math.Cos(alfa) + sy * Math.Sin(alfa);
                start.y = -sx * Math.Sin(alfa) + sy * Math.Cos(alfa);
                end.x = ex * Math.Cos(alfa) + ey * Math.Sin(alfa);
                end.y = -ex * Math.Sin(alfa) + ey * Math.Cos(alfa);
            }

            if (Math.Abs(start.y-end.y)>0.0000001)
            {
                System.Console.WriteLine("EdgeTest ERROR! (start.y - end.y) = " +(start.y-end.y));
                return null;
            }

            double l = -start.y; // distance from cutter to edge
            if (l < 0)
                System.Console.WriteLine("EdgeTest ERROR! l<0 !");

            // System.Console.WriteLine("l=" + l+" start.y="+start.y+" end.y="+end.y);

            // now we have two different algorithms depending on the cutter:
            if (cu.r == 0)
            {
                // this is the flat endmill case
                // it is easier and faster than the general case, so we handle it separately
                if (l > cu.R) // edge is outside of the cutter
                    return null;
                else // we are inside the cutter
                {   // so calculate CC point
                    double xc1 = Math.Sqrt(Math.Pow(cu.R, 2) - Math.Pow(l, 2));
                    double xc2 = -xc1;
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;

                    // choose the higher point
                    double zc,xc;
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }

                    // now that we have a CC point, check if it's in the edge
                    if ((start.x > xc) && (xc < end.x))
                        return null;
                    else if ((end.x < xc) && (xc > start.x))
                        return null;
                    else
                        return zc;

                }
                // unreachable place (according to compiler)
            } // end of flat endmill (r=0) case
            else if (cu.r > 0)
            {
                // System.Console.WriteLine("edgetest r>0 case!");

                // this is the general case (r>0)   ball-nose or bull-nose (spherical or toroidal)
                // later a separate case for the ball-cutter might be added (for performance)

                double xd=0, w=0, h=0, xd1=0, xd2=0, xc=0 , ze=0, zc=0;

                if (l > cu.R) // edge is outside of the cutter
                    return null;
                else if (((cu.R-cu.r)<l)&&(l<=cu.R))
                {    // toroidal case
                    xd=0; // center of ellipse
                    w=Math.Sqrt(Math.Pow(cu.R,2)-Math.Pow(l,2)); // width of ellipse
                    h=Math.Sqrt(Math.Pow(cu.r,2)-Math.Pow((l-(cu.R-cu.r)),2)); // height of ellipse
                }
                else if ((cu.R-cu.r)>=l)
                {
                    // quarter ellipse case
                    xd1=Math.Sqrt( Math.Pow((cu.R-cu.r),2)-Math.Pow(l,2));
                    xd2=-xd1;
                    h=cu.r; // ellipse height
                    w=Math.Sqrt( Math.Pow(cu.R,2)-Math.Pow(l,2) )- Math.Sqrt( Math.Pow((cu.R-cu.r),2)-Math.Pow(l,2) ); // ellipse height
                }

                // now there is a special case where the theta calculation will fail if
                // the segment is horziontal, i.e. start.z==end.z  so we need to catch that here
                if (start.z==end.z)
                {
                    if ((cu.R-cu.r)<l)
                    {
                        // half-ellipse case
                        xc=0;
                        h=Math.Sqrt(Math.Pow(cu.r,2)-Math.Pow((l-(cu.R-cu.r)),2));
                        ze = start.z + h - cu.r;
                    }
                    else if ((cu.R - cu.r) > l)
                    {
                        // quarter ellipse case
                        xc = 0;
                        ze = start.z;
                    }

                    // now we have a CC point
                    // so we need to check if the CC point is in the edge
                    if (isinrange(start.x, end.x, xc))
                        return ze;
                    else
                        return null;

                } // end horizontal edge special case

                // now the general case where the theta calculation works
                double theta = Math.Atan( h*(start.x-end.x)/(w*(start.z-end.z))  );

                // based on this calculate the CC point
                if (((cu.R - cu.r) < l) && (cu.R <= l))
                {
                    // half-ellipse case
                    double xc1 = xd + Math.Abs(w * Math.Cos(theta));
                    double xc2 = xd - Math.Abs(w * Math.Cos(theta));
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    // select the higher point:
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }

                }
                else if ((cu.R - cu.r) > l)
                {
                    // quarter ellipse case
                    double xc1 = xd1 + Math.Abs(w * Math.Cos(theta));
                    double xc2 = xd2 - Math.Abs(w * Math.Cos(theta));
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    // select the higher point:
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }
                }

                // now we have a valid xc value, so calculate the ze value:
                ze = zc + Math.Abs(h * Math.Sin(theta)) - cu.r;

                // finally, check that the CC point is in the edge
                if (isinrange(start.x,end.x,xc))
                    return ze;
                else
                    return null;

                // this line is unreachable (according to compiler)

            } // end of toroidal/spherical case

            // if we ever get here it is probably a serious error!
            System.Console.WriteLine("EdgeTest: ERROR: no case returned a valid ze!");
            return null;
        }
Example #6
0
        public static double? VertexTest(Cutter c,Point e, Point p)
        {
            // c.R and c.r define the cutter
               // e.x and e.y is the xy-position of the cutter (e.z is ignored)
               // p is the vertex tested against

               // q is the distance along xy-plane from e to vertex
               double q = Math.Sqrt(Math.Pow(e.x - p.x, 2) + Math.Pow((e.y - p.y), 2));

               if (q > c.R)
               {
               // vertex is outside cutter. no need to do anything!
               return null;
               }
               else if (q <= (c.R - c.r))
               {
                // vertex is in the cylindical/flat part of the cutter
               return p.z;
               }
               else if ((q > (c.R - c.r)) && (q <= c.R))
               {
               // vertex is in the toroidal part of the cutter
               double h2 = Math.Sqrt(Math.Pow(c.r, 2) - Math.Pow((q - (c.R - c.r)), 2));
               double h1 = c.r - h2;
               return p.z - h1;
               }
               else
               {
               // SERIOUS ERROR, we should not be here!
               System.Console.WriteLine("DropCutter: VertexTest: ERROR!");
               return null;
               }
        }
Example #7
0
        public static double? FacetTest(Cutter cu, Point e, Tri t)
        {
            // local copy of the surface normal

            t.recalc_normals(); // don't trust the pre-calculated normal! calculate it separately here.

            Vector n = new Vector(t.n.x, t.n.y, t.n.z);
            Point cc;

            if (n.z == 0)
            {
                // vertical plane, can't touch cutter against that!
                return null;
            }
            else if (n.z < 0)
            {
                // flip the normal so it points up (? is this always required?)
                n = -1*n;
            }

            // define plane containing facet
            double a = n.x;
            double b = n.y;
            double c = n.z;
            double d = - n.x * t.p[0].x - n.y * t.p[0].y - n.z * t.p[0].z;

            // the z-direction normal is a special case (?required?)
            // in debug phase, see if this is a useful case!
            if ((a == 0) && (b == 0))
            {
                // System.Console.WriteLine("facet-test:z-dir normal case!");
                e.z = t.p[0].z;
                cc = new Point(e.x,e.y,e.z);
                if (isinside(t, cc))
                {
                    // System.Console.WriteLine("facet-test:z-dir normal case!, returning {0}",e.z);
                    // System.Console.ReadKey();
                    return e.z;
                }
                else
                    return null;
            }

            // System.Console.WriteLine("facet-test:general case!");
            // facet test general case
            // uses trigonometry, so might be too slow?

            // flat endmill and ballnose should be simple to do without trig
            // toroidal case might require offset-ellipse idea?

            /*
            theta = asin(c);
            zf= -d/c - (a*xe+b*ye)/c+ (R-r)/tan(theta) + r/sin(theta) -r;
            e=[xe ye zf];
            u=[0  0  1];
            rc=e + ((R-r)*tan(theta)+r)*u - ((R-r)/cos(theta) + r)*n;
            t=isinside(p1,p2,p3,rc);
            */

            double theta = Math.Asin(c);
            double zf = -d/c - (a*e.x+b*e.y)/c + (cu.R-cu.r)/Math.Tan(theta) + cu.r/Math.Sin(theta) - cu.r;
            Vector ve = new Vector(e.x,e.y,zf);
            Vector u = new Vector(0,0,1);
            Vector rc = new Vector();
            rc = ve +((cu.R-cu.r)*Math.Tan(theta)+cu.r)*u - ((cu.R-cu.r)/Math.Cos(theta)+cu.r)*n;

            /*
            if (rc.z > 1000)
                System.Console.WriteLine("z>1000 !");
             */

            cc = new Point(rc.x, rc.y, rc.z);

            // check that CC lies in plane:
            // a*rc(1)+b*rc(2)+c*rc(3)+d
            double test = a * cc.x + b * cc.y + c * cc.z + d;
            if (test > 0.000001)
                System.Console.WriteLine("FacetTest ERROR! CC point not in plane");

            if (isinside(t, cc))
            {
                if (Math.Abs(zf) > 100)
                {
                    System.Console.WriteLine("serious problem... at" +e.x + "," + e.y);
                }
                return zf;
            }
            else
                return null;
        }
Example #8
0
       } // end VertexTest

        public static double? FacetTest(Cutter cu, Geo.Point e, Geo.Tri t)
        { 
            // local copy of the surface normal

            t.recalc_normals(); // don't trust the pre-calculated normal! calculate it separately here.

            Vector n = new Vector(t.n.x, t.n.y, t.n.z);
            Geo.Point cc;

            if (n.z == 0)
            {
                // vertical plane, can't touch cutter against that!
                return null;
            }
            else if (n.z < 0)
            {
                // flip the normal so it points up (? is this always required?)
                n = -1*n;
            }

            // define plane containing facet
            double a = n.x;
            double b = n.y;
            double c = n.z;
            double d = - n.x * t.p[0].x - n.y * t.p[0].y - n.z * t.p[0].z;

            // the z-direction normal is a special case (?required?)
            // in debug phase, see if this is a useful case!
            if ((a == 0) && (b == 0))
            {
                // System.Console.WriteLine("facet-test:z-dir normal case!");
                e.z = t.p[0].z;
                cc = new Geo.Point(e.x,e.y,e.z);
                if (isinside(t, cc))
                {
                    // System.Console.WriteLine("facet-test:z-dir normal case!, returning {0}",e.z);
                    // System.Console.ReadKey();
                    return e.z;
                }
                else
                    return null;
            }

            // System.Console.WriteLine("facet-test:general case!");
            // facet test general case
            // uses trigonometry, so might be too slow?

            // flat endmill and ballnose should be simple to do without trig
            // toroidal case might require offset-ellipse idea?

            /*
            theta = asin(c);
            zf= -d/c - (a*xe+b*ye)/c+ (R-r)/tan(theta) + r/sin(theta) -r;
            e=[xe ye zf];
            u=[0  0  1];
            rc=e + ((R-r)*tan(theta)+r)*u - ((R-r)/cos(theta) + r)*n;
            t=isinside(p1,p2,p3,rc);
            */

            double theta = Math.Asin(c);
            double zf = -d/c - (a*e.x+b*e.y)/c + (cu.R-cu.r)/Math.Tan(theta) + cu.r/Math.Sin(theta) - cu.r;
            Vector ve = new Vector(e.x,e.y,zf);
            Vector u = new Vector(0,0,1);
            Vector rc = new Vector();
            rc = ve +((cu.R-cu.r)*Math.Tan(theta)+cu.r)*u - ((cu.R-cu.r)/Math.Cos(theta)+cu.r)*n;

            /*
            if (rc.z > 1000)
                System.Console.WriteLine("z>1000 !");
             */

            cc = new Geo.Point(rc.x, rc.y, rc.z);

            // check that CC lies in plane:
            // a*rc(1)+b*rc(2)+c*rc(3)+d
            double test = a * cc.x + b * cc.y + c * cc.z + d;
            if (test > 0.000001)
                System.Console.WriteLine("FacetTest ERROR! CC point not in plane");

            if (isinside(t, cc))
            {
                if (Math.Abs(zf) > 100)
                {
                    System.Console.WriteLine("serious problem... at" +e.x + "," + e.y);
                }
                return zf;
            }
            else
                return null;

        } // end FacetTest
Example #9
0
        } // end FacetTest

        public static double? EdgeTest(Cutter cu, Geo.Point e, Geo.Point p1, Geo.Point p2)
        { 
            // contact cutter against edge from p1 to p2

            // translate segment so that cutter is at (0,0)
            Geo.Point start = new Geo.Point(p1.x - e.x, p1.y - e.y, p1.z);
            Geo.Point end = new Geo.Point(p2.x - e.x, p2.y - e.y, p2.z);

            // find angle btw. segment and X-axis
            double dx = end.x - start.x;
            double dy = end.y - start.y;
            double alfa;
            if (dx != 0)
                alfa = Math.Atan(dy / dx);
            else
                alfa = Math.PI / 2;

            //alfa = -alfa;
            // rotation matrix for rotation around z-axis:
            // should probably implement a matrix class later

            // rotate by angle alfa
            // need copy of data that does not change as we go through each line:
            double sx = start.x, sy = start.y, ex = end.x, ey = end.y;
            start.x = sx * Math.Cos(alfa) + sy * Math.Sin(alfa);
            start.y = -sx * Math.Sin(alfa) + sy * Math.Cos(alfa);
            end.x = ex * Math.Cos(alfa) + ey * Math.Sin(alfa);
            end.y = -ex * Math.Sin(alfa) + ey * Math.Cos(alfa);


            // check if segment is below cutter
            
            if (start.y > 0)
            {   
                alfa = alfa+Math.PI;
                start.x = sx * Math.Cos(alfa) + sy * Math.Sin(alfa);
                start.y = -sx * Math.Sin(alfa) + sy * Math.Cos(alfa);
                end.x = ex * Math.Cos(alfa) + ey * Math.Sin(alfa);
                end.y = -ex * Math.Sin(alfa) + ey * Math.Cos(alfa);
            }

            if (Math.Abs(start.y-end.y)>0.0000001)
            {
                System.Console.WriteLine("EdgeTest ERROR! (start.y - end.y) = " +(start.y-end.y));
                return null;
            }

            double l = -start.y; // distance from cutter to edge
            if (l < 0)
                System.Console.WriteLine("EdgeTest ERROR! l<0 !");

 
                
            
            // System.Console.WriteLine("l=" + l+" start.y="+start.y+" end.y="+end.y);
            

            // now we have two different algorithms depending on the cutter:
            if (cu.r == 0)
            {
                // this is the flat endmill case
                // it is easier and faster than the general case, so we handle it separately
                if (l > cu.R) // edge is outside of the cutter
                    return null;
                else // we are inside the cutter
                {   // so calculate CC point
                    double xc1 = Math.Sqrt(Math.Pow(cu.R, 2) - Math.Pow(l, 2));
                    double xc2 = -xc1;
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;

                    // choose the higher point
                    double zc,xc;
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }

                    // now that we have a CC point, check if it's in the edge
                    if ((start.x > xc) && (xc < end.x))
                        return null;
                    else if ((end.x < xc) && (xc > start.x))
                        return null;
                    else
                        return zc;

                }
                // unreachable place (according to compiler)
            } // end of flat endmill (r=0) case
            else if (cu.r > 0)
            {
                // System.Console.WriteLine("edgetest r>0 case!");

                // this is the general case (r>0)   ball-nose or bull-nose (spherical or toroidal)
                // later a separate case for the ball-cutter might be added (for performance)

                double xd=0, w=0, h=0, xd1=0, xd2=0, xc=0 , ze=0, zc=0;

                if (l > cu.R) // edge is outside of the cutter
                    return null;
                else if (((cu.R-cu.r)<l)&&(l<=cu.R))
                {    // toroidal case
                    xd=0; // center of ellipse
                    w=Math.Sqrt(Math.Pow(cu.R,2)-Math.Pow(l,2)); // width of ellipse
                    h=Math.Sqrt(Math.Pow(cu.r,2)-Math.Pow((l-(cu.R-cu.r)),2)); // height of ellipse
                }
                else if ((cu.R-cu.r)>=l)
                {
                    // quarter ellipse case
                    xd1=Math.Sqrt( Math.Pow((cu.R-cu.r),2)-Math.Pow(l,2));
                    xd2=-xd1;
                    h=cu.r; // ellipse height
                    w=Math.Sqrt( Math.Pow(cu.R,2)-Math.Pow(l,2) )- Math.Sqrt( Math.Pow((cu.R-cu.r),2)-Math.Pow(l,2) ); // ellipse height
                }

                // now there is a special case where the theta calculation will fail if
                // the segment is horziontal, i.e. start.z==end.z  so we need to catch that here
                if (start.z==end.z)
                {
                    if ((cu.R-cu.r)<l) 
                    {
                        // half-ellipse case
                        xc=0;
                        h=Math.Sqrt(Math.Pow(cu.r,2)-Math.Pow((l-(cu.R-cu.r)),2));
                        ze = start.z + h - cu.r;
                    }
                    else if ((cu.R - cu.r) > l)
                    {
                        // quarter ellipse case
                        xc = 0;
                        ze = start.z;
                    }

                    // now we have a CC point
                    // so we need to check if the CC point is in the edge
                    if (isinrange(start.x, end.x, xc))
                        return ze;
                    else
                        return null;

                } // end horizontal edge special case


                // now the general case where the theta calculation works
                double theta = Math.Atan( h*(start.x-end.x)/(w*(start.z-end.z))  );

                // based on this calculate the CC point
                if (((cu.R - cu.r) < l) && (cu.R <= l))
                {
                    // half-ellipse case
                    double xc1 = xd + Math.Abs(w * Math.Cos(theta));
                    double xc2 = xd - Math.Abs(w * Math.Cos(theta));
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    // select the higher point:
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }

                }
                else if ((cu.R - cu.r) > l)
                { 
                    // quarter ellipse case
                    double xc1 = xd1 + Math.Abs(w * Math.Cos(theta));
                    double xc2 = xd2 - Math.Abs(w * Math.Cos(theta));
                    double zc1 = ((xc1 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    double zc2 = ((xc2 - start.x) / (end.x - start.x)) * (end.z - start.z) + start.z;
                    // select the higher point:
                    if (zc1 > zc2)
                    {
                        zc = zc1;
                        xc = xc1;
                    }
                    else
                    {
                        zc = zc2;
                        xc = xc2;
                    }
                }

                // now we have a valid xc value, so calculate the ze value:
                ze = zc + Math.Abs(h * Math.Sin(theta)) - cu.r;

                // finally, check that the CC point is in the edge
                if (isinrange(start.x,end.x,xc))
                    return ze;
                else
                    return null;

     


                // this line is unreachable (according to compiler)
                
            } // end of toroidal/spherical case
 
            
            // if we ever get here it is probably a serious error!
            System.Console.WriteLine("EdgeTest: ERROR: no case returned a valid ze!");
            return null;

        } // end of EdgeTest method
Example #10
0
        public static void search_kdtree(List <Tri> tlist, Point p, Cutter c, kd_node node)
        {
            ns += 1;

            if (node.tris != null)
            {
                if (node.tris.Count > 0)
                {   // add all triangles of a bucket node
                    foreach (Tri t in node.tris)
                    {
                        // check that t belongs
                        if ((p.x + c.R) < t.bb.minx)
                        {
                            return;
                        }
                        else if ((p.x - c.R) > t.bb.maxx)
                        {
                            return;
                        }
                        else if ((p.y + c.R) < t.bb.miny)
                        {
                            return;
                        }
                        else if ((p.y - c.R) > t.bb.maxy)
                        {
                            return;
                        }
                        else
                        {
                            tlist.Add(t);
                        }
                    }
                    return;
                }
            }

            switch (node.dim)
            {
            case 0:     // cut along xplus
                if (node.cutval <= p.x - c.R)
                {
                    search_kdtree(tlist, p, c, node.hi);
                }
                else
                {
                    search_kdtree(tlist, p, c, node.hi);
                    search_kdtree(tlist, p, c, node.lo);
                }
                break;

            case 1:     // cut along xminus
                if (node.cutval >= p.x + c.R)
                {
                    search_kdtree(tlist, p, c, node.lo);
                }
                else
                {
                    search_kdtree(tlist, p, c, node.hi);
                    search_kdtree(tlist, p, c, node.lo);
                }
                break;

            case 2:     // cut along yplus
                if (node.cutval <= p.y - c.R)
                {
                    search_kdtree(tlist, p, c, node.hi);
                }
                else
                {
                    search_kdtree(tlist, p, c, node.hi);
                    search_kdtree(tlist, p, c, node.lo);
                }
                break;

            case 3:     // cut along yminus
                if (node.cutval >= p.y + c.R)
                {
                    search_kdtree(tlist, p, c, node.lo);
                }
                {
                    search_kdtree(tlist, p, c, node.hi);
                    search_kdtree(tlist, p, c, node.lo);
                }
                break;
            }
            return;
        }
Example #11
0
        public static void stlmachine(STLSurf s, GeoCollection g)
        {
            List<Point> pointlist=new List<Point>();

            // seems to work...
            // foreach (Geo.Tri t in s.tris)
            //    System.Console.WriteLine("loop1 triangles " + t);
            // System.Console.ReadKey();

            // recalculate normal data
            // create bounding box data
            foreach (Tri t in s.tris)
            {
                t.recalc_normals();  // FIXME why don't new values stick??
                t.calc_bbox();       // FIXME: why doen't bb-data 'stick' ??
            }

            /*
            // FIXME: if we check bb-data here it is gone!!(??)
            foreach (Geo.Tri t in s.tris)
            {
                System.Console.WriteLine("loop2 triangles " + t);
                System.Console.WriteLine("loop2 direct maxx" + t.bb.maxx + " minx:" + t.bb.minx);
            }
            System.Console.ReadKey();
            */

            // find bounding box (this should probably be done in the STLSurf class?)
            double minx = 0, maxx = 10, miny = 0, maxy = 10;

            // generate XY pattern (a general zigzag-strategy, needed also for pocketing)
            // store in a list called pointlist
            double Nx=30;
            double Ny=40;
            double dx=(maxx-minx)/(double)(Nx-1);
            double dy = (maxy - miny) / (double)(Ny-1);
            double x = minx;
            for (int n = 0; n < Nx; n++)
            {
                if (n%2==0)
                {
                    double y = miny;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Point(x,y,5));
                        // System.Console.WriteLine("x:"+x+" y:"+y);
                        y += dy; // go forward in the y-axis direction
                        // System.Console.ReadKey();
                    }
                }
                else
                {
                    double y = maxy;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Point(x,y,5));
                        //System.Console.WriteLine("x:" + x + " y:" + y);
                        y -= dy; // go backward in the y-axis direction
                        //System.Console.ReadKey();
                    }
                }
                x += dx;
            }

            // drop cutter (i.e. add z-data)

            double R=1,r=0.2; // this is the cutter definition
            Cutter cu = new Cutter(R,r);

            List<Point> drop_points = new List<Point>();
            double redundant = 0; // number of unneccesary calls to drop-cutter
            double checks = 0;    // number of relevant calls

            // build the kd-tree
            Stopwatch st = new Stopwatch();
            Console.WriteLine("Building kd-tree. Stopwatch start");
            st.Start();
            kd_node root;
            root = kdtree.build_kdtree(s.tris);
            st.Stop();
            Console.WriteLine("Elapsed = {0}", st.Elapsed.ToString());

            // FIXME: these calls to drop-cutter are independent of each other
            // thus the points could/should be divided into many subsets
            // and each subset is processed by a seprarate thread
            // this should give a substantial speedup on multi-core cpus
            Console.WriteLine("Running drop-cutter. Stopwatch start");
            st.Start();
            foreach (Point p in pointlist) // loop through each point
            {
                double? v1 = null,v2=null,v3=null,z_new=null,f=null,e1=null,e2=null,e3=null;

                // store the possible z-values in this list
                // the highest one of these should be chosen in the end
                List<double> zlist = new List<double>();

                // find triangles under cutter using kd-tree

                int mode = 1;
                List<Tri> tris_to_search = new List<Tri>();

                if (mode == 0)
                {
                    tris_to_search = s.tris;
                }
                else if (mode == 1)
                {
                    kdtree.search_kdtree(tris_to_search, p, cu, root);
                }
                //Console.WriteLine("searching {0} tris",tris_to_search.Count);
                //Console.ReadKey();

                // loop through each triangle
                foreach (Tri t in tris_to_search)
                {
                    checks++;
                    t.calc_bbox(); // FIXME: why do we have to re-calculate bb-data here??

                    //System.Console.WriteLine("testing triangle" + t);

                    // here are four ways the triangle bounding box can be
                    // outside the cutter bounding box
                    // redundant could be used to test the performance of bucketing/kd-tree
                    if (t.bb.minx > (p.x + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    else if (t.bb.maxx < (p.x - cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.miny > (p.y + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.maxy < (p.y - cu.R))
                    {
                        redundant++;
                        continue;
                    }

                    // test cutter against each vertex
                    v1 = DropCutter.VertexTest(cu, p, t.p[0]);
                    v2 = DropCutter.VertexTest(cu, p, t.p[1]);
                    v3 = DropCutter.VertexTest(cu, p, t.p[2]);
                    if (v2 != null)
                    {
                        zlist.Add((double)v2);
                    }
                    if (v1 != null)
                    {
                        zlist.Add((double)v1);
                    }
                    if (v3 != null)
                    {
                        zlist.Add((double)v3);
                    }

                    // test cutter against facet
                    f = DropCutter.FacetTest(cu, p, t);
                    if (f != null)
                    {
                        zlist.Add((double)f);
                    }

                    // test cutter against each edge
                    e1 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[1]);
                    e2 = DropCutter.EdgeTest(cu, p, t.p[1], t.p[2]);
                    e3 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[2]);
                    if (e1 != null)
                        zlist.Add((double)e1);
                    if (e2 != null)
                        zlist.Add((double)e2);
                    if (e3 != null)
                        zlist.Add((double)e3);

                    // now we have some suggestions for z in zlist
                    // by sorting it we get the highest one at the end of the list
                    zlist.Sort();

                    // if there's anything in the list, return the last element
                    if (zlist.Count > 0)
                        z_new = zlist[zlist.Count-1];

                } // end triangle loop

                // we've gone through all triangles for this XY-location
                // if we found a z-value, let's add the valid cutter location
                // to a list drop_points
                if (z_new != null)
                {
                    drop_points.Add(new Point(p.x, p.y, (double)z_new));
                }

            } // end point-list loop
            st.Stop();
            Console.WriteLine("Elapsed = {0}", st.Elapsed.ToString());

            // print some statistics:
            System.Console.WriteLine("checked: "+ checks + " redundant: " + redundant);
            double fraction=(100*(double)(checks-redundant)/(double)checks);
            System.Console.WriteLine("relevant: "+(checks-redundant) + "  ("+fraction.ToString("N3")+"%)");

            // FIXME: now a toolpath object should be created
            // that has rapids/feeds according to the points calculated above
            int i = 1;
            Point p0=new Point();

            // this is needed so we get decimal points, not commas
            System.Globalization.CultureInfo glob = new System.Globalization.CultureInfo("en-GB");
            Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-GB");

            foreach (Point p in drop_points)
            {

                if (i == 1) // first move
                {
                    p0 = new Point(p.x, p.y, 12);

                    camtest.outfile.WriteLine("Cylinder");
                    camtest.outfile.WriteLine("{0},{1},{2}", p0.x.ToString("0.000", glob), p0.y.ToString("0.000", glob), p0.z.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0}", 0.01.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0},{1},{2}", p.x.ToString("0.000", glob), p.y.ToString("0.000", glob), p.z.ToString("0.000", glob));
                    Line l = new Line(p0, p);
                    g.add(l); //  ADD geometry to toolpath

                    p0 = p;
                }
                else
                {

                    camtest.outfile.WriteLine("Cylinder");
                    camtest.outfile.WriteLine("{0},{1},{2}", p0.x.ToString("0.000", glob), p0.y.ToString("0.000", glob), p0.z.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0}", 0.01.ToString("0.000", glob));
                    camtest.outfile.WriteLine("{0},{1},{2}", p.x.ToString("0.000", glob), p.y.ToString("0.000", glob), p.z.ToString("0.000", glob));
                    Line l = new Line(p0, p);
                    g.add(l);  // ADD geometry to toolpath
                    p0 = p;
                }
                i++;
            }
        }
Example #12
0
        public static void stlmachine(GLWindow g, STLSurf s)
        {
            List <Geo.Point> pointlist = new List <Geo.Point>();

            // seems to work...
            // foreach (Geo.Tri t in s.tris)
            //    System.Console.WriteLine("loop1 triangles " + t);
            // System.Console.ReadKey();

            // recalculate normal data
            // create bounding box data
            foreach (Geo.Tri t in s.tris)
            {
                t.recalc_normals(); // FIXME why don't new values stick??
                t.calc_bbox();      // FIXME: why doen't bb-data 'stick' ??
            }

            /*
             * // FIXME: if we check bb-data here it is gone!!(??)
             * foreach (Geo.Tri t in s.tris)
             * {
             *  System.Console.WriteLine("loop2 triangles " + t);
             *  System.Console.WriteLine("loop2 direct maxx" + t.bb.maxx + " minx:" + t.bb.minx);
             * }
             * System.Console.ReadKey();
             */

            // find bounding box (this should probably be done in the STLSurf class?)
            double minx = 0, maxx = 10, miny = 0, maxy = 10;

            // generate XY pattern (a general zigzag-strategy, needed also for pocketing)
            double Nx = 50;
            double Ny = 50;
            double dx = (maxx - minx) / (double)(Nx - 1);
            double dy = (maxy - miny) / (double)(Ny - 1);
            double x  = minx;

            for (int n = 0; n < Nx; n++)
            {
                if (n % 2 == 0)
                {
                    double y = miny;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Geo.Point(x, y, 5));
                        // System.Console.WriteLine("x:"+x+" y:"+y);
                        y += dy;
                        // System.Console.ReadKey();
                    }
                }
                else
                {
                    double y = maxy;
                    for (int m = 0; m < Ny; m++)
                    {
                        pointlist.Add(new Geo.Point(x, y, 5));
                        //System.Console.WriteLine("x:" + x + " y:" + y);
                        y -= dy;
                        //System.Console.ReadKey();
                    }
                }
                x += dx;
            }


            // drop cutter (i.e. add z-data)
            double           R = 1, r = 0.2;
            Cutter           cu          = new Cutter(R, r);
            List <Geo.Point> drop_points = new List <Geo.Point>();
            double           redundant   = 0;
            double           checks      = 0;

            foreach (Geo.Point p in pointlist)
            {
                double?       v1 = null, v2 = null, v3 = null, z_new = null, f = null, e1 = null, e2 = null, e3 = null;
                List <double> zlist = new List <double>();

                foreach (Geo.Tri t in s.tris)
                {
                    checks++;
                    t.calc_bbox(); // why do we have to re-calculate bb-data here??

                    //System.Console.WriteLine("testing triangle" + t);
                    if (t.bb.minx > (p.x + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    else if (t.bb.maxx < (p.x - cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.miny > (p.y + cu.R))
                    {
                        redundant++;
                        continue;
                    }
                    if (t.bb.maxy < (p.y - cu.R))
                    {
                        redundant++;
                        continue;
                    }



                    v1 = DropCutter.VertexTest(cu, p, t.p[0]);
                    v2 = DropCutter.VertexTest(cu, p, t.p[1]);
                    v3 = DropCutter.VertexTest(cu, p, t.p[2]);
                    if (v2 != null)
                    {
                        zlist.Add((double)v2);
                    }
                    if (v1 != null)
                    {
                        zlist.Add((double)v1);
                    }
                    if (v3 != null)
                    {
                        zlist.Add((double)v3);
                    }



                    f = DropCutter.FacetTest(cu, p, t);
                    if (f != null)
                    {
                        zlist.Add((double)f);
                    }


                    e1 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[1]);
                    e2 = DropCutter.EdgeTest(cu, p, t.p[1], t.p[2]);
                    e3 = DropCutter.EdgeTest(cu, p, t.p[0], t.p[2]);

                    if (e1 != null)
                    {
                        zlist.Add((double)e1);
                    }
                    if (e2 != null)
                    {
                        zlist.Add((double)e2);
                    }
                    if (e3 != null)
                    {
                        zlist.Add((double)e3);
                    }



                    /*
                     * if (zlist.Count > 1)
                     * {
                     *  System.Console.Write("Before: ");
                     *  foreach (double d in zlist)
                     *      System.Console.Write(d.ToString() + " ");
                     *  System.Console.Write("\n");
                     * }
                     */

                    zlist.Sort();

                    /*
                     * if (zlist.Count > 2)
                     * {
                     *  System.Console.Write("After: ");
                     *  foreach (double d in zlist)
                     *      System.Console.Write(d.ToString() + " ");
                     *  System.Console.Write("\n");
                     * }
                     */
                    // System.Console.Write("Sorted: ");
                    // foreach (double d in zlist)
                    //    System.Console.Write(d.ToString() + " ");
                    // System.Console.Write("\n");

                    if (zlist.Count > 0)
                    {
                        z_new = zlist[zlist.Count - 1];
                    }

                    /*
                     * if (zlist.Count > 1)
                     *  System.Console.WriteLine("chosen: " + z_new);
                     */
                    // System.Console.ReadKey();
                } // end triangle loop

                if (z_new != null)
                {
                    drop_points.Add(new Geo.Point(p.x, p.y, (double)z_new));
                }
            } // end point-list loop

            System.Console.WriteLine("checked: " + checks + " redundant: " + redundant);
            System.Console.WriteLine("relevant: " + (checks - redundant) + "  (" + 100 * (double)(checks - redundant) / (double)checks + "%)");

            // check to see that STL has not changed


            // display drop-points
            int i = 1;

            Geo.Point p0 = new Geo.Point();
            foreach (Geo.Point p in drop_points)
            {
                if (i == 1) // first move
                {
                    p0 = new Geo.Point(p.x, p.y, 10);
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Yellow;
                    g.addGeom(l);
                    p0 = p;
                }
                else  // don't do anything for last move
                {
                    GeoLine l = new GeoLine(p0, p);
                    l.color = System.Drawing.Color.Magenta;
                    g.addGeom(l);
                    p0 = p;
                }
                i++;


                /*
                 * GeoPoint pg = new GeoPoint(p);
                 * pg.color = System.Drawing.Color.Aqua;
                 * g.addGeom(pg);
                 */
            }


            // display zigzag and points

            /*
             * i = 1;
             * foreach (Geo.Point p in pointlist)
             * {
             *  if (i == 1)
             *  {
             *      p0 = new Geo.Point(p.x, p.y, 10);
             *      GeoLine l = new GeoLine(p0, p);
             *      l.color = System.Drawing.Color.Yellow;
             *      g.addGeom(l);
             *      p0 = p;
             *  }
             *  else
             *  {
             *      GeoLine l = new GeoLine(p0, p);
             *      l.color = System.Drawing.Color.Cyan;
             *      g.addGeom(l);
             *      p0 = p;
             *  }
             *  i++;
             * }
             */


            // dummy test:

            /*
             * foreach (Geo.Tri t in s.tris)
             * {
             *  GeoPoint p = new GeoPoint(t.p[0].x, t.p[0].y, t.p[0].z);
             *  pointlist.Add(p);
             * }
             */
        }