Is it possible to add a custom entity already resident in the drawing as a node in a AcDbEvalGraph using AcDbEvalExpr directly or do I need to use reference ids instead?
Solved! Go to Solution.
A node class is derived from AcDbEvalExpr and the implementation of its Evaluate method is based on what you are trying to do with the custom entity. So, since it is your class which is acting as a node, I think both the ways are possible, but I havent tried adding the entity directly as a node.
If the custom entity is already database resident, you will need its ObjectId to access and perform the evaluation and storing its ObjectId is the straight-forward approach.
Storing the custom entity pointer in a AcDbEvalExpr is troublesome and in this case you will need to ensure that you can access the custom entity inside the Evaluate method.
If you can provide more details on what kind of evaluation you are trying to perform using the graph and some details about the custom entity, then it might help in providing a more specific answer.
Here is what I am trying to accomplish and the approach that I am currently implementing.
I have created two custom entities that are drawing special graphics in the drawing. They are working OK at the moment.
I have created links between them using AcDbObjectIdArrays because they are interrelated and data on one affect the behavior of the other on the drawing.
I wanted to write an algorithm to search the data and collect for example a group of my custom entities drawn on the drawing according to specified criteria that the user will enter. Like the shortest route problem for example.
I came across Evaluation Graphs in ObjectArx and currently I am investigating how to replace the links that I already store in my custom entities using AcDbObjectIdArrays with a Graph instead.
I believe that will be more efficient. Is that correct?
The approach I am using at the moment is that I created a custom AcDbEvalGraph and stored it in a custom dictionary container as an individual named entry not as extension dictionary. I also create two different types of custom AcDbEvalConnectable nodes, the first one is interrelated to the first custom entity and the other to the other one.
I store on the Node the objectId of the Graphic entity and on the graphic entity the objectId of the node that way when the user erases an entity from the drawing, the graph, I noticed, can be updated whenever the objectId's stored on the nodes become invalid so the graph can remove those nodes.
Now, I came that far. I am having real trouble figuring out how the mechanism of AcDbEvalConnectable works, and more specifically how do you add keys on them. I cannot find any guidance anywhere can you advice?
Thank you very much for your advice,
The concept of graphs is relatively new to me. After further reading I have decided to use AcDbObjectIdGraph instead. Create new nodes corresponding to each custom entity that I have and create the links between the entities within the graph which I will store in the same container as before within a custom AcDbObject so I will have the capability to save and restore with dwg before any custom entities that are contained within are saved or restored.
Now, do I recreate the graph nodes and links (now edges of the graph) within dwgin of my existing custom entities in thus replacing the arrays that I already use to store those links with edges within the graph, Is that correct?
Sorry for the delay in replying to you.
I donot think that the AcDbObjectIdGraph can be persisted while the drawing is saved and so you will need to reconstruct the graph everytime. Using an AcDbEvalGraph should serve your purpose or instead of the graph, you may consider using the persistent reactors.
If entity1 is being associated with entity2, you will first create a custom object that holds the ObjectId of the entity2. The custom object will be stored in the Named Object Dictionary and its ObjectId will be set as the persistent reactor to entity1. This way, an entity may be associated with more than one entity and they get saved along with the drawing.
I have attached a sample project demonstrating this. To try it :
- Appload the arx
- Run the "Test1" command which creates a few circles and lines
- Run the "Test2" command and select the first entity and then the second entity to associate.
- You can repeat "Test2" to associate other entities to the first entity.
- If the color of the first entity is modified, then the persistent reactor will change the color of all the associated entities.
If you have any specific issue with the use of AcDbEvalGraph or with the use of persistent reactors, please do let me know.
You have opened a new door with persistent reactors which I haven't considered before.
The way I build object links at the moment is as follows.
For simplification assume that myLine entity is derived from AcDbLine.
MyLine has a member variable mLinks(AcDbObjectIdArray).
When I create a sequence of MyLine entities I do the following
at the end of the above sequence every one of MyLine's has its mLink variable with one or two objectId's
Now, I updated the above sequence and used ssget "x" to find at every point that the user inputs whether there are any existing MyLine's with startPoint or endPoint equal to the given one. If found I also update the mLinks of every found or newly created entity.
At the end everyone of MyLine entities knows the other MyLine entities that it is linked with, by holding one or more objectIs's within the mLink variable.
Now, you are suggesting to replace the above with persistent reactors.
First question, I will create a new MyLineLinks custom object with mLinks member variable and add it as a persistent reactor to MyLine entity.
Can I store this object within the extension dictionary of MyLine entity?
That way I do not populate ASDK_DICT with MyLineLinks objects of erased entities. Is that correct?
Second question, I found, I think, I haven't fully implemented it yet, a way using AcDbSpatialIndex that I could use, so that when the user starts a grip edit operation on either the startPoint or endPoint of MyLine entity that entity will be able to find other MyLine entities at the end of the grip edit operation and update the mLinks member variables of all involved MyLine entities. Is this OK or there is another better way of doing this. What are AcEdInputContextReactor AcEdSSGetFilter classes used for? How can I initiate these reactors?
Third question, will a persisted reactor's modified function be called whenever I open MyLine, update one of its member variable's and close it? or does it need user intervention, or I simply call the modified function? can that be propagated to every linked object by updating some member variable on each visited one?
Thanks again, I hope the above is clearly presented.
I hope this answers your queries :
Q) Can I store this object within the extension dictionary of MyLine entity? That way I do not populate ASDK_DICT with MyLineLinks objects of erased entities. Is that correct?
Yes, The “addPersistentReactor” method only requires an ObjectId and it does not matter the custom object is stored in NOD or the entity extension dictionary.
Q) Second question, I found, I think, I haven't fully implemented it yet, a way using AcDbSpatialIndex that I could use, so that when the user starts a grip edit operation on either the startPoint or endPoint of MyLine entity that entity will be able to find other MyLine entities at the end of the grip edit operation and update the mLinks member variables of all involved MyLine entities. Is this OK or there is another better way of doing this. What are AcEdInputContextReactor AcEdSSGetFilter classes used for? How can I initiate these reactors?
If entity-1 has multiple persistent reactors set, simply changing the property (say its color) of entity-1 will intitiate the reactors.
Q)Third question, will a persisted reactor's modified function be called whenever I open MyLine, update one of its member variable's and close it? or does it need user intervention, or I simply call the modified function? can that be propagated to every linked object by updating some member variable on each visited one?
It does not need an user intervention. For example, if entity-1 has a persistent reactor that modifies entity-2 and Entity-2 has a persistent reactor that modifies entity-3 :
A property change in entity-1 will initiate the whole chain of persistent reactors and all the three entities will get modified.
Great support, you have clarified all my queries and now I have a better understanding of how this mechanism works.
This has saved me a lot of trial and error.
I will go ahead and implement it now.
I have on more question.
Is it necessary to update a spatial index everytime, prior to spatial intex iteration or this is done automatically by AutoCAD at the regen level and everytime entities are added to the drawing.
Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register