Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by tbexon

  1. Hello All I'm pretty sure I know the answer to this already... BUT is there anyway BuildResourceListN (or any of the similar BuildResource command) can access a VW drawing of an earlier version? (e.g Active Drawing is in 2022, and target drawing is 2021) Everytime I try this it just fails to import anything. Which I suppose makes sense, but I was hoping for the sake of cross version plug-in compatibility there may be a solution (other than the obvious convert the target drawing to the required version)? Thanks in Advance!
  2. Following on from this, a question about the actual plug in files themselves (VSM,VSO etc). Should these be backwards compatible with previous VW versions? Or do I need to distribute them in the oldest version I want to support and then when the user first runs the command it will automatically update it to the latest version?
  3. Thanks Josh, When you say the Data Folder do you mean /Plug-ins/Data or /Plug-ins/Common/Data? Given that vs.GetFolderPath() has an attribute for Common/Data but not /Data I should probably use the Common folder?
  4. So I was doing some bug hunting within one of my plug ins, and I seem to be getting some unexpected results from the vs.FindFileInPluginFolder() function. I'm using the function to retrieve the filepath for a file within my plug ins folder, which works absolutely fine. Where I'm running into problems is when I'm trying to handle a situation where said file does NOT exist... Below is the test code i'm using: import vs ok,path = vs.FindFileInPluginFolder('FileName.ini') if ok: # If File Exists vs.AlrtDialog("ok") else: # If File Does NOT Exist vs.AlrtDialog("no") The problem I seem to be running into is that the ok Boolean keeps returning True even when the file is definitely not present within the Plug Ins folder. First I thought it was still just cached in VW memory somewhere, so tried the old restarting VW trick. Same result. Eventually I noticed that I had another File called "FileName.vso" in the plug ins folder. a bit of experimentation later yielded these results: When FileName.ini is NOT present within Plug Ins Folder, but FileName.vso IS present: FindFileInPluginFolder('FileName.ini') Returns True FindFileInPluginFolder('RandomName.ini') Returns False FindFileInPluginFolder('FileName.randomfileextension') Returns True So from this it would suggest to me that FindFilePluginFolder command ignores file extensions and just looks for the File Name. Is this working as intended? The Function reference does say it searches for File Name, but then the example further down has an extension attached to it, and I believe it's fairly common practice within most filename/path related programming functions to take the extension into account? If this is working as intended does anyone have a nice workaround for dealing with same file names but different extensions. I was thinking I could probably do something with vs.GetFolderPath(-2) and some os.path commands... I realize the simplest solution is just to make sure every file has a unique name, which is probably what i'll end up doing, but thought i'd see if anyone has any helpful insights before I go digging through all my code for every reference to this particular file...
  5. I thought as much, are you aware of any handy guide or helpful threads that may point me in the right direction? (I can't say i've delved too far into the SDK yet)
  6. Thanks Yasen, that makes sense. Quick follow up question, is there a way (via Vectorscript) to add parameters to the Lighting Device Parameter worksheet?
  7. I have not seen the notes, do you have a link to them? I had a search on developer.vectorworks.com for them but it doesn't seem to return any results? I think what i've discovered is that using Circles as my testing object, was a poor choice, from what I can gather FindObjAtPt_Create will only return a circle object if the radius intersects with perimeter of said object. Luckily with both PIOs and Rectangles (which are the two main object types i'm interested in right now) the function does return any part of the object that is within the radius.
  8. Thanks Josh I've been having a play with FindObjAtPt_Create, and I'm struggling to understand how the radius parameters works. I've drawn a circle with a radius of 20000mm, and placed a number of objects within it and outside (see below image), however the results I'm getting are not as expected. If I set the functions radius to 20000 it still picks up objects slightly out of that radius, for instance the object with the red circle around it gets picked up even though the distance from centre (which is the location i'm selecting each time for the starting co ordinates) is 22608. Strangely even though it's picking up objects further away than the overall Circle, it's not picking the containing circle itself... Also from what I can tell I need to set the radius large enough to encompass the entire object for it to be included in the list. I've adapted the code from the example on the wiki as below: import vs def PickPointCallback(pt): startContainer = vs.Handle(); list = vs.FindObjAtPt_Create(startContainer, 1, 0, pt[0], pt[1], 20000) cnt = vs.FindObjAtPt_GetCount(list) vs.AlrtDialog("Initial Co ords: "+str(pt[0])+ ' '+str(pt[1])) for i in range(cnt): hObj = vs.FindObjAtPt_GetObj( list, i ) x2,y2 = vs.HCenter(hObj) d = vs.Distance(pt[0], pt[1], x2, y2) vs.AlrtDialog( 'Index: ' + str(i) + ' Obj Type: ' + str(vs.GetTypeN(hObj)) + ' Dist: '+str(d) ) vs.FindObjAtPt_Delete( list ) vs.GetPt( PickPointCallback )
  9. Hi All Apologies if this has been covered somewhere else, though I'm struggling to find any similar topics, could just be i'm not using the right terminology. I'm trying to recreate the functionality similar to that of Spotlight Hanging Positions and their ability to automatically assign Positions to Fixtures that overlap with the HP. e.g: I want to have a "base" PIO and when I insert a different PIO (Say PIO 2) into the drawing, PIO 2 calculates if it overlaps with any "Base" PIO's and if so queries said "Base" object and retrieves some information from it. The bit I'm struggling with is how to go about working out what objects overlap with said PIO 2. I suppose I could get PIO 2's bounding box co ords and then somehow query if there are any other objects within those same Coordinates. But I though I'd ask if anyone has any better ideas before I go down this route? Thanks In advance!
  10. So I I go about this a slightly different way. I'm not saying it's the correct way, or that there aren't better ways, but it atleast works for me! To get a Lighting Device parameter I simply do a GetRField() command on the objects 'Lighting Device' Parametric Record (which as far as i'm aware is attached to all Spotlight Lighting Devices) I did a test comparing both methods, and got the same results as you with LDevice_GetParamStr not returning Inst Type, however querying the record via GetRField did return the correct results. I also confirmed that LDevice_GetParamStr does work on some fields (such as Position). (Apologies it's written in Python Script rather than Vectorscript, but the results should be the same!) import vs field = 'Inst Type' handle = vs.FSActLayer() param = vs.LDevice_GetParamStr(handle, 0, -1, field) vs.AlrtDialog("Param: {}".format(param)) val = vs.GetRField(handle, 'Lighting Device', field) vs.AlrtDialog("Rec Val: {}".format(str(val))) It is strange that LDevice_GetParamStr doesn't return certain field (and some fairly critical fields one could argue) could this be a potential bug? @JBenghiat or @K.Lalkovski Have you come across this at all?
  11. Ok cool so i can use vs.EvalStr(vs.Handle(0), 1=1) to get the localized string for True and then just compare that to the results from the records?
  12. So I have an event enabled PIO with a couple of Boolean parameters. Up until now I've been using the below to get the parameter's current state by converting the string to bool, as GetRField returns strings, which I thought was fine. show_weight_bool = strtobool(vs.GetRField(objectHand, objectName, "Show Weight")) HOWEVER An unexpected bug has come up, from someone who tried this plug in on a non english version of Vectorworks (it was German in this particular instance). The error thrown from the strtobool function, was: ValueError: invalid truth value 'wahr' From what I can gather, the GetRField seems to be returning the localized value for the checkbox (in this instance 'wahr' which I'm given to understand from a quick google means True), rather than, as I was hoping just a pythonic True, but in string form. Firstly is this working as intended? I presume so as it would make sense that if you were extracting the string you would want said string to be in the localized language rather than always in english... SO does anyone have any clever ways around this? I've been hunting through the Function Reference but nothing obvious has jumped out at me, I was hoping it might be as simple as there was a vs.GetRBool or something similar that returns a BOOLEAN value, but so far I can't find it (I'm certainly not saying it's not there, just that I have not been able to locate it!) I'm hoping there's a super obvious answer that I'm just missing here!
  13. val = vs.GetLBHeaderTextWidth('Some Text', False) vs.Message(val) I just tried this on win10 in VW 2021 SP2 (574483) 64 bit and it crashed my VW straight away.
  14. I'm running Windows @domC Following you're suggested process, I got the same results. Strangely when I look at the environment paths within the VW Python environment, using sys.path(), "Python Externals" is in there. I'm still having issues with my specific package (pyOpenSSL) DLL load failed while importing _openssl: The specified module could not be found. If I try running with a clean 3.8 interpreter outside of VW it runs fine, same as within 2020.
  15. There is a work around. Rather than writing the script within the Plug in script itself write it in a YourScriptName.py file located in the same directory as the .vsm file within you're plug in folder. Then, within the Plug In Script, you just need to import the other script: import YourScriptName The .py File is still easily read so the next step, when you're ready to encrypt and distribute said plugin, is to swap the .py for the compiled python file( .pyc), which is located within the "__pycache__" folder of whatever directory the .py file is stored in. (for more info on .pyc files check out this) As long as you put the .pyc in the exact same location as where the .py was, it should function exactly the same. This still isn't perfect. Compiled files can still be de compiled but this requires a much higher level of knowledge than simply opening in a text editor! For more general info on encrypting python plug ins check out this thread
  16. So I just moved all my plugins across to VW 2021, and I'm now getting Import Errors for Plug ins that use the External Package PyOpenSSL. The error i'm getting is: DLL load failed while importing _openssl: The specified module could not be found. I've tried both deleting and reinstalling PyOpenSSL via VerifyOrGetLib, aswell as simply copying the working "Python Externals" from 2020 Plug in folder, neither seems to solve the issue. Pip does seem to be successfully installing PyOpenSSL, with the most up to date versions of it's dependents. I'm aware that with 2021 the Python distribution has been upgraded to 3.8, so I'm wondering if something to do with that could be causing this? Checking the docs here it is compatible with 3.5+ I don't believe it's an issue with the package itself as if I install it, and run from my local copy of Python 3.8 via IDLE it imports fine. Any thoughts would be greatly appreciated! This is rather where my knowledge reaches it's limit!
  17. So from my understanding the when you install the ZIP file it copies all the contents of the Zip FIle into the Users Plug in folder, so could you not package the Rource file within the .Zip then use vs.GetFolderPath() to get the users plug in folder, aswell as Library Folder and use shutil.move to move them from plugins folder to required folder. import shutil import os import vs def manualPackageInstall(foldername): shutil.move(os.path.join(vs.GetFolderPath(-2) , foldername ), # Path to Folder to move in plugin Folder os.path.join(vs.GetFolderPath(-13) , foldername)) # Path to Libraries in User Folder Something like that?
  18. I know this has been discussed in several threads before, but after extensive reading and experimenting I'm still clearly missing something. I'm trying to get the handle for a user selected object within an event enabled Plug in Tool. e.g User clicks button in OIP -> Highlight mode is turned on and user clicks on desired object -> Handle is returned and code continues onwards. I've created the event enabled object, and added the button to the OIP fine, and used TrackObjectN() to allow highlighting of only relevant objects. The issue I'm running into is actually getting the handle of the object. I understand that TrackObjectN is only highlighting, and not a selection mode, but from my reading of the wiki for TrackObjectN: def vs.TrackObjectN(traverseType, callback): return (outObj, p) It should return the handle and Co Ords whenever the user mouses over or clicks an object that relates to the criteria. e.g if the last action is a click on the desired object it should return that handle, or atleast it's co ordinates from which I could then use PickObject to get the handle. In reality when I try: outObj , p = vs.TrackObjectN(0, trackObjCallback) It throws a TypeError 'NoneType' object is not iterable. Given that when I try: vs.TrackObjectN(0,trackObjCallback) It functions as expected, but without returning any handle or co ordinates i'm guessing either i'm using this wrong or it doesn't actually return such information. I'm wondering if I need to try using vstGetEventInfo to look for a mouse button click and then capture the mouse's current Co Ordinates, however after searching "MiniCadHookIntf.h" I couldn't obviously see any obvious constant for a mouse click. TL/DR I'm trying to capture a handle for a user selected object, within a event enabled object and have clearly missed a step somewhere! Any help or nudges in the right direction would be greatly appreciated! Relevant parts of current code pasted below: import vs def makeOIP(): link_pos_button_id = 1234 # User Button Id theEvent, theEventData = vs.vsoGetEventInfo() # Gets Object Event info if theEvent == tb.Constants.kObjOnInitXProperties: # If the event is the initialisation of the object ok = vs.SetObjPropVS(tb.Constants.kObjXPropPreference, True) # Allows for creation of custom OIP?????? ok = vs.SetObjPropVS(tb.Constants.kObjXPropHasUIOverride, True) # Custom OIP Overrides standard UI vs.vsoInsertAllParams() # Inserts all Parameters into OIP displayString = "Link to HP" # text for button result = vs.vsoAppendWidget(tb.Constants.kWidgetButton,link_pos_button_id,displayString,doesNothing()) # Add Button to OIP if theEvent == tb.Constants.kObjOnObjectUIButtonHit: # If the event is a button being pressed if theEventData == link_pos_button_id: link_to_hp() # Function to run to allow user to select object. if theEvent == tb.Constants.kResetEventID: # If Object is reset # Code to run on object reset def doesNothing(): pass def trackObjCallback(h,x,y): HPHandle = vs.PickObject((x,y)) if vs.GetTypeN(h) == 86: return True def link_to_hp(): vs.TrackObjectN(0, trackObjCallback) outAction, outMessage1, outMessage2 = vs.vstGetEventInfo() #vs.Message(str(outObj)) makeOIP()
  19. Have a look at this thread, i'm not sure how much experience with python you have, but basically VW comes with Python 3.5 packaged within the VW environment, you ~could~ download python 3.6 and manually replace it within the VW installation, HOWEVER I wouldn't recommend this, as you have no way of knowing how that may affect the stability and functionality of Vectorworks itself which, as I understand it, also utilizes said python installation. I believe python may be getting upgraded in an upcoming future release, however @Vlado is the man to answer that.
  20. Thanks @Andy Broomell I had looked through that folder, don't know how I missed that!
  21. Ok this one may be a bit of a morph of scripting and more general VW user question. I've made use of the predefined dialog vs.AlertInformDontShowAgain within one of my scripts, which works absolutely fine, however now that i've checked 'don't show again' to test that it did do as advertised I can't seem to find a way to get that alert to show again. Is there a settings dialog or file squirreled away somewhere with a list of all suppressed dialogs? Looking at the python example for the function is looks like the dialog is stored somewhere, but I can't for the life of me find any reference to where! def Example(): arrayText = ('DontShowDialogAgainCategory', 'DontShowDialogAgainItem', #{Should be unique for every AlertInformDontShowAgain} '') # python uses a tuple vs.AlertInformDontShowAgain('This is an invalid item.', '', False, arrayText); Example()
  22. Thanks! You're script worked as expected! @Pat Stanford You were correct that NextObj(Fin3D) does return the Symbol for the Hanging Position, or interestingly the CustomObjectProfileGroup should the HP be made of multiple pieces of Truss Objects, which is extremely handy! I thought I was going to have to calculate the individual dimensions for each truss object and add them together for those kind of HPs! It's a shame that my method didn't work, would have been quite a simple solution to what I was trying to achieve! Luckily thanks to you're help, I found a different method that works just aswell, just with a few more lines of code! Just for my own understanding does anyone know why the Co Ordinates don't update until after the script has run? I assume it's not so much that the geometry is not updating but instead whatever script Spotlight needs to run to recalculate the object after changing the record, doesn't run until the users script has finished?
  • Create New...