Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by BillW

  1. Following on from my initial post, thought I'd pass on an unencrypted full blown example of a python based menu command "Convert from Faces.." which places a symbol consisting of a 2D locus at locations around/on 2D/3D objects which can take account of adjacent 3D faces to determine direction. There's a lot of work with planar objects and vectors. I include an install file "install convertfromfaces.zip" which you can install in Vectorworks via Tools>Plugins Manager>Third-party Plug-ins>install... You will need to add command to a workspace via Tools>Workspaces...> Menus>WHW 3D modelling>Convert from Faces... The zip file contains the VSM file and supporting python files. As python files can't be uploaded, I include source code text files "convertfrom faces 2020", "convsf_classes" and "convsf_utils". Note, I use class convSF to store operational variables. Classes entmat, vertexdef and multidef are used to store geometry definitions. Displacement Offset works in local axes but Rotation works in world axes. Haven't figured out a local axes rotation yet. Hope this will pass on some inspiration. install convertfromfaces.zip convsf_classes source.txt convsf_utils source.txt convertfromfaces 2020 source.txt
  2. Thanks PatW - duly bookmarked - just whats needed.
  3. Just give some idea on converting a Vectorscript palette script to Python. The code splits a polyline/polygon into seperate line segments or linked curve segments which will give some idea how to traverse polylines/polygons including holes. Hope the code is useful. I did find that the VS call IsPolyClosed(polyH) is unreliable when you have invisible segments other than the last and doesnt handle holes so I wrote my own "IsClosed" I use a lot of STRUCTURE's in vectorscript which I have transposed into classes in python. Similarly there is no "repeat/until" in python which is handled by "while 1:" with a "break" call. Also vectorscript "case of" will have to wait for Python 3.10 version "match case" - use "if elif else" for the time being. Arrays such as "enddefs : array[1..250] of multidef;" are handled by a python class "multidef" and appended to a list via "enddefs.append(multidef(vstart,1))" Also note the use of GetEntityMatrix and SetEntityMatrix to align new content with the existing poly. Find enclosed text content of equivalent Vectorscript/Python code, a VW2020 file I used for testing with a script palette "Palette-1" and scripts "mark verts vs, split poly vs, split poly py" Been scripting for decades mostly in Vectorscript and mainly between my day job of 3D modelling. Lot's of relearning for Python needed. split spline test vw2020.vwx split poly vs.txt split poly py.txt
  4. Has anyone managed to get procedure "ConsolidatePlanar(obj1,obj2) : BOOLEAN" to work. In the attached VW2020 file I have a polygon (named "testpoly") which is rotated in 3D by 45degrees around the X axis. In the script palette I have a script "test consolidateplanar" which when run shows new/old objects are planar but ConsolidatePlanar fails. The new locus is in the correct X/Y position but not aligned with the rotated polygon ie Z direction is vertical. I can do what I want with vector routines but thought ConsolidatePlanar might be easier. I tried reseting the new object, bounding box or 3DOrientation with now luck. As an aside, I noted when I used an oval it wasn't in the correct position when viewed from Top/Plan. Anyone had any luck?? procedure test; Var objH : HANDLE; refID :LONGINT; x1,y1,x2,y2,z2 : REAL; consolidated,planar1,planar2,btest : BOOLEAN; begin objH := getobject('testpoly'); dselectall; setselect(objH); if objH <> NIL then begin refID := GetPlanarRef(objH); GetPolyPt(objH,1,x1,y1); btest := PlanarPtTo3DModelPt(refID,x1,y1,x2,y2,z2); locus(x2,y2); {OvalN(x2,y2, 1, 0, 50, 50);} consolidated := ConsolidatePlanar(objH,LNewobj); {align new object with existing object??} planar1 := getObjectVariableBoolean(objH,1161); planar2 := getObjectVariableBoolean(LNewobj,1161); message(planar1,' ',planar2,' consolidated ',consolidated); end; end; run(test); consolidate planar test VW2020.vwx
  5. As an aside I found some code for handling euler and quaterion rotations which I'm trying to figure out. As far as I can tell 3D rotations in VW code are world based which doesnt help if you want to rotate an object around it's local orientation. Find attached a zip file with the main python code being 'pyrotation.py' which needs numpy loaded. pyrotation.zip
  6. I had a go at converting python code for vectors back in 2016 see attached. I never really used the code as I can't guarantee that the vector python file will exist in all settings. It may be of use. Also units in VW python are not really handled as in Vectorscript ie 20mm in code will be automatically converted to the current units - not so in python. Find attached a go at handling automatic conversion. PS I couldnt upload .py files so I had to rename files below as .txt files. Just rename back to .py vwvector.txt vwunits.txt
  7. Just to say I successfully loaded numpy "1.18.5 cp35" in VW2021 via DomC's node and copied the folder "Python Externals" back to folder ...Appdata/Roaming/Nemetschek/Vectorworks/2020 I also successfully ran script below import numpy as np a = np.asarray((1,0,0,0,1,0,0,0,1)) vs.AlrtDialog(str(a)) I can now learn/try out some open source python code for Euler/Quaterion rotations.
  8. I tried running DomC's node "Install numpy" on it's own and got an error "module numpy cannot be downloaded". Running VW 2020 SP6 on PC I checked the file path from https://pypi.org/project/numpy/1.17.4/#files and copied link to check and it matched the node entry below: numpy = 'https://files.pythonhosted.org/packages/25/71/37628d7654da4a539f33497c9d9d6713d2bb3c9e35638776b3eea38ca04a/numpy-1.17.4-cp35-cp35m-win_amd64.whl' I even tried pasting into a browser which allowed me to download ".whl" file. I tried alternative pre path "https://pypi.python.org/packages" - same error I even tried (as VW2020 uses Python 3.5) https://files.pythonhosted.org/packages/ed/09/ff8f529a5548ff788765f66a81ef751130f26f8c7d517e94d3dbf3ba1ed5/numpy-1.18.5-cp35-cp35m-win_amd64.whl I'm kind of stuck
  9. Thanks to Kostadin Ivanov - "The problem is that at the moment the function ResList_ActFolder and ResList_Filter cannot be used in one script. use only ResList_Filter" The previous reslist version has been modified to be equivalent to the first version "setactivesymbol.txt" and uses the resource browser interface. It refers to symbols in the active document. Alternatively use ResList_ActFolder if you are happy to display symbols in the specified folder and all symbols in any nested symbol folders. The root folder is ResList_ActFolder(fID,'') setactivesymbol_reslist v2.TXT
  10. A follow up. I've got a dialog working using "ResList_" functions/procedures - see attached. The only drawback is the selected folder includes symbols in that folder and all symbols in any nested folders which may be what you want. In the example in the first post I only display symbols in the selected folder and ignore nested folders. I was hoping to use ResList_Filter( uniqueID:STRING; callback:PROCEDURE) ; to show only symbols in the selected folder. I have established that the callback is a function which I thought would be of the form: function chksyms(symH : HANDLE) : BOOLEAN; Var foldH : HANDLE; begin foldH := getobject(foldname); chksyms := (getparent(symH) = foldH); end; ResList_ActFolder(fID,foldname); ResList_Filter(fID,chksyms); Unfortunately this doesnt seem to work. Anyone have any ideas on the form of the callback? Using ResList procedures/functions certainly make the code much simpler. setactivesymbol_reslist.txt
  11. Just a note - I found out how to use uniqueID - see below. I just need to investigate further. procedure test; Var fID : STRING; itemName : STRING; onlyCurrentDocument,searchOnline, skipCurrentDocument : BOOLEAN; begin (* with settings Top level symbols Symbol-1 Symbol-2 Symbol folder Folder-1 Symbol-3 Symbol-4 Symbols in order of creation *) fID := CreateUUID; ResList_Init(fID, 16); ResList_ActFolder(fID,'Folder-1'); {returns Symbol-3 in ResList_SelFAvail} {first available item in the resource popup} ResList_SelFAvail(fID,itemName,onlyCurrentDocument,searchOnline,skipCurrentDocument); message(itemname,' ',onlyCurrentDocument,' ',searchOnline,' ',skipCurrentDocument); end; run(test);
  12. That's what I was trying to establish - that "ResList_" procedures were not applicable to dialog boxes - however see below. So if they relate to the Resource Manager where does the uniqueID:STRING come from - or is the uniqueID set from a call to "ResList_Init" There is a call ResList_DlgInit( uniqueID:STRING; dlgID:INTEGER; ctrlID:INTEGER) ; which says Use this call during dialog initialization to associate a popup control or resource popup and initialized by the ResList_* calls of the uniqueID identifying the resource list data. The problem is there are no examples in the "Script Function Reference" Thanks anyway.
  13. For processing resource lists, has anyone tried using the procedures begining with "ResList_" ie PROCEDURE ResList_Init( uniqueID:STRING; objectType:INTEGER) ; I'm trying to figure out where I can get a control's "UniqueID" say for a reference to a "CreateThumbnailPopup( dialog, ksymbolpop);" in a scripted dialog. Controls are normally referenced by number. I'm wondering if the "ResList_" procedures relate to only controls shown in the object info palette for PIO's. I have a working dialog version using "symID := BuildResourceList(16,0,'',numSyms);" but was wondering if there is a better way. See the old school method shown in a prototype scripted dialog below setactivesymbol.txt
  14. Thanks. Managed to get things working.
  15. Marissa did a quick test. I tried using the #COMMAND line ie using [UsrLib] which failed with message dialog "The referenced file was not found" I then tried the full path to the file - see attached image - got the same message. The file does exist (on PC) - see below Will keep on trying. Could it be a case sensitive issue with .PY instead of .py
  16. Thanks. I did all of the above and have a functioning user library. My question was can I add nodes to the Marionette Default Library node list. If I craft some NURBS nodes for example, I don't want two locations for NURBS nodes (one set in Default library and another set in User library). I suppose I could have my own version of the Default library which would need to be updated at subsequent Vectorworks releases. Will probably just stick with my User library setup. As an aside, for a user library can the code be stored in .py files similar to Default library. Default nodes have a first line in the script: #COMMAND;READONLYREFFILE;[VWLibDef]/Input\Point2.py; Is there an equivalent path to "VWLibDef" for user nodes (for example UserLibDef)
  17. I have a bunch of nodes which I would like to embed in the standard Marionette tool list. I understand the standard nodes are stored in (PC) "Program files/Vectorworks 2018/Libraries/Defaults/Marionette/Marionette Default Library.vwx" I can setup a separate User defined list of nodes by placing my library file in for example "Users/<username>/Appdata/Roaming/Nemetschek/Vectorworks/2018/Libraries/Defaults/Marionette/Marionette User Library.vwx" What do I need to do to embed user nodes in the standard Marionette tool list? I did notice some folders in the user location ie Attributes$ , Math$ , Textures$ and Objects/NURB$ but I am not sure how to use/implement them. Can I create a new category ie Tools$ It's been quite interesting using Marionette as a front end to plugin objects. TIA
  18. Why not use Python equivalent of PointAlongPoly(h: HANDLE; dist: REAL; VAR ptX, ptY, ptZ: REAL; VAR tangentX, tangentY, tangentZ: REAL) : BOOLEAN; Always a good idea to check file "VWPluginLibraryRoutines.p" in user plugins folder for non documented calls.
  19. Still trying to understand Nurbs particularly how knot values work. Still cant figure out the logic for knot values in all cases - see below (might help others understanding). Please comment if the information is incorrect. I have also noticed when I "Export to script" a nurbs curve with more than 1 piece (ie from NurbsCurveGetNumPieces and with different degree values), if imported (via the script) a nurbs curve is created for each piece. There doesn't seem to be a way of creating (via script) a multi piece nurbs curve as far as I can tell. To solve my problem, I think I will have to convert the (mutli piece) nurbs curve to 3D polygons (one for each piece, grouped), create/modify the 3D polygons and convert back to nurbs. I need the nurbs for internal workings of path based plugins.
  20. I am trying to shorten a nurbs curve. There is an "ExtendNurbsCurve" function but no shorten option. I can move the start point of a nurbs curve with the following code curveH := CreateDuplicateObject(srcH,NIL); if (startoffset > 0) then begin curvelen := hlength(srcH); inPercentOfLength := startoffset / curvelen; if GetPointAndParameterOnNurbsCurveAtGivenLength(curveH,inPercentOfLength,px,py,pz,outParam,outIndex) then begin NurbsSetPt3D(curveH,0,outIndex,px,py,pz); resetobject(curveH); end; end; The problem is with getting the curve alignment correct. I assume I have to set the correct knot values for curve vertex points 0 and 1 with NurbsSetKnot(objH,curveH,0,0) and NurbsSetKnot(objH,curveH,0,1). I can get the existing knot values with NurbsKnot(srcH,curveH,0,0) and NurbsKnot(objH,srcH,0,1) . The question is how will the knot values change - what is the relationship? TIA Bill Wood
  21. That's the problem solved. Thanks vey much. Bill Wood
  22. Marissa, I loaded your script into my VW file - see attached. Weird, I still cannot get it to run. The VW file has popups which do run. I am on Windows 7 Professional SP1 and VW 2018 SP1. Previously, I pretty much made the same sort of edits as your version. angle test.vwx
  23. Marissa, I tried your suggestions but still cannot get any output ie from Marionette.PortOut('Type') even with debug set. I tried various things including merging the content and params classes, replacing the .nodename and .nodedesc with fixed strings and even externally building the getcontent() full string and embedding as a fixed string. I even upgraded Vectorworks 2018 to SP 1 and set Marionette preferences>Cache Last Run in Debug On and Off. I have the feeling that Marionette.WidgetType.Popup does not like long lists. I also understand that by default the popup widget returns a number relating to the selected item from the list. Can you try at your end to see if you can get it to work - it might be my VW installation.
  24. Thanks Marissa. I managed to get the popup filled with content from a standard plugin data file - see below. For some reason I cannot get any output from the node ie self.Params.sectionsize.value = sectionType Tried passing the output to an alertdialog node - nothing. Is it the definition of class content before @Marionette.NodeDefinition causing the problem. import os class content: nodename = "Angle-Metric" nodedesc = 'Select an Angle-Metric section size' def getcontent(): fref = os.path.join(vs.GetFolderPath(20) , 'Angle-Metric.txt' ) content = [] if os.path.exists(fref): f = open(fref) line = f.readline() # First line not used line = f.readline() while line: sline = line.split('\t',1) content.append(sline[0]) line = f.readline() f.close() else: content = ['Undefined'] return content @Marionette.NodeDefinition class Params(metaclass = Marionette.OrderedClass): #APPEARANCE #Name this = Marionette.Node( content.nodename ) this.SetDescription( content.nodedesc ) #OIP Controls sectionType = Marionette.OIPControl('Section Type', Marionette.WidgetType.Popup, 0, content.getcontent() ) sectionType.SetDescription( "List of valid section types" ) #Output Ports sectionsize = Marionette.PortOut('Type') sectionsize.SetDescription( "The resultant section definition" ) #BEHAVIOR def RunNode(self): #inputs sectionType = self.Params.sectionType.value #outputs self.Params.sectionsize.value = sectionType
  25. Trying to tie some of my tools into Marionette. Before diving in further, is it possible to dynamically fill a popup controls choice content from say a text file? Can I add a function to class Params and reference in the OIPControl definition (ie this.getcontent('options.txt')) - see below (example from Marionette website) TIA Bill Wood @Marionette.NodeDefinition class Params(metaclass = Marionette.OrderedClass): this = Marionette.Node( 'Add' ) a = Marionette.PortIn( 0 ) b = Marionette.PortIn( 0 ) out = Marionette.PortOut() k = Marionette.OIPControl( 'Multiplier', Marionette.WidgetType.Real, 1) p10 = Marionette.OIPControl( 'Popup', Marionette.WidgetType.Popup, 0, ['choice 1', 'choice 2']) def RunNode(self): sum = self.Params.a.value + self.Params.b.value self.Params.out.value = sum * self.Params.k.value
  • Create New...