Sparx Systems Forum
Enterprise Architect => Automation Interface, Add-Ins and Tools => Topic started by: Rik van der Schalie on July 30, 2020, 05:15:00 pm
-
Enterprise Architect seemingly knows which elements are contained within a boundary in a diagram; when the boundary is dragged, all elements within are dragged along.
However, when programming against EA, I do not seem to be able to find the Elements contained within a Boundary; the Boundary can be found as a DiagramObject, but the Elements and Connectors collections of the Boundary are both empty, and I cannot glance from the documentation how to find the Elements.
I'd appreciate any hints on how to proceed. T.I.A.
-
Doing it programmatically you have to do geometry (compare coordinates). The UI of EA does that internally.
q.
-
Which, of course, is a nightmare for custom boundaries. But thanks for the answer.
Are there any code examples for this?
-
Well, no. Horizontal coordinates go from 0 upwards. Vertical from 0 towards negative. Not difficult, just cumbersome.
q.
-
My point is that with a user-defined boundary the shape is not a simple rectangle, so the different edges of the diagram can have different Top, Bottom, Left and Right values. The small Element is not contained within the Boundary, yet according to the simple Top, Bottom, Left and Right values it would appear to be.
_______________
| |
| | ______
| | | |
| | --------
| -----------
| |
-------------------------------
-
Well, remember your school geometry. EA's boundaries are always square (even the oval ones).
q.
-
That's more than 40 years ago ::)
I do know that the StyleEx attribute contains the Path, consisting of a list of x-y coordinates of the corner points. The trick is of course to separate the complex shape into a set of simple rectangles.
-
Hi rchalie,
Yes, this is a real pain in the butt when working programmatically with diagram objects inside boundaries. Sparx EA ABSOLUTELY can make this easier by utilising the "Parent_ID" (or even introduce a new "Boundary_ID") column in the t_object table. Alas, good user experience is hard to find in the product because it seems "...why click once when a user can click FIVE times to achieve the same outcome? Come on! If it ain't broke (like unsorted lists all over the place)... we ain't gonna fixxy wixxy".
Nevertheless, here's a script I've used to resolve a similar problem. It's based on the same logic I believe the product uses internally to calculate whether or not an element is WITHIN a boundary:
var diagram as EA.Diagram;
diagram = Repository.GetDiagramByID(diagramID);
var diagramObjects as EA.Collection;
diagramObjects = diagram.DiagramObjects;
var loadedElms = []; // elements contained within a boundary
var unprocessed = [];
var boundaries = [];
// iterate all elements on the diagram and find boundaries and non-boundaries
for(var i = 0; i < diagramObjects.Count; i++) {
var dob as EA.DiagramObject;
dob = diagramObjects.GetAt(i);
var currentElement as EA.Element;
currentElement = Repository.GetElementByID(dob.ElementID);
if (currentElement.Type !== "Boundary"){
loadedElms.push({ name: currentElement.Name, notes: currentElement.Notes, dob: dob });
continue;
}
boundaries.push(dob);
}
// we want to sort the elements alphabetically
loadedElms.sort(sortArray);
// mark all elements as NOT contained in a boundary so later processing will remove them;
// whatever's left are elements NOT contained by a boundary
for(var i=0;i<loadedElms.length;i++)
unprocessed.push(loadedElms[i].dob.ElementID);
for(var i=0;i<boundaries.length;i++){
var dob = boundaries[i];
var left = dob.left;
var top = dob.top;
var right = dob.right;
var bottom = dob.bottom;
var count = 0;
var sortedElms = [];
for (var j = 0; j < loadedElms.length; j++) {
var elm = loadedElms[j];
if (!elm)
continue;
var diagramObject2 = elm.dob;
if (diagramObject2.left>= left &
diagramObject2.top <= top &
diagramObject2.right<=right &
diagramObject2.bottom >= bottom){
sortedElms.push({ name: elm.name, notes: elm.notes });
count += 1;
// this element is part of this boundary, so ... you know... let's remove it
unprocessed[j] = -1;
}
}
if (count){
// use srotedElms to iterate the elements for THIS boundary // For exaMple, you could populate a template or do some other processing with the elements inside the boundary
}
sortedElms= [];
count = 0;
}
-
Hi Michael,
Thanks! I'm going to look into this, but my issue is that you work here on the assumption that the boundary is a simple rectangle. My boundary is a user-define boundary, so an irregular shape (with only orthogonal angles). I need a way to separate my irregular boundary in a set of rectangular boundaries, based only on a list of corner points. I cannot make an assumption on where on my user-defined boundary that list starts. I think I cannot even make an assumption on whether the list of corner points is in the clockwise or anti-clockwise direction along the boundary border.
-
...you work here on the assumption that the boundary is a simple rectangle. My boundary is a user-define boundary, so an irregular shape...
Every shape can be broken down into a series of smaller rectangles. If you want to determine whether an element is part of an irregular shape, you'd need to check if an element's "bounding box" is contained fully or partially by one or more of rectangles that make up the irregular shape.
Referring to your earlier post...
...The small Element is not contained within the Boundary, yet according to the simple Top, Bottom, Left and Right values it would appear to be....
_______________
| |
| | ______
| | | |
| | --------
| -----------
| |
-------------------------------
Could you please validate inside the t_diagramobjects table that this is indeed the case? Each element on a diagram canvas has the required bounding box dimensions, so if, according to the post above, the small element is *outside* the irregular shape, then the bounding boxes for the irregular shape and the small element contained in t_diagramobjects table will indeed reflect that.
Now, how to go about to determine if the small element is inside an irregular shape with straigh edges?
I see a two-step approach could be helpful:
Step one: break into smaller rectangles
_______________
| |
| | ______
| #1 | | |
| | --------
_______________
|------------------------------
| #2 |
-------------------------------
Step two: use the script code provided to test if the small element is contained within [#1] or [#2].
-
The only graphical information I can find about the irregular Boundary is, in the StyleEx atttribute, a Path, consisting of an ordered set of corners of the type "X1:Y1@X2:Y2@X3:Y3@X4:Y4@X5:Y5@X6:Y6" for a boundary with six corners (which could be split up in two rectangles X1:Y1@X2:Y2@X2:Y6@X6:Y6 and X2:Y4@X4:Y4@X5:Y5@Xx:Y5). The issue is of course that an irregular boundary would have to be split up in (N-4)/2 rectangles for N corners, so 6 corners will give two rectangles, 10 corners will give 4 rectangles. The thing is, there are multiple ways of splitting any irregular boundary into rectangles.
-
I'm not sure what you think you see there. EA diagram objects are either rectangles or drawn via shape script. From where do you take this path information?
q.
-
...EA diagram objects are either rectangles or drawn via shape script. From where do you take this path information?
StyleEx is located in the t_object table; ObjectStyle column in the t_diagramobjects table.
-
Interesting. How do you define a boundary with, say, L-shape? Is that new with V15?
I skimmed these columns and none has anything like the above path. At least that path must be preprended with some "key=". Which would that be? Path? And how does it interact with shape scripts???
q.
-
...How do you define a boundary with, say, L-shape? Is that new with V15?...
- Drag a boundary object onto a diagram canvas
- Double-click to bring up the properties dialog
- Select "User Defined - Orthogonal"
- Randomly click around the border using shift key to create "bends" (I say randomly, because it's tremendously pixel-perfect accuracy that's required)
- When new "section" has been born, drag it around to create a necessary "L-Shape"
The data is stored in t_object in the StyleEx column. For example, I did an L-Shape and got this data "BT=81;Path=124:-493@505:-493@505:-599@306:-599@306:-747@124:-747;". Then in t_diagramobjects, the ObjectStyle column records this data "DUID=1D9BC707;shape=freestyle;"
...Is that new with V15?...
Yes.
...And how does it interact with shape scripts???...
I'm not sure; I have only worked with rectangular boundaries in scripts. However, rchalie wants to work with L-Shaped boundaries and then calculate while diagram objects are "contained" within it.
-
Interesting. How do you define a boundary with, say, L-shape? Is that new with V15?
Introduced in EA14
-
Enterprise Architect seemingly knows which elements are contained within a boundary in a diagram; when the boundary is dragged, all elements within are dragged along.
However, when programming against EA, I do not seem to be able to find the Elements contained within a Boundary; the Boundary can be found as a DiagramObject, but the Elements and Connectors collections of the Boundary are both empty, and I cannot glance from the documentation how to find the Elements.
I'd appreciate any hints on how to proceed. T.I.A.
AFAIK, there is NO actual API to return this information. We did a lot of work in detecting visual embedding for model analysis purposes and we had to write a sophisticated script to do the work.
Paolo
-
Ok, thanks. Looks like I have to make an update to my Inside book.
q.
P.S. A shape script overrides any custom shape. The bends are still selectable (which gives the right Sparx-feeling). And the outmost dimension define the 100x100 area for the shape script.
-
I now have a working solution. By the way, for simple rectangles the StyleEx attribute is empty. You will need to get the dimensions of the boundary from the DiagramObject itself.