public override async Task Apply(CADDocument doc, params string[] args) { Editor ed = doc.Editor; ed.PickedSelection.Clear(); var p1 = await ed.GetPoint("Start point: "); if (p1.Result != ResultMode.OK) { return; } var p2 = await ed.GetPoint("End point: ", p1.Value); if (p2.Result != ResultMode.OK) { return; } QuadraticBezier cons = new QuadraticBezier(p1.Value, Point2D.Average(p1.Value, p2.Value), p2.Value); doc.Jigged.Add(cons); var p3 = await ed.GetPoint("Control point: ", (p) => cons.P1 = p); doc.Jigged.Remove(cons); if (p3.Result != ResultMode.OK) { return; } Drawable newItem = new QuadraticBezier(p1.Value, p3.Value, p2.Value); doc.Model.Add(newItem); }
private void AddParabola(Point2D site) { if (m_root == null) { m_root = new VParabolaNode(site); } else if (m_root.EnumerateLeaves().All((leaf) => leaf.Site.Y == site.Y)) { // Degenerate case - all parabola sites on the same y-value. // If this happens, then our edge starts between us and our nearest point, and we need // to force affected edges (left and right) to recalculate their edge starts. var cutParabola = m_root.GetParabolaByX(site.X, site.Y); var newParabola = new VParabolaNode(site); var middle = Point2D.Average(cutParabola.Site, newParabola.Site); // store old parabola parent so we can append junction node there var cutParent = cutParabola.Parent; // note: edge ctor appends child parabolas to itself. VEdgeNode edge; if (cutParabola.Site.X < newParabola.Site.X) { edge = new VEdgeNode(middle, Vector2D.UnitXPlus, cutParabola, newParabola); } else { edge = new VEdgeNode(middle, Vector2D.UnitXPlus, newParabola, cutParabola); } // append edge node to old cutparabola parent if (cutParent != null) { if (cutParent.Left == null) { cutParent.Left = edge; } else { cutParent.Right = edge; } } } else { var cutParabola = m_root.GetParabolaByX(site.X, site.Y); // store old parabola parent so we can append junction node there var cutParent = cutParabola.Parent; // :: determine the parabolas left and right of the cut parabola. This is important // :: for the "Swallowing" of parabolas by circle events. var cutParabolaLeft = (VParabolaNode)cutParabola.GetLeftLeaf(); var cutParabolaRight = (VParabolaNode)cutParabola.GetRightLeaf(); // :: determine the left, middle, and right parabolas formed by this cut. var left = cutParabola; var middle = new VParabolaNode(site); var right = cutParabola.Clone(); // :: determine where the new "middle" parabola meets the "cut" parabola var intersection = cutParabola.CalculatePointAtX(site.X, site.Y); // create the left and right edges... var vCutMiddle = middle.Site - cutParabola.Site; var rightDirection = vCutMiddle.Perp(); // performs 90deg counterclockwise rotation in euclidean space var leftDirection = rightDirection.Flip(); var leftEdge = new VEdgeNode(intersection, leftDirection, left, middle); var rightEdge = new VEdgeNode(intersection, leftDirection, leftEdge, right); if (cutParent.Left == null) { cutParent.Left = rightEdge; } else { cutParent.Right = rightEdge; } // :: Manage Circle Events // Unregister the cut parabola node's event, which is now invalidated. if (cutParabola.CircleEvent != null) { m_queue.Remove(cutParabola.CircleEvent); cutParabola.CircleEvent = null; } // Register the left, right, and middle circle events if (cutParabolaLeft != null) { RegisterCircleEvent(cutParabolaLeft, left, middle); } if (cutParabolaRight != null) { RegisterCircleEvent(middle, right, cutParabolaRight); } if (cutParabolaLeft != null && cutParabolaRight != null) { RegisterCircleEvent(left, middle, right); // wtf? Shouldn't be necessary, right? } } }