Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by MullinRJ

  1. OS 10.15.x is the minimum for VW 2022. I am using a MacMini (late 2012) and it runs well, even with the "under powered" onboard graphics chips (also, I don't do rendering). One caveat - OS 10.15.x does not run 32 bit applications any more, so if you have old software you need to use, consider that before upgrading your OS. Raymond
  2. Josh, Based on your last comment, this may not be related, but another way to get a locus is to delete a SymDef when that Symbol is still in the drawing. You mentioned Locus which I interpret as a 2D Locus. Deleting a SymDef would leave 3D Loci in the drawing. If you are getting a 2D Locus, then this is not the reason why. Raymond
  3. Hi @Pat Stanford , I've used that call in another script and it worked nicely. The following script is not a 2-liner, but it's still a simple approach. With no object selected, the dialog opens with the active class selected. For the case of editing an object's class, you just need to change the active class before opening the dialog, then restore the active class when done. For a more ubiquitous experience, Waldo's help must be enlisted. @The Hamma , This script should do what you want. If not, please write back. PROCEDURE EditClass; { Open the Organization Dialog and select the class of the first selected object, { or select the Active Class, if no object is selected. } { 24 Jun 2021 - Raymond J Mullin. } { THIS SCRIPT WAS ONLY WHIMSICALLY TESTED. NO WARRANTIES ARE EXPRESSED OR IMPLIED. } { Feel free to modify this script 'til your heart's content. } VAR H :Handle; ActiveCl, aClass :String; BEGIN ActiveCl := ActiveClass; { save current Active Class } aClass := ActiveCl; H := FSActLayer; if (H <> nil) then aClass := GetClass(H); { get class of selected object } NameClass(aClass); { set class to edit before dialog opens } DisplayOrganizationDialog(1); { show Classes tab } NameClass(ActiveCl); { restore active class to original state } END; Run(EditClass); Raymond
  4. @Sloader , From the function's description in the Script Reference there are no arguments, so you are not missing anything there. This function emulates the menu command Import Single DXF/DWG... There does not seem to be a command that will open DXF files without system dialogs opening. Raymond
  5. Hi Malcolm, After looking at the text file you posted, I surmised all the values were Z values and the XY values were implied from the position of the numbers in the data array - 500 values per row, and 500 rows. I then cobbled together a quick script that generated a Locus3D() VectorScript command for each of the values. My assumption was that one row of data from the file had one Y-value and 500 X-values. The next row of data had the next Y-value and the same 500 X-values. Two FOR loops generated all of the intermediate values and assembled the Locus3D() statements. When done I had a text file with 250K lines which I imported into a blank VW file. If my assumptions about the X and Y positions are incorrect, then the Locus array may be flipped. Please inspect the file carefully before using the data. VW 2021 is a bit slow these days when importing large VS files, so I typically use VW 2009 to do the import, which is very quick in comparison, and then open the file in VW 2021. With a little more finesse the script could be written to directly create the Loci in VW, but speed issues become significant when large amounts of data are generated. This can always change and I haven't tested it recently, but it has been an issue for me in the recent past, which is why I prefer writing VS text files and importing them into older versions of the software. This approach is still faster than working directly in newer versions of VW. HTH, Raymond
  6. @Malcolm Woodruff , If you want to see what your data looks like in VW, I've attached a VW 2021 file below with the data imported from your file above. Since I don't know the finer details of the LIDAR file format, I made some assumptions, such as the X values increase from left to right, and the Y values increase from top to bottom as you read your file. If I got the directions wrong, the map may be flipped from what is shown. Also, this file is NOT georeferenced, so you may need to do some more editing. As to graphic performance, it actually navigates faster in VW 2009, but most people probably don't have the older versions loaded. It is possible that it will perform better on your machine than mine as I'm running a macMINI from 2012 with onboard graphics chips (which is nothing I should be bragging about.) That said, it works well enough for what I currently need. Your file only contains 250K Loci, so if you plan to view larger data sets, be warned, it only gets slower. HTH, Raymond sz6090_DSM_2M v2021.vwx
  7. @AlHanson , As you've already discovered, plug-in objects execute quite differently from menu commands. To fully appreciate what is going on behind the scene you should trap each PIO event and display it in an Alert Dialog, just like you displayed the events being presented to your Modern Dialog. In your PIO Event loop, place an Alert Dialog at the top of your event loop just after the lines that return the Custom Object Info, the Event Info, and the New Object status as shown here: CR = chr(13) # define Carriage Return character NIL = vs.Handle() # define NIL ... # Beginning of Event Loop (gFlag, gPIOName, ghParm, ghParmRecord, ghWall) = vs.GetCustomObjectInfo() (gTheEvent, gMessage) = vs.vsoGetEventInfo() gNewObj = vs.IsNewCustomObject(gPIOName) vs.AlrtDialog(vs.Concat('Event = ', gTheEvent, CR, 'Message = ', gMessage, CR, 'New Obj = ', gNewObj, CR, 'Object Handle = ', ghParm != NIL)); if (gTheEvent == kObjOnInitXProperties): # kObjOnInitXProperties = 5 elif (gTheEvent == kParametricRecalculate): # kParametricRecalculate = 3 elif (): # etc. - other events # End of Event Loop Also, be aware that the events your PIO will receive are subject to the flags you set with the vs.SetObjPropVS() function, usually in event kObjOnInitXProperties (5). Setting all of the relevant flags is tricky, at best. The best way to get started is to copy existing examples. Trial and error is also your friend. A list of the Plug-in Object Extended Properties descriptions can be found in this SDK file: .../SDK/SDKVW(<VW build number>)/SDKLib/Include/Kernel/MiniCadHookIntf.h HTH, Raymond
  8. @AlHanson , I would have thought someone would have responded before now, but since no one has, here is my follow up. If you've already solved your problem, please read no further. Otherwise, try the following code snippet. To make your example work I had to add "1" to the value returned in the "data" variable. I did not dig deeply into this and I quit messing with it when it finally worked. You may want to examine this further. Remove the "+ 1" to see what happens with your last symbol icon. Also, I added an IF clause in your "item == SetupDialogC" code to accept the first symbol after the popup is populated. If you don't click in the popup, "bSymbol" is never set to True, which makes it kind of hard to accept the first symbol without a lot of extra clicks to change the popup selection then change it back. Word of caution – The vs.BuildResourceList() command and the other three similar calls (vs.BuildResourceList2, vs.BuildResourceListN, and vs.BuildResourceListN2) are quite persnickety. You have to guess a lot to get what you want. Read the function descriptions carefully. This example works because there is only one file in the specified subfolder. Not sure what happens if there are multiple files in the subfolder and you only want to examine one file. I'll leave that to you if it ever becomes relevant. Lastly, take note of my use of GLOBAL variables. Because the Dialog_Handler() code gets executed repeatedly when the dialog is open, any change made on one pass that is needed for future passes has got to be GLOBAL to that routine, otherwise values will be lost before the dialog finishes executing. import vs debugMode = False btnOK = 1 btnCancel = 2 kThumbnailPopup = 101 SetupDialogC = 12255 LibraryFolder = -13 # "Libraries" folder in VW app folder resourceType = 16 # Symbol Definitions symList = 0 iSymbol = -1 bSymbol = False def Dialog_Handler(item, data): global symList, iSymbol, bSymbol if debugMode: text = 'Running Dialog Handler. Values Returned:\r\ritem: ' + str(item) + ' | data: ' + str(data) vs.AlertCritical('DIALOG HANDLER', text) if item == SetupDialogC: subPath = "Objects - Building Equip_Appliances" (symList, numItems) = vs.BuildResourceList(resourceType, LibraryFolder, subPath) if (numItems > 0): # select the first symbol in the popup bSymbol = True iSymbol = 1 for i in range(numItems+1): name = vs.GetNameFromResourceList(symList, i) #if name[:7] == 'zNested': # continue vs.InsertImagePopupResource(dialog, kThumbnailPopup, symList, i) if item == kThumbnailPopup: # Interaction with Pulldown Menu bSymbol = True iSymbol = data + 1 if debugMode: vs.AlertCritical('Clicked something in popup, setting iSymbol to: ', str(iSymbol)) if (item == btnOK) and bSymbol: # OK Button Pressed and symbol has been selected hSymbol = vs.ImportResourceToCurrentFile(symList, iSymbol) vs.Symbol(vs.GetName(hSymbol), (0, 0), 0) if debugMode: vs.AlertCritical('OK BUTTON!', 'iSymbol: ' + str(iSymbol)) # End of Dialog_Handler def CreateSampleDialog(): global dialog dialog = vs.CreateLayout('Add Choice Sample', 1, 'OK', 'Cancel') vs.CreateThumbnailPopup(dialog, kThumbnailPopup) vs.SetFirstLayoutItem(dialog, kThumbnailPopup) vs.RunLayoutDialog(dialog, Dialog_Handler) # End of CreateSampleDialog vs.SetPref(412, True) # PersistentPythonEngine Pref CreateSampleDialog() HTH, Raymond
  9. @AndreaWok , I exported the VW2013 files to DWG, then saved the files in VW 2021 format, so you can view them in newer VW Viewer versions for years to come. MINICAD 2 DWG & VW2021.zip HTH, Raymond
  10. Hi @AlHanson , Ok, easy question first. Your unknown constant is issued when you close the Popup window. const Sint32 kThumbnailPopupClose = -12613; You can find it documented in: "MiniCadCallbacks.X.h", which can be found in the same directory as "MiniCadCallBacks.h". As to your other issues, I'll have to play with it more to understand. Perhaps someone may beat me to it. Gotta run now. More later, if needed. Raymond PS - Are you getting your popup loaded? I do not see any icons, even though the file you mention is in my application folder. Also, what version of VW are you using and on what platform. A Forum signature would help.
  11. Sam, For starters, the ListBox is 0-based, so to select all items you will need to count from 0 to n-1. SelectChoice() seems to only select one item at a time, so only the item with the last value of index will be selected. In your example, item NumLLs is outside the range of choices. Use NumLLs-1 to select the last item. I am not sure how SetSelectionRange() is supposed to work. I get the same results as you. If there is a VS command to set multiple selections, @_c_ is probably your best bet for a quick answer. Raymond
  12. I especially like your last tip. Raymond
  13. Hi @Andy Broomell , Yes, with some minor changes to the preceding script, the following script "should" convert the entire Symbol Library, but there are no guarantees. I will leave it to you to tell me if it works. It's 2 AM and I only whimsically ran this script through its paces, meaning I tried it once, it ran, and I posted it below. I did test it on Symbols stored in Folders and it appears to work. Try it on COPIES of your working files several times before committing to your real work. Procedure AllSymbolContentsNotByClass; { This script converts every object inside all symbol definitions } { to REMOVE the SetByClass option for all object attributes. } { 24 March 2021 - Raymond Mullin } { This has been less than lightly tested. Pat Stanford recommends you: } { "Use this on a copy of your primary file. No warranty expressed or implied. } { Use at your own risk. Do not operate heavy machinery while using this script." } { I concur. } function RemoveSetByClass(SymH :Handle) :Boolean; Var H: Handle; B, visibility :Boolean; thickBasis, angul, Opasity, PenOp, FillOp :Integer; style, Red, Grn, Blu :Longint; size, wydth, thickness :Real; Begin if (GetTypeN(SymH) = 16) then begin { if it is a Symbol Definition } H := FInSymDef(SymH); while (H <> Nil) do begin SetLW(H, GetLW(H)); SetLSN(H, GetLSN(H)); GetPenFore(H, Red, Grn, Blu); SetPenFore(H, Red, Grn, Blu); GetPenBack(H, Red, Grn, Blu); SetPenBack(H, Red, Grn, Blu); SetFPat(H, GetFPat(H)); GetFillFore(H, Red, Grn, Blu); SetFillFore(H, Red, Grn, Blu); GetFillBack(H, Red, Grn, Blu); SetFillBack(H, Red, Grn, Blu); if GetObjBeginningMarker(H, style, angul, size, wydth, thickBasis, thickness, visibility) then B := SetObjBeginningMarker(H, style, angul, size, wydth, thickBasis, thickness, visibility); if GetObjEndMarker(H, style, angul, size, wydth, thickBasis, thickness, visibility) then B := SetObjEndMarker(H, style, angul, size, wydth, thickBasis, thickness, visibility); { For VW 2016 and earlier, use the following for Opacity: } { GetOpacity(H, Opasity); } { SetOpacity(H, Opasity); } { For VW 2017 and later, use the following for Opacity: } if GetOpacityN(H, PenOp, FillOp) then B := SetOpacityN(H, PenOp, FillOp); H := NextObj(H); end; { while (H <> Nil) } ResetObject(SymH); end; { if } End; { RemoveSetByClass } BEGIN ForEachObjectInList(RemoveSetByClass, 0, 2, FSymDef); SysBeep; { make noise when done } END; Run(AllSymbolContentsNotByClass); Good night, and good luck, Raymond
  14. Do you have an` import vs at the very top of your CreateData.py file? Raymond`
  15. @matteoluigi , Try this Python conversion. I used your PON='Space' suggestion for the criteria, since it simplifies the runtime. Also note that you have to declare SpaceH as a global variable, since it cannot be passed in the function's calling parameter list. This may be why it wasn't working for you. import vs # Script to test the ObjInSpace function. # 14 Mar 2021 - Raymond Mullin # GOLBALS NIL = vs.Handle() # constant for readability SpaceH = NIL # initialize variable def ObjInSpace(H1): # Return a handle to the Space object that contaons object H, or NIL if none is found. # 14 Mar 2021 - Raymond Mullin def InSpace(SpcH): global SpaceH RecH = vs.GetParametricRecord(SpcH) if (RecH != NIL): PolyH = vs.Space_GetGrossPoly(SpcH) if vs.PtInPoly(X, Y, PolyH): SpaceH = SpcH X, Y = vs.HCenter(H1) vs.ForEachObject(InSpace, "PON='Space'") return SpaceH H0 = vs.FSActLayer() SpaceH = ObjInSpace(H0) if (SpaceH != NIL): SpaceName = vs.GetRField(SpaceH, 'Space', 'Name') SpaceNum = int(vs.Str2Num(vs.GetRField(SpaceH, 'Space', 'Number'))) vs.Message(SpaceName, ' ', SpaceNum) else: vs.Message('Selected object is not contained in any Space objects in the drawing.') vs.SysBeep() HTH, Raymond
  16. @Martin Crawford , I'm not sure exactly what you did. I assume you have a MAIN.py file (I'm guessing at the name) and a Utility.py file. The import command should go at the top of the MAIN.py file, which is the file you will execute. This will enable all of the functions defined in the Utility.py file to be called from the MAIN program. import Utility # goes at top of MAIN.py If I guessed wrong about how you set it up, please explain in greater detail. Thanks, Raymond
  17. Hello @matteoluigi Pat's right, there is a typo. if ((RecH != '') & (RechN == 'Space')): should read: if ((RecH != '') & (RecHN == 'Space')): HTH, Raymond
  18. @Martin Crawford , Open the Script Editor window. At the bottom there is a button "Script Options...". Click it and you will see a path to your Marionette folder in your user folder. ADD a new path to your utility functions folder. You can have more than one .py file in that folder. Then use the import command at the top of your script to include your functions file. e.g., import MyPyFunctions where MyPyFunctions.py is your utility function file. If this isn't clear enough, someone more versed in VW Python will explain better. HTH, Raymond
  19. Hello @lilianikolova , Did you ever get these files converted? Apologies for the long delay, but I have been out of circulation for the last few months. I was able to convert your files today to VW 2021 format, but if you need them in an older version I can do that, too. I did not convert them to DWG because there are a lot of fonts in your files that I don't have on my machine. VW uses font substitution in such instances. I believe if you open the updated files on your machine then you would see the correct fonts, and your DWG conversion would look much cleaner. Please send me a PM with your email address and the version of VW you want. All the best, Raymond
  20. @matteoluigi , Sorry, I misunderstood the question and the nature of the WS functions. Here is a short Pascal script, lightly tested, that searches every Space object in the drawing and tests if the object passed to the function is inside any Space. Now the functions I posted earlier will return the correct results AFTER the new function is called which returns the appropriate Space handle. It shouldn't be too hard to Pythonize the script. As a simplification, I am using the center point of the referenced object to make the test, and not testing the object's bounding box. Feel free to modify this to your heart's content. PROCEDURE xxx; { Script to test the ObjInSpace function. } { 14 Mar 2021 - Raymond Mullin } VAR H0, SpaceH :Handle; SpaceNum :Integer; SpaceName :String; function ObjInSpace(H :Handle) :Handle; { Return a handle to the Space object that contaons object H, or NIL if none is found. } { 14 Mar 2021 - Raymond Mullin } Var SpaceH :Handle; X, Y :Real; procedure InSpace(SpcH :Handle); Var RecH, PolyH :Handle; Begin RecH := GetParametricRecord(SpcH); if (RecH <> nil) & (GetName(RecH) = 'Space') then begin PolyH := Space_GetGrossPoly(SpcH); if PtInPoly(X, Y, PolyH) then SpaceH := SpcH; end; { if } End; { InSpace } Begin { ObjInSpace } hCenter(H, X, Y); SpaceH := nil; ForEachObject(InSpace, T=86); ObjInSpace := SpaceH; End; { ObjInSpace } BEGIN H0 := FSActLayer; SpaceH := ObjInSpace(H0); if (SpaceH <> nil) then begin SpaceName := GetRField(SpaceH, 'Space', 'Name'); SpaceNum := Str2Num(GetRField(SpaceH, 'Space', 'Number')); message(SpaceName, ' ', SpaceNum); end { if } else message('Selected object is not contained in any Space objects in the drawing.'); SysBeep; END; Run(xxx); HTH, Raymond
  21. @matteoluigi , Have you tried querying the PIO record for the name and number? SpaceName = vs.GetRField(vs.FSActLayer(), 'Space', 'Name') SpaceNum = int(vs.GetRField(vs.FSActLayer(), 'Space', 'Number')) And if you need it, SpaceArea = vs.Str2Num(vs.GetRField(vs.FSActLayer(), 'Space', 'Area')) HTH, Raymond
  22. Hi @Martin Crawford , Yes. When you make a change to the first, you will have to erase the second menu and repopulate it with new values. See documentation on vs.RemoveChoice(), and vs.AddChoice(). These calls will be issued in your dialog event loop under the item number that controls the first menu. To delete the second menu, execute a loop that deletes the first item of the second menu n-times, where n is the number of items currently in the menu. Then add your new choices. HTH, Raymond
  23. Sorry, I misread your post. I see you want 3DM files, not 3DS files. I don't believe there is a canned function that supports 3DM files. You might try: vs.DoMenuTextByName('Import Rhino 3DM (3D only)', 0) This call will present an Open File dialog, same as the menu item. Not sure if this helps. Raymond
  24. @oldluke Yes, check out the Script Function Reference, either in your application folder in the HELP directory, or online at the Developer Wiki at https://developer.vectorworks.net/index.php/Main_Page and use the search function. I find the one in the HELP folder much quicker to use, but often there are more comments in the online version. Use both. FUNCTION Import3DSFile ( fileName :DYNARRAY[] of CHAR; atOrigCoords :BOOLEAN; positionX, positionY :REAL ) :BOOLEAN ; def vs.Import3DSFile(fileName, atOrigCoords, positionX, positionY):    return BOOLEAN HTH, Raymond
  • Create New...