Esempio n. 1
0
        // with the manual startpoint, which is a hint
        private static Point2F prepare_segments_w_hinted_starpoint(Topographer topo, List <Line2F> segments, Segpool pool, double min_dist_to_wall, double general_tolerance, Point2F startpoint)
        {
            // same as automatic, but seek the segment with the closest end to startpoint
            double  min_dist   = double.MaxValue;
            Point2F tree_start = Point2F.Undefined;

            foreach (Line2F seg in segments)
            {
                double r1 = topo.Get_dist_to_wall(seg.p1);
                double r2 = topo.Get_dist_to_wall(seg.p2);

                if (r1 >= min_dist_to_wall)
                {
                    pool.Add(seg, false);
                    double dist = startpoint.DistanceTo(seg.p1);
                    if (dist < min_dist)
                    {
                        min_dist   = dist;
                        tree_start = seg.p1;
                    }
                }
                if (r2 >= min_dist_to_wall)
                {
                    pool.Add(seg, true);
                    double dist = startpoint.DistanceTo(seg.p2);
                    if (dist < min_dist)
                    {
                        min_dist   = dist;
                        tree_start = seg.p2;
                    }
                }
            }

            return(tree_start);
        }
Esempio n. 2
0
        // with the manual startpoint
        private static Point2F prepare_segments_w_manual_starpoint(Topographer topo, List <Line2F> segments, Segpool pool, double min_dist_to_wall, double general_tolerance, Point2F startpoint)
        {
            // same as automatic, but seek the segment with the closest end to startpoint
            if (!topo.Is_line_inside_region(new Line2F(startpoint, startpoint), general_tolerance))
            {
                Logger.warn("startpoint is outside the pocket");
                return(Point2F.Undefined);
            }

            if (topo.Get_dist_to_wall(startpoint) < min_dist_to_wall)
            {
                Logger.warn("startpoint radius < tool radius");
                return(Point2F.Undefined);
            }

            double  min_dist   = double.MaxValue;
            Point2F tree_start = Point2F.Undefined;

            foreach (Line2F seg in segments)
            {
                double r1 = topo.Get_dist_to_wall(seg.p1);
                double r2 = topo.Get_dist_to_wall(seg.p2);

                if (r1 >= min_dist_to_wall)
                {
                    pool.Add(seg, false);
                    double dist = startpoint.DistanceTo(seg.p1);
                    if (dist < min_dist && topo.Is_line_inside_region(new Line2F(startpoint, seg.p1), general_tolerance))
                    {
                        min_dist   = dist;
                        tree_start = seg.p1;
                    }
                }
                if (r2 >= min_dist_to_wall)
                {
                    pool.Add(seg, true);
                    double dist = startpoint.DistanceTo(seg.p2);
                    if (dist < min_dist && topo.Is_line_inside_region(new Line2F(startpoint, seg.p2), general_tolerance))
                    {
                        min_dist   = dist;
                        tree_start = seg.p2;
                    }
                }
            }

            return(tree_start);
        }
Esempio n. 3
0
        public static bool Build(Medial_branch root, Topographer topo, List <Point2F> samples, double general_tolerance, Point2F startpoint, double min_dist_to_wall, bool startpoint_is_a_hint)
        {
            List <Line2F> medial_axis_segments = get_medial_axis_segments(topo, samples, general_tolerance);

            Logger.log("analyzing segments");

            Segpool pool = new Segpool(medial_axis_segments.Count, general_tolerance);

            Point2F tree_start;

            if (startpoint.IsUndefined)
            {
                tree_start = prepare_segments_w_auto_startpoint(topo, medial_axis_segments, pool, min_dist_to_wall);
            }
            else if (startpoint_is_a_hint)
            {
                tree_start = prepare_segments_w_hinted_starpoint(topo, medial_axis_segments, pool, min_dist_to_wall, general_tolerance, startpoint);
            }
            else
            {
                tree_start = prepare_segments_w_manual_starpoint(topo, medial_axis_segments, pool, min_dist_to_wall, general_tolerance, startpoint);
            }

            if (tree_start.IsUndefined)
            {
                Logger.warn("failed to choose tree start point");
                return(false);
            }

            Logger.log("done analyzing segments");
            Logger.log("got {0} hashes", pool.N_hashes);

            if (!(startpoint.IsUndefined || startpoint_is_a_hint))
            {
                root.Add_point(startpoint);
            }

            root.Add_point(tree_start);

            build_tree(root, pool, general_tolerance);
            return(true);
        }
Esempio n. 4
0
        private static Point2F prepare_segments_w_auto_startpoint(Topographer topo, List <Line2F> segments, Segpool pool, double min_dist_to_wall)
        {
            // segments are analyzed for mic radius from both ends. passed segmens are inserted in segpool
            // hashed by one or both endpoints. if endpoint is not hashed, segment wouldn't be followed
            // from that side, preventing formation of bad tree.
            // segments are connected later in a greedy fashion, hopefully forming a medial axis covering all
            // pocket.
            // start segment is the one with the largest mic

            double  max_r      = double.MinValue;
            Point2F tree_start = Point2F.Undefined;

            foreach (Line2F seg in segments)
            {
                double r1 = topo.Get_dist_to_wall(seg.p1);
                double r2 = topo.Get_dist_to_wall(seg.p2);

                if (r1 >= min_dist_to_wall)
                {
                    pool.Add(seg, false);
                    if (r1 > max_r)
                    {
                        max_r      = r1;
                        tree_start = seg.p1;
                    }
                }
                if (r2 >= min_dist_to_wall)
                {
                    pool.Add(seg, true);
                    if (r2 > max_r)
                    {
                        max_r      = r2;
                        tree_start = seg.p2;
                    }
                }
            }

            return(tree_start);
        }
Esempio n. 5
0
        public Sliced_path run()
        {
            if (_dir == RotationDirection.Unknown && _should_smooth_chords)
            {
                throw new Exception("smooth chords are not allowed for the variable mill direction");
            }

            _topo = new Topographer(_poly, new Polyline[] { });

            double         step          = calc_optimal_step();
            List <Point2F> slice_centers = _topo.Get_samples_exact(step);

            Bypoint_slicer slicer = new Bypoint_slicer(_topo.Min, _topo.Max, _general_tolerance);

            slicer.Slice_leadin_angle  = _slice_leadin_angle;
            slicer.Slice_leadout_angle = _slice_leadout_angle;

            Logger.log("generating slices");
            Slice_sequence sequence = slicer.Run(slice_centers, _tool_r, _slice_radius, _dir);

            Logger.log("generating path");
            return(generate_path(sequence));
        }
Esempio n. 6
0
        private static List <Line2F> get_medial_axis_segments(Topographer topo, List <Point2F> samples, double general_tolerance)
        {
            double[] xs = new double[samples.Count + 1];
            double[] ys = new double[samples.Count + 1];

            double min_x = double.MaxValue;
            double max_x = double.MinValue;
            double min_y = double.MaxValue;
            double max_y = double.MinValue;

            // HACK
            // There is a bug in Voronoi generator implementation. Sometimes it produces a completely crazy partitioning.
            // Looks like its overly sensitive to the first processed points, their count and location. If first stages
            // go ok, then everything comes nice. Beeing a Steven Fortune's algorithm, it process points by a moving sweep line.
            // Looks like the line is moving from the bottom to the top, thus sensitive points are the most bottom ones.
            // We try to cheat and add one more point so it would be the single most bottom point.
            // Then generator initially will see just one point, do a right magic and continue with a sane result :-)
            // We place this initial point under the lefmost bottom point at the sufficient distance,
            // then these two points will form a separate Voronoi cite not influencing the remaining partition.
            // Sufficient distance is defined as region width / 2 for now.

            int lb_idx = 0;

            for (int i = 0; i < samples.Count; i++)
            {
                xs[i] = samples[i].X;
                ys[i] = samples[i].Y;
                if (xs[i] < min_x)
                {
                    min_x = xs[i];
                }
                if (xs[i] > max_x)
                {
                    max_x = xs[i];
                }
                if (ys[i] > max_y)
                {
                    max_y = ys[i];
                }

                if (ys[i] <= min_y)
                {
                    if (ys[i] < min_y)
                    {
                        min_y  = ys[i];
                        lb_idx = i;  // stricly less, it's a new leftmost bottom for sure
                    }
                    else
                    {
                        if (xs[i] < xs[lb_idx])  // it's a new leftmost bottom if more lefty
                        {
                            lb_idx = i;
                        }
                    }
                }
            }

            double width = max_x - min_x;

            xs[samples.Count] = xs[lb_idx];
            ys[samples.Count] = ys[lb_idx] - width / 2;

            min_x -= VORONOI_MARGIN;
            max_x += VORONOI_MARGIN;
            min_y -= VORONOI_MARGIN + width / 2;
            max_y += VORONOI_MARGIN;

            List <GraphEdge> edges = new Voronoi(general_tolerance).generateVoronoi(xs, ys, min_x, max_x, min_y, max_y);

            Logger.log("voronoi partitioning completed. got {0} edges", edges.Count);

            List <Line2F> inner_segments = new List <Line2F>();

            foreach (GraphEdge e in edges)
            {
                Line2F seg = new Line2F(e.x1, e.y1, e.x2, e.y2);
                if (seg.Length() < double.Epsilon)
                {
                    continue;                                   // extra small segment, discard
                }
                if (!topo.Is_line_inside_region(seg, ANALIZE_INNER_INTERSECTIONS, general_tolerance))
                {
                    continue;
                }
                inner_segments.Add(seg);
            }

            return(inner_segments);
        }
Esempio n. 7
0
 public Pocket_generator(Polyline outline, Polyline[] islands)
 {
     _topo = new Topographer(outline, islands);
 }