Jump to content

Paolo

Member
  • Content Count

    88
  • Joined

  • Last visited

Posts posted by Paolo


  1. Is there someone that can test the marionette node contained in this file (it should install PIL python module in the user folder) on Vectorworks 2020 SP4 on Windows?

     

    Download PIL.vwx

     

    It worked some time ago, it does not anymore.

    Something has changed with the recent SP4 (maybe) and the VerifyOrGetLib() seems to refuse to install python modules.

    I have checked (on Mac) and VerifyOrGetLib() is identical to SP3 version (see the code in the first post).

    The bug should reside in pip3.exe, since the ret_code is 1 (what does it mean?), see code below.

    I have no way to test it by myself, cause I am on Mac (and Mac does not have this problem…)

     

    any help?

     

    @Marissa Farrell, @JBenghiat, @relume

    if sys.platform == 'win32': 
    					piploc = 'Python35\Scripts\pip3.exe'
    					pathpip = 'Python35\Scripts'  
    					cdpath = os.path.join(appfolder, pathpip)
    					cmdpip = os.path.join(appfolder, piploc)
    					wd = os.getcwd()  
    					if os.path.exists(cmd) and os.path.exists(cmdpip):
    						os.chdir(cdpath)
    						ret_code = subprocess.call([cmdpip, 'install', missingLibURL, '-t', cmd ])
    						if ret_code > 0:
    							vs.AlrtDialog('Module ', missingLib, ' cannot be downloaded.') 
    							exit_code = False
    						else:
    							exit_code = True
    							sys.path.append(cmd + '\\')
    							os.chdir(wd)
    							vs.AlrtDialog('Module ', missingLib, ' has been successfully installed.')

     


  2. I distribute a plugin written in Python that makes use of the PIL module.

    To import the module I use the Marionette function VerifyOrGetLib() as seen in some marionette examples from Marissa Farrell and others.

     

    	if platform == 2: #windows
    		PIL = 'https://pypi.python.org/packages/bb/f7/d644a9a65a25ff0bf43b7f69ce3ef9803742a5d6e438ddfc7e925c007e6c/Pillow-7.1.2-cp35-cp35m-win_amd64.whl#md5=6d62274af5c88c1cfe31c977f7531ed6'
    	else: #Mac
    		PIL = 'https://files.pythonhosted.org/packages/7d/b4/755848342213bcb5a5c570657ca21f20ebc104daf15d7847b08e18b4d2fd/Pillow-7.1.2-cp35-cp35m-macosx_10_10_intel.whl'
    			
    	if Marionette.VerifyOrGetLib('PIL', PIL):

     

    Now I am receiving messages from some Windows users saying the installation fails.

    Unfortunately I am on a Mac and cannot test it directly.

    While the directory Python Externals is correctly created inside the user folder a message is shown saying that the module cannot be downloaded.

    But the above link, if copied directly in a browser, indeed download a 2Mb file (Pillow-7.1.2-cp35-cp35m-win_amd64.whl)

     

    Here's the code of the VerifyOrGetLib() (contained in the Marionette module)

    def VerifyOrGetLib(missingLib, missingLibURL):
    	# try to install user's package
    	exit_code = False
    	appfolder = vs.GetFolderPath(1)
    	appuserfldr = vs.GetFolderPath(12)
    	
    	cmd = 'Python Externals'
    	cmd = appuserfldr + cmd
    	
    	if not os.path.exists(cmd):
    		os.makedirs(cmd)
    	try:	
    		try:
    			importlib.import_module(missingLib)
    			exit_code = True
    		except ImportError:
    			#show dialog here
    			question = 'Python module ' + missingLib + ' is not installed. Would you like to download and install it now?'
    			res = vs. AlertQuestion(question,'', 1,'','','','') 
    			if res == 1 :
    				if sys.platform == 'win32': 
    					piploc = 'Python35\Scripts\pip3.exe'
    					pathpip = 'Python35\Scripts'  
    					cdpath = os.path.join(appfolder, pathpip)
    					cmdpip = os.path.join(appfolder, piploc)
    					wd = os.getcwd()  
    					if os.path.exists(cmd) and os.path.exists(cmdpip):
    						os.chdir(cdpath)
    						ret_code = subprocess.call([cmdpip, 'install', missingLibURL, '-t', cmd ])
    						if ret_code > 0:
    							vs.AlrtDialog('Module ', missingLib, ' cannot be downloaded.') 
    							exit_code = False
    						else:
    							exit_code = True
    							sys.path.append(cmd + '\\')
    							os.chdir(wd)
    							vs.AlrtDialog('Module ', missingLib, ' has been successfully installed.')
    				elif  sys.platform == 'darwin':
    					import pip
    					import shlex
    					pos1 = missingLibURL.rfind('/')
    					pos2 = missingLibURL.rfind('whl')
    					downloadedfile = missingLibURL[pos1+1:pos2] +'whl'
    					destination = appuserfldr + downloadedfile
    					command_line = "curl -o " + '\"' + destination + '\"' + "  "+ missingLibURL
    					args = shlex.split(command_line)
    					ret_code = subprocess.call(args)
    					if ret_code == 0:
    						sys_executable_orig = sys.executable
    						sys.executable = '/usr/bin/python'
    						ret_code = pip.main(['install', destination,'-q','--target', cmd])
    						sys.executable = sys_executable_orig
    						if ret_code > 0:
    							vs.AlrtDialog('Module ', missingLib, ' cannot be installed.')
    							exit_code = False
    						else:
    							vs.AlrtDialog('Module ', missingLib, ' has been successfully installed.')
    							exit_code = True
    					else:
    						vs.AlrtDialog('Module ', missingLib, ' cannot be installed.')
    						exit_code = False
    					sys.path.append(cmd+'/')
    			else:
    				exit_code = False
    	except:
    		pass	
    	return exit_code  

    Is someone experiencing the same problem?

    Any help is wellcome!


  3. Thank you JBenghiat, just tested and it works!

     

    r, offset, rotationXAngle, rotationYAngle, rotationZAngle = vs.GetEntityMatrix(imageHandle)

    rotationZAngle is the image (imageHandle) rotation value (the same showed in the OIP)


  4. Did you forget to take some measures during your last architectonical survey?

    That's a bummer! But, wait… You've got some pictures? Then Plumb-Bob's got your back!

    Plumb-Bob is a perfect completion for your architectural survey!

    Everything you need is an image (even one taken from your phone), in which four known key points are clearly visible.

     

    Here's what you can do with Plumb-Bob:

     

     

    You can obtain the Plumb-Bob plugin for just €10+ via the Gumroad® platform at my personal page or starting from the plugin dedicated page here below:

    https://fitplot.it/vwplugins/PlumbBobPlugin.html

    • Like 2

  5. Hello all,

    is there a way to get the rotation angle of an image (bitmap) inserted in Vectorworks?

    The angle is clearly shown in the OIP but it seems to be unreachable by code 🤔 

     

    Here's what I tried:

    vs.HAngle(h)

    This returns always 0.

     

    I also searched in the appendix for some documented index to get the angle, but found nothing…

    vs.GetObjectVariableReal(h, index)

     

    Also tried to get it from record fields…

    vs.GetParametricRecord(h)

    but Bitmaps are a native type and not plugin objects, so neither this worked…

     

    Other ideas / suggestions?


  6. Ready, at last!

    Plumb-Bob for Vectorworks is available on the Gumroad® platform at €10+.

     

    You can get it from the official page here:

    https://fitplot.it/vwplugins/PlumbBobPlugin.html

     

    or from my Gumroad® page here:

    https://gumroad.com/pamarcu

     

    Note for Vectorworks italian users:

    This same plugin should be included in the next Vectorworks update (italian version) , under the name Ortofoto.

     

    Hope you enjoy it,

    Paolo

    • Like 1

  7. I am almost ready to release my PlumbBob for Vectorworks version, here's the new Plugin Icon:109625071_icona-plumBob-x-VWuniversal@2x.thumb.png.e7ce0021afa27564c7e4009eb491ec3d.png

    …and a screenshot of the plugin in action:

     

    1991818195_Schermata2020-05-01alle10_34_15.thumb.png.349341716535d794a8d7380a46305545.png

     

    Purpose of the Plugin:

    Starting from a picture, and knowing 4 points on it (for example a window's four corners), it is possible to rectify the picture so that you can take exact measurements of all openings lying on the plan to which the points (window in the example) belong.

    Also the plugin does the same operation on 2D objects traced on the picture (points, lines, polygons etc.)

    Also the plugin is able to do the reverse operation, transporting bitmaps and 2D objects from the rectified plan to the original picture point of view.

     

    While I had way to develop and test it on my Mac version of Vectorworks 2020, I still need someone to try it on Windows.

    This test is needed since the program relies on Pillow, a python library (for image manipulation) that is downloaded and installed (at first run) in the user library of Vectorworks.

    Please, if you are interested in testing PlumbBob (and get it for free, of course), leave me note (mouse over my icon and click ✉️Message).

    I'll provide to send you the plugin and necessary instructions.

     

    Thank you in advance

     

    • Like 1

  8. Hello,

    Is there a way to programmatically import an image as png with alpha channel, without showing up the import dialog as in:

    def vs.ImportImageFileN(filePath, importPt, mode):
        return HANDLE

    I am aware of:

    def vs.ImportImageFile(filePath, importPt):
        return HANDLE

    but I am wondering if there is a way to force the default import preferences (JPEG) as PNG with ALPHA channel.

     

    This is needed in my perspective rectifier plugin, where a new image (PNG with ALPHA) is created and imported on the fly.

     


  9. Vectorworks® plugins, symbols and scripts © Paolo Marcuccetti 2020

     

    A collection of digital products for Vectorworks®,

    some for free and some for a fee!

     

    New Barroom symbols

    Bar rooms (full package) includes about 400 symbols 2D/3D, gathered in 11 files  (Vectorworks® 2020).
    These symbols are all originally made by me (based on real objects) in my 20 years experience in the bar room / retail design.
    You can purchase the full package or single packages or even single symbols.

     

    Paid products are sold on:

    https://gumroad.com/pamarcu

     

    image.png

    • Like 2

  10. I am trying to use this function 

    FindFile(whichPath, relFilePath; VAR outPath)

    I am searching for a specific file in Libraries/Defaults, but I want it to be found either in program folder or user folder or any workgroups folder, so the code is:

    resultBoolean := FindFile(14, 'MoouldingsLib.vwx', outPath);

    I have tried it in a document script and it works perfectly, but, while transposing this script in an include file (.vss), where I need it to be, it crashes Vectorworks.

     

    Any suggestion?

    Are there alternative work arounds to get the full path of a file inside Libraries/Defaults, independently if this is in a workgroup or user or program folder?

     

    Thank you for the help.


  11. By popular demand, I have just released a Mouldings plugins DEMO version, so you can evaluate them all and, in case, proceed to buy.

     

    You can download the demo and find more info on Mouldings plugins starting from:

    https://fitplot.it/vwplugins/mouldings.html


    The DEMO plugins do all what the full version does, but they have, of course, some limitations.

    Each time you change a parameter of a Mouldings object, a message shows up, reminding you that you are running the DEMO.

    995083478_Schermata2019-11-29alle16_56_43.thumb.png.f4d5795a22c155bf2fd782e013de38cc.png

    You can exit this dialog clicking the link button to Mouldings page (with the chance to buy) or clicking Close.

    The close button halts execution for 5 seconds, but after that, changes to the object are regularly applied.

     

    Installation…

    1. Unzip the downloaded file.
    2. You get two folders and a pdf (Mouldings plugin IV Manual).
    3. Move the “Mouldings” folder inside your Vectorworks Plug-ins folder.
    4. Move the “Moulding - Models” folder inside Vectorworks Libraries/Defaults folder.
    5. Restart Vectorworks.
    6. Edit your workspace adding the (Mouldings) plugins.

     

    Whenever you'll upgrade to the full version, you’ll just have to replace the two folders above with the new ones I'll send, restart Vectorworks (no need to edit the workspace again) and your saved works will recognise the new plugins seamlessly.

    • Like 2

  12. I am happy to announce the release of Mouldings plugins version IV.

    It includes new parametric objects and a vaste library of profiles.

    Works with Vectorworks 2019 and 2020.

     

    Profile-selection-dialog.thumb.png.071544dd0d0903d6374f0429690ed38b.png

     

    More info on the site at https://fitplot.it/vwplugins/mouldings.html

    Here you can take a look at the Mouldings plugins Manual (Version IV).

    Use the on site form (scroll to bottom) to get in touch.

     

    Here's a short video of the new Frames (array) object suitable for wainscoting, complex doors etc. etc.

     

     

    And here one longer showing other parametric objects in the Mouldings plugins package:

     


  13. Thank you for your reply.

    I have seen the attached example, but I need something different.

     

    After various tries, I have opted for the image control, though I am not 100% happy because symbols converted in images shows a "2" in the lower right side of the icon (to show that are 2D symbols).

    You can see (in the attached image) the difference between the big tile (obtained with CreateImgFromSymbol) and the smaller tiles (obtained with CreateImageControl).

    It is not what I wish to get from a "Modern Dialog", but I can live with it...

    307960845_Schermata2019-09-10alle20_51_23.thumb.png.c8369ed9cd4278f2732fd68f50f10cf1.png

     

    For those that may be interested, since there are not plenty of examples around, here's the code to get the dialog above (kLib is the path to single files and folders whose name is, as symbols, in the vectorworks file at path symLib.

     

    PROCEDURE Example;
    const
    kLib = '/Applications/Vectorworks 2019 IT/Risorse/Elementi base/Mouldings - Models/Cornices';
    symLib = '/Applications/Vectorworks 2019 IT/Risorse/Elementi base/Mouldings - Models/Cornices/MouldingsLib.vwx';
    
    maxFolders = 1000;
    kTreeControlID = 4;
    kChosenSymbol = 5;
    kChosenText = 6;
    kBackwardBtn = 7;
    kForwardBtn = 8;
    kPages = 9;
    kFirstSymbol = 101;
    kSymbolWidth = 50;
    kRows 			= 6;
    kColumns 		= 7;
    
    
    TYPE
    menuItem = STRUCTURE
    	voce: string;
    	idx : integer;
    END;
    
    VAR
    dialog1 :INTEGER;
    result  :INTEGER;
    widthInChars, heightInChars :INTEGER;
    root1, root2, child1, child2 :INTEGER;
    
    folders : array[0..maxFolders] of menuItem;
    buttons : array[0..maxFolders] of menuItem;
    c, r : integer;
    pagina, numeroPagine, numeroFiles: integer;
    
    function validProfileFile(name: string): boolean;
    begin
    	validProfileFile := Pos('.cpf', name) > 0;
    end;
    
    	
    procedure ricorsione(node: string; livello: integer; previous: integer);
    
    var
    i: integer;
    foldername: string;
    root: integer;
    
    begin
    i := 1;
    
    folderName := GetFilesInFolder(node, 1);
    
    
    WHILE (folderName <> '') DO BEGIN
    
    	{writeln(livello, '. ', i, ' -> ', foldername);}
    	
    	{se è una folder, faccio un altro giro}
    	if Pos('.', folderName) = 0 then 
    	begin {è una cartella}
    		root := InsertTreeControlItem(dialog1, kTreeControlID, folderName, previous, livello);
    
    		folders[root].voce := concat(node, '/', foldername);
    		folders[root].idx := root;
    		
    		ricorsione(concat(node,'/', folderName), livello+1, root);		
    	end;
    		
    	i := i+1;
    	folderName := GetFilesInFolder(node, i);
    END;
    end;
    
    procedure updateDialog;
    var
    j : integer;
    idx : integer;
    
    begin
    			for j := kFirstSymbol+(pagina-1)*kColumns*kRows to kFirstSymbol+(pagina)*kColumns*kRows-1 do
    			begin
                idx := j-(pagina-1)*kColumns*kRows;
    			beginContext;
    			IF CopySymbol(symLib, buttons[j].voce) then 
    				begin
    					Symbol(buttons[j].voce, 0, 0, 0);
    					SetImageControlHandle(dialog1, idx,getObject(buttons[j].voce));
    					SetItemClickable(dialog1, idx, TRUE);
    					EnableItem(dialog1, idx, true);
    					SetHelpText(dialog1, idx,buttons[j].voce);
    					ShowItem(dialog1, idx, true);
    				end else begin
    					SetImageControlHandle(dialog1, idx,nil);
    					SetHelpText(dialog1, idx,'');
    					ShowItem(dialog1, idx, false);
    				end;
    			endContext(0);	
    			end;
    end;
    
    
    
    PROCEDURE Dialog_Handler(VAR item :LONGINT; data :LONGINT);
    var
    result: boolean;
    i,j : integer;
    fileName : string;
    idItem : integer;
    x : integer;
    deltaPagina : integer;
    
    BEGIN
    
    x := item-kFirstSymbol;
    deltaPagina := (pagina-1)*kRows*kColumns;
    
    CASE item OF
    	SetupDialogC:
    		BEGIN
    			ricorsione(klib, 1, -1);
    			updateDialog;
    		END;
    		
    	kTreeControlID : BEGIN
    			{reinizializzo array}
    			for i := 0 to maxFolders do
    			begin
    				buttons[i].voce := '';
    			end;
    			
    			result := GetTreeControlSelectedItem(dialog1, kTreeControlID, idItem);
    			
    			i := 1;
    			j := 0;
    
    			fileName := GetFilesInFolder(folders[idItem].voce, i);
    
    			WHILE (fileName <> '') DO BEGIN
    				{se è un file…}
    				if validProfileFile(fileName) then 
    				begin
    					buttons[kFirstSymbol+j].voce := fileName;
    				
    				end else
    				begin
    					j := j-1;
    				end;
    				j := j+1;
    				i := i+1;
    				fileName := GetFilesInFolder(folders[idItem].voce, i);
    			END;
    			
    			numeroFiles := j;
    			pagina := 1;
    			numeroPagine := trunc(j / (kColumns*kRows))+1;
    			
    			{completo con quelli vuoti}
    			for j := j to kRows*kColumns do
    				begin
    					buttons[kFirstSymbol+j].voce := '';
    				end;
    
    			SetItemText(dialog1, kchosenText, 'choose a symbol');
    			SetItemText(dialog1, kPages, concat(num2str(0, pagina), '/', num2Str(0, numeroPagine)));
    			updateDialog;
    		END;
    		
    	kBackwardBtn : BEGIN
    			pagina := pagina - 1;
    			if pagina < 1 then pagina := numeroPagine;
    			SetItemText(dialog1, kPages, concat(num2str(0, pagina), '/', num2Str(0, numeroPagine)));
    			updateDialog;
    		END;
    	
    	kForwardBtn :BEGIN
    			pagina := pagina + 1;
    			if pagina > numeroPagine then pagina := 1;
    			SetItemText(dialog1, kPages, concat(num2str(0, pagina), '/', num2Str(0, numeroPagine)));
    			updateDialog;
    		END;
    
    	kFirstSymbol..kFirstSymbol+kRows*kColumns: 
    		BEGIN
    			beginContext;
    			IF CopySymbol(symLib, buttons[kFirstSymbol+x+deltaPagina].voce) then Symbol(buttons[kFirstSymbol+x+deltaPagina].voce, 0, 0, 0);
    			updateSymbolDisplayControl(dialog1, kChosenSymbol, buttons[kFirstSymbol+x+deltaPagina].voce, 0, 2);
    			SetHelpText(dialog1, kChosenSymbol,buttons[kFirstSymbol+x+deltaPagina].voce);
    			endContext(0);
    			SetItemText(dialog1, kchosenText, buttons[kFirstSymbol+x+deltaPagina].voce);
    		END;
    
    END;
    END;
    
    
    
    BEGIN
    dialog1 := CreateLayout('Example Dialog', TRUE, 'OK', 'Cancel');
    widthInChars := 28;
    heightInChars := 28;
    CreateTreeControl(dialog1, kTreeControlID, widthInChars, heightInChars);
    SetFirstLayoutItem(dialog1, kTreeControlID);
    
    CreateSymbolDisplayControl(dialog1,  kChosenSymbol, '', kSymbolWidth*3, kSymbolWidth*3, 5 , 0 , 2);
    SetRightItem(dialog1, kTreeControlID, kChosenSymbol,0,0);
    
    CreateStyledStatic(dialog1, kChosenText, 'Chosen symbol', 30,2);
    SetStaticTextColor(dialog1, kchosenText, 256,0,0);
    SetRightItem(dialog1, kChosenSymbol, kChosenText,0,0);
    
    CreatePushButton(dialog1, kBackwardBtn, '<-️︎');
    CreatePushButton(dialog1, kForwardBtn, '->️');
    CreateCenteredStatic(dialog1, kPages, '1/1', 6);
                  
    SetBelowItem(dialog1, kTreeControlID,kBackwardBtn,0,0);
    SetRightItem(dialog1, kBackwardBtn, kPages,0,0);
    SetRightItem(dialog1, kPages, kForwardBtn,0,0);
    
    	for c := 0 to kColumns-1 do
    	for r := 0 to kRows-1 do
    		begin
    		{CreateSymbolDisplayControl(dialog1,  kFirstSymbol+c+kColumns*r, '', kSymbolWidth, kSymbolWidth, 5, 0, 2);}
    		CreateImageControl(dialog1, kFirstSymbol+c+kColumns*r, kSymbolWidth, kSymbolWidth, nil);
     
    		if (c=0) and (r = 0) then SetBelowItem(dialog1, kChosenSymbol, kFirstSymbol +c+kColumns*r,0,0);
    		if (c=0) and (r > 0) then SetBelowItem(dialog1, kFirstSymbol +c+kColumns*(r-1), kFirstSymbol +c+kColumns*r,0,-1);
    		if (c>0) then SetRightItem(dialog1, kFirstSymbol +c+kColumns*r-1, kFirstSymbol +c+kColumns*r,-1,0);
    		
    		end;
    		
    
    result := RunLayoutDialog(dialog1, Dialog_Handler);
     
    END;
    RUN(Example);

     


  14. I have tried also with the Image Control that responds to clicks but I did not get it to display the symbol image!

     

    I am doing this way:

    hImg := CreateImgFromSymbol('AM-530', 128,128, 0, 11, 9);
    if hImg <> nil then CreateImageControl(dialog1, 4, 200, 200, hImg);

    but, though the hImg is not nil, the symbol is not displayed. It is replaced by the Vectorworks icon.

     

    Below the code I am using to test.

    Of course, replace ''AM-530" with a symbol in your document.

     

    PROCEDURE Example;
    VAR
    dialog1 :INTEGER;
    int     :INTEGER;
    hImg : handle;
    
    PROCEDURE dialog1_Handler(VAR item :LONGINT; data :LONGINT);
    BEGIN
    
    CASE item OF
    	SetupDialogC:
    	BEGIN
    		SetItemClickable(dialog1, 4, TRUE);
    		EnableItem(dialog1, 4, TRUE);
    	END;
    		
    	4 : BEGIN
    			writeln('Strike!');
    		END;
    END;
    END;
    
    BEGIN
    writeln('Inizio');
    dialog1 := CreateLayout('Example', TRUE, 'OK', 'Cancel');
    
    {CreateSymbolDisplayControl(dialog1,  4,  'AM-530', 128, 128, 5, 0, 2);}
    hImg := CreateImgFromSymbol('AM-530', 128,128, 5, 0, 2);  
    if hImg <> nil then CreateImageControl(dialog1, 4, 200, 200, hImg);
    
    SetFirstLayoutItem(dialog1,  4);
    int := RunLayoutDialog(dialog1, dialog1_Handler);
    END;
    RUN(Example);

    Here's the results:

    838738230_Schermata2019-09-07alle16_10_53.thumb.png.7ca99592f4e4ea5055c6b2f3a5d2eeb7.png

    With the symbol control, the dialog is ok, but I cannot get clicks on the symbol…

     

    802949179_Schermata2019-09-07alle16_11_37.thumb.png.867fca6e3647aff2be48faafbcf16f5a.png

    With the image control, I get clicks fired, but not the correct image 🤔

     

 

7150 Riverwood Drive, Columbia, Maryland 21046, USA   |   Contact Us:   410-290-5114

 

© 2018 Vectorworks, Inc. All Rights Reserved. Vectorworks, Inc. is part of the Nemetschek Group.

×
×
  • Create New...