我一整天都在尝试这样做.基本上,我有一条线和一条点.我希望线条能够弯曲并穿过那个点,但我不想要一条平滑的曲线.我不能像我这样定义曲线中的步数(谨防粗略的mspaint绘图):
等等.我尝试了各种各样的东西,比如从初始线的中心取角度,然后在角度引导的点处分割线,但是我的长度有问题.我会把初始长度除以我所处的步数,但这不太对.
有人知道这样做的方法吗?
谢谢.
解决方法
您可能需要自己编写代码.我认为你可以通过在代码中实现二次贝塞尔曲线函数来实现它,可以找到
here.你可以通过仅求解几个值来决定你想要增量的精度.如果你想要一条直线,只求解0和1并用线连接这些点.如果您想要一个角度示例,请求解0,0.5和1并按顺序连接点.如果你想要你的第三个例子,求解0,0.25,0.5,0.75和1.最好将它放在一个for循环中,如下所示:
float stepValue = (float)0.25; float lastCalculatedValue; for (float t = 0; t <= 1; t += stepValue) { // Solve the quadratic bezier function to get the point at t. // If this is not the first point,connect it to the prevIoUs point with a line. // Store the new value in lastCalculatedValue. }
编辑:实际上,看起来您希望线路通过您的控制点.如果是这种情况,您不希望使用二次贝塞尔曲线.相反,您可能想要拉格朗日曲线.该网站可能有助于公式:http://www.math.ucla.edu/~baker/java/hoefer/Lagrange.htm.但在任何一种情况下,您都可以使用相同类型的循环来控制平滑度.
第2编辑:这似乎有效.只需将numberOfSteps成员更改为所需的线段总数,并相应地设置点数组.顺便说一句,你可以使用三个以上的点.它只会在它们之间分配线段的总数.但我初始化了数组,结果看起来像你的最后一个例子.
第3次编辑:我稍微更新了代码,因此您可以左键单击表单以添加点,然后右键单击以删除最后一点.另外,我在底部添加了一个NumericUpDown,因此您可以在运行时更改段的数量.
public class Form1 : Form { private int numberOfSegments = 4; private double[,] multipliers; private List<Point> points; private NumericUpDown numberOfSegmentsUpDown; public Form1() { this.numberOfSegmentsUpDown = new NumericUpDown(); this.numberOfSegmentsUpDown.Value = this.numberOfSegments; this.numberOfSegmentsUpDown.ValueChanged += new System.EventHandler(this.numberOfSegmentsUpDown_ValueChanged); this.numberOfSegmentsUpDown.Dock = DockStyle.Bottom; this.Controls.Add(this.numberOfSegmentsUpDown); this.points = new List<Point> { new Point(100,110),new Point(50,60),new Point(100,10)}; this.PrecomputeMultipliers(); } public void PrecomputeMultipliers() { this.multipliers = new double[this.points.Count,this.numberOfSegments + 1]; double pointCountMinusOne = (double)(this.points.Count - 1); for (int currentStep = 0; currentStep <= this.numberOfSegments; currentStep++) { double t = currentStep / (double)this.numberOfSegments; for (int pointIndex1 = 0; pointIndex1 < this.points.Count; pointIndex1++) { double point1Weight = pointIndex1 / pointCountMinusOne; double currentMultiplier = 1; for (int pointIndex2 = 0; pointIndex2 < this.points.Count; pointIndex2++) { if (pointIndex2 == pointIndex1) continue; double point2Weight = pointIndex2 / pointCountMinusOne; currentMultiplier *= (t - point2Weight) / (point1Weight - point2Weight); } this.multipliers[pointIndex1,currentStep] = currentMultiplier; } } } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Point? prevIoUsPoint = null; for (int currentStep = 0; currentStep <= numberOfSegments; currentStep++) { double sumX = 0; double sumY = 0; for (int pointIndex = 0; pointIndex < points.Count; pointIndex++) { sumX += points[pointIndex].X * multipliers[pointIndex,currentStep]; sumY += points[pointIndex].Y * multipliers[pointIndex,currentStep]; } Point newPoint = new Point((int)Math.Round(sumX),(int)Math.Round(sumY)); if (prevIoUsPoint.HasValue) e.Graphics.DrawLine(Pens.Black,prevIoUsPoint.Value,newPoint); prevIoUsPoint = newPoint; } for (int pointIndex = 0; pointIndex < this.points.Count; pointIndex++) { Point point = this.points[pointIndex]; e.Graphics.FillRectangle(Brushes.Black,new Rectangle(point.X - 1,point.Y - 1,2,2)); } } protected override void OnMouseClick(MouseEventArgs e) { base.OnMouseClick(e); if (e.Button == MouseButtons.Left) { this.points.Add(e.Location); } else { this.points.RemoveAt(this.points.Count - 1); } this.PrecomputeMultipliers(); this.Invalidate(); } private void numberOfSegmentsUpDown_ValueChanged(object sender,EventArgs e) { this.numberOfSegments = (int)this.numberOfSegmentsUpDown.Value; this.PrecomputeMultipliers(); this.Invalidate(); } }