OberonPlace.com Forums  

Go Back   OberonPlace.com Forums > Developer Forums > VBA > CorelDRAW/Corel DESIGNER VBA

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 28-04-2005, 12:05
ddonnahoe's Avatar
ddonnahoe ddonnahoe is offline
Senior Member
 
Join Date: Jan 2004
Location: Louisville, KY
Posts: 552
Send a message via ICQ to ddonnahoe Send a message via AIM to ddonnahoe Send a message via MSN to ddonnahoe Send a message via Yahoo to ddonnahoe
Default Looking for info on method...

Does anyone have any documentation on "CreateCurveFromArray" method of Document? (for CD12)
I have an idea for a macro, but need more info on this tiny little morsel.
__________________
Sean
Waiting for a ride in the T.A.R.D.I.S.
Reply With Quote
  #2  
Old 28-04-2005, 13:06
Alex's Avatar
Alex Alex is offline
Administrator
 
Join Date: Nov 2002
Posts: 1,941
Blog Entries: 4
Default

CreateCurveArray takes an array of CurveElement structures. Each element represents a curve node (starting node of a path, line, curve or control point). This is actually the internal representation of curves in CorelDRAW and therefore this method works very efficiently, so if you want to create complex curves quickly, CreateCurveArray is the way to go.

Here is an example. The following code creates an arrow shown in the attached image:

Code:
Sub CreateArrow()
    Dim ci(0 To 5) As CurveElement
    Dim s As Shape
    
    With ci(0)
        .PositionX = 3
        .PositionY = 4
        .ElementType = cdrElementStart
        .NodeType = cdrCuspNode
        .flags = cdrFlagValid + cdrFlagUser + cdrFlagClosed
    End With
    With ci(1)
        .PositionX = 4
        .PositionY = 4.5
        .ElementType = cdrElementControl
        .flags = cdrFlagValid
    End With
    With ci(2)
        .PositionX = 5
        .PositionY = 4.5
        .ElementType = cdrElementControl
        .flags = cdrFlagValid
    End With
    With ci(3)
        .PositionX = 6
        .PositionY = 4
        .ElementType = cdrElementCurve
        .NodeType = cdrCuspNode
        .flags = cdrFlagValid + cdrFlagUser
    End With
    With ci(4)
        .PositionX = 4.5
        .PositionY = 7
        .ElementType = cdrElementLine
        .NodeType = cdrCuspNode
        .flags = cdrFlagValid + cdrFlagUser
    End With
    With ci(5)
        .PositionX = 3
        .PositionY = 4
        .ElementType = cdrElementLine
        .NodeType = cdrCuspNode
        .flags = cdrFlagValid + cdrFlagClosed
    End With
    Set s = ActiveLayer.CreateCurve(ActiveDocument.CreateCurveFromArray(ci))
    s.Fill.UniformColor.CMYKAssign 0, 0, 100, 0
End Sub
A curve (or a new subpaths) must start with a node of type "cdrElementStart". A line segments ends with a node of type "cdrElementLine". A curve segment must have a set of three nodes following - two of type "cdrElementControl" for control points ending with "cdrElementCurve".

If you want to create a closed path (to be filled), then the first and the last nodes of the path must conicide (have the same coordinates) and both must be marked as closed (cdrFlagClosed). Each node selectable by a user (most regular nodes) must bear a flag cdrFlagUser. Note that curve control points (cdrElementControl) must not have the User flag, neither does the last node of a closed path.

CreateCurveArray does some minimal check on the parameters supplied but it is up to you to provide valid parameters. You can run a risk of created corrupt curves if you are not careful, so it is your responsibility to proivde proper data for this function.

The easiest way to get all this data is to create a curve by hand in CorelDRAW, and then use ActiveShape.Curve.GetCurveInfo() to retrieve the array of CurveElement's for the curve and get all the coordinates, flags, node types from there.

If you want just to be able to recreate a preset curves in your macros (that is, if the shape of the curve is not dynamically created), you might want to consider this little function which allows you to do this: http://forum.oberonplace.com/showthread.php?t=978
Attached Images
 
Reply With Quote
  #3  
Old 12-04-2007, 00:04
squonk
Guest
 
Posts: n/a
Default same in C++

Alex, could you please provide a similar code snippet in C++. More precisely, I need only
the SAFEARRAY part (since CDrawDocument::CreateCurveFromArray() takes it on input).

Here's what I've come up with:

Code:
CurveElement ce [6];

... filling in the 'ce' array as per the sample

SAFEARRAY sa;
memset (& sa, 0, sizeof (sa));

sa.cDims = 1;
sa.fFeatures = FADF_AUTO;
sa.cbElements = sizeof (CurveElement);
sa.pvData = ce;
sa.rgsabound[0].lLbound = 0;
sa.rgsabound[0].cElements = sizeof (ce) / sizeof (ce[0]);

SAFEARRAY * psa = & sa;
LPDISPATCH pNewCurve = doc.CreateCurveFromArray (& psa, sizeof (ce) / sizeof (ce[0]));
The last line throws an exception (Internal Applicaton Error).
I'm working with Corel Draw 13.

Thank you
Reply With Quote
  #4  
Old 12-04-2007, 16:28
Alex's Avatar
Alex Alex is offline
Administrator
 
Join Date: Nov 2002
Posts: 1,941
Blog Entries: 4
Default

It's a litte non-trivial, isn't it?

Well, first, you can't just declare SAFEARRAY on stack. You need to call one of the SafeArray functions, such as SafeArrayCreate or SafeArrayCreateVector.

Now, it is a bit more difficult to create an array of structures. You need to call the SafeArrayCreateEx function and pass IRecordInfo interface describing the record (structure) type you are using...

Anyway, here is a Visual Studio 2005 C++ project that I have created. I just created a simple console application, imported CorelDRAW typelibraries using the #import instruction and used CorelDRAW method to do the same things as in the VBA sample in my previous post above:

Code:
// CurveElemet.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#import "VGCoreAuto.tlb"
#import "CorelDRAW.tlb"

void FillCurveElementData(CorelDRAW::CurveElement* pData, const int nNumElements)
{
  memset(pData, 0, sizeof(CorelDRAW::CurveElement) * nNumElements);

  pData[0].PositionX = 3;
  pData[0].PositionY = 4;
  pData[0].ElementType = CorelDRAW::cdrElementStart;
  pData[0].NodeType = CorelDRAW::cdrCuspNode;
  pData[0].Flags = CorelDRAW::cdrFlagValid | CorelDRAW::cdrFlagUser | CorelDRAW::cdrFlagClosed;

  pData[1].PositionX = 4;
  pData[1].PositionY = 4.5;
  pData[1].ElementType = CorelDRAW::cdrElementControl;
  pData[1].Flags = CorelDRAW::cdrFlagValid;

  pData[2].PositionX = 5;
  pData[2].PositionY = 4.5;
  pData[2].ElementType = CorelDRAW::cdrElementControl;
  pData[2].Flags = CorelDRAW::cdrFlagValid;

  pData[3].PositionX = 6;
  pData[3].PositionY = 4;
  pData[3].ElementType = CorelDRAW::cdrElementCurve;
  pData[3].NodeType = CorelDRAW::cdrCuspNode;
  pData[3].Flags = CorelDRAW::cdrFlagValid | CorelDRAW::cdrFlagUser;

  pData[4].PositionX = 4.5;
  pData[4].PositionY = 7;
  pData[4].ElementType = CorelDRAW::cdrElementLine;
  pData[4].NodeType = CorelDRAW::cdrCuspNode;
  pData[4].Flags = CorelDRAW::cdrFlagValid | CorelDRAW::cdrFlagUser;

  pData[5].PositionX = 3;
  pData[5].PositionY = 4;
  pData[5].ElementType = CorelDRAW::cdrElementLine;
  pData[5].NodeType = CorelDRAW::cdrCuspNode;
  pData[5].Flags = CorelDRAW::cdrFlagValid | CorelDRAW::cdrFlagClosed;
}

int _tmain(int argc, _TCHAR* argv[])
{
  CoInitialize(NULL);
  try
  {
    CorelDRAW::IDrawApplicationPtr app(__uuidof(CorelDRAW::Application));
    CorelDRAW::IDrawDocumentPtr doc = app->CreateDocument();
    const int nNumElements = 6;

    IRecordInfo* pRecInfo = NULL;
    HRESULT hr = GetRecordInfoFromGuids(  __uuidof(CorelDRAW::__CorelDRAW), 
                                          app->PlatformVersionMajor, 
                                          app->PlatformVersionMinor, 
                                          LOCALE_SYSTEM_DEFAULT, 
                                          __uuidof(CorelDRAW::CurveElement),
                                          &pRecInfo );

    if(SUCCEEDED(hr))
    {
      SAFEARRAY* psa = SafeArrayCreateVectorEx(VT_RECORD, 0, nNumElements, pRecInfo);
      pRecInfo->Release();
      if(psa)
      {
        CorelDRAW::CurveElement* pData = NULL;
        hr = SafeArrayAccessData(psa, (void**)&pData);
        if(SUCCEEDED(hr))
        {
          FillCurveElementData(pData, nNumElements);
          SafeArrayUnaccessData(psa);
        }

        CorelDRAW::IDrawShapePtr s = doc->ActiveLayer->CreateCurve(doc->CreateCurveFromArray(&psa, -1));
        s->Fill->UniformColor->CMYKAssign(0, 0, 100, 0);

        SafeArrayDestroy(psa);
      }
    }
    else
    {
      MessageBox(NULL, _T("Unable to get type information"), _T("Error"), MB_OK);
    }
  }
  catch(_com_error& e)
  {
    MessageBox(NULL, e.ErrorMessage(), _T("Error"), MB_OK);
  }
  CoUninitialize();
  return 0;
}
I hope this helps.
Reply With Quote
  #5  
Old 12-04-2007, 17:23
squonk
Guest
 
Posts: n/a
Default now it works

Yes it does!
Many thanks Alex
Reply With Quote
  #6  
Old 24-08-2009, 18:47
jemmyell jemmyell is offline
Senior Member
 
Join Date: Jan 2005
Location: Orange County, California, USA, Earth, Solar System, Milky Way Galaxy
Posts: 157
Default Calculating CurveElement data from raw data

Hi Alex,

I would like to use this method to speed up the drawing of raw LINE and ARC data. It seems the LINEs are just vertex to vertex, but it is unclear how I would translate an ARCs parameters to a CurveElement. Could you show how to do this programmatically without extracting info from an existing drawing?

-James
__________________
-James Leonard
CNC Inlay Guy - www.CorelDRAWCadCam.com
Reply With Quote
  #7  
Old 30-08-2009, 17:00
shelbym's Avatar
shelbym shelbym is offline
Senior Member
 
Join Date: Nov 2002
Location: Cheyenne, WY
Posts: 1,791
Blog Entries: 15
Send a message via ICQ to shelbym Send a message via AIM to shelbym Send a message via MSN to shelbym Send a message via Yahoo to shelbym
Default Calculating CurveElement data from raw data

Curve Approximation of an Arc takes a bit of work and a bit of math. Hopefully this will get you started, it is by far not complete but all I have time for at the moment. First you may find these links helpful in finishing what you need:

Bézier Curve Approximation of an Arc
APPROXIMATION OF A CUBIC BEZIER CURVE BY CIRCULAR ARCS AND VICE VERSA

The following code will create and arc then approximate the arc with a bezier curve. The curve in on top of the the arc, so if you wish to see the arc just move the curve.
Code:
Sub CurveApproximation()
    Dim sArc As Shape, lr As Layer
    Dim crv As Curve, sCurve As Shape, sp As SubPath
    Dim x1 As Double, y1 As Double
    Dim x4 As Double, y4 As Double
    Dim x2 As Double, y2 As Double
    Dim x3 As Double, y3 As Double
    Dim xc As Double, yc As Double
    Dim ax As Double, ay As Double
    Dim bx As Double, by As Double
    Dim q1 As Double, q2 As Double
    Dim k2 As Double
    
    xc = 0
    yc = 0
    
    Set lr = ActiveLayer
    Set s = lr.CreateEllipse2(xc, yc, 0.5, 0.5, 300, 60) 'Create an arc
    
    s.DisplayCurve.Nodes.Last.GetPosition x1, y1 'Get the position of the nodes
    s.DisplayCurve.Nodes.First.GetPosition x4, y4

    ax = x1 - xc
    ay = y1 - yc
    bx = x4 - xc
    by = y4 - yc
    q1 = ax * ax + ay * ay
    q2 = q1 + ax * bx + ay * by
    k2 = (4 / 3) * ((Sqr(2 * q1 * q2) - q2) / (ax * by - ay * bx))
    
    x2 = xc + x1 - k2 * y1
    y2 = yc + y1 + k2 * x1
    x3 = xc + x4 + k2 * y4
    y3 = yc + y4 - k2 * x4
    
    Set crv = Application.CreateCurve(ActiveDocument)
    Set sp = crv.CreateSubPath(x1, y1)
        sp.AppendCurveSegment2 x4, y4, x2, y2, x3, y3
        sp.Closed = False
    Set sCurve = ActiveLayer.CreateCurve(crv)
    sCurve.Outline.SetProperties Color:=CreateCMYKColor(0, 100, 100, 0)
End Sub
You can of course, create the curve from raw data, you just need your start, end, center of arc.

Again this was not meant to be a complete example, just hopefully point you in the correct direction and show that what you ask it possible, just be sure to have on your math hat. ;-)

Best of luck,

-Shelby
Reply With Quote
  #8  
Old 30-08-2009, 18:14
jemmyell jemmyell is offline
Senior Member
 
Join Date: Jan 2005
Location: Orange County, California, USA, Earth, Solar System, Milky Way Galaxy
Posts: 157
Default Thanks so much

Hi Shelby,

Thanks so much. I will try this and let you know how it goes.

-James
__________________
-James Leonard
CNC Inlay Guy - www.CorelDRAWCadCam.com
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
why can't we use "drivelistbox, dirlistbox etc" olympiatr CorelDRAW/Corel DESIGNER VBA 4 20-10-2004 08:33
SaveAs Method throwing an in consistent error wbochar CorelDRAW/Corel DESIGNER VBA 1 20-03-2003 14:37


All times are GMT -5. The time now is 01:21.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2023, Jelsoft Enterprises Ltd.
Copyright © 2011, Oberonplace.com