Jump to content

Scoping out an idea


Recommended Posts

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...

  • Like 1
Link to comment

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.


image.png.2130598541eece30ca7a1c1415e83273.png

Link to comment

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);
	

 

Link to comment

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.

 

image.thumb.png.fe3e7f3b2203f1324bf1b1a8f6b47ad2.png

 

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.
image.thumb.png.294e68d10dc11e1b5f55b73f8b659bc0.png

 

I'm going to try some more debugging on it tomorrow to see what I can do.

 

Thanks for your help!

 

Link to comment

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

Link to comment

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);

 

Link to comment

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.

Link to comment
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.

  • Like 1
Link to comment
  • Vectorworks, Inc Employee

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

Link to comment

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...

  • Like 1
Link to comment

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.

  • Like 4
Link to comment
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.

Link to comment

@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.

Link to comment
Posted (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 by spettitt
Link to comment
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.

Link to comment

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()

 

 

Link to comment

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.

  • Like 1
Link to comment

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.

Link to comment

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...