Jump to content

MullinRJ

Member
  • Content Count

    1,307
  • Joined

  • Last visited

Everything posted by MullinRJ

  1. It would make sense if the text position were an attribute of the symbol instance rather than the symbol definition.
  2. To all interested, Here is a (simple? - it started out as simple) script that will assign colors by palette position to selected objects. To use the program, select the object(s) to modify. Launch the script. Enter a number for the palette position (0-255) and optionally enter the 2 character Palette Code. Since there are 4 color palettes, you have the option of specifying which palette to use - Pen Foreground (PF), Pen Background (PB), Fill Foreground (FF), & Fill Background (FB). I have arbitrarily chosen the Pen Foreground (PF) palette to be the default. Users may change the constant 'DefaultCPalette' to any other palette value (1-4) to suit their interests. When entering data, type the palette position number, in the range of 0-255, followed by the optional characters 'PF', 'PB', 'FF', or 'FB' for the four palettes respectively. Mis-typing a palette code will not cause an error, but will assign your color from the Default Palette. Use Undo to correct. Example : '5 FF' Sets the Fill Foreground color to YELLOW. Spaces are optional, and '5ff' will also work as entry is case insensitive. 'FF5' will also yield the same result. Unless the default constant is changed, 'PF' does not need to be typed for setting the Pen Foreground color as it is the default palette. So, '251pf' is the same as '251' and will set the Pen Foreground color to DARK BLUE. Note : Colors may (most likely will) vary if the Color Palettes are modified, or swapped out. Drawings converted from older versions (MC7 and earlier) will have the older palettes if they weren't updated, and the colors will be very different from the default palettes used in versions 8, 9 & 10. Any feedback on the use of this program is welcome. code: Procedure SetColorByNum; { Set the color of the selected objects by Color Palette position number. } { Copyright ?2003 - Raymond Mullin } { The dialog box is set up to take a string containing a number and optionally a Palette Code. } { The number is the color palette position in the range of 0-255. } { The Palette Code uses the following: } { PF = 1 = Pen Foreground Color Palette - This is default palette. } { PB = 2 = Pen Background Color Palette } { FF = 3 = Fill Foreground Color Palette } { FB = 4 = Fill Background Color Palette } { eg. 231ff - sets the Fill Foreground Color to palette postion 231 } CONST DefaultCPalette = 1; VAR H :Handle; DataGood :Boolean; I, Index, CPalette :Integer; R, G, B :Longint; S :String; Function FSObj :Handle; VAR LocHnd, H :Handle; Begin Locus(0, 0); LocHnd := LNewObj; H := GetParent(LocHnd); DelObject(LocHnd); case GetType(H) of 31: H := FSActLayer; { Layer } 11,16,24,34,38,71,83,84,95: begin H := FIn3D(H); if not Selected(H) then H := NextSObj(H); end; Otherwise H := nil; end; { case } FSObj := H; End; { FSObj } function Ch(S :String; I :Integer):Char; { Return a character from string S in position I. } Begin Ch := copy(S, I, 1); End; { Ch } BEGIN DataGood := False; repeat S := StrDialog('Palette Index (0-255) (PF-PenFore, PB-PenBack, FF-FillFore, FB-FillBack) = Optional', '0'); ClrMessage; UprString(S); CPalette := DefaultCPalette; if (Pos('PF',S)>0) then CPalette := 1 else if (Pos('PB',S)>0) then CPalette := 2 else if (Pos('FF',S)>0) then CPalette := 3 else if (Pos('FB',S)>0) then CPalette := 4; I := len(S); { strip end of string } while ((I>0) & ((ord(Ch(S,I))<ord('0')) | (ord(Ch(S,I))>ord('9')))) do I := I - 1; if (I<len(S)) then delete(S, I+1, len(S)-I); I := 1; { strip front of string } while ((I<len(S)) & ((ord(Ch(S,I))<ord('0')) | (ord(Ch(S,I))>ord('9')))) do I := I + 1; if (I>1) then delete(S, 1, I-1); Index := Str2Num(S); { Palette position } DataGood := (Index>-1) & (Index<256); if not (DataGood or DidCancel) then begin Sysbeep; if (not DataGood and not DidCancel) then Message('Index = ', Index,'. Out of range (0-255)'); end; until DataGood or DidCancel; if DataGood and not DidCancel then begin ColorIndexToRGB(Index, R, G, B); H := FSObj; while (H<>nil) do begin case CPalette of 1: SetPenFore(H, R, G, B); 2: SetPenBack(H, R, G, B); 3: SetFillFore(H, R, G, B); 4: SetFillBack(H, R, G, B); end; { case } H := NextSObj(H); end; { while } end; { if } END; Run(SetColorByNum);[/code] [ 02-25-2003, 03:16 AM: Message edited by: MullinRJ ]
  3. Kristen, I just tried it in VW8.5.2 and ROUND only accepts 1 argument, but the documentation shows that it accepts 2. Probably an error in the documentation, or just wishful thinking. Try: =Round(123.456789*10^3)/10^3 to get 3 decimals of precision, where 10^3 is 10 raised to the 3rd power, or 1000. Change the 3 to whatever precision you desire. This should evaluate as: Round(123456.789)/1000 -> 123457/1000 -> 123.457 HTH, Raymond
  4. Paolo, After overthinking the problem a bit, I finally realized it wasn't all that complicated. Here is my distilled version: code: function VecRot3D(V :Vector; RotX, RotY, RotZ :Real) :Vector; { Rotate a 3D vector by the amount specified in each axis. Rotation is in degrees. } { 14 February 2003 - Raymond Mullin } Var U :Vector; procedure PartialRot(var X, Y :Real; Ang :Real); var W : Vector; Begin W[1] := X; W[2] := Y; W[3] := 0; W := Ang2Vec(Vec2Ang(W)+Ang, Norm(W)); X := W[1]; Y := W[2]; End; { PartialRot } Begin U := V; PartialRot(U[2], U[3], RotX); PartialRot(U[3], U[1], RotY); PartialRot(U[1], U[2], RotZ); VecRot3D := U; End; { VecRot3D }[/code] Best wishes, Raymond
  5. You may also have to stretch your palette down to see the info at the bottom. Raymond
  6. Paolo, Can you describe how you want your function to work? In my limited understanding of 3D vector math, I do know that the order of rotations affects the orientation of the result. For example, rotate X 90?, rotate Y 90?, rotate Z 90? yields a different result than, rotate Y 90?, rotate Z 90?, rotate X 90?. In the case of the VS command, Rotate3D, the axes are rotated in XYZ order. Raymond
  7. ccroft, You are correct. UpStr is used to make the data case insensitive by converting all the strings to uppercase before they are compared. I put it in because I like to use functions over procedures for routines that return only one variable. If I had used the plain vanilla VS procedure UprString, I would have had to write the following 3 lines inside the while loop: TmpName := VectorFillList(I); UprString(TmpName); Match := TmpName = VFName; For readability, I like code on one line, so I wrote UpStr to be able to write the following: Match := UpStr(VectorFillList(I)) = VFName; which sets Match to TRUE if the hatch name in the list equals the hatch name passed to the function GetVectorFillIndex. The procedure UprString needs a variable passed to it, so VectorFillList(I) must first be assigned to a variable, which can then be passed to UprString, where it gets modified, returned, and subsequently used in a boolean comparison. Granted, UpStr does not save a lot of room in this program, but I will use it elsewhere then the need arises. This has been a very interesting topic. I have not followed it closely, but when I get a little free time I intend to come back and pick through all the code. Thanks to all for writing. Raymond
  8. Alexandre, I have run into the missing Get/Set statement often in the past. Sometimes however, there are enough statements available to script the missing code. You are lucky today. Here is a short function that will get the index number from the hatch name. The function returns 0 (zero) if the hatch name is not found, and the hatch name is case insensitive. Best wishes, Raymond code: function GetVectorFillIndex(VFName :String) :Longint; { Return a VectorFill index # from a VectorFill name. } { Raymond Mullin - 6 February 2003 } Var Done, Match :Boolean; I, VFCnt :Longint; function UpStr(S :String) :String; { An upper string FUNCTION. } Begin UprString(S); UpStr := S; End; { UpStr } Begin VFCnt := NumVectorFills; UprString(VFName); I := 0; Match := False; Done := VFCnt = 0; while not Done do begin I := I + 1; Match := UpStr(VectorFillList(I)) = VFName; Done := Match | (I = VFCnt); end; if not Match then I := 0; GetVectorFillIndex := I; End; { GetVectorFillIndex } Example: Var VFIndexNum :Longint; HatchName :String; ... HatchName := 'any Hatch Name'; VFIndexNum := GetVectorFillIndex(HatchName); [/code]
  9. Does anybody use the Extend Tool to extend arcs or polys to boundary objects, or is the majority of its use for snapping lines to boundaries? Raymond
  10. Your guess is correct, move the difference. If you haven't already written one, here's a short procedure I've used before for Set3DCntr. HTH, Raymond Procedure Set3DCntr(H :Handle; x, y, z :Real); { Set the 3D center point of the object referenced by handle "H", to the coordinates specified by "x", "y" & "z" } Var u, v, w :Real; Begin Get3DCntr(H, u, v, w); Move3DObj(H, x-u, y-v, z-w); End;
  11. Dan, I will have to play with the tool a bit before I can commit a solution to you. The offset tool is not one I use very much. Looking at the VS commands, I don't see a general Offset command. There is a new OffsetPoly command in VW10, which may make coding a new tool possible. Can you tell me on which object types you use the tool? OK, I've played a bit. I notice the tool works nicely on Lines, Arcs, Ovals, Rects, and Polys; but Polylines suffer from too many new points being created, and RoundRects, not so hot, at least on VW852. It should be possible to do what you want with a script, but it will depend on the object types you want to offset. Now, I did notice that if you select multiple objects and set an offset distance, then each time you click, the next selected object gets offset by the preset amount. It's not the most elegant feel for a tool, but it might be useful in some applications. However, if you click too many times, it comes back through the list again - not what I would want it to do. Just out of curiosity, have you tried this modality? Raymond
  12. To get your desired result, you could always run a script... I have one here... ************* procedure RenameDimClass; { Change the class name for all objects in the DIMENSION class. } Procedure NewClass(H :Handle); Begin SetClass(H, 'A-ANNO-DIMS'); End; { NewClass } BEGIN ForEachObject(NewClass, C='Dimension'); END; Run(RenameDimClass); ************* If you make this a Plug-In Menu, and add it to your workspace, it will be available all the time. This script will not change the class of dimensions that are embedded in Symbols, but it will work on dimensions that are grouped. If you need to enter Symbols, just ask, I can show you how to do that too. HTH, Raymond
  13. MullinRJ

    FONT ID SCRIPT

    axiom, This script is not elegant, but it will give you the FontID of the first selected object, if it is of type TEXT. For scripting questions, you would do better to post them in the VectorScript section of the board. I would not have seen your question in the LANDMARK section had the title not caught my eye on the main topic page. HTH, Raymond Procedure GetFID; { Get a text object's Font ID. } VAR TxtHnd: Handle; BEGIN TxtHnd := FSActLayer; if (TxtHnd<>nil) and (GetType(TxtHnd)=10) then Message('FID = ', GetTextFont(TxtHnd, 0)); END; { End GetFID } Run(GetFID);
  14. You are very welcome and I'm glad I could help. Have a great New Year! Raymond
  15. For even tighter code, the calling procs can be written like this, Rect(1.5, 1, 3.5, 0); KlipSurface(hl, lnewobj, False); KlipSurface(hr, lnewobj, True); if procedure KlipSurface is defined like this, Procedure KlipSurface(var H1 :Handle; H2 :Handle; DelTrimObj :Boolean); HOWEVER, the first way of defining KlipSurface is safer. BECAUSE, if procedure KlipSurface (defined the second way) is called with two user defined handle variables AND DelTrimObj is set to TRUE, then the object referenced by H2 gets deleted, and H2 is set to NIL, but the NIL value is not passed back to the calling procedure. So, Rect(1.5, 1, 3.5, 0); hn := lnewobj; KlipSurface(hr, hn, True); will result in 'hn' being defined incorrectly after the call. If you are careful in your programming skills, then the shorter code looks and reads better, just be careful of the side effects. Happy New Year. HTH, Raymond
  16. Jason, You can get the handle to the new surface with a little finesse. Since it is not obvious where the new object is in the active layer, it is necessary to count the position (N) of the pre-clipped object, and then reassign the handle to the Nth object after clipping. The procedure KlipSurface, in the modified code below, can be used in place of ClipSurface. For tidiness sake, I also added a boolean to the call to delete the clipping object, if so desired. It is assumed that H1 points to an object on the active layer for this procedure to work. If H1 points to an object on another layer, or H1 is NIL, it should do nothing. I hope this helps. Raymond PROCEDURE Notcher; VAR hl, hr, hn :HANDLE; Procedure KlipSurface(var H1, H2 :Handle; DelTrimObj :Boolean); { Clip surface of object pointed to by H1, by object pointed to by H2. } { Return a handle to the new surface in H1. If DelTrimObj is true, } { then delete the trimming object. } Var I, J :Integer; TmpHnd :Handle; Begin { Find position of handle H1 in the stacking order. } I := 0; TmpHnd := LActLayer; while (TmpHnd<>H1) & (TmpHnd<>nil) do begin I := I + 1; TmpHnd := PrevObj(TmpHnd); end; { while } if (TmpHnd<>nil) then begin clipsurface(H1, H2); { Recover handle H1 } H1 := LActLayer; for J := 1 to I do H1 := PrevObj(H1); { Delete trimming object? } if DelTrimObj then DelObject(H2); end; { if (TmpHnd<>nil) } End; { KlipSurface } BEGIN Rect(0, 2, 2, 0); {*first rectangle*} hl := lnewobj; Rect(3, 2, 5, 0); {*SECOND rectangle*} hr := lnewobj; Rect(1.5, 2, 3.5, 1.5); {*Clipper*} hn := lnewobj; KlipSurface(hr, hn, False); KlipSurface(hl, hn, True); Rect(1.5, 1, 3.5, 0); {*next clipper*} hn := lnewobj; KlipSurface(hl, hn, False); KlipSurface(hr, hn, True); END; Run(Notcher);
  17. I would like to extend my warmest wishes for this holiday season to all who participate on this board. You have made a big difference in my appreciation for this wonderful product. I especially wish to thank Katie, the two Roberts, Jeff, and the rest of the NNA staff who go well beyond the 9-5 grind to make our lives better. May all your holidays be joyous, your families healthy, and this New Year the best one yet. Happy Holidays, Raymond Mullin
  18. << Can I give a group a handle? >> A GROUP is just another object, but it contains objects within it. You can ascertain an objects type by using the GETTYPE(hnd :Handle) function. It will return an integer representing the type of the object currently pointed to by the variable 'hnd'. Group is #11 in the list of object types. The numbers are listed in << Can I give objects dotted linestyles? >> Once you have a handle to your line, set line style and weight using: SetLS (hnd : Handle; LS : Integer); { sets line pattern, LS is between 0 & 71 } SetLS (hnd : Handle; LS : Integer); { sets line style, LS is between -8 & -1 } SetLW (hnd : Handle; LW : Integer); { sets line weight, LW is between 0 & 255 } SetPenFore (hnd : Handle; R,G,B : Longint); { sets foreground line color, R,G,B are between 0 & 65535 } SetPenBack (hnd : Handle; R,G,B : Longint); { sets background line color, R,G,B are between 0 & 65535 and is needed for PATTERNED lines } As you get comfortable getting handles to objects in lists, try using the procedures ForEachObject, ForEachObjectInLayer, & ForEachObjectInList. They will save you a lot of programming if you want to find objects that may be nested in groups or symbols. Though they may be hard to learn at first, you need only come back to this board for even longer diatribes on the subject. Have fun programming. HTH, Raymond PS - If you haven't downloaded the VS Function Reference guide you need to do so. Pick your flavor, Mac or PC, on page Documentation.
  19. If you haven't already seen one yet, here is a simple loop that will traverse a list of selected objects on the active layer. The I variable is incremented each time through the loop and displayed in a Message at the end. ************** Procedure ListWalk; VAR hnd : Handle; I :Integer; BEGIN I := 0; { initialize counter } hnd := FSActLayer; { get first object in list } while (hnd <> nil) do begin { test for end of list here } { do things of interest here } I := I + 1; hnd := NextSObj(hnd); { get next Selected object in list } end; { while } If (I=1) then Message ('There is 1 selected object on this layer.') else Message ('There are ', I, ' selected objects on this layer.'); END; Run (ListWalk); ************** continued...
  20. justin1974, There is very little you can't do with VectorScript. On the flip side, the really intricate stuff can take a good while to develop. << Does each object have to have its own handle? >> Yes, actually, each object already has a handle which is nothing more than a unique number (an internal address) that is maintained by the software. Your program needs to get handles to the objects before you can do anything to those objects with the VS handle calls. Think of each object on a layer as stacked one on top of another, until you get to the last object created, which is on top of all the others on that layer. It doesn't have to be drawn on top of anything else, but a list of each object is maintained, and that list is ordered. Each layer is actually a doubly-linked list of objects. That means if you have the handle to any object in the list then you can get the handle to the Previous and/or Next object in the list. A CAD file is a giant list of lists. Getting a handle to an object is easy, but knowing what object you have a handle to requires a little care. To get a handle in your program, consider using one of the following commands where 'hnd' is a variable declared as 'HANDLE'. VAR hnd : HANDLE; hnd := FSActLayer; { this is how it's used. } FSActLayer - very popular, gets handle to the First Selected object on the Active Layer. FActLayer - gets handle to the First object on the Active Layer , selected or not. LSActLayer - gets handle to the Last Selected object on the Active Layer. LActLayer - gets handle to the Last object on the Active Layer , selected or not. LNewObj {This one is also very useful as it returns a handle to the Last newly created object on the layer } To get the NEXT or PREVIOUS object in the list, use NextObj or PrevObj respectively. hnd := NextObj(hnd); { This is how it is used } Notice that 'hnd' is passed as an argument to NextObj as that tells NextObj what list you are in and which way you want to go. NEXT takes you toward the top (end) of the list, and PREV takes you to the bottom (front) of the list. When you run out of objects in the list you are traversing NextObj and PrevObj will return the value NIL (a fancy name for zero) to indicate there are no more objects. Further calls to NextObj or PrevObj will result in a runtime error. continued...
  21. P Retondo, Do you have Snap-to-Surface on at the same time? I have noticed inadvertent snapping, but only when I had multiple constraints on at the same time. If it happens when you only have the Snap-to-Object constraint selected, then you do have a problem. Best wishes, Raymond
  22. MullinRJ

    duplicate

    Sorry, on second thought, I believe it was LActLayer for the last object on the active layer. When dupliated, your new object will be on top, and therefore the last object on the active layer. HTH, Raymond
  23. MullinRJ

    duplicate

    I ran into this before. I believe I used LObject for the Last Object in the document. Your duplicated object should be the last object until another is created. HTH, Raymond
  24. Thanks, Ionw. I see the difference now. So now Option-Drag is consistent in its treatment of PIO's inserted in walls and the way it affects all other objects. Yes, I can see where that would be a big improvement. Thanks for clarifying. Raymond
  25. MullinRJ

    search criteria

    Amazingly enough, I could not find this info in any of the VS References either, so I typed what I could find here. The list should have more entries due to VW advances, but this should get you started. Sorry, tabs don't make it to the BB. You can replace the ' - ' string to a TAB to get a better view Best wishes, Raymond Criteria Name - Code - Example Arrowhead - AR - (AR=1) Class Name - C - (C='aClassName') Every Object - All - A(All) Fill Background - FB - (FB=1) Fill Foreground - FF - (FF=2) Fill Pattern - FP - (FP=3) Layer Name - L - (L='aLayerName') Line Style - PP - (PP=2) Line Weight - LW - (LW=10) Object Name - N - (N='anObjectName') Object Record - R - (R IN ['aRecordName']) Object Type - T - (T=Rect) Pen Background - PB - (PB=White) Pen Foreground - PF - (PF=Black) Pen Pattern - PP - (PP=4) Selected Status - Sel - (SEL=TRUE) Symbol Name - S - (S='aSymbolName') Visibility - V - (V=TRUE) Object Types are as follows: Line - Line Rectangle - Rect Oval - Oval Polygon - Poly Arc - Arc Freehand line - FHand 3D Locus - Locus3D Text - Text Group - Group Quarter Arc - QArc Rounded rectangle - RRect PICT - PICT BMP - BMP Symbol - Symbol 2D Locus - Locus Worksheet - SprdSheet Polyline - Polyline Extrude - Xtrd 3D Polygon - Poly3D Layer link - LayerLink Sweep - Sweep Multiple extrude - MXtrd Mesh - Mesh Dimension - Dimension Wall - Wall Light - Light Roof / Floor - Slab

 

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...