帮助分析软件/程序如何构建贝塞尔曲线
我试图了解由 cambridgesoft 开发的业界领先的化学工具 ChemDraw 如何构建贝塞尔曲线,以便我可以手动将其他程序/例程(例如自制的 Delphi/C# 实用程序)中的贝塞尔曲线点转换为ChemDraw 可识别的曲线数据。在开始之前,我必须承认我是在问某些黑盒内部是如何工作的,因此对任何麻烦表示歉意并感谢任何帮助!
我在ChemDraw中制作了四种最简单的贝塞尔曲线,并将它们保存为.CDXML文件,其曲线部分已粘贴在最后。 .CDXML 文件和相应的图片都可以从 fileserve 下载。 在此处下载 Bezier_curve_ChemDraw_sample。 ChemDraw 试用版可在此处下载。
问题
问题1.以“Line”类型的曲线点为例,我在制作这条曲线时总共使用了两个点。为什么 ChemDraw 为其存储六个点? ChemDraw 是如何准确解释这些点的呢?其他三种类型也存在同样的问题,最多使用四个显式点。
问题2. 如果ChemDraw 中显示“使用三点的贝塞尔曲线-第一种类型”的内容,可以看到第一个点不可能是(12.22, 104.25)。我的意思是,它的X坐标明显大于12。为什么会发生这种情况呢? ChemDraw 是否对数据进行一些转换? “使用四点的贝塞尔曲线”也存在同样的问题。
问题 3. CurvePoints 属性末尾的额外空白字符似乎有所不同。到底有什么区别呢?
有人可以告诉我这些问题吗?
ChemDraw .CDXML 文件中的曲线部分
============ 线 ==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="143.47 116.25 143.47 116.25 143.47 116.25 300.22 117.75 300.22 117.75 300.22 117.75"
/>
============ 使用三点的贝塞尔曲线 - 第一种类型 ===== =========
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="12.22 104.25 121.72 106.5 231.22 108.75 230.47 204 230.47 204 230.47 204"
/>
============ 使用三点的贝塞尔曲线- 第二种==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="134.47 97.5 134.47 97.5 134.47 97.5 231.22 60.75 229.72 109.5 228.22 158.25"
/>
============ 使用四点的贝塞尔曲线==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="5.47 93.75 123.22 93.75 240.97 93.75 351.22 177.75 236.47 177.75 121.72 177.75"
/>
生成相同曲线的示例 C# 程序
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WinForms_2_DrawBezier
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Text = "Draw Bezier Curve";
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// DrawBezier_1(this, e);
// DrawBezier_2(this, e);
// DrawBezier_3(this, e);
DrawBezier_4(this, e);
}
private void DrawBezier_1(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(143.47f, 116.25f);
PointF l_pt2 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt3 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt4 = new PointF(300.22f, 117.75f);
PointF l_pt5 = new PointF(l_pt4.X, l_pt4.Y);
PointF l_pt6 = new PointF(l_pt4.X, l_pt4.Y);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt2, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_2(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(12.22f, 104.25f);
PointF l_pt2 = new PointF(121.72f, 106.5f);
PointF l_pt3 = new PointF(231.22f, 108.75f);
PointF l_pt4 = new PointF(230.47f, 204f);
PointF l_pt5 = new PointF(l_pt4.X, l_pt4.Y);
PointF l_pt6 = new PointF(l_pt4.X, l_pt4.Y);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt2, l_pt3, l_pt4);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_3(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(134.47f, 97.5f);
PointF l_pt2 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt3 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt4 = new PointF(231.22f, 60.75f);
PointF l_pt5 = new PointF(229.72f, 109.5f);
PointF l_pt6 = new PointF(228.22f, 158.25f);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt3, l_pt4, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_4(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(5.47f, 93.75f);
PointF l_pt2 = new PointF(123.22f, 93.75f);
PointF l_pt3 = new PointF(240.97f, 93.75f);
PointF l_pt4 = new PointF(351.22f, 177.75f);
PointF l_pt5 = new PointF(236.47f, 177.75f);
PointF l_pt6 = new PointF(121.72f, 177.75f);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt4, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
}
}
但是,我无法制作此 C# 实用程序生成的曲线与 ChemDraw 显示的曲线相同,但第一个 Line
类型除外。
I am trying to understand how ChemDraw, a Industry-Leading Chemistry Tool developed by cambridgesoft, constructs Bezier curves, so that I can manually translate the Bezier curve points from other programs/routines (such as home-made Delphi/C# utilities) into the curve data recognizable for ChemDraw. Before starting, I must admit that I am asking how certain blackbox works internally, and therefore want to appologize for any trouble and appreciate any help!
I have made in ChemDraw four types of simplest Bezier curves and saved them as .CDXML file, the curve section of which have been pasted in the end. Both the .CDXML files and corresponding pictures can be downloaded from fileserve. Download Bezier_curve_ChemDraw_sample here. ChemDraw trial edition can be downloaded here.
Questions
Question 1. Take the curve points of the "Line" type for example, there are overall two points that I used when making this curve. Why does ChemDraw store six points for it? And how does ChemDraw interpret these points exactly? The same question exists for the other three types, which employs four explicit points at most.
Question 2. If the content of "Bezier curve using three points - first type" is displayed in ChemDraw, one can see the first point can not be (12.22, 104.25). I mean, its X coordinate is obviously larger than 12. Why is this happening? Does ChemDraw do some transformation with the data? The same question exists for "Bezier curve using four points".
Question 3. It seems the extra blank character at the end of the CurvePoints attribute makes difference. What is the difference exactly?
Could some one enlighten me about these problems?
Curve sections in the ChemDraw .CDXML files
============ Line ==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="143.47 116.25 143.47 116.25 143.47 116.25 300.22 117.75 300.22 117.75 300.22 117.75"
/>
============ Bezier curve using three points - first type ==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="12.22 104.25 121.72 106.5 231.22 108.75 230.47 204 230.47 204 230.47 204"
/>
============ Bezier curve using three points - second type ==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="134.47 97.5 134.47 97.5 134.47 97.5 231.22 60.75 229.72 109.5 228.22 158.25"
/>
============ Bezier curve using four points ==============
<curve
id="2"
Z="1"
ArrowheadType="Solid"
CurvePoints="5.47 93.75 123.22 93.75 240.97 93.75 351.22 177.75 236.47 177.75 121.72 177.75"
/>
Example C# program to generate the same curves
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WinForms_2_DrawBezier
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Text = "Draw Bezier Curve";
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// DrawBezier_1(this, e);
// DrawBezier_2(this, e);
// DrawBezier_3(this, e);
DrawBezier_4(this, e);
}
private void DrawBezier_1(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(143.47f, 116.25f);
PointF l_pt2 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt3 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt4 = new PointF(300.22f, 117.75f);
PointF l_pt5 = new PointF(l_pt4.X, l_pt4.Y);
PointF l_pt6 = new PointF(l_pt4.X, l_pt4.Y);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt2, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_2(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(12.22f, 104.25f);
PointF l_pt2 = new PointF(121.72f, 106.5f);
PointF l_pt3 = new PointF(231.22f, 108.75f);
PointF l_pt4 = new PointF(230.47f, 204f);
PointF l_pt5 = new PointF(l_pt4.X, l_pt4.Y);
PointF l_pt6 = new PointF(l_pt4.X, l_pt4.Y);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt2, l_pt3, l_pt4);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_3(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(134.47f, 97.5f);
PointF l_pt2 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt3 = new PointF(l_pt1.X, l_pt1.Y);
PointF l_pt4 = new PointF(231.22f, 60.75f);
PointF l_pt5 = new PointF(229.72f, 109.5f);
PointF l_pt6 = new PointF(228.22f, 158.25f);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt3, l_pt4, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
private void DrawBezier_4(object sender, PaintEventArgs e)
{
Pen l_pen = new Pen(Color.Black);
PointF l_pt1 = new PointF(5.47f, 93.75f);
PointF l_pt2 = new PointF(123.22f, 93.75f);
PointF l_pt3 = new PointF(240.97f, 93.75f);
PointF l_pt4 = new PointF(351.22f, 177.75f);
PointF l_pt5 = new PointF(236.47f, 177.75f);
PointF l_pt6 = new PointF(121.72f, 177.75f);
PointF[] l_pts = new PointF[6];
l_pts[0] = l_pt1;
l_pts[1] = l_pt2;
l_pts[2] = l_pt3;
l_pts[3] = l_pt4;
l_pts[4] = l_pt5;
l_pts[5] = l_pt6;
// e.Graphics.DrawBezier(l_pen, l_pt1, l_pt4, l_pt5, l_pt6);
e.Graphics.DrawBezier(l_pen, l_pt1, l_pt3, l_pt4, l_pt6); // As suggested by Dani
// e.Graphics.DrawBeziers(l_pen, l_pts);
}
}
}
However, I cannot make this C# utility generate the same curves as ChemDraw displays except for the first Line
type.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它使用标准贝塞尔曲线算法,可以采用任意数量的点来构建曲线。看看贝塞尔曲线
编辑:
C# DrawBezier 仅支持二次(四点)贝塞尔曲线。您的四点贝塞尔曲线将使用以下方法转换为 C#:
其中
GetCurvePoints()
只为您提供来自CurvePoints
xml 属性的点列表。编辑2:
重现
最后一条曲线所有曲线的代码:结果:

Its using the standard bezier curve algorithm which can take any amount of points to construct a curve. look at Bézier curve
Edit:
C# DrawBezier only supports quadratic (four points) bezier. You four point bezier will be translated to C# using:
Where
GetCurvePoints()
just gives you the list of points fromCurvePoints
xml attribute.Edit 2:
Code to reproduce
the last curveall curves:Result:
