/// <summary> /// Create and add new control point to the given curve at a given Vec2F gpt</summary> /// <param name="curve">Curve to modify</param> /// <param name="gpt">Location on the x-axis at which to add a control point. Whether /// or not the y-coordinate is used depends on 'insert' parameter.</param> /// <param name="insert">If true, the y-value is inserted on the existing curve, using /// curve.Evaluate(gpt.X). If false, the y-value comes from gpt.Y.</param> /// <param name="computeTangent">Whether ComputeTangent() should be called</param> public static void AddControlPoint(ICurve curve, Vec2F gpt, bool insert, bool computeTangent) { if (curve == null) { throw new ArgumentNullException("curve"); } // add/insert new control point to the given curve. Using the following rules. // if adding then add the point at gpt and set is tangent type to spline. // if inserting then add the point at (gpt.x,curve.eval(gpt.x)) and compute its tangent at the point. // recompute tangents for the curve. // find insersion index. int index = GetValidInsertionIndex(curve, gpt.X); if (index >= 0) { IControlPoint p = curve.CreateControlPoint(); p.EditorData.SelectedRegion = PointSelectionRegions.None; if (insert) { p.X = gpt.X; ICurveEvaluator cv = CurveUtils.CreateCurveEvaluator(curve); float prevY = cv.Evaluate(gpt.X - s_epsilone); float nextY = cv.Evaluate(gpt.X + s_epsilone); p.Y = cv.Evaluate(gpt.X); p.TangentInType = CurveTangentTypes.Fixed; p.TangentOutType = CurveTangentTypes.Fixed; Vec2F tanIn = new Vec2F(s_epsilone, p.Y - prevY); tanIn.Normalize(); Vec2F tanOut = new Vec2F(s_epsilone, nextY - p.Y); tanOut.Normalize(); p.TangentIn = tanIn; p.TangentOut = tanOut; } else { p.X = gpt.X; p.Y = gpt.Y; p.TangentInType = CurveTangentTypes.Spline; p.TangentOutType = CurveTangentTypes.Spline; } curve.InsertControlPoint(index, p); if (computeTangent) { ComputeTangent(curve); } } }
/// <summary> /// Hit test curve</summary> /// <param name="curve">Curve</param> /// <param name="pickRect">Rectangle</param> /// <returns>True iff hit</returns> public bool HitTest(ICurve curve, RectangleF pickRect) { if (curve == null) { return(false); } ReadOnlyCollection <IControlPoint> points = curve.ControlPoints; if (!curve.Visible || points.Count == 0) { return(false); } float step = m_tessellation / m_canvas.Zoom.X; ICurveEvaluator cv = CurveUtils.CreateCurveEvaluator(curve); float start = m_canvas.ClientToGraph(pickRect.X); float end = m_canvas.ClientToGraph(pickRect.Right); float rangeX = end - start; PointF scrPt = new PointF(); float fpx = points[0].X; float lpx = points[points.Count - 1].X; if ((start < fpx && end < fpx) || (start > lpx && end > lpx)) { return(false); } for (float x = 0; x < rangeX; x += step) { float xv = start + x; float y = cv.Evaluate(xv); scrPt = m_canvas.GraphToClient(xv, y); if (pickRect.Contains(scrPt)) { return(true); } } return(false); }
/// <summary> /// Draws given curve</summary> /// <param name="curve">Curve</param> /// <param name="g">Graphics object</param> public void DrawCurve(ICurve curve, Graphics g) { // draw pre-infinity // draw actual // draw post-inifiny. ReadOnlyCollection <IControlPoint> points = curve.ControlPoints; if (points.Count == 0) { return; } m_infinityPen.Color = curve.CurveColor; m_curvePen.Color = curve.CurveColor; if (points.Count == 1) { Vec2F p = m_canvas.GraphToClient(0, points[0].Y); g.DrawLine(m_infinityPen, 0, p.Y, m_canvas.ClientSize.Width, p.Y); return; } float w = m_canvas.ClientSize.Width; float h = m_canvas.ClientSize.Height; float x0 = m_canvas.ClientToGraph(0); float x1 = m_canvas.ClientToGraph(w); IControlPoint fpt = points[0]; IControlPoint lpt = points[points.Count - 1]; float step = m_tessellation / m_canvas.Zoom.X; List <PointF> pointList = new List <PointF>(m_canvas.Width / m_tessellation); ICurveEvaluator cv = CurveUtils.CreateCurveEvaluator(curve); PointF scrPt = new PointF(); float bound = 500; // guard again gdi+ overflow. float minY = -bound; float maxY = h + bound; // draw pre infinity if (fpt.X > x0) { float start = x0; float end = Math.Min(fpt.X, x1); float rangeX = end - start; for (float x = 0; x < rangeX; x += step) { float xv = start + x; float y = cv.Evaluate(xv); scrPt = m_canvas.GraphToClient(xv, y); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); } scrPt = m_canvas.GraphToClient(end, cv.Evaluate(end)); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); if (pointList.Count > 1) { g.DrawLines(m_infinityPen, pointList.ToArray()); } } // draw actual if ((fpt.X > x0 || lpt.X > x0) && (fpt.X < x1 || lpt.X < x1)) { int leftIndex; int rightIndex; ComputeIndices(curve, out leftIndex, out rightIndex); if (curve.CurveInterpolation == InterpolationTypes.Linear) { for (int i = leftIndex; i < rightIndex; i++) { IControlPoint p1 = points[i]; IControlPoint p2 = points[i + 1]; PointF cp1 = m_canvas.GraphToClient(p1.X, p1.Y); PointF cp2 = m_canvas.GraphToClient(p2.X, p2.Y); g.DrawLine(m_curvePen, cp1.X, cp1.Y, cp2.X, cp2.Y); } } else { for (int i = leftIndex; i < rightIndex; i++) { IControlPoint p1 = points[i]; IControlPoint p2 = points[i + 1]; if (p1.TangentOutType == CurveTangentTypes.Stepped) { PointF cp1 = m_canvas.GraphToClient(p1.X, p1.Y); PointF cp2 = m_canvas.GraphToClient(p2.X, p2.Y); g.DrawLine(m_curvePen, cp1.X, cp1.Y, cp2.X, cp1.Y); g.DrawLine(m_curvePen, cp2.X, cp1.Y, cp2.X, cp2.Y); } else if (p1.TangentOutType != CurveTangentTypes.SteppedNext) { float start = Math.Max(p1.X, x0); float end = Math.Min(p2.X, x1); pointList.Clear(); float rangeX = end - start; for (float x = 0; x < rangeX; x += step) { float xv = start + x; float y = cv.Evaluate(xv); scrPt = m_canvas.GraphToClient(xv, y); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); } scrPt = m_canvas.GraphToClient(end, cv.Evaluate(end)); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); if (pointList.Count > 1) { g.DrawLines(m_curvePen, pointList.ToArray()); } } }// for (int i = leftIndex; i < rightIndex; i++) } } //draw post-infinity. if (lpt.X < x1) { pointList.Clear(); float start = Math.Max(x0, lpt.X); float end = x1; float rangeX = end - start; for (float x = 0; x < rangeX; x += step) { float xv = start + x; float y = cv.Evaluate(xv); scrPt = m_canvas.GraphToClient(xv, y); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); } scrPt = m_canvas.GraphToClient(end, cv.Evaluate(end)); scrPt.Y = MathUtil.Clamp(scrPt.Y, minY, maxY); pointList.Add(scrPt); if (pointList.Count > 1) { g.DrawLines(m_infinityPen, pointList.ToArray()); } } }