ObjectARX & Dummies

Course Index

*Course support: Click here!
*Course and User samples: Download here!

Saturday, June 04, 2005

Class 14 - Creating a Custom Entity (step by step)

Hello,

On this class I will complete the Class 13 with a tutorial to show you how to create a simple custom entity step by step. This entity has some features that will help you to see what is possible to do using ObjectARX. Please read carefully the following instructions.

-Create a Blank Solution called CustomEntitySample;
-Add a new DBX project called CustEntityDBX;
-Add a new ARX project called CustEntityARX;
-Remember to enable MFC Extension on both projects;
-Create a dependency from ARX project to DBX:



-Go to DBX project and open Autodesk Class Explorer;
-Right click on CustEntityDBX node and select "Add ObjectDBX Custom Object...":



-Choose MyCustomEntity as class name and derive it from AcDbEntity;
-Other fields will be filled automatically (you may change these values);



-Go to the Protocols TAB and enable both Osnap and Grip-points protocols:



-Rebuild your project to see if everything is ok;
-Now, open again the Autodesk Class Explorer, go to CustEntityDBX project;
-Select the MyCustomEntity node (if it is not there, click on Refresh icon);
-Right click on it and select "Add Variable...":



-Name it as "m_PtA", type will be an AcGePoint3d and its access will be protected;
-Enable "Participate to DWG filing protocol", disable "Increase Version number";
-Enable "Implement Get/Put methods" and fill desired comments for it;
-Repeat the process and create : "m_PtB", "m_PtAB" and "m_PtBA":



-Now, add a CString variable called "m_Text";
-Remember to correct the CString manipulation and filing as we have done in Lab3;
-Now you should compile your code ok;



Before continue, we will need to remove some functions that we will not use. First remove the following from .H file:

virtual Acad::ErrorStatus getGripPoints (
AcDbGripDataPtrArray &grips, const double curViewUnitSize, const int gripSize,
const AcGeVector3d &curViewDir, const int bitflags) const;

virtual Acad::ErrorStatus moveGripPointsAt (
const AcDbVoidPtrArray &gripAppData,
const AcGeVector3d &offset, const int bitflags);


There are 4 methods getOsnapPoints(). We will only use the following method:

virtual Acad::ErrorStatus getOsnapPoints (
AcDb::OsnapMode osnapMode, int gsSelectionMark, const AcGePoint3d &pickPoint,
const AcGePoint3d &lastPoint, const AcGeMatrix3d &viewXform,
AcGePoint3dArray &snapPoints, AcDbIntArray &geomIds) const ;


Now, you will need to delete the body of these functions from cpp file.

WORLDDRAW

-To draw our custom entity, we will need to add the following code to worldDraw() method:

assertReadEnabled();
// Bounding Polyline
AcGePoint3d pts[4];
pts[0] = m_PtA;
pts[1] = m_PtAB;
pts[2] = m_PtB;
pts[3] = m_PtBA;

mode->subEntityTraits().setSelectionMarker(1); // Mark 1
mode->subEntityTraits().setColor(1); // Red
mode->geometry().polygon(4,pts);

// Entity's Text
mode->subEntityTraits().setSelectionMarker(2); // Mark 2
mode->subEntityTraits().setColor(256); // ByLayer

AcGiTextStyle style;
style.setFileName(_T("txt.shx"));
style.setBigFontFileName(_T(""));
style.setTextSize(25);
style.loadStyleRec();

AcGePoint3d txtPt((m_PtB.x+m_PtA.x)/2.0, (m_PtB.y+m_PtA.y)/2.0, m_PtA.z);

mode->geometry().text(txtPt, AcGeVector3d::kZAxis,
(m_PtAB-m_PtA),m_Text, m_Text.GetLength(),Adesk::kFalse, style);

return Adesk::kTrue;


GRIP Points

-Open remaining getGripPoints() method inside MyCustomEntity implementation (cpp);
-We would like to enable 5 grips for this entity. One at each point (A,B,AB and BA) plus one at the center;
-Inside the getGripPoints(), add the following code:

gripPoints.append(m_PtA);
gripPoints.append(m_PtAB);
gripPoints.append(m_PtB);
gripPoints.append(m_PtBA);
gripPoints.append(AcGePoint3d((m_PtB.x+m_PtA.x)/2.0,
(m_PtB.y+m_PtA.y)/2.0,m_PtA.z));

-Now, when user clicks on each Grip we would like to perform an action. This is done using the moveGripPointsAt() method;
-We need to check the index of each fired grip accordingly to the getGripPoints() method and then apply the transformation;
-Inside remaining moveGripPointsAt() method, add the following code:

assertWriteEnabled();
for(int i=0; i<indices.length(); i++) {
int idx = indices.at(i);
// For A and center point
if (idx==0 idx==4) m_PtA += offset;
// For AB and center point
if (idx==1 idx==4) m_PtAB += offset;
// For B and center point
if (idx==2 idx==4) m_PtB += offset;
// For BA and center point
if (idx==3 idx==4) m_PtBA += offset;
}
return (Acad::eOk);


OSNAP Points


-Open the getOsnapPoints() method. We will add 3 Osnap modes: EndPoint, MidPoint and Center:

assertReadEnabled();
switch (osnapMode) {

case AcDb::kOsModeEnd:
snapPoints.append(m_PtA);
snapPoints.append(m_PtAB);
snapPoints.append(m_PtB);
snapPoints.append(m_PtBA);
break;

case AcDb::kOsModeMid:
snapPoints.append(m_PtA+((m_PtAB-m_PtA).length()/2.0)*((m_PtAB-m_PtA).normalize()));
snapPoints.append(m_PtAB+((m_PtB-m_PtAB).length()/2.0)*((m_PtB-m_PtAB).normalize()));
snapPoints.append(m_PtB+((m_PtBA-m_PtB).length()/2.0)*((m_PtBA-m_PtB).normalize()));
snapPoints.append(m_PtBA+((m_PtA-m_PtBA).length()/2.0)*((m_PtA-m_PtBA).normalize()));
break;

case AcDb::kOsModeCen:
snapPoints.append(AcGePoint3d((m_PtB.x+m_PtA.x)/2.0,
(m_PtB.y+m_PtA.y)/2.0, m_PtA.z));
break;

}
return (Acad::eOk);


TRANSFORMATION


-The custom entity transformation is done through transformBy() method;
-Open the Autodesk Class Explorer, expand the MyCustomEntity node, expand Base Classes node and then expand AcDbEntity node;
-Scroll down the list and select:

Acad::ErrorStatus transformBy(const AcGeMatrix3d &);

-Right click on this method and select "Implement Base Class Method";
-This function logic is very simple, just add the following code:

assertWriteEnabled();
m_PtA.transformBy(xform);
m_PtAB.transformBy(xform);
m_PtB.transformBy(xform);
m_PtBA.transformBy(xform);
return (Acad::eOk);

-This function will allow the custom entity to be transformed;

ARX PROJECT

-First we will need to add a new command called "MyCustEnt";
-This will create a method inside acxrEntryPoint.cpp file;
-Now, add the necessary include instruction after the #include "StdAfx.h":

#include "..\CustEntityDBX\MyCustomEntity.h"

-Inside the method we will create our entity:

// Input information
ads_point pt1,pt2;
if (acedGetPoint(NULL,_T("Set the first point:\n"),pt1) != RTNORM)
return;
if (acedGetCorner(pt1,_T("Set the second point:\n"),pt2) != RTNORM)
return;

TCHAR buffer[512];
if (acedGetString(0,_T("Enter the text:\n"),buffer) != RTNORM)
return;

// Setup entity
MyCustomEntity *pEnt = new MyCustomEntity();
pEnt->put_m_PtA(asPnt3d(pt1));
pEnt->put_m_PtAB(AcGePoint3d(pt2[X],pt1[Y],pt1[Z]));
pEnt->put_m_PtB(asPnt3d(pt2));
pEnt->put_m_PtBA(AcGePoint3d(pt1[X],pt2[Y],pt2[Z]));
pEnt->put_m_Text(buffer);

// Post to Database
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable,
AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,AcDb::kForWrite);
pBlockTable->close();

AcDbObjectId retId = AcDbObjectId::kNull;
pBlockTableRecord->appendAcDbEntity(retId, pEnt);
pBlockTableRecord->close();
pEnt->close();


TEST

-Rebuild your project;
-Open AutoCAD and load DBX module first and then load the ARX;
-Fire command MYCUSTENT and create as many entities as you want;
-Test it against GRIP edit, MOVE, ROTATE, SCALE;
-Fire a LINE command and try to get precision points (EndPoint, MidPoint and Center) over your entities;





56 Comments:

  • Hello,thanks a lot for such a good web page about ObjectARX. Very nice tutorials even better than Tutorial of AutoDesk:)))

    I stuck in the first step.I am creating the DBX,ARX modules adding dependencies and compiling. I gives such an error:

    'CustEntityDBXDLL':undeclared identifier
    'InitAdUiDLLL':undeclared identifier

    The problem is at the Macro AC_IMPLEMENT_EXTENSION_MODULE(CustEntityDBXDLL) and the in the CustEntityDBX.cpp.

    Obviously something wrong with the MFC support???

    What do you think the problem is???

    By Anonymous Mazhar Basa, at 5:31 AM  

  • Hey thanks to your finished project!! it helped me solve his problem.


    There is something wrong with the ARXWizard. It has to add "#include "AcExtensionModule.h" at the end of the "Stdafx.h" file of DBX module. You have to add this at the end after creating your DBX module wşth MFC extension.

    Thanks anyways

    By Anonymous Mazhar Basa, at 6:26 AM  

  • Hello Mazhar,

    Yes, exactly that. ARXWizard is missing this include.

    Hope you are doing great and thank you for attending this course.

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 8:08 AM  

  • Ok here is my new question how can I add Arrays of points like those above?

    When I use a single AcDbPoint3d and use Get/Put functions options while adding variables from wizard, there is no problem. But if I use an array of AcDbPoint3d it gives errors.

    So what if we want to use arrays in our custom entity?

    By Anonymous Mazhar Basa, at 11:08 AM  

  • Hi Mazhar,

    You need to declare a member variable as an AcGePoint3dArray.
    It is a dynamic array of AcGePoint3d.

    To save, first save the length of this array using length() method then, traverse the array and save each item as AcGePoint3d.

    To load, first load the saved lenght then create a FOR statement, read each point and add it to the this array. It is important to zero the array's lengh before adding elements through the FOR statement.

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 11:21 AM  

  • I am sorry I meant "dwgIn" and "dwgOut" functions not "get/put" functions.

    By Anonymous Mazhar Basa, at 2:37 AM  

  • Hello Firnds.

    Can somebody help me? I have problem with "add member variable wizard". It returns mi a javascript error in line 472 col 3. I do not now how to fix this. :( I'm using VS 2005 and objectarx 2007.

    By Anonymous Anonymous, at 6:39 AM  

  • Hello,

    Please, try to uninstall the ARX Wizard and then install again. Make sure this will be done with all Visual Studio 2005 instances closed.

    Cheers,
    Fernando.

    By Blogger Fernando Malard, at 9:08 AM  

  • Hi Fernando,
    congratulations for your excellent work!
    After creating your CustEntity, what does it take to be able to change for example the text of an existing object through the properties window or by double clicking it?
    Thank you in advance,
    Panos Mavridis
    Structural Engineer,
    Chalkis, Evia, Greece.

    By Blogger Panos Mavridis, at 6:00 AM  

  • Hello Panos,

    The Properties Palette is implemented through the use of some COM interfaces.

    The base class, AcDbEntity, already implement basic features like Layer, Color, etc.

    Once you implement your own COM interface it will display the properties as you wish.

    Take a look at the Smiley sample and pay attention to the module SmileyDBCom.

    \ObjectARX 2008\samples\entity\Smiley\SmileyDbCom

    Regards.

    By Blogger Fernando Malard, at 9:09 AM  

  • Hello Fernando,
    Thank you for your amazing Tutorials!

    I have some problems?
    How can i make my custom entity repond the fillet and chamfer command of autoCAD?
    Which functions should i implement ?


    Thank you!
    sc from china.

    By Anonymous sc, at 6:53 AM  

  • Hello sc,

    I'm afraid you can't.
    These commands has no special method to be implemented.

    If your entity derive direct from AcDbEntity these commands will not work but if you derive from AcDbCurve is there a change they will work by default.

    The SDK documentation said that you need to override intersectWith() method for the fillet command but this seems to be not what happens in fact.

    Regards,

    By Blogger Fernando Malard, at 8:17 AM  

  • Thank you for your reply!

    i have got my entity derived from AcDbPolyline, it works!!!

    i hope to copy the AcDbPolyline to my Entity PiAcDbPolyline, i use copyFrom to do it.

    but it can't copy the data to my Entity.

    How can i do that?

    sc.

    By Anonymous Anonymous, at 6:48 AM  

  • Hello,

    You can override the method:

    virtual Acad::ErrorStatus
    copyFrom(const AcRxObject* other);

    Inside it, do your stuff and pass the call to your base class.

    Regards,

    By Blogger Fernando Malard, at 10:43 AM  

  • Thanks for writing this very useful tutorial!

    I have some questions regarding this tutorial:

    - Using selection marker is the only way to change sub-item color, linetype and other properties or other way also exists?.
    In current sample, we can't capture text(as supposed to do by using selection markers), may be the reason is work not done in this sample to do this! If we want to do so, what event we have to implement?.

    - I tried to know what the code insdie getOsnapPoints function is doing by moving custom entity around, but could't find its behaviour!
    Check to comment out this also, could't recognize any change in object's behaviour. Please explain it.

    By Blogger Sikander, at 9:54 AM  

  • Sikander,

    The selection marker is necessary to divide your entity graphics allowing you to use different colors, linetypes, layers and more for each part of your drawing. It can be used later through the AutoCAD selection set funtions which will return you the selection marker clicked during the selection procedure.

    The getOsnapPoints() method is used to provide precision points from your entity when the AutoCAD demands. This will occur, for exemple, when the user is creating a LINE and approaches your custom entity asking for an ENDPOINT. AutoCAD will call your getOsnapPoints() method passing in the kOsModeEnd as the current request and you just need to fill the array in with the desired points. AutoCAD will take care, using the current appearture, to find out which EndPoint is closer than the current mouse position. As soon as you move the mouse some other points you have provided may turn on/off.

    Regards.

    By Blogger Fernando Malard, at 8:27 AM  

  • Hi(it's Zix again:)).

    After creating these two projects I rebuilt it and following error occurred: Error 3 error C2990: 'AcArray' : non-class template has already been declared as a class template c:\objectarx 2005\inc\dbplotsetval.h 36 CustEntityDBX

    Any suggestion?

    Thanks

    By Anonymous Anonymous, at 10:57 AM  

  • Hi Zix,

    I suspect the AcArray class may have changed since 2005. Check if you are including the proper file which is "acarray.h".

    Also, check if you have some hard-coded definition for AcArray inside your project and remove it using now the ObjectARX one.

    Regards.

    By Blogger Fernando Malard, at 11:08 AM  

  • This is the line where error points:

    class AcArray;

    By Anonymous Anonymous, at 11:11 AM  

  • So try to remove this (because it is a forward declaration) and use the include:

    #include "acarray.h"

    Should work.

    By Blogger Fernando Malard, at 11:18 AM  

  • I have a Custom Object derived from AcDbPolyline. I want an onwership from my CO to a blockreference.
    pBlkRef->SetOwnerId() works, but on save of the dwg I get this nasty message:
    *Warning* Multiply owned object
    How can I get rid of it ?

    By Anonymous Mark, at 12:16 PM  

  • Hi Mark,

    You can't have multiple owners.
    If you want to add your custom entity to a block you will need to create the block and add your entity.

    Each block is a BlockTableRecord as the ModelSpace is. So the way you build the Block by adding entities is pretty much the same as you did with Model Space.

    The only trick is to create a BlockReference refering to this block into Model Space (this is the block insertion) to allow it to appear inside the current drawing.

    Take a look at AcDbBlockReference class at ObjectARX docs for further information.

    Regards,

    By Blogger Fernando Malard, at 5:07 PM  

  • Fernando,

    my Custom Object is db-resident in the model-space. I now want to "drag" a db-resident blockreference onto my CO and make the CO owner of the BR.
    Do you mean I have to create a Blocktablerecord and append my CO and the BR to it ?

    Thanks

    By Anonymous Mark, at 8:00 AM  

  • Mark,

    The only solution on this case is to make your CO as owner of this BlockReference is by embedding it as a member of your CO class.

    This way, into your worldDraw() you would call its drawing method, dwgIn/dwgOut, transformBy(), etc.

    The problem is that you cannot derive from BlockTableRecord and thus create a new block behavior.

    Regards.

    By Blogger Fernando Malard, at 8:47 AM  

  • Hhmm,

    what do you mean with "embed" ? There is no such thing as pFiler->writeBlockReference.
    The BRs I want to add are very different from each other and I do not want to replicate the standard BR functionality just for establishing a "simple" ownership.

    By Anonymous Mark, at 10:31 AM  

  • Mark,

    Take a look at this example:

    http://arxdummies.blogspot.com/2009/05/au2008-class.html

    I have embedded the AcDbHatch class into my Custom Entity.

    You can do the same with your BlockReferece.

    You don't need to call any special method just forward your calls to the embedded object.

    pBRef->dwgOutFields(pFiler);
    pBRef->worldDraw(mode);
    etc...

    Regards.

    By Blogger Fernando Malard, at 10:46 AM  

  • Hi Fernando,

    I looked at your example, but unfortunately it does not solve my problem.
    You create a hatch and feed it from your AuPolyline data.
    My BRs are totally unrelated to my CO data. So I would have to read in all the Attributes etc. and store it with my CO, so that I can rebuild the BR on dwgIn. That's way too much effort.

    By Anonymous Mark, at 2:01 PM  

  • Mark,

    So, gettting back to the major question: Can you make your CO be the owner of a BlockReference? No.

    So, the only options you have is to add it as an embedded object OR establish a no-owner relatioship with HardPointers.

    So from inside your CO you create a member of type HardPointerId and save it with the BlockReference ObjectId. This way you will have some level of relationship.

    Maybe if you explain better what do you want to do I could suggest other approach.

    Regards.

    By Blogger Fernando Malard, at 2:13 PM  

  • Fernando,

    thank you for your efforts at first.

    At the moment I save the AcDbSoftPointerId of each attached BR with my CO. This takes place in the DBX.
    In my "ARX-program" which is written in VB.NET the following scenario happens:
    1. The users selects an object in ACAD.
    2. I check the type of the object.
    3. If it is a BR I want to know if this BR is attached to any of my COs.
    4. The user can drag away a BR from a CO. In that case the BR shall remain intact, only the ownership to the CO is removed.

    Of course I can walk through all my COs and check whether the BR is pointed to by any of my COs.
    But that looks like bad performance.
    So I thought an easy solution would be to set the Ownerid of the BR to the "owning" CO. This works well, but gives the unacceptable multiply owned message on save of the dwg.

    By Anonymous Mark, at 4:54 AM  

  • Mark,

    In this case, the best option is to handle this behavior through a Reactor.

    An object reactor can be attached to the BR so as soon as it is edited, moved, erased, etc. you can go to your CO and remove the reference.

    I can't see any other easier way to accomplish that...

    Sorry.

    By Blogger Fernando Malard, at 9:33 AM  

  • Yes,

    I experimented with it. At first in my CO I tried
    this->addPersistentReactor(pbr->objectId());
    But this does not work :) You have to use
    pbr->addPersistentReactor(this->objectId());
    Then the CO can receive notifications. This at least gives an indirect object hierarchy.

    Alternatively I tried to keep track of my object hierarchy in my VB.NET application. But storing your own data runs you into another general problem:
    Whenever you hit ^Z ( = undo) ACAD takes care for you to restore the previous state of your dwg-data. Now you have to design an Undo-history for your own data.

    How do you handle this problem ? Is there some general or recommended technique ?

    By Anonymous Mark, at 4:30 PM  

  • One question on Persistant Reactors:

    If I delete my CO do I have to remove all Persistant Reactors for this CO ?
    If yes, what happens if I do not ?

    By Anonymous Mark, at 4:40 PM  

  • Mark,

    No, you did it wrong.
    You need to create another class to be the reactor and attach it to the BlockReference and your CO.

    There is a very good example at the SDK which demonstrate this technique:

    \Samples\Reactors\persreac_dg

    In this example it attaches the reactor to two different lines linking each other.

    I think you can accomplish the same results.
    If one of the objects linked is gone the reactor will fail to access the other object.

    You can always check if an ObjectId is still valid by calling the IsValid() method.

    Hope this help you.

    By Blogger Fernando Malard, at 5:31 PM  

  • Regarding the AcArray error...

    I would avoid including the header. Forward declarations are a better practice when you don't need a comlete type (less dependencies). The only problem in this case is that AcArray is a template with two parameters (not a class). So the forward declaration should look like this:

    template <class, class> class AcArray;

    Hope you find it useful.

    By OpenID 0xc0de, at 11:01 PM  

  • Hello,

    Yes, in fact but there is a trick in regards of which version of this class you are using. It provides two quite different internal templates:

    template <class T> class AcArrayMemCopyReallocator

    template <class T> class AcArrayObjectCopyReallocator

    The default is:

    template <class T, class R = AcArrayMemCopyReallocator<T> > class AcArray

    So I don't know by using your template which version it will use in fact.

    Better to use the include because some day Autodesk may change the templates again and you would run the wrong version with unpredictable results.

    Regards.

    By Blogger Fernando Malard, at 9:14 AM  

  • Hi Fernando.

    Still, the default template argument of a class template (like AcArray) has no influence on a forward declaration. It doesn't really matter for the forward declaration the type by which the template will be instantiated.

    A reason that would cause the code to break is if AcArray changes its interface (for example, taking one more template parameter) in the future. However, if this really happens there are changes that other parts of the code break anyway. Maybe, it would even be better for you to know that AcArray changed. :)

    By the way, I forget to say in the first post. Nice blog!

    By OpenID 0xc0de, at 7:38 PM  

  • Hi,

    I have a custom entity that has to be drawn differently when selected. I have tried implimenting getGripPoints(), but it is const. I also tried AcEdInputContextReactor::endEntsel() to get notified if my entity gets selected, but with no luck. Can anybody help?

    Dawie

    By Anonymous Anonymous, at 5:03 AM  

  • Hello Dawie,

    I can't think an easy way to do that but I would bet there could be some possible solution by using:
    AcEdInputPointFilter::processInputPoint()

    through the parameter: pickedEntities

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 8:17 AM  

  • Hi Fernando,

    I am very interesting about ObjectARX lessons. However, all the links to download the samples are missing, such as this link http://files.ofcdesk.com/ThirdParty/files/ObjectARX/VS2005/CustomEntitySample.zip

    Could you please give me the links to download sample projects to learn. I appreciate for your help.

    Thank you,

    Khoa Ho

    By Blogger Khoa Ho, at 3:14 AM  

  • Khoa Ho,

    Yes, all the download links are broken right now.

    I'm trying to address this and hope to get it working next week.

    Thank you.

    By Blogger Fernando Malard, at 3:52 PM  

  • Hello Fernando,
    Can you please tell me can we prevent (disable) some commands for custom entities, such as Explode. If yes then how?

    You are doing a great work. Heard a lot about you for ObjectARX. Keep it up. And thanks in advance.


    Regards,
    Piyush

    By Blogger piyush, at 7:53 AM  

  • Hello Piyush, thank you for contacting me.

    Basically you have two options:

    1) For those commands bound to specific methods like EXPLODE you just need to implement the method and "do nothing". Once the user fire EXPLODE AutoCAD will call this method and do what you have coded.

    2) For those commands not bound or more complex there isn't much to do except by locking the entities before the user select them. This could be done by using a command React which will track the commands you want to block. So, whenever the user fire those commands you capture the start event, move the entities to a locked layer and when the command is either finished or cancelled you put them back the original layer. Be aware also of GRIP editing commands because they fire different reactors.

    Hope this help you.
    Regards.

    By Blogger Fernando Malard, at 8:01 AM  

  • Hello Fernando,

    I guess that should work.
    Thanks for such a fast reply.

    Regards,
    Piyush.

    By Blogger piyush, at 8:16 AM  

  • Hello Fernando,

    Can you please tell me how to add any entity (circle for example) into a region.
    I tried to get the array of points for circle through EXPLODE api to insert them into region but that's not working.

    Thanks in advance

    Regards,
    Piyush

    By Blogger piyush, at 11:45 AM  

  • Piyush,

    You cannot add an entity into an existing Region but you can create a new region with your entities then merge with another region.

    AcDbRegion class does provide a method for that:

    virtual Acad::ErrorStatus booleanOper(
    AcDb::BoolOperType operation,
    AcDbRegion* otherRegion
    );

    The THIS entity will be the new one with the merge result. Be aware that this operation may fail if the boolean type requested is not possible.

    Hope this help.

    By Blogger Fernando Malard, at 11:56 AM  

  • Hello Fernando,
    I think I did a mistake in explaining to you. I want to explode circle programmatically and then want to get array of points. Here's a sample code that explains what I am trying to do.

    AcDbVoidPtrArray curveSegments;
    Acad::ErrorStatus hr = cir->explode(curveSegments);

    The problem here is that "hr" returns "eNotApplicable" and the AcDbVoidPtrArray is empty. Is there any way to get the array of points of that circle.

    Later I will put the array of points in AcDbRegion but that's later. First I should get the array of points through explode() api or some other mechanism.

    Thanks & Regards,
    Piyush.

    By Blogger piyush, at 12:13 PM  

  • Piyush,

    You cannot explode a Circle because it is a basic entity. This is the reason you are receiving eNotApplicable as a result error.

    What you can do to obtain the points around the circle line is to obtain the parametric points of it. As AcDbCircle derives from AcDbCurve, it is a parametric curve.

    So you have methods that return you a point at a specific parameter. With the other methods that return you the start and the end parameters it is just a meter of divide the parameter size by the number of subdivisions you want to calculate the step. Then create a FOR loop incrementing the parameter by the step you calculated previously thus allowing you to get a point at every parameter increment.

    With that you can get as many points you want.

    Not that this will work for all curves derived from AcDbCurve.

    Hope this work.

    By Blogger Fernando Malard, at 1:11 PM  

  • Fernando,
    Thanks for the idea and info. But can you share a sample code snippet for the same.

    Thanks & Regards,
    Piyush.

    By Blogger piyush, at 5:48 AM  

  • Piyush,

    Sorry but I don't have any sample for that. It should be very straight forward.

    Open the circle for read, get its start and end parameters, calculate the difference. Divide the value by the number of points you want. Create a loop and increment a counter with the step value you calculated before. For each parameter value, get the point with the method getPointAtParam().

    Regards.

    By Blogger Fernando Malard, at 8:56 AM  

  • I created a custom Entity. declare a

    AcArray mType;

    member array.

    When I calling a custom member function. The error occurred on

    mType.at(i); refer to isValid(i) in acarray.h.

    in further tracing, I discovered that the mType.length() is not a constant value.

    What shall I notice to overcome this error? Please help.

    By Blogger Jack, at 4:24 AM  

  • Jack,

    AcArray is a dynamic array so length() method will return you the current length and not the initial length. Further, some methods like at() are available with a CONST so the object returned buy it is CONSTANT. Also the method at() itself is a CONST in this case and it can't be called by a non constant pointer.

    Same behavior for the [] operator. It has a CONST override which will work for constant calls.

    Hope this help you.
    Regards,

    By Blogger Fernando Malard, at 10:04 AM  

  • Fernando,

    I’m currently trying to derive a custom AcDbPolyline object and access it via VB.net (as shown in the SimpleSquare project) using mixed managed code.

    I have everything working fine, but I’m stuck trying to cast the object right before I append it to the database….. In the sample provided they do it
    By passing it through an entityjig – making this legal:

    m_jigSquare = CType(Entity, MgSimpleSquare)

    or
    variable=Ctype(Obj as Expression, Object)

    so here (as part of a class implanting EntityJig, or because MgSimpleSquare is a derivative of Entity,
    the first I think…) Entity is an expression… but I’m not feeding my custom object through a jig, so Entity is a Type in my case!

    I’ve tried throwing it left right and center, but to no avail. I’ve created Entities and Polylines and tried casting my object into them,
    Tried casting it into itself, but at the end of the day, even though the class seems to be working and stepping through, I’m just not returning any classID for my custom class even though it’s properties and such are saving :*(

    Any ideas???


    By Anonymous Anonymous, at 10:50 PM  

  • Hello,

    I think somebody else has experienced the same issues. Take a look at the comments section of this page into my Blog:

    http://arxdummies.blogspot.com.br/2005/04/class-11-custom-objectarx-class.html

    There are some other helpful links mentioned in between the messages.

    Regards,

    By Blogger Fernando Malard, at 5:40 PM  

  • Hello Fernando Malard,

    I'm Kyle

    I created a custom entity in VS2010 - ObjectArx2012, following your instructions.

    But, the functions : subGetGripPoints, subMoveGripPointsAt, subTransformBy weren't called.

    And, the functions: GetGripPoints, MoveGripPointsAt, TransformBy can't use (I get the error: cannot override sealed function).

    I can't understand why...

    Could you help me..., give me further guides... Thanks very much...

    By Blogger Trieu Trung Nghia, at 11:59 AM  

  • Hello Kyle,

    Autodesk renamed essential overridable methods due some .NET technology (entity overrule) they implemented on ObjectARX lately.

    Due that, some methods were renamed by adding "sub" as a prefix.

    The project sample you downloaded was created with an old version of ARXWizard so it does not meet these requirements.

    I would encourage you to create a brand new project with the 2012 ARXWizard and add the methods you want to override from its handy tools.

    For example, worldDraw() is now subWorldDraw(), etc.

    This explains why your methods are not being called.

    Pay attention also to some method signatures changes once they may slightly change and if you override them with a different set of parameters it would be never called as well.

    Good luck.

    By Blogger Fernando Malard, at 12:12 PM  

  • Thank Fernando Malard...

    I did understand.
    -Kyle-

    By Blogger Trieu Trung Nghia, at 3:28 PM  

Post a Comment

<< Home