![]() |
#1
|
||||
|
||||
![]()
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. |
#2
|
||||
|
||||
![]()
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 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 |
#3
|
|||
|
|||
![]()
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])); I'm working with Corel Draw 13. Thank you |
#4
|
||||
|
||||
![]()
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; } |
#5
|
|||
|
|||
![]()
Yes it does!
Many thanks Alex |
#6
|
|||
|
|||
![]()
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 |
#7
|
||||
|
||||
![]()
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 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 |
#8
|
|||
|
|||
![]()
Hi Shelby,
Thanks so much. I will try this and let you know how it goes. -James |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | Search this Thread |
Display Modes | |
|
|
![]() |
||||
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 |