Помогите проанализировать, как программное обеспечение / программа строит кривую Безье - PullRequest
7 голосов
/ 22 августа 2011

Я пытаюсь понять, как ChemDraw, лидирующий в отрасли инструмент химии, разработанный cambridgesoft, создает кривые Безье, чтобы я мог вручную переводить точки кривой Безье из других программ / подпрограмм (таких как домашние утилиты Delphi / C #) в данные кривой, распознаваемые для ChemDraw.Прежде чем начать, я должен признать, что спрашиваю, как работает определенный черный ящик внутри, и поэтому хочу извиниться за любые проблемы и признателен за любую помощь!

Я сделал в ChemDraw четыре типа простейших кривых Безье и сохранил их какФайл .CDXML, участок кривой которого был вставлен в конце.Файлы .CDXML и соответствующие изображения можно загрузить из fileserve. Скачать Bezier_curve_ChemDraw_sample здесь . Пробную версию ChemDraw можно скачать здесь .

Вопросы

Вопрос 1. Например, возьмите точки кривой типа «Линия», в целом есть две точки, которые яиспользуется при создании этой кривой.Почему ChemDraw хранит шесть очков за это?И как ChemDraw интерпретирует эти точки точно?Тот же вопрос существует и для остальных трех типов, в которых используются не более четырех явных точек.

Вопрос 2. Если в «ChemDraw» отображается содержимое «кривой Безье, использующей три точки - первый тип», можно увидетьПервой точки быть не может (12.22, 104.25).Я имею в виду, что его координата X явно больше 12. Почему это происходит?Делает ли ChemDraw какие-либо преобразования с данными?Тот же вопрос существует для «кривой Безье, использующей четыре точки».

Вопрос 3. Кажется, что дополнительный пустой символ в конце атрибута CurvePoints имеет значение.В чем разница?

Может ли кто-нибудь рассказать мне об этих проблемах?

Кривые сечения в файлах ChemDraw .CDXML

============ Линия ==============
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"  
 />  

============ Кривая Безье с использованием трех точек- первый тип ==============
Curve - three points - drag the starting point

 <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 - three points - drag the stopping point

 <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 - three points - drag both the starting and the stopping 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"   
 />  

Пример программы 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.
C# DrawBezier_1 screen-capture
C# DrawBezier_2 screen-capture C# DrawBezier_3 screen-capture C# DrawBezier_4 screen-capture

1 Ответ

7 голосов
/ 22 августа 2011

Используется стандартный алгоритм кривой Безье, который может использовать любое количество точек для построения кривой. посмотрите на кривую Безье

Edit:
C # DrawBezier поддерживает только квадратичный (четыре точки) Безье. Ваш четырехточечный Безье будет переведен на C # с помощью:

float[] CurvePoints = GetCurvePoints();

DrawBezier(Pen, CurvePoints[0], CurvePoints[1], CurvePoints[4], CurvePoints[5],
                CurvePoints[6], CurvePoints[7], CurvePoints[10], CurvePoints[11]);

Где GetCurvePoints() просто дает вам список точек из CurvePoints атрибута xml.

Редактировать 2:
Код для воспроизведения последней кривой всех кривых:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Linq;
using System.Collections.Generic;

public class Bezier : Form
{
    static public void Main ()
    {
        Application.Run (new Bezier ());
    }

    protected override void OnPaint (PaintEventArgs e)
    {
        // The input with all points
        string CurveDataString = "5.47 93.75 123.22 93.75 240.97 93.75 351.22 177.75 236.47 177.75 121.72 177.75";

        string[] CurveDataStringParts = CurveDataString.Split(' ');

        int[] Keep = {2, 3, 4, 5, 6, 7, 8, 9};
        float[] CurveData = (from i in Keep select float.Parse(CurveDataStringParts[i])).ToArray();

        e.Graphics.DrawBezier(Pens.Black, CurveData[0], CurveData[1], CurveData[2], CurveData[3],
                                          CurveData[4], CurveData[5], CurveData[6], CurveData[7]);

        for(int i = 0; i < CurveData.Length; i += 2)
        {
            e.Graphics.FillEllipse(Brushes.Black, new RectangleF(CurveData[i] - 2, CurveData[i + 1] - 2, 4, 4));
        }

        base.OnPaint (e);
    }
}

Результат:
Bezier example

...