2011-08-21 3 views
7

Sto cercando di capire come ChemDraw, uno strumento di chimica leader del settore sviluppato da cambridgesoft, costruisca curve di Bezier, in modo da poter tradurre manualmente i punti di curva di Bezier da altri programmi/routine (come le utilità Delphi/C# fatte in casa) nei dati della curva riconoscibili per ChemDraw. Prima di iniziare, devo ammettere che sto chiedendo come funziona un certo blackbox internamente, e quindi voglio chiedermi qualsiasi problema e apprezzare qualsiasi aiuto!Aiuto per analizzare come un software/programma costruisce la curva di Bezier

Ho creato in ChemDraw quattro tipi di curve di Bézier più semplici e li ho salvati come file .CDXML, la cui sezione curva è stata incollata alla fine. Sia i file .CDXML che le immagini corrispondenti possono essere scaricati dal fileserve. Download Bezier_curve_ChemDraw_sample here. ChemDraw trial edition can be downloaded here.

Domande

Domanda 1. Prendere i punti della curva del tipo "Linea", per esempio, ci sono complessivamente due punti che ho usato quando si effettua questa curva. Perché ChemDraw memorizza sei punti per questo? E in che modo ChemDraw interpreta questi punti esattamente? La stessa domanda esiste per gli altri tre tipi, che impiegano al massimo quattro punti espliciti.

Domanda 2. Se in ChemDraw viene visualizzato il contenuto di "curva di Bezier utilizzando tre punti - primo tipo", è possibile vedere il primo punto non può essere (12.22, 104.25). Voglio dire, la sua coordinata X è ovviamente più grande di 12. Perché sta succedendo questo? ChemDraw fa qualche trasformazione con i dati? La stessa domanda esiste per "curva di Bézier usando quattro punti".

Domanda 3. Sembra che il carattere in bianco extra alla fine dell'attributo CurvePoints faccia la differenza. Qual è esattamente la differenza?

Qualcuno potrebbe illuminarmi su questi problemi?

sezioni curva nel file ChemDraw .CDXML

============ Linea ==============
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" 
/> 

curva ============ Bezier utilizzando tre punti - primo tipo ==============
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" 
/> 

============ Bezier curva utilizzando tre punti - secondo tipo ==============
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" 
/> 

===== ======= curva Bezier utilizzando quattro punti ==============
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" 
/> 

Esempio C# programma per generare le stesse curve

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); 
     } 
    } 
} 

Tuttavia, non posso fare in modo che questa utility C# generi le stesse curve dei display ChemDraw ad eccezione del primo tipo Line.
C# DrawBezier_1 screen-capture
C# DrawBezier_2 screen-capture C# DrawBezier_3 screen-capture C# DrawBezier_4 screen-capture

+2

upvoted a causa della domanda dettagliata. –

risposta

7

sua usando l'algoritmo standard curva di Bezier che può assumere qualsiasi quantità di punti per costruire una curva. guarda Bézier curve

Modifica:
C# DrawBezier supporta solo il quadratico (quattro punti) bezier. È a quattro punti di Bezier sarà tradotto in C# utilizzando:

float[] CurvePoints = GetCurvePoints(); 

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

Dove GetCurvePoints() appena ti dà la lista dei punti da CurvePoints attributo XML.

Edit 2:
codice per riprodurre all'ultima curva tutti curve:

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); 
    } 
} 

Risultato:
Bezier example

+0

Grazie per i vostri commenti molto! Ti riferisci a "Elevazione in gradi"? Inoltre, potresti aiutare a commentare un po 'di più su come trasformare in pratica i punti utilizzati, ad esempio, nella funzione C# Graphics.DrawBezier/DrawBeziers da/per i punti utilizzati nel ChemDraw sopra menzionato? – SOUser

+0

@Xichen Li: aggiunto in modifica. – Dani

+0

Grazie per la tua elaborazione! Vuoi dire se lascio 'GetCurvePoints' restituire i dati contenuti nell'attributo xml di ChemDraw CurvePoints, C# Graphics.DrawBezier genererà la stessa curva mostrata da ChemDraw? Mi dispiace ma (1) l'attributo xml di ChemDraw CurvePoints contiene sei punti per i quattro esempi pubblicati sopra, (2) 'DrawBezier' accetta quattro punti e (3)' DrawBeziers' sembra accettare 4 + 3n punti. PS: ho provato a fornire 'DrawBeziers' con quei sei punti e non ho potuto ottenere la stessa immagine o anche quella valida. Potresti aiutare a commentare? – SOUser