简体   繁体   English

如何在C#中找到开始,结束和2个交叉点的BezierSegment的控制点 - AKA Cubic Bezier 4点插值

[英]How to find control points for a BezierSegment given Start, End, and 2 Intersection Pts in C# - AKA Cubic Bezier 4-point Interpolation

I've been struggling looking for an understandable way to do this. 我一直在努力寻找一种可以理解的方法来做到这一点。 I have four points, a StartPt, EndPoint, and Intersection points to represent the peak and valley in the bezier. 我有四个点,一个StartPt,EndPoint和Intersection点来表示贝塞尔曲线中的峰值和谷值。

The BezierSegment in C# requires start, controlPoint 1, controlPoint 2, endpoint - however I don't have any control points I only have these two points that lie along the bezier curves (i'm calling them intersection points above)... how can I calculate the two control points? C#中的BezierSegment需要start,controlPoint 1,controlPoint 2,endpoint - 但是我没有任何控制点我只有这两个点位于贝塞尔曲线上(我称之为上面的交点)...我可以计算出两个控制点吗?

Thanks in advance, this has been driving me crazy. 在此先感谢,这一直让我发疯。

There's some kind of explanation here: http://www.tinaja.com/glib/nubz4pts1.pdf but it's written in postscript and that language makes no sense to me at all - it's over my head. 这里有一些解释: http//www.tinaja.com/glib/nubz4pts1.pdf,但它是用postscript写的,而且这种语言对我来说毫无意义 - 这是我的头脑。

There are an infinite number of solutions to a curve passing through 4 points, but the best simple solution is to try to make the curve segment lengths proportional to the chord lengths. 通过4个点的曲线有无数个解,但最好的简单解决方案是尝试使曲线段长度与弦长成比例。 The code you link to is the a first order approximation that works well and is pretty fast. 您链接的代码是一阶近似,效果很好并且非常快。

Here's the C# translation of the PostScript code: 这是PostScript代码的C#转换:

static class DrawingUtility
{
    // linear equation solver utility for ai + bj = c and di + ej = f
    static void solvexy(double a, double b, double c, double d, double e, double f, out double i, out double j)
    {
        j = (c - a / d * f) / (b - a * e / d);
        i = (c - (b * j)) / a;
    }

    // basis functions
    static double b0(double t) { return Math.Pow(1 - t, 3); }
    static double b1(double t) { return t * (1 - t) * (1 - t) * 3; }
    static double b2(double t) { return (1 - t) * t * t * 3; }
    static double b3(double t) { return Math.Pow(t, 3); }

    static void bez4pts1(double x0, double y0, double x4, double y4, double x5, double y5, double x3, double y3, out double x1, out double y1, out double x2, out double y2)
    {
        // find chord lengths
        double c1 = Math.Sqrt((x4 - x0) * (x4 - x0) + (y4 - y0) * (y4 - y0));
        double c2 = Math.Sqrt((x5 - x4) * (x5 - x4) + (y5 - y4) * (y5 - y4));
        double c3 = Math.Sqrt((x3 - x5) * (x3 - x5) + (y3 - y5) * (y3 - y5));
        // guess "best" t
        double t1 = c1 / (c1 + c2 + c3);
        double t2 = (c1 + c2) / (c1 + c2 + c3);
        // transform x1 and x2
        solvexy(b1(t1), b2(t1), x4 - (x0 * b0(t1)) - (x3 * b3(t1)), b1(t2), b2(t2), x5 - (x0 * b0(t2)) - (x3 * b3(t2)), out x1, out x2);
        // transform y1 and y2
        solvexy(b1(t1), b2(t1), y4 - (y0 * b0(t1)) - (y3 * b3(t1)), b1(t2), b2(t2), y5 - (y0 * b0(t2)) - (y3 * b3(t2)), out y1, out y2);
    }

    static public PathFigure BezierFromIntersection(Point startPt, Point int1, Point int2, Point endPt)
    {
        double x1, y1, x2, y2;
        bez4pts1(startPt.X, startPt.Y, int1.X, int1.Y, int2.X, int2.Y, endPt.X, endPt.Y, out x1, out y1, out x2, out y2);
        PathFigure p = new PathFigure { StartPoint = startPt };
        p.Segments.Add(new BezierSegment { Point1 = new Point(x1, y1), Point2 = new Point(x2, y2), Point3 = endPt } );
        return p;
    }
}

I haven't tested it, but it compiles. 我没有测试它,但它编译。 Just call DrawingUtility.BezierFromIntersection with the 4 points you have, and it will return a PathFigure for drawing the curve. 只需使用您拥有的4个点调用DrawingUtility.BezierFromIntersection ,它将返回一个用于绘制曲线的PathFigure

You should consider using Cardinal (Canonical) Splines, which use a set of points that exist on the path, plus a "tension" parameter that controls how sharply corners are smoothed to corner tangents. 您应该考虑使用Cardinal(Canonical)Splines,它使用路径上存在的一组点,加上一个“张力”参数,用于控制角落平滑到角落切线的程度。

In Windows Forms, one would use the DrawCurve and DrawClosedCurve methods. 在Windows窗体中,可以使用DrawCurveDrawClosedCurve方法。 In WPF there are no direct equivalents. 在WPF中没有直接的等价物。 Here are two articles that describe using cardinal splines in WPF with C#. 这里有两篇文章描述了使用C#在WPF中使用基数样条线。

Floris - AddCurve For WPF Cardinal Spline Floris - 用于WPF Cardinal Spline的AddCurve

Petzold - Canonical Splines In WPF And Silverlight Petzold - WPF和Silverlight中的典型样条

as3 version: as3版本:

package 
{
    import flash.geom.Vector3D;

    public class DrawingUtility 
    {
        private var x1:Number; 
        private var y1:Number; 
        private var x2:Number;
        private var y2:Number;

        // linear equation solver utility for ai + bj = c and di + ej = f
        private function solvexy(a:Number, b:Number, c:Number, d:Number, e:Number, f:Number):Vector.<Number>
        {
            var returnVal:Vector.<Number> = new Vector.<Number>();
            var j:Number = (c - a / d * f) / (b - a * e / d);
            var i:Number = (c - (b * j)) / a;
            returnVal[0] = i;
            returnVal[1] = j;
            return returnVal;
        }

        // basis functions
        private function b0(t:Number):Number { 
            return Math.pow(1 - t, 3);
        }
        private function b1(t:Number):Number {
            return t * (1 - t) * (1 - t) * 3;
        }
        private function b2(t:Number):Number {
            return (1 - t) * t * t * 3;
        }
        private function b3(t:Number):Number {
            return Math.pow(t, 3);
        }

        private function bez4pts1(x0:Number, y0:Number, x4:Number, y4:Number, x5:Number, y5:Number, x3:Number, y3:Number):void
        {
            // find chord lengths
            var c1:Number = Math.sqrt((x4 - x0) * (x4 - x0) + (y4 - y0) * (y4 - y0));
            var c2:Number = Math.sqrt((x5 - x4) * (x5 - x4) + (y5 - y4) * (y5 - y4));
            var c3:Number = Math.sqrt((x3 - x5) * (x3 - x5) + (y3 - y5) * (y3 - y5));
            // guess "best" t
            var t1:Number = c1 / (c1 + c2 + c3);
            var t2:Number = (c1 + c2) / (c1 + c2 + c3);
            // transform x1 and x2
            var x1x2:Vector.<Number> = solvexy(b1(t1), b2(t1), x4 - (x0 * b0(t1)) - (x3 * b3(t1)), b1(t2), b2(t2), x5 - (x0 * b0(t2)) - (x3 * b3(t2)));
            x1 = x1x2[0];
            x2 = x1x2[1];
            // transform y1 and y2
            var y1y2:Vector.<Number> = solvexy(b1(t1), b2(t1), y4 - (y0 * b0(t1)) - (y3 * b3(t1)), b1(t2), b2(t2), y5 - (y0 * b0(t2)) - (y3 * b3(t2)));
            y1 = y1y2[0];
            y2 = y1y2[1];
        }

        public function BezierFromIntersection(startPt:Vector3D, int1:Vector3D, int2:Vector3D, endPt:Vector3D):Vector.<Vector3D>
        {
            var returnVec:Vector.<Vector3D> = new Vector.<Vector3D>();
            bez4pts1(startPt.x, startPt.y, int1.x, int1.y, int2.x, int2.y, endPt.x, endPt.y);

            returnVec.push(startPt);
            returnVec.push(new Vector3D(x1, y1));
            returnVec.push(new Vector3D(x2, y2));
            returnVec.push(endPt);
            return returnVec;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在C#中沿贝塞尔曲线指定给定起点,终点和1个点的情况下,找到QuadraticBezierSegment的控制点-QuadraticBezier 3点插值 - Find Control Point for QuadraticBezierSegment when given Start, End, and 1 Point lying along the bezier in C# - QuadraticBezier 3-point Interpolation 如何获得最接近给定点的三次贝塞尔曲线? - How can I get a cubic bezier curve closest to given points? 图表C#在三次贝塞尔曲线中添加数据点 - Chart C# add Data Point in cubic bezier curve 如何计算仅包含起点和终点的贝塞尔曲线? - How to calculate a bezier curve with only start and end points? 在给定开始,结束和圆心(圆)点的位置找到弧的中点 - Find arc's mid-point given start, end, and center (of circle) points 计算给定角度的贝塞尔曲线控制点 - Calculate bezier curve control points with given angle 如何找到贝塞尔曲线的控制点? - How do I find the control points for a Bezier curve? 如何在UWP C#中使用BezierSegment在画布上渲染InkStroke - How to render InkStroke on Canvas using BezierSegment in UWP C# 如何在C#中找出具有给定时间范围的时间范围的交点? - How to find out Intersection of a time range with the given set of time ranges in C#? 在C#中给定2个点和距离来查找未知点(x,y) - Finding unkown point (x,y) given 2 points and distance in c#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM