Exemplo n.º 1
0
        private static double get_ted(double prev_r, double this_r, double tool_r)
        {
            double prev_wall_r = prev_r + tool_r;
            double this_wall_r = this_r + tool_r;

            if (this_r - prev_wall_r >= tool_r)
            {
                return(double.MaxValue);
            }

            if (prev_wall_r - this_r >= tool_r)
            {
                return(double.MinValue);
            }

            // get intersection of two cicles = cutter circle and prev wall
            Circle2F prev_wall   = new Circle2F(new Point2F(0, 0), prev_wall_r);
            Circle2F tool_circle = new Circle2F(new Point2F(this_r, 0), tool_r);

            Line2F insects = prev_wall.CircleIntersect(tool_circle);

            if (insects.p1.IsUndefined || insects.p2.IsUndefined)
            {
                return(0);
            }

            double ted = this_wall_r - insects.p1.X;

            return(ted);
        }
Exemplo n.º 2
0
 public bool Is_line_inside_region(Line2F line, bool should_analize_inner_intersections, double tolerance)
 {
     if (!_outline.PointInPolyline(line.p1, tolerance))
     {
         return(false);     // p1 is outside of outer curve boundary
     }
     if (!_outline.PointInPolyline(line.p2, tolerance))
     {
         return(false);  // p2 is outside of outer curve boundary
     }
     if (should_analize_inner_intersections && _outline.LineIntersections(line, tolerance).Length != 0)
     {
         return(false); // both endpoints are inside, but there are intersections, outer curve must be concave
     }
     foreach (Polyline island in _islands)
     {
         if (island.PointInPolyline(line.p1, tolerance))
         {
             return(false);  // p1 is inside hole
         }
         if (island.PointInPolyline(line.p2, tolerance))
         {
             return(false);  // p2 is inside hole
         }
         if (should_analize_inner_intersections && island.LineIntersections(line, tolerance).Length != 0)
         {
             return(false); // p1, p2 are outside hole, but there are intersections
         }
     }
     return(true);
 }
Exemplo n.º 3
0
        private double calc_ted(Point2F tool_center, double tool_r)
        {
            Circle2F parent_wall = new Circle2F(_parent.Center, _parent.Radius + tool_r);

            // find the points tool touching parent wall
            Circle2F cut_circle = new Circle2F(tool_center, tool_r);
            Line2F   insects    = cut_circle.CircleIntersect(parent_wall);

            if (insects.p1.IsUndefined || insects.p2.IsUndefined)
            {
                Logger.err("no wall intersections #0");
                return(0);
            }

            // we're interested in tool head point, so choose more advanced point in mill direction

            Vector2d v1 = new Vector2d(_parent.Center, insects.p1);
            Vector2d v_parent_to_tool_center = new Vector2d(_parent.Center, tool_center);
            Point2F  cut_head = v_parent_to_tool_center.Det(v1) * (int)this.Dir > 0 ? insects.p1 : insects.p2;

            // project headpoint to the center find TED
            Vector2d v_me_to_tool_center = new Vector2d(this.Center, tool_center);
            Vector2d v_me_to_cut_head    = new Vector2d(this.Center, cut_head);

            double ted = this.Radius + tool_r - v_me_to_cut_head * v_me_to_tool_center.Unit();

            return(ted > 0 ? ted : 0);
        }
Exemplo n.º 4
0
        private void calc_teds(double tool_r)
        {
            // expand both slices to form walls
            Circle2F parent_wall = new Circle2F(_parent.Center, _parent.Radius + tool_r);
            Circle2F this_wall   = new Circle2F(this.Center, this.Radius + tool_r);

            // find the point of cut start (intersection of walls)
            Line2F wall_insects = parent_wall.CircleIntersect(this_wall);

            if (wall_insects.p1.IsUndefined || wall_insects.p2.IsUndefined)
            {
                Logger.err("no wall intersections #1");
                return;
            }

            Vector2d v_move   = new Vector2d(_parent.Center, this.Center);
            Vector2d v1       = new Vector2d(_parent.Center, wall_insects.p1);
            Point2F  cut_tail = v_move.Det(v1) * (int)this.Dir < 0 ? wall_insects.p1 : wall_insects.p2;
            Vector2d v_tail   = new Vector2d(this.Center, cut_tail);

            Point2F entry_tool_center = this.Center + (v_tail.Unit() * this.Radius).Point;

            _entry_ted = calc_ted(entry_tool_center, tool_r);

            Point2F mid_tool_center = this.Center + (v_move.Unit() * this.Radius).Point;

            _mid_ted = calc_ted(mid_tool_center, tool_r);
        }
Exemplo n.º 5
0
        private void insert_in_t4(Polyline p)
        {
            for (int i = 0; i < p.NumSegments; i++)
            {
                object  seg = p.GetSegment(i);
                T4_rect rect;

                if (seg is Line2F)
                {
                    Line2F line = ((Line2F)seg);
                    rect = new T4_rect(Math.Min(line.p1.X, line.p2.X),
                                       Math.Min(line.p1.Y, line.p2.Y),
                                       Math.Max(line.p1.X, line.p2.X),
                                       Math.Max(line.p1.Y, line.p2.Y));
                }
                else if (seg is Arc2F)
                {
                    Point2F min = Point2F.Undefined;
                    Point2F max = Point2F.Undefined;
                    ((Arc2F)seg).GetExtrema(ref min, ref max);
                    rect = new T4_rect(min.X, min.Y, max.X, max.Y);
                }
                else
                {
                    throw new Exception("unknown segment type");
                }

                _t4.Add(rect, seg);
            }
        }
Exemplo n.º 6
0
 private void remove_seg(ulong h, Line2F seg)
 {
     if (_pool.ContainsKey(h))
     {
         _pool[h].Remove(seg);
     }
 }
Exemplo n.º 7
0
        // add line hashed by the beginning or end point
        public void Add(Line2F seg, bool reverse)
        {
            ulong[] h = hash(reverse ? seg.p2 : seg.p1);

            insert_seg(h[0], seg);
            insert_seg(h[1], seg);
            insert_seg(h[2], seg);
            insert_seg(h[3], seg);
        }
Exemplo n.º 8
0
 private void insert_seg(ulong h, Line2F seg)
 {
     if (!_pool.ContainsKey(h))
     {
         _pool[h] = new List <Line2F>();
     }
     if (!_pool[h].Contains(seg))
     {
         _pool[h].Add(seg);
     }
 }
Exemplo n.º 9
0
        public void Remove(Line2F seg)
        {
            ulong[] h1 = hash(seg.p1);

            remove_seg(h1[0], seg);
            remove_seg(h1[1], seg);
            remove_seg(h1[2], seg);
            remove_seg(h1[3], seg);

            ulong[] h2 = hash(seg.p2);

            remove_seg(h2[0], seg);
            remove_seg(h2[1], seg);
            remove_seg(h2[2], seg);
            remove_seg(h2[3], seg);
        }
Exemplo n.º 10
0
        private List <Circle2F> find_intersecting_balls(Line2F line)
        {
            T4_rect rect = new T4_rect(Math.Min(line.p1.X, line.p2.X),
                                       Math.Min(line.p1.Y, line.p2.Y),
                                       Math.Max(line.p1.X, line.p2.X),
                                       Math.Max(line.p1.Y, line.p2.Y));

            List <Circle2F> balls = new List <Circle2F>();

            // since objects in t4 are generic, convert convert rects backs to balls
            foreach (T4_rect ballrect in _t4.Get_colliding_obj_rects(rect))
            {
                balls.Add(new Circle2F(new Point2F(ballrect.Xc, ballrect.Yc), ballrect.W / 2));
            }

            return(balls);
        }
Exemplo n.º 11
0
        private Vector2F calc_start_tangent(Polyline poly)
        {
            object   obj     = poly.GetSegment(0);
            Vector2F tangent = new Vector2F();

            if (obj is Line2F)
            {
                Line2F line = (Line2F)obj;
                tangent = new Vector2F(line.p1, line.p2);
            }
            else if (obj is Arc2F)
            {
                Arc2F arc = (Arc2F)obj;
                tangent = new Vector2F(arc.Center, arc.P1).Normal();
                if (arc.Direction == RotationDirection.CW)
                {
                    tangent.Invert();
                }
            }

            return(tangent);
        }
Exemplo n.º 12
0
        private Sliced_path generate_path(Slice_sequence sequence)
        {
            Sliced_path_generator gen;

            if (!_should_smooth_chords)
            {
                gen = new Sliced_path_generator(_general_tolerance);
            }
            else
            {
                gen = new Sliced_path_smooth_generator(_general_tolerance, 0.1 * _tool_r);
            }

            // NOTE: this manipulations are to make the beginning of spiral tangent to the polyline
            object   obj     = _poly.GetSegment(0);
            Vector2d tangent = new Vector2d();

            if (obj is Line2F)
            {
                Line2F line = (Line2F)obj;
                tangent = new Vector2d(line.p1, line.p2);
            }
            else if (obj is Arc2F)
            {
                Arc2F arc = (Arc2F)obj;
                tangent = new Vector2d(arc.Center, arc.P1).Normal();
                if (arc.Direction == RotationDirection.CW)
                {
                    tangent = tangent.Inverted();
                }
            }

            gen.Append_spiral(sequence.Root_slice.Center, sequence.Root_slice.End, tangent, _max_ted, _tool_r, _dir == RotationDirection.Unknown ? RotationDirection.CCW : _dir);
            gen.Append_slice_sequence(sequence);

            return(gen.Path);
        }
Exemplo n.º 13
0
        private static object[] calc_arcs(Point2F p1, Vector2d t1, Point2F p2, Vector2d t2, Point2F pm)
        {
            object[] segs = new object[2];

            Vector2d n1 = t1.Normal();

            Vector2d pm_minus_p1 = new Vector2d(pm - p1);
            double   c1_denom    = 2 * (n1 * pm_minus_p1);

            if (c1_denom == 0)  // c1 is at infinity, replace arc with line
            {
                segs[0] = new Line2F(p1, pm);
            }
            else
            {
                Point2F           c1   = p1 + (pm_minus_p1 * pm_minus_p1 / c1_denom * n1).Point;
                RotationDirection dir1 = new Vector2d(p1 - c1) * n1 > 0 ? RotationDirection.CW : RotationDirection.CCW;
                segs[0] = new Arc2F(c1, p1, pm, dir1);
            }

            Vector2d n2          = t2.Normal();
            Vector2d pm_minus_p2 = new Vector2d(pm - p2);
            double   c2_denom    = 2 * (n2 * pm_minus_p2);

            if (c2_denom == 0)  // c2 is at infinity, replace arc with line
            {
                segs[1] = new Line2F(pm, p2);
            }
            else
            {
                Point2F           c2   = p2 + (pm_minus_p2 * pm_minus_p2 / c2_denom * n2).Point;
                RotationDirection dir2 = new Vector2d(p2 - c2) * n2 > 0 ? RotationDirection.CW : RotationDirection.CCW;
                segs[1] = new Arc2F(c2, pm, p2, dir2);
            }

            return(segs);
        }
Exemplo n.º 14
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);
        }
Exemplo n.º 15
0
        // we are collecting all the intersections and tracking the list of balls we're inside
        // at any given point. If list becomes empty, we can't shortcut
        public bool Is_line_inside_region(Line2F line, double tolerance)
        {
            Point2F a = line.p1;
            Point2F b = line.p2;

            SortedList <double, List <Circle2F> > intersections = new SortedList <double, List <Circle2F> >();
            List <Circle2F> running_balls = new List <Circle2F>();

            foreach (Circle2F ball in find_intersecting_balls(line))
            {
                Line2F insects = ball.LineIntersect(line, tolerance);

                if (insects.p1.IsUndefined && insects.p2.IsUndefined)
                {
                    // no intersections: check if whole path lay inside the circle
                    if (a.DistanceTo(ball.Center) < ball.Radius + tolerance &&
                        b.DistanceTo(ball.Center) < ball.Radius + tolerance)
                    {
                        return(true);
                    }
                }
                else if (insects.p1.IsUndefined || insects.p2.IsUndefined)
                {
                    // single intersection. one of the path ends must be inside the circle, otherwise it is a tangent case
                    // and should be ignored
                    if (a.DistanceTo(ball.Center) < ball.Radius + tolerance)
                    {
                        running_balls.Add(ball);
                    }
                    else if (b.DistanceTo(ball.Center) < ball.Radius + tolerance)
                    {
                        ;
                    }
                    else
                    {
                        continue;
                    }

                    Point2F c = insects.p1.IsUndefined ? insects.p2 : insects.p1;
                    double  d = c.DistanceTo(a);
                    if (!intersections.ContainsKey(d))
                    {
                        intersections.Add(d, new List <Circle2F>());
                    }
                    intersections[d].Add(ball);
                }
                else
                {
                    // double intersection
                    double d = insects.p1.DistanceTo(a);
                    if (!intersections.ContainsKey(d))
                    {
                        intersections.Add(d, new List <Circle2F>());
                    }
                    intersections[d].Add(ball);

                    d = insects.p2.DistanceTo(a);
                    if (!intersections.ContainsKey(d))
                    {
                        intersections.Add(d, new List <Circle2F>());
                    }
                    intersections[d].Add(ball);
                }
            }

            if (running_balls.Count == 0)
            {
                return(false);
            }

            foreach (var ins in intersections)
            {
                foreach (Circle2F s in ins.Value)
                {
                    if (running_balls.Contains(s))
                    {
                        running_balls.Remove(s);
                    }
                    else
                    {
                        running_balls.Add(s);
                    }
                }

                if (running_balls.Count == 0 && (ins.Key + tolerance < a.DistanceTo(b)))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 16
0
        public void Refine(List <Slice> colliding_slices, double end_clearance, double tool_r)
        {
            double clearance = end_clearance;

            // check if arc is small. refining is worthless in this case
            // criterion for smallness: there should be at least 4 segments with chord = clearance, plus
            // one segment to space ends far enough. A pentagon with a 5 segments with edge length = clearance
            // will define the min radius of circumscribed circle. clearance = 2 * R * sin (Pi / 5),
            // R = clearance / 2 / sin (Pi / 5)

            if (_segments.Count != 1)
            {
                throw new Exception("attempt to refine slice with n segments != 1");
            }

            Arc2F arc = _segments[0];

            double r_min = clearance / 2 / Math.Sin(Math.PI / 5.0);

            if (arc.Radius <= r_min)
            {
                return;
            }

            if (colliding_slices.Contains(this))
            {
                throw new Exception("attempt to collide slice with itself");
            }

            // now apply the colliding slices. to keep things simple and robust, we apply just one slice - the one who trims
            // us most (removed length of arc is greatest).

            // end clearance adjustment:
            // to guarantee the tool will never hit the unmilled area while rapiding between segments,
            // arc will always have original ends, trimming will happen in the middle only.
            // to prevent the tool from milling extra small end segments and minimize numeric errors at small tangents,
            // original ends would always stick at least for a clearance (chordal) length.
            // i.e. if the point of intersection of arc and colliding circle is closer than clearance to the end,
            // it is moved to clearance distance.

            // there is a two cases of intersecting circles: with single intersection and with a double intersection.
            // double intersections splits arc to three pieces (length of the middle part is the measure),
            // single intesections splits arc in two (the part inside the circle is removed, its length is the measure).
            // in both cases the intersection points are subject to "end clearance adjustment".
            // single intersections are transformed to the double intersections, second point being one of the end clearances.

            // TODO: calculate clearance point the right way, with math :-)
            Line2F  c1_insects = arc.CircleIntersect(new Circle2F(arc.P1, clearance));
            Line2F  c2_insects = arc.CircleIntersect(new Circle2F(arc.P2, clearance));
            Point2F c1         = c1_insects.p1.IsUndefined ? c1_insects.p2 : c1_insects.p1;
            Point2F c2         = c2_insects.p1.IsUndefined ? c2_insects.p2 : c2_insects.p1;

            Line2F max_secant = new Line2F();
            double max_sweep  = 0;

            foreach (Slice s in colliding_slices)
            {
                if (s == _parent)
                {
                    continue;  // no reason to process it
                }
                Line2F secant = arc.CircleIntersect(s.Ball);

                if (secant.p1.IsUndefined && secant.p2.IsUndefined)
                {
                    continue;
                }

                if (secant.p1.IsUndefined || secant.p2.IsUndefined)
                {
                    // single intersection
                    Point2F splitpt = secant.p1.IsUndefined ? secant.p2 : secant.p1;
                    if (arc.P1.DistanceTo(s.Center) < arc.P2.DistanceTo(s.Center))
                    {
                        if (splitpt.DistanceTo(arc.P1) < clearance)
                        {
                            continue;  // nothing to remove
                        }
                        else if (splitpt.DistanceTo(arc.P2) < clearance)
                        {
                            secant = new Line2F(c1, c2);
                        }
                        else
                        {
                            secant = new Line2F(c1, splitpt);
                        }
                    }
                    else
                    {
                        // remove second segment
                        if (splitpt.DistanceTo(arc.P2) < clearance)
                        {
                            continue;
                        }
                        else if (splitpt.DistanceTo(arc.P1) < clearance)
                        {
                            secant = new Line2F(c1, c2);
                        }
                        else
                        {
                            secant = new Line2F(splitpt, c2);
                        }
                    }
                }
                else
                {
                    // double intersection
                    if (secant.p1.DistanceTo(arc.P1) < clearance)
                    {
                        secant.p1 = c1;
                    }
                    else if (secant.p1.DistanceTo(arc.P2) < clearance)
                    {
                        secant.p1 = c2;
                    }

                    if (secant.p2.DistanceTo(arc.P1) < clearance)
                    {
                        secant.p2 = c1;
                    }
                    else if (secant.p2.DistanceTo(arc.P2) < clearance)
                    {
                        secant.p2 = c2;
                    }
                }

                if (secant.p1.DistanceTo(secant.p2) < clearance * 2) // segment is too short, ignore it
                {
                    continue;
                }

                // sort insects by sweep (already sorted for single, may be unsorted for the double)
                Vector2d v_p1   = new Vector2d(arc.Center, arc.P1);
                Vector2d v_ins1 = new Vector2d(arc.Center, secant.p1);
                Vector2d v_ins2 = new Vector2d(arc.Center, secant.p2);


                double sweep = angle_between_vectors(v_ins1, v_ins2, arc.Direction);

                if (angle_between_vectors(v_p1, v_ins1, arc.Direction) > angle_between_vectors(v_p1, v_ins2, arc.Direction))
                {
                    secant = new Line2F(secant.p2, secant.p1);
                    sweep  = 2.0 * Math.PI - sweep;
                }

                if (sweep > max_sweep)
                {
                    // ok, a last check - removed arc midpoint should be inside the colliding circle
                    Arc2F check_arc = new Arc2F(arc.Center, secant.p1, secant.p2, arc.Direction);
                    if (check_arc.Midpoint.DistanceTo(s.Center) < s.Radius)
                    {
                        max_sweep  = sweep;
                        max_secant = secant;
                    }
                }
            }

            if (max_sweep == 0)
            {
                return;
            }

            Arc2F head = new Arc2F(arc.Center, arc.P1, max_secant.p1, arc.Direction);
            Arc2F tail = new Arc2F(arc.Center, max_secant.p2, arc.P2, arc.Direction);

            _segments.Clear();
            _segments.Add(head);
            _segments.Add(tail);

            // recalculate max TED accounting for the new endpoints.
            // this TED is 'virtual' and averaged with previous max_ted to make arcs look more pretty

            // if ends of removed segment are at the same side of direction vector,
            // midpoint is still present, _max_ted is valid and is maximum for sure
            Vector2d v_move       = new Vector2d(_parent.Center, this.Center);
            Vector2d v_removed_p1 = new Vector2d(_parent.Center, max_secant.p1);
            Vector2d v_removed_p2 = new Vector2d(_parent.Center, max_secant.p2);

            if (v_move.Det(v_removed_p1) * v_move.Det(v_removed_p2) > 0)
            {
                return;
            }

            double ted_head_end   = calc_ted(max_secant.p1, tool_r);
            double ted_tail_start = calc_ted(max_secant.p2, tool_r);

            double ted = Math.Max(ted_head_end, ted_tail_start);

            if (ted <= 0)
            {
                Logger.err("max TED vanished after refining the slice !");
                return;
            }

            ted      = (ted + _mid_ted) / 2;
            _max_ted = Math.Max(ted, _entry_ted);
        }
Exemplo n.º 17
0
 public bool Is_line_inside_region(Line2F line, double tolerance)
 {
     return(Is_line_inside_region(line, true, tolerance));
 }
Exemplo n.º 18
0
        public Slice(Slice parent, Point2F center, double radius, RotationDirection dir, double tool_r, Point2F magnet)
        {
            _parent = parent;
            _ball   = new Circle2F(center, radius);

            double dist       = Point2F.Distance(center, parent.Center);
            double delta_r    = this.Radius - parent.Radius;
            double coarse_ted = dist + delta_r;

            // 1) one ball is inside other, no intersections
            // 2) balls are spaced too far and do not intersect, TED is 0, distance is positive
            // 3) balls are intersect, TED is valid
            if (dist <= Math.Abs(delta_r))
            {
                _placement = Slice_placement.INSIDE_ANOTHER;
                return;
            }

            if (dist >= this.Radius + parent.Radius)
            {
                _placement = Slice_placement.TOO_FAR;
                return;
            }
            // TED can't be more >= tool diameter, this check prevents fails during the calculation of real angle-based TED
            if (coarse_ted > tool_r * 1.999)
            {
                _placement = Slice_placement.TOO_FAR;
                return;
            }

            Line2F insects = _parent.Ball.CircleIntersect(this._ball);

            if (insects.p1.IsUndefined || insects.p2.IsUndefined)
            {
                // try to return meaningful result even if CB routine had failed (unlikely)
                Logger.err("no intersections found there intersections should be (_parent.Ball.CircleIntersect(_ball))");
                _placement = (dist <= this.Radius || dist <= parent.Radius) ? Slice_placement.INSIDE_ANOTHER : Slice_placement.TOO_FAR;
                return;
            }

            _placement = Slice_placement.NORMAL;

            Vector2d          v_move      = new Vector2d(_parent.Center, this.Center);
            Vector2d          v1          = new Vector2d(_parent.Center, insects.p1);
            RotationDirection default_dir = v_move.Det(v1) > 0 ? RotationDirection.CW : RotationDirection.CCW;

            if (dir == RotationDirection.Unknown)
            {
                if (magnet.IsUndefined)
                {
                    dir = RotationDirection.CCW;    // just something
                }
                else
                {
                    if (insects.p1.DistanceTo(magnet) < insects.p2.DistanceTo(magnet))  // match, use existing dir
                    {
                        dir = default_dir;
                    }
                    else
                    {
                        dir = (default_dir == RotationDirection.CCW) ? RotationDirection.CW : RotationDirection.CCW;   // flip
                    }
                }
            }

            Arc2F arc;

            if (default_dir == dir)
            {
                arc = new Arc2F(this.Center, insects.p1, insects.p2, dir);
            }
            else
            {
                arc = new Arc2F(this.Center, insects.p2, insects.p1, dir);
            }

            _segments.Add(arc);

            calc_teds(tool_r);

            if (_mid_ted <= 0)
            {
                Logger.warn("forced to patch mid_ted");
                _mid_ted = coarse_ted;    // shouldn't be, but ok
            }

            _max_ted = Math.Max(_mid_ted, _entry_ted);
        }
Exemplo n.º 19
0
        //-----------------------------------------------------------------------------
        // Vector graphics
        //-----------------------------------------------------------------------------

        // Draws the specified line.
        public void DrawLine(Line2F line, float thickness, Color color, float depth = 0.0f)
        {
            DrawImage(white1x1, line.Center + new Vector2F(0.5f, 0.5f), new Vector2F(0.5f, 0.5f),
                      new Vector2F((line.Length + thickness), thickness),
                      line.Direction, color, SpriteEffects.None, depth);
        }