Jump to content

MullinRJ

Member
  • Posts

    1,991
  • Joined

  • Last visited

Posts posted by MullinRJ

  1. An easy way to search a string for a prefix is to use the vs.Pos() function. Without looking it up there is a Python syntax that does the same.

     

    prefix = "A-"
    aClassName = vs.ActiveClass()	# or any class name
    if (vs.Pos(prefix, aClassName) == 1):
          vs.HideClass(aClassName)
    
    
    OK I looked it up:
    
    prefix = "A-"
    aClassName = vs.ActiveClass()	# or any class name
    if (aClassName[0:2] == prefix):	# grab 1st 2 chars and compare
          vs.ShowClass(aClassName)


     

    Raymond

     

    • Like 2
  2. If adding INSYMBOL to your criteria doesn't do what you want, you might need to use one of the other ForEachObject... functions. Then you might need to use "Waldo". If you search the Forum you should find references to this mysterious name.

     

    Essentially Waldo, (reminiscent of "Where's Waldo") is the colloquial name given to a function that gets an object handle when you are running a script inside a container object, like a Symbol Definition, or a Group, and you only want to process the objects in that container. When you are working on a Design Layer, then FSActLayer works well. Waldo's will also work on Design Layers.

     

    Try:

    function Waldo1 :Handle;
    { return handle to selected object on bottom of stacking order }
    Begin
    	Locus(0, 0);			{ drop a bread crumb }
    	HMoveBackward(LNewObj, True);	{ move it to the front of stacking order }
    	Waldo := NextSObj(LNewObj);	{ use NextSObj or NextObj, as required }
    	DelObject(LNewObj);		{ remove bread crumb }
    End;
    
    function Waldo2 :Handle;
    { return handle to selected object on top of stacking order }
    Begin
    	Locus(0, 0);			{ drop a bread crumb }
    	Waldo := PrevSObj(LNewObj);	{ use PrevSObj or PrevObj, as required }
    	DelObject(LNewObj);		{ remove bread crumb }
    End;

     

    If you are using the ForEachObjectInList() function, then use Waldo1, as the those functions work from the bottom up. If you are traversing a list manually, then you can choose which Waldo you need. Waldo1 works with NextObj() and NextSObj() in your program loop, where Waldo2 works with PrevObj(), and PrevSObj().

     

    If you are specifically using ForEachObject(), then you are going to process the whole document. And there are other ways to navigate, but I cannot advise you further without knowing exactly how you intend your script to run. Pick your poison, carefully.

     

    HTH,

    Raymond

    • Like 3
  3. Good morning, @DomC.

       One thing about the Entity Matrix (EM) that is NOT in the documentation – The EM for symbols and images is encoded differently from all other 2D planar objects on the same plane. The EM for symbols and images contain information about their rotations on the plane, combined with the location and rotation of the plane where they reside. This means the EM for a symbol on a WP is NOT the same as that of a rectangle, line, locus, or circle on the same WP. The latter four will all have the same EM if they exist on the same WP, as the EM is supposed to define the WP, and not the object on the plane.

     

       I spent almost an entire summer figuring exactly how symbols and image EMs are put together and how to take them apart, only to realize that all I needed was a Working Plane's Reference ID to manipulate objects freely on Working Planes or move objects between them. Does Marionette have access to RefIDs? If not, you should request that it does. EMs are way too clunky to deal with, and they are not consistent between object types on the same plane. 

     

    My 2¢,

    Raymond

  4. Hi @DomC,

       From the picture and movie you posted, you have everything you need to define a working plane (WP) at each vertex, with no additional math required.

    1) Your WP Origin is the vertex p_corner.

    2) The local WP Xaxis, or Uvec, is p1-p_corner (vector subtraction). You'll need to spin your own function for this if you don't want to import any modules. Easy.

    3) Your WP Normal vector is p1xp2, or vs.CrossProduct(p1, p2), or vs.CrossProduct(p2, p1)*.

    4) And your WP Yaxis, or Vvec, (which is not needed to define the plane, but may be nice to have) is CrossProduct(Normal, Uvec).

     

    To define a WP at point p_corner use:

        vs.SetWorkingPlaneN(p_corner, Normal, Uvec)

     

    Easy Peasy. You don't need to convert your 3DPoly points to rotation angles, but you can use vs.GetWorkingPlane() after you set the WP with vs.SetWorkingPlaneN() and VW will give you a set of rotation angles that will be equivalent.

     

    * The only finesse point concerns which side of the corner vertex is the UP side of the WP. Since the Poly is in 3D space, there really is no Up side and your Normal could point in in either direction. vs.CrossProduct(p1, p2), or vs.CrossProduct(p2, p1) point in opposite directions. If it's not important, use either one. If you are familiar with the Right Hand Rule, you can visualize which way the Normal vector points relative to the 3 points you're using to define the plane. If not, google Right Hand Rule and you will find tons of websites showing how to use it. There are lots of videos are out there.

     

    If I left anything out, let me know.

     

    Raymond

     

    • Like 1
  5. @DomC,

       What do your 3 points represent?

    P1 = Plane's center point?

    P2-P1 = Plane's Normal vector?

    P3-P1 = Plane's X` axis (or U vector)?

    Or something else? 

     

    I believe what you want is doable, but would require going back to college texts, or the internet, a bunch. Do you have a specific problem you are trying to solve?

     

    Raymond

  6. You could create another button that has "place but don't close" functionality. It can have a keyboard shortcut assigned to it. 

     

    If you did assign a keyboard shortcut to the OK / PLACE button, there is no way you could distinguish between the shortcut being pressed and the button being clicked. To have two functions in your dialog, you will need two buttons. 

     

    Raymond

    • Like 1
  7. Hi  @MarcelP102,

       Sweeps are tricky. You can individually scale the radius/diameter, but only if your view is looking down the center, i.e., along the axis of rotation. This would be a FRONT or a BACK view for an unrotated Sweep. You can then scale the height, but only if you are looking at a TOP, LEFT, RIGHT, or BOTTOM view of an unrotated Sweep. If the Sweep object is rotated, you have to set up custom views to access a local FRONT view, and then the local TOP view. I know this because it's how I scale sweeps in my Reshaper plug-in, and I can tell you it's a LOT of code to resize a Sweep. 

     

       Another approach would be to completely un-rotate the Sweep, then jump to the FRONT view to scale the Sweep's diameter, and then the TOP view to scale the Sweep's height. When done, re-rotate the Sweep to its original angles. If necessary, move it back into position. Again, a lot of code.

     

    *****

     

    In modern dialog code there is an Event Loop. In your example you call it "Dialog_Handler", but there is nothing in it. When you press the OK button, dialog item = 1, you need to read the EditReal fields into variables with GetEditReal() when this event is detected. Use a CASE statement on the "item" variable to detect different events. With those variables loaded you can execute your scaling code. You can either do this inside the dialog code, or outside after the dialog closes, but you only do so if the user pressed the OK button; item=1 inside the dialog, or Result=1 outside the dialog.

     

    Raymond

    • Like 1
  8. Hello @MarcelP102,

       The big difference between Scale and HScale2D, is that Scale operates on all selected objects with no finesse, while HScale2D operates on a single item identified by its handle. There is a lot more control afforded by the latter command, but more diligence must be taken to pass meaningful parameters, thus making for longer scripts. 

     

       I only modified your first script, and I added a clause in your CASE statement to show you how to scale Multiple Extrudes. Sweeps should be similar, but you have to scale the Ht (height) and Wid (width) dimensions the same, because Sweeps are always circular. The Thk (thickness) dimension can be scaled a different value, if you like. I also swapped out your two dialog calls for one call that allows you to enter 2 numbers at once. If you want "fancy", then you'll have to code a small custom dialog, but for quick and dirty, this gets the job done with a one-line call.

     

       All of my changes are commented. If you have any questions, please don't hesitate to write back. You're off to a good start.

     

    Enjoy,

    Raymond

     

    PROCEDURE RandomScaleObjects;
    {Scales each selected object in the active layer randomly within a user given range}
    
    {© 17-06-2022 Arnhem - The Netherlands, Marcel Plomp}
    {With the help of Pat Stanford and others}
    { 18 Jun 2022 - Show how to scale MExtrudes, and some small mods made by "Others". }
    
    {Licensed under the GNU Lesser General Public License}
    
    VAR
    	rScaleFactor 				:REAL;
    	rScaleMax, rScaleMin			:REAL;
    	rCenterX, rCenterY, rCenterZ 		:REAL;
    	rCenterX1, rCenterY1, rCenterZ1		:REAL;	{ need more variables }
    	Ht, Wid, Thk				:REAL;	{ need more variables }
    	iObjectType				:INTEGER;
    
    Procedure WithIt(Hd:Handle);
    BEGIN
    	iObjectType := GetTypeN(Hd);
    	rScaleFactor := Round(100 * (Random*(rScaleMax - rScaleMin) + rScaleMin)) / 100;
    	CASE iObjectType OF
    		{Scales the Line, Rectangle, Oval, Polygon, Arc, Freehand, Text, Rounded rectangle and Polyline}
    		2..6,8,10,13,21:		
    			BEGIN
    				HCenter(Hd, rCenterX, rCenterY);
    				HScale2D(Hd, rCenterX, rCenterY, rScaleFactor, rScaleFactor, True);
    			END;
    
    		{Scales the Extrude, Sweep,  Mesh, CSG Solid, Nurbs Curve and Nurbs surface}
    		{3D Polygon = 25, Sweep=34 and Multi extrude=38 does not work??}
    		24, 40, 84, 111, 113:		
    			BEGIN
    				HCenter(Hd, rCenterX, rCenterY);
    				HScale3D(Hd, rCenterX, rCenterY, 0, rScaleFactor, rScaleFactor, rScaleFactor);
    			END;
    
    		38:	BEGIN	{ MExtrude }
    				Get3DCntr(Hd, rCenterX, rCenterY, rCenterZ); 		{ original 3D center }
    				Get3DInfo(Hd, Ht, Wid, Thk);				{ 3D Size }
    
    				Set3DInfo(Hd, Ht*rScaleFactor, Wid*rScaleFactor, Thk*rScaleFactor);
    
    				Get3DCntr(Hd, rCenterX1, rCenterY1, rCenterZ1);		{ center after scaling }
    				Move3DObj(Hd, rCenterX-rCenterX1, rCenterY-rCenterY1, rCenterZ-rCenterZ1);	{ move it back }
    			END;
    
    		15:	BEGIN	{ Symbol }
    				SetObjectVariableInt(Hd, 101, 2);
    				SetObjectVariableReal(Hd, 102, rScaleFactor);
    			END;
    
    		{Look into if I want to add architectural objects like: 68,71,81,83,86,89
    		Bitmap (=14) can be scaled with Hscale2D but moves in place..}
    	END;
    END;		{ WithIt }
    
    BEGIN
    	{ Use standard Point Dialog to collect 2 numbers. }
    	PtDialog('Enter Max and Min scale factors in X&Y fields below.', '1.0', '0.01', rScaleMax, rScaleMin);
    	ForEachObject(WithIt, InSymbol & VSEL);		{ don't need excess parens }
    	ReDrawAll;
    END;
    Run(RandomScaleObjects);

     

    • Like 2
  9. If you are using GetPtL(), GetLine(), or any of the other interactive functions to draw your path, then YES, you can test the Command, Option, CapsLock, and Shift functions to see if any were pressed when an interactive function was running. If you are using standard VW Drawing Tools, then I don't think so.

     

    I'm not your final authority, so wait to see if better advice arrives.

     

    Raymond

  10. You could attach a record with an object's density, and/or, its weight per unit_length. You cannot post the calculation in the OIP without creating a PIO to manage all attributes of volume & density, or length & wt/length, but you can easily (relatively speaking) get those values to display in a Worksheet.

     

    A PIO would be a more elegant solution, and the values could easily display in the OIP, but the amount of programming is many times more complicated.

     

    Raymond

    • Like 1
  11. OK, this is weird. When I wrote the above, I was testing objects on a Design Layer. I just now tested the same objects inside a Symbol Definition.

     

    A Layer Plane Object inside a SymDef shows in the OIP as being on the Symbol Definition plane. It displays on the 3D side of the symbol. It tests as 3D, but does not test as Layer Plane. On a Design Layer, the same object will test as 3D, AND as Layer Plane.

     

    Bottom Line : Test you code very carefully.

     

    Raymond

    • Like 1
  12. Hello @sandertb,

       You can get into a symbol definition with H = Fin3D(GetObject("SymDefName")) which will give you a handle to the first object in a named symbol definition. Then step through the object list with H = vs.NextObj(H) and test each object's 3D-ness with:    

     

    H = vs.FSActLayer()
    is3D = vs.GetObjectVariableBoolean(H, 650)    # 3D

     

       You may have to make a decision how to treat Layer Plane objects and 3D Plane (2D Planar) objects. Technically, Layer Plane objects which look like 2D objects, are considered 3D by the ObjVar_650 test, as are 2D Planar objects.

     

    # This will keep Screen & Layer Plane (Symbol Definition Plane) objects, and exclude "classic" 3D objects (Extrudes, Sweeps, 3D Lock, 3D Polys, Solids, etc.)

    H = vs.FSActLayer()
    is3D = vs.GetObjectVariableBoolean(H, 650) and not vs.GetObjectVariableBoolean(H, 1161)    # 3D and not Planar

     

    Use ObjVars:

       651 for 2D;

       650 for 3D;

       1160 for Screen Plane;

       1161 for Planar;

       1162 for Layer Plane

    testing. You may have to craft the logic that filters out exactly what you don't want. 

     

       When you decide to delete an object, make sure you get your next object handle FIRST, before you delete anything.

     

       Additionally, you can use ForEachObjectInList() to step through a symbol's elements, but that tutorial is longer.

     

    HTH,

    Raymond

     

    PS - There are no simple questions, and fewer simple answers.

     

    • Like 1
  13. @Pat Stanford,

       OK, I see what you mean, but that behavior only applies to menu commands Send Forward and Send Backward. Menu commands Send to Front and Send to Back still work "the old fashioned way."

     

       However, from a script, HMoveForward() and HMoveBackward(), work by adjusting the stacking order of the object list, regardless of visible overlapping. I assume @Sam Jones is wanting to use a script to do his dirty work, but if he is tempted to use "DoMenuTextByName('Send Forward', 0)", he's all yours, and I shall remain politely silent.

     

    Raymond

     

    PS - Whenever the behavior changed for menu commands Send Forward and Send Backward, it has been longer than that that I have used either of those commands. Menu commands Send to Front and Send to Back, I use daily. It's interesting how habits get engrained.

  14. 1 hour ago, Pat Stanford said:

    At some point they have "smartened" Send Back/Send Forward Now they only work with overlapping objects.  In the ancient past (when I last played with this) the code I provided did change the entire stacking list.

     

    Hi @Pat Stanford,

       I don't think this has ever changed. If it had, a lot of the scripts I've written over the years would have failed miserably. If you use HMoveForward() or HMoveBackward(), they will change the stacking order whether you move an object one position, or all the way to the front or back. Overlapping objects was never a condition of how the functions work. It is true however, that you won't perceive a difference of a changed stacking order if objects don't overlap.

     

       Of course, if you are referring to another way to, as you say above, "Send Back/Send Forward", then I may have completely misunderstood and I will gladly ingest this post if I did.

     

    Raymond

  15. @Sam Jones,

       If Kevin Linzey's method doesn't work, you can build an array of layer handles, stored in order of course. Then use GetLayer(objHnd) to get an object's layer handle. To compare two objects, get their layer handles and search the array of layer handles. The object with the higher array index number is on top. Tedious, but doable. If you need more help, you know where to find me.

     

    Raymond

  16.    Many numbers on the VW Forum are expressed in a condensed form, such as the number of Total Topics – 80.7k, or Total Posts – 412.3k, or the number of posts in the sub-forum Troubleshooting – 41.4k. It would be nice if a condensed number would expand to its exact value when you hover your cursor over it for a second or two, as happens when you hover over a date or time and you see the exact date and time of an event – Joined "1 hour ago" expands to "6/3/2022 @ 7:46 PM."  (Welcome @kma3)

     

       My real curiosity is to know how many Posts and the Reputation @Pat Stanford really has. Currently if you hover over his avatar, you can only ballpark it at Posts = 9.2k and Reputation = 2.4k. Surely, it would be nice to know exactly how well he is doing. I bet even @Pat Stanford would like to know.

     

       The fact it can be done for dates and times leads me to believe it can be done for any number displayed in a compressed format.

     

    Thank you,

    Raymond Mullin

  17. 10 minutes ago, Pat Stanford said:

    I think Sam, Raymond and I all assumed (we all know what what means) that since classes are not "resources" than can be seen in the Resource Manager they would not respond to the BuildResourceList commands. And never bothered (or needed) to test that assumption.

     

    I can neither confirm nor deny my ignorance on the matter of Classes as observable resources in other files.

×
×
  • Create New...