spettitt Posted April 17 Share Posted April 17 I'm just scoping out an idea to see if I want to throw some proper hours at it or not. We use data tags to tag all of our trusses with their Position name, trim height and a colour. The colour is currently done by data vis, but as mentioned in other threads, I need to communicate the colour externally via script and data vis is behind a wall, so data vis needs to be replaced by class colours. Vectorworks lacks the AutoCAD functionality of 'ByLayer', whereby the contents of a symbol (or data tag) can inherit attributes from whatever class(layer) their container instance is placed on. This means I need a DT style for every Position name, with the contents on different classes. People could name their trusses anything, so I then need a one-shot cleanup script that gets unique position names, makes classes for any that don't exist, then duplicates DT styles for each one and reclasses the contents, then goes through any DTs placed on the drawing and re-assigns them to the right DT style. I think it would work, but it's not particularly slick. So, I wondered about making a parametric object whereby it looks and functions like the data tag - having an association to a truss object, but being able to reclass it's filled polyline geometry to whatever class name matches the Position value. It wouldn't really even need any OIP controls, just the easiest way to create an association to a picked truss. Just wondered if anyone thought this sounded possible or a terrible idea... 1 Quote Link to comment
JBenghiat Posted April 18 Share Posted April 18 @spettitt are you just looking for the label to adopt the class of the rigging object it’s attached to? If so, I think this would be a fairly straightforward feature to add to Savvy Position Labels. 1 Quote Link to comment
spettitt Posted April 19 Author Share Posted April 19 It's this cell on the bottom of our truss tags, which need to re-colour based on the Position field of a truss object (we don't use hanging positions). The object would need to move the class of this cell to the named class matching the Position value of the tagged truss. Quote Link to comment
Pat Stanford Posted April 21 Share Posted April 21 I think you might be able to create a PIO that could be placed inside a Data Tag that could do this. The PIO would need to: Draw the polyline to be colored. Get its parent (the Data Tag) Get the Associated Object (the Truss) Read the Truss Record.Field Change the class of the poly line to the field value. The attached code sets the class of the PIO to that of the DT associated object. You should be able to do the modifications to read the value from the Record.Field. The tricky part is that the objects in the DataTag are enclosed inside a group, kind of like the Viewport Crop and Viewport Annotation Groups, so you have to use the extra GetParent to get the handle to the Data Tag to be able to get the association. Create a Point Type PIO and paste the following code into the Script. Add the PIO to your workspace. Insert the PIO into a Data Tag. Associate the Data Tag with an Object. The PIO will take on the class of the Associated Object and use the Fill Color of that class. HTH Procedure PIOClassFromDTAssocObj; {©2024 Pat Stanford - pat@coviana.com} {licensed under the Boost Software License 1.0} {https://github.com/boostorg/boost/blob/master/LICENSE_1_0.txt} {TL/DR Use as you want, attribution for source, No warranty} VAR objHand,H2,H3,H4, recHand, wallHand: HANDLE; Rec,Fld, Obj: String; B1: Boolean; N1,N2,N3: Integer; BEGIN B1:=GetCustomObjectInfo(obj, objHand, recHand, wallHand); {Info on running PIO} H2:=GetParent(objHand); {Get Handle to object Group inside Data Tag} H2:=GetParent(H2); {Get Handle to Data Tag} H4:=GetAssociation(H2, 0, N1, N2); {Get Object Associated to Data Tag} Rect(0,0,-5',-5'); {Draw Rectangle} H3:=LNewObj; SetFillColorByClass(H3); {Set Rectangle Fill Color to ByClass} SetClass(H3,GetClass(H4)); {Set the Class of the Rectangle to the Class of the Associated Object} { Message(Obj,' : ', objHand,N3,' : ',H2, ' : ',GetTypeN(H2),' : ',H4, ' : ', GetClass(H4));} End; Run(PIOClassFromDTAssocObj); Quote Link to comment
spettitt Posted April 21 Author Share Posted April 21 Thanks so much for this Pat - this looks perfect for what I need. So far it reliably draws the rectangle but doesn't colour it. I uncommented your debugging message and get this. The second segment (the long integer) changes every time the object moves. However, if I open Plug-In Manager and edit the point PIO script, even if I make no changes, when I return to the drawing I do see the full lookup taking place. The rectangle remains unfilled though, and the '...PR60' class has a solid pink fill. Moving either the truss or the tag returns it to the state above. I'm going to try some more debugging on it tomorrow to see what I can do. Thanks for your help! Quote Link to comment
Pat Stanford Posted April 21 Share Posted April 21 Here is my full test file you so you can see what I did. With the three objects in classes, the DT color swatch changes based on the object. Yeah, I did not do enough testing. There is definitely a rest problem of some sort. When I edit the script then all the tags color properly. If I move either the tag or the associated object or if I Reset All Plug-ins then the rectangle switches to white. 😞 My guess is the Data Tags are closer to Symbols with Linked Text To Record than I thought. It looks like the rest of the Data Tag is making it redraw the cache of the color swatch and not actually running the PIO. The class of the rect is being switched back to None so you are getting the fill color from None. None of the easy tricks work. Maybe attach a record to the rect and store the class name there and then assigned the class from that? Sorry, out of ideas and time for the afternoon. Color from Associated Object.vwx Quote Link to comment
spettitt Posted April 22 Author Share Posted April 22 Thanks. Trying it some more today, the first issue appears to be that every time the DT moves/resets, the objHand is refreshing but H2 remains 0. I can only get NAssoc to print '1' when editing the script, afterwards, it only ever prints 0. By hard-coding a class name, the object does reliably colour, but it seems like it's the GetParent process that gets nulled for cached data on a reset. @Nikolay Zhelyazkov just wondered if you had any insight in to how this might work best in a data tag please? Procedure PIOClassFromDTAssocObj; // Original: {©2024 Pat Stanford - pat@coviana.com} {licensed under the Boost Software License 1.0} {https://github.com/boostorg/boost/blob/master/LICENSE_1_0.txt} {TL/DR Use as you want, attribution for source, No warranty} Edits by SMP 22-04-24 // VAR objHand,H2,H3,H4,H5, recHand, wallHand: HANDLE; Rec,Fld, Obj: String; B1: Boolean; N1,N2,NAssoc: Integer; BEGIN B1:=GetCustomObjectInfo(obj, objHand, recHand, wallHand); {Info on running PIO} H2:=GetParent(objHand); {Get Handle to object Group inside Data Tag} H3:=GetParent(H2); {Get Handle to Data Tag} NAssoc:=GetNumAssociations(H3); {H5:=GetAssociation(H3, 0, N1, N2); } {Get Object Associated to Data Tag} Rect(0,0,500,500); {Draw Rectangle} H5:=LNewObj; SetFillColorByClass(H5); {Set Rectangle Fill Color to ByClass} SetClass(H5,'LX1'); {Set the Class of the Rectangle to the Class of the Associated Object} UpdatePIOFromStyle(H3); Message(Obj,' : ObjHand: ', objHand, ' : H2: ', H2, ' : NAssoc: ', NAssoc,' Type: ',GetTypeN(H2),' : H3: ',H3, ' : ', GetClass(H3)); End; Run(PIOClassFromDTAssocObj); Quote Link to comment
JBenghiat Posted April 22 Share Posted April 22 It's been a couple years since I experimented, but when I last checked, they way Data Tags copy objects from their profile group (where layout objects are stored) to the object didn't work with PIO's. If I remember correctly, it basically gets converted to group before it gets copied. Quote Link to comment
Pat Stanford Posted April 22 Share Posted April 22 In the Debug List View Explorer, it shows that the PIO is included in Data Tag. But that may just be in the file and not how it is drawn. 😞 Quote Link to comment
spettitt Posted April 22 Author Share Posted April 22 2 minutes ago, Pat Stanford said: In the Debug List View Explorer, it shows that the PIO is included in Data Tag. But that may just be in the file and not how it is drawn. 😞 I had a look at that as well. I think my next attempt tomorrow will be a standalone Point PIO that replicates a data tag, rather than within a data tag. I just need to have a go with making an association to another object. Hopefully it doesn't need to be event enabled as I haven't reached that yet. It only needs three named bits of data from the associated truss parameters, two bits to display values of and one to set the class. 1 Quote Link to comment
Pat Stanford Posted April 22 Share Posted April 22 I don't think associations require Event Enabled. Unless you want something like delete tag on delete object. Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted April 23 Vectorworks, Inc Employee Share Posted April 23 Hello @spettitt, @Pat Stanford, The reason why this is not working is that it is being executed when the PIO gets copied from the profile group of the data tag to the drawing. But at this step the PIO is just copied and it is not in the drawing. It gets added at a later step and that is why at this time it does not have a parent. I do not think that there is any way to get this done with such a PIO as it will not get notified when it gets inserted in the drawing -> you cannot really get its parent. So yes, maybe the way to go is with a tag like object and associations. Best Regards, Nikolay Zhelyazkov Quote Link to comment
spettitt Posted April 23 Author Share Posted April 23 Thanks for clarifying @Nikolay Zhelyazkov. I need to put some time in to figuring out the best way to make the association. I guess it needs a 'Pick Truss' button in the OIP, as it wouldn't know which Truss object to associate to otherwise. Or maybe the PIO should figure out the nearest Truss object and use that. An evening project I think... 1 Quote Link to comment
Jesse Cogswell Posted April 23 Share Posted April 23 This post from 2023 might help you get started on a basic way of pulling your truss info using PickObject. The code is in Vectorscript but it is very basic and should be easily translated to Python: In terms of building associations like what you're looking for, the AddAssociation functions don't quite work the way you might want them to. At the moment, the only options you have is to delete or reset your object if the associated object is deleted. There's not currently a way to have a an associated PIO update itself if the associated object has been changed (such as trim height in your case), so I always add a "Refresh Object" button to the OIP or write a menu command to refresh all of the desired PIOs in the drawing. The good news is that AddAssociation does not require the PIO to be event enabled. The bad news is that if you want to add buttons to the OIP, the PIO must be event enabled. I wrote up something of a "basic" event enabled plug-in with everything commented in case you would like to learn event handling. @FranAJA even adapted some of the code into Python, so you might find it useful: If you wanted to keep your PIO simple, what you might consider doing is using PickObject similar to my example above to pull the UUID of the truss object, then having a boolean parameter called "Lock" that would disable the PickObject code and keep the PIO associated with whatever object it last picked up with PickObject. OR you could get fancy by using a Control Point parameter and have the PickObject use the Control Point to pull the handle, so that the label can be wherever and the invisible control point just needs to be in contact with the truss. 4 Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 14 hours ago, Jesse Cogswell said: This post from 2023 might help you get started on a basic way of pulling your truss info using PickObject. The code is in Vectorscript but it is very basic and should be easily translated to Python: In terms of building associations like what you're looking for, the AddAssociation functions don't quite work the way you might want them to. At the moment, the only options you have is to delete or reset your object if the associated object is deleted. There's not currently a way to have a an associated PIO update itself if the associated object has been changed (such as trim height in your case), so I always add a "Refresh Object" button to the OIP or write a menu command to refresh all of the desired PIOs in the drawing. The good news is that AddAssociation does not require the PIO to be event enabled. The bad news is that if you want to add buttons to the OIP, the PIO must be event enabled. I wrote up something of a "basic" event enabled plug-in with everything commented in case you would like to learn event handling. @FranAJA even adapted some of the code into Python, so you might find it useful: If you wanted to keep your PIO simple, what you might consider doing is using PickObject similar to my example above to pull the UUID of the truss object, then having a boolean parameter called "Lock" that would disable the PickObject code and keep the PIO associated with whatever object it last picked up with PickObject. OR you could get fancy by using a Control Point parameter and have the PickObject use the Control Point to pull the handle, so that the label can be wherever and the invisible control point just needs to be in contact with the truss. @Jesse Cogswell - thanks so much for this! I hope over time I can give back to this forum in the way it's given to me. I've got your first example running nicely with Vectorscript, and my next task will be to rewrite in Python so I can see how such a PIO might handle the same task. From there, I don't think it'll be too hard to pull the truss data and class the PIO geometry. I have two other big Python projects on outside of Vectorworks (though using Vectorworks data), and I don't think my little mind can handle looking at events right now. If I can get the simple version working, potentially with the 'Lock' parameter, that would be great for the moment and I'll come back to the events thread above when the time is right. Quote Link to comment
Jesse Cogswell Posted April 24 Share Posted April 24 @spettitt You should be able to do the control point solution without needing events, and it might be cleaner from a usability standpoint. You would just need to specify a control point parameter and then pull it using the standard PControlPoint01X and PControlPoint01Y like you would any other parameter value. If I can wrap up my immediate tasks this morning, I can fab up a Vectorscript example for you. Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 (edited) I've gotten to this point. If I uncomment point = vs.GetSymLoc(objHd) and comment out point = (vs.PControlPoint01X, vs.PControlPoint01Y) then placing the PIO directly on the truss works fine and the text reclasses it self suitably. But as-is, it reports a valid set of coords but reports no handle. I don't know if it's something to do with the way I'm packing the tuple, but I usually have good results packing and unpacking tuples for x/y points. def PickTest(): #linkedPos = PlinkedPos linkedPos = 'Unlinked' bool, objName, objHd, recHd, wallHd = vs.GetCustomObjectInfo() if objName: #point = vs.GetSymLoc(objHd) point = (vs.PControlPoint01X, vs.PControlPoint01Y) vs.AlrtDialog(f'You picked point x-{vs.PControlPoint01X} y-{vs.PControlPoint01Y}') pickHd= vs.PickObject(point) vs.AlrtDialog(f'Handle is {pickHd}') if pickHd and vs.GetObjectVariableInt(pickHd, 1165) == 641: if(vs.GetRField(pickHd,'TrussItem','PositionName') != linkedPos): linkedPos=vs.GetRField(pickHd,'TrussItem','PositionName') vs.SetRField(objHd,vs.GetName(recHd),'linkedPos',linkedPos) vs.ResetObject(objHd) vs.Locus(0,0) vs.CreateText(linkedPos) text=vs.LNewObj() vs.SetClassN(text, linkedPos,False) vs.SetPenColorByClass(text) PickTest() Edited April 24 by spettitt Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 I think part of the problem is that the control point coords are relative to the insertion point of the PIO, whereas I need to give vs.PickObject absolute coordinates. Will continue on this more tonight. Quote Link to comment
Pat Stanford Posted April 24 Share Posted April 24 Maybe also look at ForEachObjectAtPoint which allows you to specify a radius rather than needing an absolute point. But I think you are correct about having to pass world coordinates not PIO coordinates. 1 Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 13 minutes ago, Pat Stanford said: Maybe also look at ForEachObjectAtPoint which allows you to specify a radius rather than needing an absolute point. But I think you are correct about having to pass world coordinates not PIO coordinates. That did look promising, but looking at the function reference, there is a note of: Quote (_c_, 2011 Oct. 06): This function only finds objects within the same parent, so it won't work from inside PIOs for finding something which is on drawing, nor does it work for finding objects on other layers, unregarded their visibility options. Looks like VS:FindObjAtPt_Create, VS:FindObjAtPt_GetObj might be an option that supports a radius, which I will try, although the function doesn't seem to trigger intellisense which doesn't seem a good sign. Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 Working: def PickTest(): linkedPos = 'Unlinked' bool, objName, objHd, recHd, wallHd = vs.GetCustomObjectInfo() if objName: x, y = vs.GetSymLoc(objHd) pointx = vs.PControlPoint01X + x pointy = vs.PControlPoint01Y + y point = (pointx, pointy) pickHd= '' #FindObjAtPt Process container = vs.Handle() list = vs.FindObjAtPt_Create(container, 1, 0, pointx, pointy, 100) count = vs.FindObjAtPt_GetCount(list) for i in range(count): pickHd = vs.FindObjAtPt_GetObj(list, i) vs.FindObjAtPt_Delete(list) #If a handle was found and if it's Truss if pickHd and vs.GetObjectVariableInt(pickHd, 1165) == 641: if(vs.GetRField(pickHd,'TrussItem','PositionName') != linkedPos): linkedPos=vs.GetRField(pickHd,'TrussItem','PositionName') vs.SetRField(objHd,vs.GetName(recHd),'linkedPos',linkedPos) vs.ResetObject(objHd) vs.Locus(0,0) vs.CreateText(linkedPos) text=vs.LNewObj() vs.SetClassN(text, 'Lighting-Position-'+ str(linkedPos),False) vs.SetPenColorByClass(text) PickTest() Quote Link to comment
Jesse Cogswell Posted April 24 Share Posted April 24 Quite right that the Control Point is going to be based off of the PIO insertion point, and you did exactly the right thing to compensate for that. As a gentle warning, also make sure that your plug-in still works if the user origin doesn't match the internal origin. Nearly every VS function references the internal origin, so things can get screwy especially if you're using a plug-in that's saving coordinates into a text field. In those cases, you will need to use GetOriginInDocUnits to pull the user origin to compensate. 1 Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 Thanks, duly noted. This is generally working pretty well. I've added a popup parameter to choose the number of colours required from one to three, which creates the same number of named classes to assign colours to, and the same number of colour cells in the tag. Only downside over a data tag is that a new position value in the truss won't trigger an update of the tag. I guess that is where things move in to event enabled, so I'll come back to that. Also, is there a way to force single-click insertion rather than click position > set rotation please? No big deal if not. 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.