Jump to content


  • Posts

  • Joined

  • Last visited

Posts posted by DomC

  1. Hi @fernicus01

    Seems like holding the ctrl key blocks keyboard-input from other keys like tab or enter.
    So in Fact on windows the workflow on my computer is:

    1. drag object in desired direction
    2. pressing and releasing tab (both Hands free now)
    3. Enter the value
    4. Pressing Enter once
    5. Holding Ctrl. Key
    6. clicking with mouse button

    On Mac

    1. drag object in desired direction
    2. pressing and releasing tab (both Hands free now)
    3. Enter the value
    4. holding alt-key
    5. pressing enter twice

    So windows is one step more and my vegetative brain can't handle that in a smooth way anymore like on my mac.
    (Too many steps and between the action using mouse button again is very un-elegant)

    I would sware, this once also was working similar on Windows. But it seems also be OS-related because also my
    VW 2016 (Oldest Version i can find on my Windows Computer) works this way.

    I will do a report. I hope, that engineers can adjust the bahaviour.

  2. Haha - I think the highest level somebody reach if he can trigger others to do the work ūüôā

    OK, I did it with the crowbar. The script now works so:
    1. Always move the points virtually on center before calculations
    2. getting zangle from p1-p2 > Easy Peasy
    3. for vertical segments taking p1-p3
    3. I take the 3 points and turn them mathematically aligned with first segment on x-axis of the standard-coord-system.
    4. then i look from coord center (from left) and geht the rotation angle by using z-difference as y coord to get xangle
    5. y angle is build from turned p1-2 segment and the xdiff of that segment and the height of that segment.

    Try to provide a node create EM form 3d points node anytime. I imagine we can create wonderful stuff with that. placing object on faces of objects! 
    For the moment my own need is nursed to hav a corner vertex matrix plane for the pipe-project.


    #just crude test-coding
    import math 
    sqr2 = 0.41421356237
    PI								= 3.141592653589793239
    kRadiansPerDegree				= PI / 180.0
    kDegreesPerRadian				= 180.0 / PI
    kNearlyEqualEpsilonForDoubles 	= 1e-13
    def point_on_line_3D(p1, p2, d): #3d Points d = distance from p1 to p2
    	x1, y1, z1 = p1
    	x2, y2, z2 = p2
    	c = vs.Distance3D(x1, y1, z1, x2, y2, z2)
    	new_pt = ((x2 - x1) / c * d + x1,  (y2- y1) / c * d + y1 , (z2 - z1) / c * d + z1)
    	return new_pt
    def DoublesAreNearlyEqual(n1, n2):
    		epsilon = kNearlyEqualEpsilonForDoubles
    		abs_n1 = abs(n1)
    		abs_n2 = abs(n2)
    		abs_n1n2 = abs(n1 - n2)
    		if ((abs_n1 <= epsilon) or (abs_n2 <= epsilon)):   # if either is very nearly zero, don't take the magnitude into account
    			return (abs_n1n2 <= epsilon)
    			temp = abs_n1 if (abs_n1 > abs_n2) else abs_n2
    			return (abs_n1n2 <= temp * epsilon)
    def DoubleIsNearlyZero(n):
    	return DoublesAreNearlyEqual(n, 0)
    def DotProduct(p1, p2):
    	return (p2[0] * p1[0]) + (p2[1] * p1[1]) + (p2[2] * p1[2])
    def Magnitude(vec):
    		return math.sqrt( vec[0]*vec[0] + vec[1]*vec[1] )
    nurbsObj = vs.FSActLayer() # take care to select a NURBS curve
    radius = 100
    segments = []
    points = []
    segmentCnt = vs.NurbsCurveGetNumPieces(nurbsObj)
    for segm in range(0, segmentCnt): # python range is always one less than pascal
    	pts_infos = []
    	vtxCnt = vs.NurbsGetNumPts(nurbsObj, segm)
    	num_knot = vs.NurbsNumKnots(nurbsObj, segm)
    	vertex_plane = []
    	for vtx in range(0, vtxCnt): # python range is always one less than pascal
    		v = vs.NurbsGetPt3D(nurbsObj, segm, vtx)
    		if vtx < vtxCnt - 1:
    			p1 = v
    			p2 = vs.NurbsGetPt3D(nurbsObj, segm, vtx+1)
    			p = point_on_line_3D(p1, p2, radius*sqr2)
    			points.append([p,1]); pts_infos.append([p, 'control_end'])
    			p = point_on_line_3D(p1, p2, radius) #start radius point
    			points.append([p,10]); pts_infos.append([p, 'segment_start'])
    			p = point_on_line_3D(p2, p1, radius) #start radius point
    			points.append([p,10]); pts_infos.append([p, 'segment_end'])
    			p = point_on_line_3D(p2, p1, radius*sqr2)
    			points.append([p,1]); pts_infos.append([p, 'control_start'])
    			pts_infos.append([p2, 'vertex'])			
    	segments.append([segm, vtxCnt, pts_infos])	
    def rotate2d(degrees,point,origin):
    	x = point[0] - origin[0]
    	yorz = point[1] - origin[1]
    	newx = (x*math.cos(math.radians(degrees))) - (yorz*math.sin(math.radians(degrees)))
    	newyorz = (x*math.sin(math.radians(degrees))) + (yorz*math.cos(math.radians(degrees)))
    	newx += origin[0]
    	newyorz += origin[1] 
    	return newx,newyorz
    def get_angle(p1, p2):
    	diffx = p1[0]
    	diffy = p1[1]
    	p2 = p2[0]-diffx, p2[1]-diffy
    	x2, y2 = p2
    	a = vs.Vec2Ang(x2,y2,0)
    	return a
    for i in range(len(segments)):
    	segm, vtxCnt, pts_infos = segments[i]
    	p1 = pts_infos[2][0] #start
    	p2 = pts_infos[4][0] #corner
    	if i < len(segments) - 1:
    		segm2, vtxCnt2, pts_infos2 = segments[i+1]
    		p3 = pts_infos2[1][0] #start next segment
    		x3, y3, z3 = p3
    		x2, y2, z2 = p2
    		x1, y1, z1 = p1
    		zangle = get_angle(p1, p2)
    		if (x1,y1) == (x2,y2): #vertical > no zangle from p1 - p2
    			zangle = get_angle(p1, p3)
    		p3_1 = rotate2d(360-zangle, p3, p1)
    		p2_1 = rotate2d(360-zangle, p2, p1)
    		p3_1_angle = get_angle(p2_1, p3_1)
    		if p3_1_angle >= 0:
    			cw_seg_2 = False #counter clockwise
    			cw_seg_2 = True #clockwise
    		diff_y = p3_1[1] - p2_1[1]
    		diff_z = p3[2] - p2[2]
    		xangle = vs.Vec2Ang(diff_y, diff_z,0)
    		diff_x = p2_1[0] - p1[0]
    		diff_z = p2[2] - p1[2]
    		#vs.AlrtDialog(str([diff_x, diff_z]))	
    		yangle = vs.Vec2Ang(diff_x, -diff_z, 0)
    		vs.Symbol('Symbol-1', p1, 0)
    		sym_h = vs.LNewObj()
    		vs.SetEntityMatrix(sym_h, p1, xangle, yangle, zangle)


  3. I think you are right. Even we do not ned to create a working plane to set the entity matrix which already can handle vectors instead angles. My bad is to look into the marionette SetEntityNode, which do not use vs.SetEntityMatrixN()
    There is no up and down. In my first example the edge symbol is inserted from bottom. 


  4. Hello @MullingRJ

    I have several specific projects but this one would be on ice right now (As a saw the matrixes I had to joine the duscussion :-) and I think it is solvable but need some investigations to have a proper and elegant solution.  
    I already have some code, which calculates points from edge of a 3D Path which a specific distance from the corners. What is needed not is a rotation vector which contains the rotation matrix related to the layer coordinate system. Thats how we insert symbols. I am pretty close to that by calculationg the x y z angle but i have not yet defined an algorithm to define if it is minus or plus angle. The code does not yet consoder, if i go up down left or right. 

    But I am pretty sure, on our old math books there is a very compact and itelligent solution.
    So it would be great if you can join the project! Thanks

    @Simon. It is just "simple trigometric" but we have to check direction to if rotation is minus or plus or 180 - rotation. Without that, we have the direction of the plane but do not know from which side we look at the plane. 

    What you see in the movie is, that I set the working plane which is defined with x, y, z, rotation. Then I place a symbol on that. That's what I want to do with the script. The plane of the corner is defined with the 3 points on the corner (i draw 3D locus to make it visible)

    "Just" left to solve to calculate the entity matrix from those 3 points on every corner. I alread have X Vector (p2, vorner_p) and Y Vector (corner_p - p3). z_vector also is defined through this two vectors I think. Now we need the rotation from that u' v' w' planen to the Layer coord plane. 

    At the end we also could place objects on 3D planes very simple with a node, that creates a plane matrix (which can be used to SetEntityMatrix) from 3D points. That is something I think would help many users. We also maybe could draw a NURBS Surfaces and evaluate points on that with the vs-Commands. But always better to do that directly with math.


    Fillet v2022.vwx

    • Like 1
  5. The Matrix node just flatten the input vector tuples. 
    (1,0,0),(0,1,0), (0,0,1), (0,0,0) ase example results in (1,0,0,0,0,1,0,0,1,0,0,0). 
    I bet, this comment do not help you really¬†ūüėÄ

    I think it could be used to serve one of the other matrix nodes. to rotate as example a matrix. 

    I am not an expert but try to explain:
    In computer-graphic, the "Eulerschen Winkel" (Formulas on the left) can be used to descripe the orientation of an object (A rotated coord system). Vectorworks uses this as example for planes, Entity Matrix etc. The Interesting point for me would be, how to get efficient such a matrix (which is just X rotation Angle, Y rotation Angle, Z rotation Angle and offset vector) as example from 3 points in space without using additional libraries (scypi, numpy etc.). I never tried this very intense but also would be interested in some explanations in this area. Something by script what we have with set working plane or automatic working plane. No function is provided for that as far as I can see. 


  6. Thanks for input Larry and Pat.
    ConvertToNURBS can't put several segments together. If that is possible it would also not be needed to draw planar polylines and rotate them into the 3D Plane. I have corner points and control points already calculated and can directly draw a NURBS in 3D. It seems, that the hurdle is, that one segment of NURBS can only handle one type of vertex. Rounded vertex or edge vertex. every time we have an unrounded edge we have to create a new segment which we can't combine together. Minimum not in an easy way. What I also thought about is, that maybe the NURBS Curve with several NURBS internally is a different object as a single segment. 

    What i maybe will try later:
    1. Creating the object with different segments seems to be an attractive and proper solution. Also additionally the Level of detail for a fitting can be implemented here.
    2. Menu Command compose making to work inside a Marionette PIO. But for that think I have to parent the Object on a layer then compose it and parent it back into the PIO. Which could work but is somehow ass-backward (Translation from "von hinten durch die Brust ins Auge" ?).

  7. Hello
    There are some old threads for this theme but it seems, there is no proper solution.
    I also searching for an elegant solution to make fillet on NURBS Curves. As the Tool works fantastic,  by script it seems to be not so trivial. Maybe because we need to combine somehow several segment of NURBS and not all parameters can be edited by script.

    So far I tinkered an approximated solution, which seems to work for my usecase it is exact enough and works but somehow not pleased yet for nitpicker like me and many of us ūüôā¬†Target is to model filled NURBS for modeling pipes without using compose as menu command.

    The Script:
    The calculation of the control points is exact. Also think about to stop pipe, insert a corner segment with right rotation (because calculation of the plane and points already done in this script) Also this could improve dramatically level of detail instead of a path extrude, which anyway have some issues when profile is bigger than radius.
    It normalize the segment line and generates offset points from the vertex points. One control point with offset from the corner point with diameter and another control point diameter * (2**0.5 -1). The same as we got with the filled tool. The issue seems to be creating a "double" point with ends line segment to a radius NURBS. We get that with the tool but by script it is still a secret. I "solved" by giving a big weight (10) at the end of the line segment and weight 1 at the control points. It draws nearly an exact radius.

    I hope maybe join again the thema and help improving the solution or can use the existing approximative method.

    import math 
    sqr2 = 0.41421356237 #faster to have constante value instead of calculation 2**0.5 several times I guess
    def point_on_line_3D(p1, p2, d): #3d Points d = distance from p1 to p2
    	x1, y1, z1 = p1
    	x2, y2, z2 = p2
    	# a little long but it just substract p1 from p2, then normalize and then multiply with new lengt and add to old point
    	c = vs.Distance3D(x1, y1, z1, x2, y2, z2)
    	new_pt = ((x2 - x1) / c * d + x1,  (y2- y1) / c * d + y1 , (z2 - z1) / c * d + z1)
    	return new_pt
    nurbsObj = vs.FSActLayer() # take care to select a NURBS curve
    radius = 100
    segments = []
    points = []
    segmentCnt = vs.NurbsCurveGetNumPieces(nurbsObj)
    for segm in range(0, segmentCnt): # python range is always one less than pascal
    	pts = []
    	vtxCnt = vs.NurbsGetNumPts(nurbsObj, segm)
    	num_knot = vs.NurbsNumKnots(nurbsObj, segm)
    	for vtx in range(0, vtxCnt): # python range is always one less than pascal
    		v = vs.NurbsGetPt3D(nurbsObj, segm, vtx)
    		if vtx < vtxCnt - 1: #some code of the developper wiki
    			p1 = v
    			p2 = vs.NurbsGetPt3D(nurbsObj, segm, vtx+1)
    			#vs.Locus3D(p1); points.append(p1) #corner point
    			p = point_on_line_3D(p1, p2, radius*sqr2)
    			points.append([p,1]); #points.append(p)		
    			p = point_on_line_3D(p1, p2, radius) #start radius point
    			p = point_on_line_3D(p2, p1, radius) #start radius point
    			p = point_on_line_3D(p2, p1, radius*sqr2)
    			points.append([p,1]); #points.append(p)					
    	segments.append([vtxCnt, num_knot, pts])	
    new_curve = vs.CreateNurbsCurve(points[0][0][0],points[0][0][1],points[0][0][2],True,3);
    for i in range(1, len(points)):
    	p, weight = points[i]
    	vs.AddVertex3D(new_curve,  p)
    	vs.NurbsSetWeight(new_curve, 0, i, weight)
    num_knots = vs.NurbsNumKnots(new_curve, 0)
    for i in range(num_knots-3):


    Fillet v2022.vwx

  8. Hello
    Someone knows the secret of tagging an object with the DataTag by script? Seems to be not so easy.
    So far my researches:

    1. Read the ASSKINDs of Object and DataTag. It shows me:

    37 for the Data-Tag 36 for the Tagged Object

    obj1 = vs.FSActLayer()
    num = vs.GetNumAssociations(obj1)
    out_str = 'Associations\r'
    for i in range(num):
        v = str(vs.GetAssociation(obj1, i))
        out_str += str(v)+'\r'

    2. Further Assiciations

    obj1 = vs.FSActLayer()
    obj2 = vs.NextSObj(obj1)
    result = vs.AddAssociation(obj1, 17, obj2) #4(deleted if delete), 5(reset if deleted) 17(?)
    vs.HMove(obj1, 1,0)

    3. Remove Associations

    obj1 = vs.FSActLayer()
    #stempel = vs.GetObject('stempel')
    num = vs.GetNumAssociations(obj1)
    out_str = 'Associations\r'
    for i in range(num):
        ioTargetObj, inKind, value = vs.GetAssociation(obj1, i)
        vs.RemoveAssociation(obj1, inKind, ioTargetObj)


    4. Maybe with a constraint?

    h1 = vs.Handle(0)
    h2 = vs.GetObject('line1')
    h3 = vs.GetObject('symbol1')
    if h2 != vs.Handle(0):
        p2 = vs.Get2DPt(h2, 0)
        x1, y1 = vs.HCenter(h3)
        obj, index, containedObj = vs.GetClosestPt( h3, x1, y1)
        vs.AlrtDialog(str([obj, index, containedObj, h1, h2, h3])) #obj1 and h1 are the same contObj1 is None
        bool = vs.SetBinaryConstraint(1, h3, h2, index, -1, 1, -1, containedObj, 0)
    if h2 != vs.Handle(0) and h3 != vs.Handle(0):
        bool = vs.HasConstraint(h2)

    This works for a line and a symbol. Maybe this works with data-tags and object also if we could find the right arguments.

  9. The Rendering in VW Design Layer:

    Rendering in Viewport:
    (Rendering is a little brighter because of image effect)

    All is set to Renderstile "Moebel freistehend"

    Panorama Export Setting:

    Here the panorama export with the same renderstile:

    The Link to the panorama

    How it would be used: This panorama is exported Renderworks but with a renderstile with a darker hdri. 


    • Like 1
  10. Hello
    Also very interested in making visible the work of an algorithm.

    I think it is possible by script to show the Objects created or manipulated by script. But a Marionette saves the view before the script runs and recovers it. Somehow this results in a different behavior from Marionette compared to a python script. I played around with this some time ago. The Attached Document shows a script that contains the same code as a Marionette. By executing the script the movement of rectangle is plotted on the screen. 



    For another example I putted every of the steps of the script on different layers. Then after the execution I batch-export the layers as pictures then combined into a movie with an external tool. Like this:

    I can't find that example anymore but I think i just hardcoded an Object creation and a vs.SetParent to put it on a new Layer


    • Like 3
  11. This looks like, the symbol was edited last while the design-layer had another layer scale thank the layer scale of the actual active layer.
    Normally it helps co activate all, cut (cmd/ctrl. + X) and paste (cmd/ctrl + V). In this case it seems, the code attached to the add-node is broken.

    I can correct it as follows:
    1. cut and paste

    2. Double click and edit "less equal" and "greater equal"

    3. Then the wires to the add node desapears and I reconnect again then it works.

    I think there is still an issue which can corrupt Marionette scripts. If you insert a red symbol on a design-layer which have a different layer scale than the layer scale was active while the symbol was created.


  12. As the concat node is, it converts the input to a string and then loop the character and adds them.

        stringIn = str(self.Params.stringIn.value)
        newString = ''
        for s in stringIn:
            newString = newString + s
        self.Params.stringOut.value = newString

    I am not sure but I would expect from this node, it should do something like this:

    stringIn = self.Params.stringIn.value
    newString = ''
    for s in stringIn:
      newString = newString + str(s)
      self.Params.stringOut.value = newString


  13. Hi
    You want to attach a Text property on a Marionette Object and then inside the Script ask for the Text Properties attached to the Marionette PIO? I think if a Marionette Object can get some infos from the text menu, it would be possible.

    You can handle the Parent PIO, but I do not see, that a Marionette can get some text Infos by the text menu. You could get the class of the Parent PIO and the Text Style of the Class as a workaround maybe. But directly the Text Style I think works not with a Marionette Object Node.

    Here An example, if you get the text style of the parent PIO class.

    Side Note:
    First Time I use concat node, it seems to convert the input list to a string instead of concat the input strings, which is somehow not what I would expect. It converts the List in a string first ...


    • Like 1
  14. Hello
    Welcome to the Marionette Forum. I think your script looks quite good. My workflow is often to first calculate all necessary points and data. After That I create the Objects. Also I use a lot of custom nodes to save number of nodes (Enhanced Rectangle, Function 2, BBox Enhanced) but this is not necessary per se.
    Creating Rectangle to find the corner point is something I would not do generally. Also Mirroring is not necessary, if your feeds are circles or squares. 

    To Mirror correctly you need one horizontal and one vertical axis. In your Script there is only one Axis. Also you need to mirror one Feed over a Diagonal Axis and if the shape is not a square, this had to be calculated. Or you Mirror at the Vertical Axis, then you mirror the resulting object along the horizontal axis. The Get Item in the Screenshot, gets the first second duplicate (top left) and mirror again along the vertical axis. 
    By the way, mirroring should work like this:


    Mirror Example.vwx

  15. tkinter could be installed with the Marionette python Modul importer. But at the Moment this maybe also not work out of the box. And by using tkinter I had negative effects resp. some functions maybe additional code to make it run in an embedded python.

    Maybe off-topic. For Crossplatform Clipboard, this script could be used:

    import math
    import os
    import subprocess
    major, minor, maintenance, platform = vs.GetVersion()
    text = 'Hello World'
    def addToClipBoardWin(text):
    	command = 'echo ' + text.strip() + ' | clip'
    def addToClipBoardMac(text):
    	process = subprocess.Popen('pbcopy', env={'LANG': 'en_US.UTF-8'}, stdin=subprocess.PIPE)
    if platform == 1:


    • Like 4
  16. That little test works here. It seems the nested callback of the wiki-example is a little bit too ambitious.

    def resultCallback1():
    	h1 = vs.FSActLayer()
    	p1 = vs.GetSegPt1(h1)
    	p2 = vs.GetSegPt2(h1)
    vs.CallTool(-201, resultCallback1)


  17. Hello
    I think the issue with the script that makes it slow is, that you loop the light devices and in that loop you give a search-request with ForEachObject. If you have many objects in your drawing a search-request over all objects in the Drawing could take maybe one second and if you have that 250 times in a loop it will take 250 seconds as example.

    The better way in my opinion
    1. Use ForEachObject just once on all Objects that could be your target light objects ()
    2. Then loop all light devices from data (as you do)
    3. Then do it as following:

    if (isAvailable):       
    	lights = [] #name, handle
    	def get_lights(h):
    		n = vs.GetName(h)
    	c = "((PON='Lighting Device'))" 
    	vs.ForEachObject(get_lights, c)  
    	for p in data['LightingDevices']:
    		uid = p['__UID']
    		for light_name, h in lights: #loop through the found light objects in the drawing
    			if light_name == uid:
    				instrType = p['instrumentType']
    				instrMode = p['fixtureMode']
    				wattage = p['wattage']
    				weight = p['weight']
    				position = p['position']
    				purpose = p['purpose']
    				channel = p['channel']
    				unitNumber = p['unitNumber']
    				universeAdress = p['patch']
    				circuitNumber = p['circuitNumber']
    				circuitName = p['circuitName']
    				dmxLine = p['dmxLine']
    				dmxFootprint = p['dmxFootprint']
    				deviceType = p['deviceType']
    				color = p['color']
    				template1 = p['template1']
    				template2 = p['template2']
    				user1 = p['userField1']
    				user2 = p['userField2']
    				user3 = p['userField3']
    				user4 = p['userField4']
    				user5 = p['userField5']
    				user6 = p['userField6']
    				className = p["class"]

    The loop in loop will be very fast. Much faster then the search-request (ForEach ...) inside a loop.
    Untested code but I bet a beer this would do the job faster


    • Like 2
  18. Hi
    It should be possible, to use the "Attributes"-Node to set fill pattern to 0. Connect it after your object and set it to Empty  Fill. After That attach your colors. The Problem could be that the "Attributes" node replace also the line weight and line style. If that is a problem you can use the "function"-Node. And just paste vs.SetFPat(x, 0) in the input field.

  19. Hi
    I think this object is between 2-40 hours to create. So I post without taking the order.
    It depends on which level of Detail you really need (Material Thickness , drillings for screws etc.) I can give you or somebody else a start-assist and a possible workflow. A sketch, what pitch, height, span, base size exactly means were nice because it is a big part of the work to specificate exactly which values should be variable. It is about the work of 3 hours (but always the first 60% from something are done very fast. It would be enough if you do not need any screws and if the material thickness on all edges would be the same and if you need just the hull of the material not the single parts and how they exactly cutted in raw form (miter etc)).

    Once more I ask myself, how it is possible to create exact Elements by using the non-metric-unit-system (just a gloss a place whenever I have the chance :-)  





    • Like 3
  • Create New...