Jump to content

MullinRJ

Member
  • Posts

    2,007
  • Joined

  • Last visited

Posts posted by MullinRJ

  1. @BillW,

       Welcome to the world of 3D programming in VW. I'm guessing it's not what you were hoping for. In looking at your file, code, and the numbers you've posted, I can tell you many of them, if not most of them, are right. Since I have to get up early tomorrow, I don't have the luxury of really digging into your code. I think you're close, but you have to move very carefully, as you've already figured out, because small changes can have profound effects on the numbers presented. Also, you have to test every one of you assumptions carefully. 

     

       If you still haven't resolved this by tomorrow when I get back, I'll jump back in. I spent the better part of a summer decoding the way the Entity Matrix was constructed for 2D shapes. I've tried to forget, but that hasn't happened completely yet. I can tell you the EM is employed the same for all 2D objects, EXCEPT for Symbols and Bitmap Images – and possibly PIOs (that part's foggy). 

     

    Nice job so far,

    Raymond

     

     

  2. Hi Pat, I found my code

     

     

    	{ build object in a symbol }
    	BeginSym(kImgSym);
    		PushAttrs;
    
    		{ create object here }
    
    		PopAttrs;
    	EndSym;		{ object symbol }
    
    	{ make image from symbol }
    	H := CreateImgFromSymbolN(kImgSym, 692, 792, 0, 0, 2, 1);	{ 692 & 792 are pixels of image}
    	DelObject(GetObject(kImgSym));		{ delete object symbol }
    
    	{ recreate the same symbol, now with dummy locus... }
    	BeginSym(kImgSym);						{ create empty symbol }
    		Locus(0, 0);						{ dummy locus }
    	EndSym;
    
    	{ ...then with image of the object }
    	B := SetParent(H, LNewObj);		{ move image into symbol }
    	GetBBox(H, P1.x, P1.y, P2.x, P2.y);	{ P1 & P2 are vectors }
    	P1 := -(P1 + P2) / 2;
    	hMove(H, P1.x, P1.y);			{ center image in symbol }
    	DelObject(FIn3D(LNewObj));		{ remove dummy locus }
    	ResetBBox(LNewObj);			{ reset symbol's BBox - very necessary }

     

       I use the same symbol name for the object and the image. After I create the bitmap, I delete the symbol then recreate it with a Locus as a place holder. Then I move the image into the symbol and remove the Locus. 

     

       If you already have the object before this point, you should be able to move it into the symbol instead of create it there, and proceed as outlined above. 

     

       If this works for you, meet me in Albuquerque and you can buy me a beer. 😉

     

    Raymond

     

     

  3. Hi Pat,

       I think I've done something similar recently, where I needed a Bitmap in a Symbol, to show in a WS. I was able to create the object, convert it to a Bitmap, then move the Bitmap into a newly created symbol – all in one script. No Event-Enabled anything. Is that close to what you are looking to do? If so, I'll dig up the code for you.

     

    Raymond

     

     

  4. Hi Sean,

       Sadly, Saved Views cannot be Copy/Paste from one file to another; nor can they be Imported. With a bit of work, it is possible that most information from a Saved View could be "gathered" in one file, saved to a neutral domain, then recreated in a second file, utilizing two scripts. I don't know if anyone has published a solution over the years, so hopefully if it has been done, someone will chime in.

     

       This has been requested many times over the years, but never implemented. I've thought of doing it several times over the past decades, but my need has never been great enough to justify the time spent. How many files do you need to update? If it's in the dozens or more and you can't find an existing solution, you might consider contracting the job out. But if you have a LOT of time on your hands, you could learn some seriously good scripting skills in the effort.

     

       Before you go any further, have you searched this Forum for this topic. I know it has come up several times, but I don't remember if any solutions were put forward.

     

     @Pat Stanford, have you any recollection of a prior solution?

     

    Raymond

  5. Hi Sean,

       It's a simple one-line script. It could be more complicated if you want, but if you have already saved a view by name, this one-line script will recall it. Since there are no variable names, the script does not need a PROCEDURE name; / BEGIN /  END; / Run(name); structure.

     

    VRestore('Your Saved View Name Here');

     

    HTH,

    Raymond

    • Like 1
  6. 2 hours ago, David O said:

    Your code is operating fine but only in 2D ...

     

    Hello David,

       That's interesting, fearing the same thing you just stated, I tried my code in 2D & 3D and it seems to work just fine. If I click near a window or a door it gets selected. If I click on the wall away from inserted objects, it selects the wall – again in both 2D & 3D.

     

       I reread your signature and notice you are using VW 2018. Is that still the case? I wrote the code using VW 2023. When I try it in VW 2018, it still works in 3D, but the selection is VERY picky and more often than not the inserted object does not get selected. This is the case with OpenGL rendering. When I change to Wireframe, it works as expected. Also, when I try it in VW 2020, it works about 50% of the time in OpenGL, which is better than VW 2018, but it works best in Wireframe. VW 2019 seems to work the same as VW 2018. The performance in VW 2023 is still better in rendered views and best in Wireframe. 

     

       Let us know what you find.

     

    Raymond 

  7. Hello Peter,

       Try this script – but only on copies of your files before you are sure it does what you want. This will convert ALL Extrudes in your Symbol Definition Library to Generic Solids. 

     

    PROCEDURE Extr2Solids;
    { Convert all Extrudes in symbol library to Generic Solids. }
    { VERY LIGHTLY TESTED - BACKUP WORK BEFORE USING, and USE ON A COPY FIRST. }
    { 13 Feb 2023 - R. Mullin }
    
    	function ConvertIt(H :Handle) :Boolean;
    	Var 
    		OT :Integer;
    	Begin
    		OT := GetTypeN(H);
    		if (OT = 24) then		{ 24 = Extrudes }
    			H := CnvrtToGenericSolid(H);
    	End;		{ ConvertIt }
    	
    BEGIN
    	ForEachObjectInList(ConvertIt, 0, 2, FSymDef);
    	SysBeep;		{ make a noise when done }
    END;
    Run(Extr2Solids);

     

    Raymond

  8. Hi Peter,

       Asked for many times, never developed. The only way to peek under the hood, is to draw something, then "Export Script..." under the File menu. It does not give you the progression of steps you are looking for, but only a static snapshot of the drawing state at the time of export.

     

       There is a lot of clutter that you can ignore at the top and bottom of the file. I typically search for "CreateLayer(" and look for the layer name you expect to find your object(s) of interest. If your file is complicated with many objects, and/or many layers, copy your object(s) of interest to a blank file and Paste_In_Place, then Export Script from that file. It will make finding your target code a lot easier.

     

    Not sure if this helps,

    Raymond

  9. I figured it out. When I tried to manually select a window and then the wall, VW popped a message at the bottom of the drawing window saying: the wall object could not be selected if an in-wall object is selected. So, selecting the wall AND the inserted PIO with a script results in ONLY the PIO being selected. The order of selection is not important. I learn something new every day, even when I don't want to.

     

    Raymond

    • Like 1
  10. @Pat Stanford,

       Try this. It works, but I don't know why. This is using your variable names.

     

    SetSelect(H1);	{ Wall handle }
    SetSelect(H2);	{ handle to sub_object in Wall }

     

    And so does this:

     

    SetSelect(H2);	{ handle to sub_object in Wall }
    SetSelect(H1);	{ Wall handle }

     

    Go figure!?!

     

    Raymond

  11. Hello, David.

       HINT: Pat's second suggestion is what you need. Try this code snippet. No error checking is done, so you'll have to add your own.

     

    PROCEDURE xxx;
    { Report the type and the PIO Name of a selected wall item. }
    VAR
    	H, subH :Handle;
    	B :Boolean;
    	I :Integer;
    	P :Vector;
    BEGIN
    	GetPt(P.x, P.y);
    	B := GetPickObjectInfo(P.x, P.y, H, subH, I);
    	message(GetTypeN(subH), '  ', GetName(GetParametricRecord(SubH)));
    	SysBeep;
    END;
    Run(xxx);

     

    HTH,

    Raymond

  12. 1 hour ago, Pat Stanford said:

    NewField adds a field to an existing record. If you pass a name for a Record that does not exist it will be created and the field added to it.

     

    What @Pat Stanford said, and...

     

    You can use NewField() to update the default value of an existing field in a record format after it exists. This only affects the field value stored in the record format but not any field values in existing records already attached to objects. It will affect new records when they are attached to objects.

     

    HTH,

    Raymond

    • Like 2
  13. @stevenmorgan94

    First off, what error are you getting? I assume you are getting syntax errors because vsoWidgetPopupClear(), and vsoWidgetPopupAdd() are not functions. They don't return values. If you're getting other errors, it might help to know what they are.

     

    Secondly, build your OIP with an empty popup widget to make sure you have all your widgets in place – sans errors.

    Then, you can add the symbol names to the popup in a loop. Something like this:

    vsoWidgetPopupClear(2);
    I := 1;
    SymNam := GetSymNameWithRec(I);		{ user defined function }
    while (SymNam <> '') do begin
    	vsoWidgetPopupAdd(2, SymNam, SymNam);
    	I := I + 1;
    	SymNam := GetSymNameWithRec(I);
    end;		{ for }

     

    Raymond

  14. Hi @fuberator,

       There are several documents you need to script effectively.

     

    1) The VW Script Function Reference. There is an HTML version in the VW Application folder, here: /VWHelp/Script Reference/ScriptFunctionReference.html.

    2) There is also an online version of the same document, and a whole lot more at: https://developer.vectorworks.net/index.php/Main_Page 

    3) There are files in the SDK containing lists of the constants used in the program. You can download the SDK here:  https://www.vectorworks.net/support/custom/sdk/sdk_license

    The files you need most are : ProgramVariables.h and ObjectVariables.h, located in the SDKLib/Include/Kernel/API/ directory.

     

    If you get this far you're probably numb from the neck up. Sadly, there is not an official Starting Place. We all recommend jumping in then requesting a life preserver. Luckily, there are many people standing around who will gladly throw you a floating device.

     

    But, to give you a nudge in the right direction, look in the VW Script Function Reference for the commands that @Pat Stanford mentioned above. You'll have lots of questions, and we'll have lots of answers.

     

    Good luck and welcome to the Deep End of the Pool,

    Raymond

     

     

    • Like 1
  15. To the best of my knowledge, you cannot create a persistent floating palette as you pictured above. You can create a dialog with those options, but it needs to open and close so you can continue editing your file.

     

    I believe what @Pat Stanford is suggesting is creating a Script Palette that contains Pascal or Python commands to achieve the various drawing states you desire.

     

    You can also turn these script commands into Menu Commands, which can be loaded into your workspace and assigned hotkeys. These would be available in every open file (new or old), as opposed to a Script Palette which would have to exist in each file, either by copying it in, or adding it to your Template Files. Menu commands can perform simple or complex functions, and if you need to provide user input, they can open dialogs like the one you designed above. If you need help going down one of these paths, please write back.

     

    Raymond

    • Like 1
  16. Hi @Nik,

       Good question. Complicated answer. As @Pat Stanford implies, there is no elegant solution. However, the ForEachObjectInLayer() function (FEOIL) can get you there, but it's still not an elegant solution. I am posting a VS code snippet and I'll leave Pythonizing it to you. The FEOIL call does all of the work on its first iteration, but it is geared to iterate over all of the objects in the drawing, only being constrained by its search arguments (3, 0, 2 in this case). The trick to get it to stop on the FIRST selected object is to have its "actionFunction" return TRUE immediately, which causes it to STOP iterating. Usually, no boolean value is returned in an actionFunction, which is equivalent to returning FALSE each time, and FEOIL will iterate through the whole document. 

     

    	Function FSObj :Handle;
    	{ Return a handle to the first visible/selected object on the Active Layer, or }
    	{ the on first Visible Layer if the Show/Snap/Modify LayerOption is enabled. }
    	{ If nothing is selected, return NIL. }
    	Var
    		ObjHnd :Handle;
    
    		Function FSEL(H :Handle) :Boolean;
    		Begin
    			ObjHnd := H;
    			FSEL := True;	{ return after first object }
    		End;		{ FSEL }
    
    	Begin		{ FSObj }
    		ForEachObjectInLayer(FSEL, 3, 0, 2);	{ Visible/Selected objects, Shallow, Visible Layers }
    		FSObj := ObjHnd;
    	End;		{ FSObj }

     

       If you want to limit the FEOIL function to only process Editable Layers use:

    ForEachObjectInLayer(FSEL, 3, 0, 4);    { Visible/Selected objects, Shallow, Editable Layers }

     

    Happy New Year,

    Raymond

    • Like 1
  17. Hey @Sam Jones,

       What @Pat Stanford said, AND, is your User Origin Shifted? If it is, you also have to remove that distance from the equation.

     

       From your comment, "SetParent() seems to be the problem.", have you verified that you have a handle to the two objects in question? I have never had a problem with SetParent() if the handles are valid and of the correct type. Also, be careful mixing objects of different types – Screen Plan, Layer Plane, and 3D objects. Mixing them will affect their visibility in different views.

     

       You know, you could make this a whole lot easier if you'd post a file with your symbol in it. There's a lot of guessing going on here. I hope you're grading us on a curve.

     

    Merry Christmas to All, and to All a good night. 🙂

  18.  @Sam Jones,

       Just remember that the (0,0) point inside a symbol definition is the Symbol's Insertion Point. In Pat's example, and you place the Locus outside the Symbol and want it in the same relative position inside the symbol, move the Locus by MINUS the symbol's insertion point.

     

    Try this.

    PROCEDURE xxx;
    { Move Locus into a Symbol at the same position as it was outside the symbol. }
    { Place a symbol, place a locus, select both, run script. }
    VAR
    	Hsym, Hsdef, Hloc :Handle;
    	Psym :Point;
    BEGIN
    	Hsym := FSActLayer;
    	Hsdef := GetObject(GetSymName(Hsym));
    	Hloc := LSActLayer;
    	GetSymLoc(Hsym, Psym.x, Psym.y);
    	
    	if SetParent(Hloc, Hsdef) then begin		
    		HMove(Hloc, -Psym.x, -Psym.y);
    		ResetBBox(Hsdef);
    		SysBeep;		{ make noise when done }
    	end;		{ if }
    END;
    Run(xxx);

     

       Are you writing code that needs to work if the User Origin is shifted? If so, I could write a lot more on how to manage coordinates between Drawing Layers and Symbol Definition spaces. If you also want your code to work in Rotated Plan View (ugh), I can help you there, too, but you'll need a good night's sleep and a large bottle of Aspirin.

     

    Merry Festivus 😉

    Raymond

×
×
  • Create New...