Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by DomC

    Just used it and it worked like a charm even without viewing the instructions 🙂 Have Potential for improvement, but since there is by far not a comparable feature 5 Stars
  1. Hi I am pretty sure, it should be possible by worksheet formula without script, is somebody long enough work on that Formula. I first attempt could be a hard-coded formula (one Formula for one parameter in one PIO) =TEILSTRING(TEILSTRING('MarionetteObject2D'.'NodeDef_OIPControls', ',', 6), ':', 2) While "Teilstring" is "SubString" and in Germany ';' must be used as delimiters instead of commas i guess. But it returns the Width of the Marionette Object. Also the reversed procedure should by possible by concat worksheet formulas. Never thought about this. 2 is the second parameter and 6 is the value. Edit: Hm reversed procedure could be tricky by writing at all data from a formula on the object
  2. Great Guys How cool is That! I will for sure use it soon to lay floor-panels soon in my basement hobby-room. Don't forget to share in the gallery.
  3. This kind of behavior is quite common. Often we need a "ResetObject" or a "ResetBBox" after some commands. I would not say this is a Bug or an error because it can be smart to not reset and recalculate everything in every single Node/Step of a script to keep it fast. The "GroupNode" resets the BBox. Also the Geometry-Grouping of Marionette Network resets the BBox of the PolyGroup by accident. You can reproduce the same behavior with a Script. h = vs.FSActLayer() num, polyGroup = vs.TrueTypeToPoly(h) bbox = vs.GetBBox(polyGroup) vs.AlrtDialog(str(bbox)) vs.ResetBBox(polyGroup) bbox = vs.GetBBox(polyGroup) vs.AlrtDialog(str(bbox)) The vs.TrueTypeToPoly() returns a group with zero size Bounding Box. We have to first reset the bbox to get the bbox size correctly. Or in the Script: Unfortunately, resetBBox (also ResetObject which is also a common needed Node) are not part of the standard Node-Content.
  4. Agree with Antonio. Alternatively set Text Properties to middle and then set Orientation to your point.
  5. Hi I wrote "low effort" so I triggered myself to try it. Here your example. I count here every 20th pixel. this is the input "Rasterabstand". What is not solved is, that the blue pixels as example not have exactly the same value. Also it counts also the white pixels. But it is a base, just to answer the initial question. Oh yes, Marionette can. counting pixel.vwx The Picture have 51 different colors. Here the counts:
  6. You can count pixels of an image by using the pillow library for python. You could install that library in 2023 with the new installer from Marionette. Some of the earlier installation nodes (from me and others) fails because of different reasons (wrong wheele Files, ssl incompatibilities etc.) But once your pillow library was working you can do that. You cant count the pixels and colors. Maybe you have to "round" color because not every green pixels have the same green etc. but it is possible with low or maximum medium effort. Some existing examples: 1. How to digitizing an Image: It counts the pixels and the the rgb values. 2. An Example how to seperate Clusters of Points. 3. An Example how to create a Hull around a "cloud" of Points. If you have generated points out of your image, you could make a shape out of this points with that. A note about Example #2 and #3. This is perfectly already solved by using an external Library like shapely etc. They can generate convex and concave shapes out of points. Also There are many other Libraries that can vectorize your images pretty good.
  7. The Text Node converts the input in a string. That should not be the issue. Try the following: 1. The Text is place by coord (0,0) you should found your text oject there. Get 2D Center or BBox Center to place your text in the middle of the poly and intert the resulting point into the text Node 2. Try to connect a prefix. Even if you do not have an area it should return the prefix There is a great DataTag Tool, that would tag your polys automatically with an area. Maybe there is no script necessary.
  8. Hi You can repeat the Wires by the value of Multiplier. The Best point is to multiply at the beginning, where are not so many wires yet. So just repeating the lines by Multiplier. Also Create some new Numbers for the space. I will upload the example to the other File in the gallery Attention: 1. In the Configuration Window, the first column A is ignored (original Space Numbers, which will not work for the space anymore very good) 2. Second Column B of my file is "11_Space Name Cust". Do not choose anything else there 3. Column C is connected to column out1 which is the space are.
  9. Got it for an example, in which the Cabinet is not rotated. At the Moment I am overhelmed by calculating the rotation angle through both PlugIns. offset it easy. It is offset vector Cabinet (related to World coords) + offset Vector Custom Part (Related to Cabinet PIO). The Rotation Matrix is cabinet angle + custom part angle or cabinet angle - custom part angle. But the rotation could be on 3 axis and it debends on the order how those angles are calculated. I think the "Matrix" Nodes would do the job but nobody seems to know, how they can be used. Because the "Set Entity Matrix" needs x y z angles and the Transform Matrix delivers u v w and x y z values. I once short got busy with it but still hoping that someone else can solve it with the Marionette Node🙂 The other thread about the Transform MAtrix: Custom Part Entity.vwx
  10. Hello every container has its own coordinate system and rotation plane. If you pull out something inside a PIO, you have to attach the PIOs Plane (Entity Matrix) on it, to convert it to the World Plane. It works, if you get the plane of the parent Object (custom part) and attach it to the Covering. O .... K, While I am writing I see, that this is not the end-solution. Because the Covering is nested in a Custom Part which is part of the Cabinet. So we have to combine the entity matrixe's of the cabinet AND the Custom Part. Another approach would be, to "convert to group" the whole cabinets and then grabbing the coverings out of the result.
  11. Hi Also Failing here. Seems the python script is waiting for the python execution and not for Vectorworks. If I as example importing 10 Symbols from a source it takes about 10 seconds. The progress bar (and Message Window) ends in 1 Second. If i build in 10 seconds of wait or sleep function it is visible 10 seconds but the execution takes then 20 seconds. Next try would be to run the function inside a dialog loop def place_symbols(): vs.ClrMessage() vs.ProgressDlgOpen("Ersetze Objekte", False) if globals.settings['Ebene'] == 1: #new Layer vs.HideLayer() l_handle = vs.CreateLayer(globals.settings['Ebene Name'], 1) vs.HideLayer() vs.ProgressDlgStart(100, len(globals.pairs)) counter = 1 for target, source in globals.pairs: #vs.ProgressDlgStart(counter, counter) sym_name, [ListID, index] = source vs.ProgressDlgSetMeter('Ersetze' + sym_name) vs.Message('Ersetze' + sym_name) vs.ProgressDlgYield(1) #time.sleep(1) if vs.GetObject(sym_name): vs.DelObject(vs.GetObject(sym_name)) vs.ImportResourceToCurrentFile(ListID, index) vs.Layer(vs.GetLName(l_handle)) vs.Symbol(sym_name, (0,0), 0) h_new = vs.LNewObj() counter += 1 off_x, off_y, off_z = target['PositionXYZ'] rot_x, rot_y, rot_z = target['RotationXYZ'] vs.SetEntityMatrix(h_new, (off_x, off_y, off_z), rot_x, rot_y, rot_z ) if globals.settings['Ebene'] == 0: #replace on active layer for target, source in globals.pairs: handle = target['handle'] if handle != vs.Handle(0): vs.DelObject(handle) vs.ClrMessage() vs.ProgressDlgEnd() vs.ProgressDlgClose()
  12. This one would update or create new textures: import os def put_bitmap_in_texture(hTexture, hPaint, image_size): #hTexture Resource, hPaint hImage = vs.CreateImageFromPaint(hPaint, 'Just_a_name') hShaderRec = vs.CreateShaderRecord(hTexture, 1, 41) #1 = Color image hTextureBitMap = vs.CreateTextureBitmapD( hShaderRec) vs.SetObjectVariableHandle(hTextureBitMap, 528, hImage) #Were the magic happens! vs.ResetObject(hTexture) vs.SetObjectVariableHandle(hTextureBitMap, 528, hImage) resolutionx = vs.GetObjectVariableLongInt(hPaint,530) resolutiony = vs.GetObjectVariableLongInt(hPaint,531) vs.SetTexBFeatureStart(hTextureBitMap, 0, 0) #pixel start vs.SetTexBFeatureEnd(hTextureBitMap, resolutionx, 0) #pixel End vs.SetTexBitFeatureSize(hTextureBitMap, image_size) #size units return hTextureBitMap major, minor, maintenance, platform = vs.GetVersion() isMac = False if platform == 1: isMac = True # define a location to import the images importPt = (0,0) image_size = 10 symCreatedCnt = 0 err, dirPath = vs.GetFolder( 'Select a Folder' ) if err == 0: # no-error hsfDirPath = dirPath if isMac: ok, hsfDirPath = vs.ConvertPosix2HSFPath( dirPath ) name_counter = 1 fileIndex = 1 while True: # loop the files fileName = vs.GetFilesInFolder( hsfDirPath, fileIndex ) fileIndex += 1 if fileName == '': # no more files break name, ext = os.path.splitext( fileName ) if ext.lower() == '.png' or ext.lower() == '.jpg': imagePath = os.path.join( dirPath, fileName ) hPaint = vs.ImportImageFile(imagePath, 0,0) #Needs to be deleted afterwards texture_name = name + "_tex" existing_obj_handle = vs.GetObject(texture_name) update_tex = False if existing_obj_handle != vs.Handle(0): #object already exists obj_type = vs.GetTypeN(existing_obj_handle) if obj_type == 97: #object is already a texture > Update hTexture = existing_obj_handle update_tex = True else: #object exists but is not a texture hTexture = vs.CreateTexture() texture_name = name + str(name_counter) +'_tex' name_counter += 1 hTextureBitMap = put_bitmap_in_texture(hTexture, hPaint, image_size) vs.UpdateThumbnailPreview(hTexture) else: #new texture hTexture = vs.CreateTexture() hTextureBitMap = put_bitmap_in_texture(hTexture, hPaint, image_size) if not update_tex: vs.SetName(hTexture, texture_name) vs.DelObject(hPaint)
  13. Hello Try to insert that lines. Looks somehow rude, but it seems to "burn" the image into the texture: Also it fixes the width of the image to (document unit?) 10. vs.SetObjectVariableHandle(hTextureBitMap, 528, hImage) #Were the magic happens! vs.ResetObject(hTexture) vs.SetObjectVariableHandle(hTextureBitMap, 528, hImage) resolutionx = vs.GetObjectVariableLongInt(hPaint,530) resolutiony = vs.GetObjectVariableLongInt(hPaint,531) vs.SetTexBFeatureStart(hTextureBitMap, 0, 0) #pixel start vs.SetTexBFeatureEnd(hTextureBitMap, resolutionx, 0) #pixel End vs.SetTexBitFeatureSize(hTextureBitMap, 10) #size units
  14. @Marissa Farrell Ist the behavior of the concat node WAD or should report a bug? I think it is a bug because it converts the list (List absorb) in a string. And then re-adds every character of that string together so the result is again str(self.Params.stringIn.value)
  15. I think right-click method is nearly as fast as shortcut but if theoretically someone is interested in the update-selected-script-variante. #DomC 2022-09-17 Use at your own risk #Recalculates selectes worksheets on the active layer. #Worksheets with the same names were also recalculated, even if #they are not on the same layer and/or are not selected selected_worsheets = [] def add_handle(h): selected_worsheets.append(h) vs.ForEachObjectInLayer(add_handle, 2, 1, 0) for worksheet_insctance_handle in selected_worsheets: sheet_resource_handle = vs.GetWSFromImage(worksheet_insctance_handle) vs.RecalculateWS(sheet_resource_handle) vs.ResetObject(worksheet_insctance_handle)
  16. With the SetRecordField, you can change parameters from PIOs. Like Diameter, Depth which would be the most common I think.
  17. Hi I would not say i am a python expert and i also was fighting a lot with path-strings (strings and text encoding generally) in the past. Let python os-module do the job. Allow me to suggest this as following: import os full_absolut_path = os.path.join('c:', 'DOCs', 'SCRIPT', 'NNR.dxf') LNR = vs.ImportDXFDWGFile(full_path, isBatch) #or in one line LNR = vs.ImportDXFDWGFile(os.path.join('c:', 'DOCs', 'SCRIPT', 'NNR.dxf'), isBatch) This would work on both platforms. Also i saw if we are reading path from os and use it as a string, it can be necessary to normalize the path string because of some special characters to make it look good in Vectorworks on both platforms: import unicodedata path_string = unicodedata.normalize('NFC', full_absolut_path) Edit: In my opinion it is just "luck", that \D and \S are no special controls in python. \n creates a new line \N --> No idea, what creates that. Something that is not compatible for unicode decoding. The String is forwarded from python to VW and VW can "parse" the path with some rules but here python itself just can't interpret the code of the programmer. string 'C:\DOCs\SCRIPT\NNR.dxf' is as unallowed as a division by 0 which also put an error on the screen without any further arguments. We could try to push a raw string to the VW function and see what happens. like that: NNR = vs.ImportDXFDWGFile(r'C:\DOCs\SCRIPT\NNR.dxf', isBatch)
  18. Hi The "Universal" (english) Names of the PIOs you can get by creating a Worksheet as example. The Formula in the worksheet will show you the Name. As far as I can see, you can start your drilling script with locus to test and debug. If it works replace the locus through the drilling. The Drilling you can insert. The Options in the Object Info Palette for PIOs you change with "Set Record Field". There is no need of creating special Nodes for that. As a Box Object your Marionette would work. Directly putting it on a part will be not a good idea as far as I can see it is getting instable. Because the part pulls out the drillings out of the marionette somehow and after moving marionette the move event does not trigger the right action to the part to release. Try it as a marionette box object.
  19. I must correct my statement It seems, that the drillings drill the part directly with the Marionette. O. M. G. Drilling with a Marionette.mp4 I could imagine to make a Frame on the Part or get automatically the part dimension and attach an own intelligent drilling pattern to the object. for me this looks like a litte revolution. Just that I said that. I do not know if this is a good Idea or if this is stable. No guarantee for that. ic marionette 2.vwx
  20. Short Test Works more like a "Drilling Stamp". Just a short raw test. There would be two bigger issues left: 1. How to get Position of Marionette Object before Objects are putted out. Because first the objects are created and after that the PIO gets his new position. 2. How to delete the existing drillings before put in some new drillings on the layer. I think theoretically solvable but I think i am notching out at this point 🤔 By the way, Box Objects would support Marionette PIOs in a Cabinet. Also the Cabinet could be reduced to a single part and then it could work together. Test Drilling Stamp.mp4 ic marionette.vwx
  21. Yes exactly. As long as the PIOs are inside the Marionette, they would not react with the interiorcad parts. Well there is always a way to get something to work. As example: - If we would create objects and then set parent Object on the layer instead of the pio - and recalculate positon and rotation outside the PIO plane to the world-plane - And regenerate/reposition the objects while executing the marionette. By linking the Objects to the script by uuid as example There seems to be some options but there is need for additional coding the script and making special nodes which do not exists.
  22. You could control those objects by insert an object as a symbol then manipulate the path. Point objects like macro or drilling you could control with "Create Custom object" also there is a "create custom object path" which would create parts or contours. At the end, those objects would not be able to "marry" with the interior custom parts if they are inside a Marionette PIO.
  23. Best Option is to sort data before creating the Objects. There is also a send backward Node here available.
  24. I wish not that we need to do this but it seemed to be necessary if i have python scripts and wants to interact with Vectorworks while script is running. Theoretically is should work with a python script, if we use the python script as a callback of the temp tool and additionally tweaks. But that seems to be even more unstylish, then embed everything into pascal scripts which handle user interactions. Can't estimate if this disadvantage of python code inside VW technically and reasonable at all can be eliminated.
  • Create New...