NytSkab Posted November 6, 2021 Share Posted November 6, 2021 I am trying to draw rectangle around bounding box of selected objects. See script below: PROCEDURE GroupBB; VAR X1,Y1,X2,Y2:Real; H1:HANDLE; BEGIN H1:=FSActLayer; WHILE (H1 <> NIL) DO BEGIN GetBBox(H1,X1,Y1,X2,Y2); AlrtDialog(Concat(GetTypeN(H1),' - ',X1,' - ',Y1,' - ',X2,' - ',Y2)); Rect(X1,Y1,X2,Y2); H1:=NextSObj(H1); END; END; Run(GroupBB); However, the script starts an infinite loop. What is wrong? Quote Link to comment
Peter Vandewalle Posted November 6, 2021 Share Posted November 6, 2021 I would use a ForEachObject with criteria selected is true. Quote Link to comment
Jesse Cogswell Posted November 6, 2021 Share Posted November 6, 2021 The reason you are getting an infinite loop is that you are creating a rectangle, which would be selected after creation, with every iteration of your loop. So there is always a selected object to use NextSObj on. Are you looking to create one rectangle around all selected objects or a rectangle around each single selected object? Right now, your script will do the latter. Depending on what your aim is here, there are different solutions. Draw one rectangle around all selected objects: This is actually very simple (with some caveats). Since the objects are all selected, you can use the Group procedure to group them all together Then do H1:=LActLayer; to get the handle to the group Use the GetBBox procedure to pull the points of the bounding box Create your rectangle Use HUngroup to ungroup your selection The major caveat is that, if objects are spread across different layers, the group command will force them all onto one layer together. If this is the case, I would use ForEachObject or something similar to the code you have to go through the selection and build DYNARRAYs of HANDLEs to both the objects themselves and their parents (in this case, the layer they live on) using GetParent. Then you can use a FOR loop to go through the array and reassign the objects to their layers using SetParent. A code sample to do this, including resetting things on multiple layers, is included below. PROCEDURE BoxAllTheThings; VAR objCount:INTEGER; objArr,parentArr:DYNARRAY OF HANDLE; PROCEDURE BuildArrays(h:HANDLE); BEGIN objCount:=objCount+1; ALLOCATE objArr[1..objCount]; ALLOCATE parentArr[1..objCount]; objArr[objCount]:=h; parentArr[objCount]:=GetParent(h); END; PROCEDURE CreateBox; VAR h:HANDLE; A,B:POINT; BEGIN Group; h:=LActLayer; GetBBox(h,A.x,A.y,B.x,B.y); HUngroup(h); Rect(A.x,A.y,B.x,B.y); END; PROCEDURE RestoreParents(objects,parents:DYNARRAY OF HANDLE; iCount:INTEGER); VAR i:INTEGER; BSB:BOOLEAN; BEGIN FOR i:=1 TO iCount DO BSB:=SetParent(objects[i],parents[i]); END; BEGIN objCount:=0; ForEachObject(BuildArrays,(SEL=TRUE)); IF(objCount>0) THEN BEGIN CreateBox; RestoreParents(objArr,parentArr,objCount); END; END; Run(BoxAllTheThings); Draw rectangles around each selected object: This one is a bit more complicated. Use either your existing WHILE loop code or ForEachObject to generate a DYNARRAY of HANDLE of all selected objects. Use a FOR loop to go through the array. For each handle, use GetBBox to poll the coordinates Create a rectangle using the coordinates Below is a code sample of how I would approach it. I prefer to use ForEachObject when doing stuff like this, it gives you a lot more control of which objects are affected (targeting selected objects only on the active layer for example). PROCEDURE BoxTheThings; VAR objCount:INTEGER; objArr:DYNARRAY OF HANDLE; PROCEDURE BuildArray(h:HANDLE); BEGIN objCount:=objCount+1; ALLOCATE objArr[1..objCount]; objArr[objCount]:=h; END; PROCEDURE CreateBoxes(objects:DYNARRAY OF HANDLE; iCount:INTEGER); VAR A,B:POINT; i:INTEGER; BEGIN FOR i:=1 TO iCount DO BEGIN GetBBox(objects[i],A.x,A.y,B.x,B.y); Rect(A.x,A.y,B.x,B.y); END; END; BEGIN objCount:=0; ForEachObject(BuildArray,(SEL=TRUE)); IF(objCount>0) THEN CreateBoxes(objArr,objCount); END; Run(BoxTheThings); 1 Quote Link to comment
NytSkab Posted November 6, 2021 Author Share Posted November 6, 2021 Thank you. I also have a selection consisting of groups of objects. I would like to create rectangles around the individual groups of objects (not every single object). How would I do that? Quote Link to comment
Jesse Cogswell Posted November 6, 2021 Share Posted November 6, 2021 That would be simple. Using my second example, change the ForEachObject criteria so that the line reads as ForEachObject(BuildArray,((SEL=TRUE) & (T=GROUP))); That's one of the reasons I prefer to use ForEachObject, it really gives you a lot of control in terms of which objects to run procedures on. Writing out the criteria sections can sometimes get tricky, and there used to be a nasty bug where if you were missing a parenthesis, compiling would cause a memory leak and crash Vectorworks (thereby throwing away all of your hard work), so if I need a complicated selection I will use the button in the upper left of the Script Editor window and select Criteria to have Vectorworks build the correct criteria string. 1 Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.