Jump to content

MullinRJ

Member
  • Posts

    1,987
  • Joined

  • Last visited

Everything posted by MullinRJ

  1. Sorry Chrissy, I do not know of a way to assign colors to the palette via VS. This appears to be another area where VS has a GET function without a SET function. I only quickly checked the v10.5 reference, perhaps it I did not see it or it has changed in v11. Maybe someone else knows better than I. Best of luck. Raymond
  2. Hi Chrissy, You are right in assuming that VW snaps assigned colors to the nearest color palette value. Try adding the following 2 lines to the end of your program to see what value is actually assigned. GetFillBack(hndObject, lngRed, lngGreen, lngBlue); Message(lngRed, ' ', lngGreen, ' ', lngBlue); Then you can take those values (/256) and plug them back into RealBasic to see how well they match. It is also possible to add colors to a color palette. You might explore adding the chosen color from RealBasic into the VW color palette and then applying it. I don't know how well they will match, but it's worth a try. Raymond
  3. One other consideration you will have to make: You will need a copy of VW8 or VW9 to be able to convert his MC6 files to VW11. This assumes that NNA still doesn't have a translator for the older versions yet. VW typically reads back 3 versions, so VW11 should be able to open VW8 files. I believe the sales department will help you bridge the gap. Raymond
  4. Hi Peter, There are different ways to work inside groups, but I tried the following code to see what would happen, and you can enter a group and do what you want the way you suggest. DoMenuTextByName('Group Navigation Chunk', 1); SelectAll; I created a group, entered it, deselected everything, then exited. With only the group selected I ran the above code. The objects inside the group are selected. On exiting the group, no other objects beside the group are selected. Raymond
  5. And UNDO only resets the unlocked line. Raymond Mac OS 10.2.8 / VW 10.5.0
  6. Hi Tom, Thanks for your response. I have been GOOGLE-ing a lot and reading everything I can find on cubic splines. Yes, finding the boundary conditions is a good part of the problem I am trying to solve. In the case where the Polyline points are of types Bezier, Arc or Corner, all the end points and control points for a given Bezier segment of the curve can be ascertained by knowing three points; the Polyline point in question, the Polyline point preceding it and the Polyline point following it. In the case where those three points are all of type Cubic Vertex, none of the control or end points are obvious, they are all virtual, meaning they must be calculated from the data at hand. I am hoping that NNA will provide a short paper on how they determine the end & control points used to implement the parametric equations for a Bezier (Cubic Spline) curve segment. How many polyline points before and after a cubic vertex are used to calculate the control points for each segment? When Cubic polyline points are adjusted with the 2D reshape tool, virtual points appear on screen with associated tangent lines. These are the points I am trying to calculate. From my rough drafting, it appears that the virtual point would be equivalent to a Bezier Vertex point and the midpoints between this virtual point and preceding and following ones would correspond to the end points P0 & P3 in the Bezier curve segment model. These three points would be enough for me to calculate the curve between them. I just need a little more help in seeing what I am missing. Raymond
  7. Hi Katie, I am trying to emulate the curves that are generated on screen using the data points that compose a polyline. The points are the ones returned with GetPolylineVertex(). I can replicate Polyline curve segments when the Polyline points are Corner Vertices, Bezier Vertices, Arc Vertices, and Cubic Vertices (if the preceding and following points are Corner points). I am having trouble figuring out how you implement a Polyline curve when it is constructed of a series of Cubic Vertices. Any technical notes you have on its mathematical implementation would be appreciated. Thank you, Raymond
  8. Do you have a tech note describing the method used to plot a Cubic Spline curve when adjacent points on a Polyline are of type Cubic Vertex? If not, can you point me to any published article that describes the model you use? I have Bezier Vertices figured out, and Cubic Vertices figured out when adjacent points are Corner Vertices, but not a succession of Cubic Vertices. I am trying to figure what implied control points are being used for the cubic formulae. I guess, while I am asking, I'd also like the model used when Cubic Vertices are flanked by Bezier Vertices. Thank you, Raymond
  9. SprdSheet() is obsolete as of VectorWorks 8.0 SprdBorder() is obsolete as of VectorWorks 9.0 The third and fourth errors are probably linked to the first two. Fix the first two and they may go away. Sorry, I don't know the newer commands to use, but you should be able to find them in the VectorScript Function Reference. You can find the various manuals to download at http://www.nemetschek.net/support/custom/vscript/docs.html HTH, Raymond
  10. Well, I may be hard pressed to explain WHY, but I'll try. Bear with me as some of it may already be obvious to you. Lists are linear, that is, they are composed of objects that are strung together like beads on a chain, each object pointing to the object immediately before it and the object immediately after it. Lists also have a beginning and an end. When you get a handle to an object you essentially have a number, or an address, that points to that object in a list. PrevObj() and NextObj() are functions that return handles to the objects that are immediately before and immediately after the object you have a handle to, respectively. When a list has no more objects in it, PrevObj() and NextObj() return NIL, or zero, as the address of the adjacent object. NIL is the special value that signifies the end, or the beginning, has been reached. There are many lists in your document at the same time. A list can be all the objects on a layer, in a group, or in a symbol definition. There are other lists as well that don't appear as objects drawn on the screen, such as the lists of symbol definitions, record definitions, worksheets, saved sheets, vectorscript routines, layers, etc. The objects in these lists can be viewed in separate windows such as the Resource Browser, command palettes, etc. Once you have a handle to an object in a list, any list, you can navigate that list forward or backward using NextObj() or PrevObj() respectively. For objects that appear in the drawing, the corresponding list is ordered in drawing order. For example, the first object in the list of objects on a layer is the first object drawn, and is the object on the bottom of the layer. The list continues to the last object which is the last object drawn and it appears on top of all other objects on that layer. This is most easily seen when the objects overlap. Layers are similarly structured, with the bottom layer drawn first and the top layer drawn last. Having said all that, let me answer a question you didn't explicitly ask, "How did I know that the AddSurface object would be before the group of symbols?" Short answer, "I didn't." I guessed. Since it was not on the top of the list, which is where I would have expected it, I went hunting for it. I ran your program many times, and stopped at various points displaying the values of handles in your code and compared them to the value of the AddSurface poly. This is what I deduced about the AddSurface command: It appears that the resultant poly will be located in the stacking order at the same level as was the lowest selected object, prior to the AddSurface command. This makes it difficult to find if you don't know this. In your case, since all objects are created by your script, they are all on the top of the list, or the top of the active layer, and therefore easy to locate, relatively speaking. A simple script I use to display the handle value of a selected object is: code: procedure ShowHandle; { Display the value of the first selected object's Handle. } { The value will vary each time the file is opened. } VAR H :Handle; BEGIN H := FSActLayer; Message(H, ' Type = ', GetType(H)); END; Run(ShowHandle);[/code] In your code you write: DeleteObjs; L := LSActLayer; { L = NIL. } SetSelect(L); { Not needed. If L<>Nil, L is already selected, based on previous line } Because the previous line de-selects all objects, LSActLayer will return NIL, as nothing is currently selected. Sometimes it is easier to get the handle you want before you perform a complex operation. You already have a handle to the original poly, h. Your duplicated poly is consumed In the AddSurface as are the remains of the decomposed symbols. All that is left is the new Poly, the original group of symbols and the original poly. It has to be one of the last three objects on the active layer. So, the new surface is either the last object, or the previous one. The original poly is the lowest object, since you never moved it since creating it. You can specify a handle to the new surface as either NextObj(h) or PrevObj(LActLayer). Either way, it is the second from the end. One thing that needs mentioning, earlier in your script you use g := LObject. This will only work IF the active layer is also the topmost layer in the drawing. You should restrict your calls to ones that return handles to objects on the active layer, otherwise your code may not work if you change you layer stacking order. To really see how your code runs, use the Debugger or use Message() to display the values of handles and other variables in your code. You can comment out the remaining code with (* and *). These comments delimiters work with {...} defined comments between them. HTH, Raymond
  11. Hi Nicholas, You picked a very intricate task to start your programming experience. You are trying to navigate a list of handles to objects while creating, modifying or destroying those objects along the way. Although it may seem easy, it?s not. That doesn?t mean it can?t be done, it just means you need to be exceptionally careful while doing it. There are some caveats you should know with VectorScript. Duplicated objects do not register as "New" objects. Ungrouping an object by handle invalidates your handle to the group, and creates new handles at the level you are in. The same applies to decomposing a symbol, so you must use the group or symbol handle to find the next item in the list BEFORE you destroy the goup or symbol it points to. There are many others that you?ll collect as you continue. It took a while for me to examine your code (entropy continues to run amok), but I think it will now do what you want. Here's the modified procedure. It may not do exactly as you intended, but you should be able to tweak it from here. It?s definitely a good example of handling objects in nested lists. Best wishes, Raymond code: PROCEDURE PolyLn; {Draws a polyline, places a symbol at each vertex, outlines the symbols and groups the result} VAR pX, pY, rotationAngle, offsetDX, offsetDY: REAL; h, g, L, L2, L3, symHd, t: HANDLE; convertAction, index, lw: INTEGER; fillPattern: LONGINT; symName, add: STRING; k, j : Handle; { new one for working inside groups } BEGIN {aquire active symbol & return nameSTRING} symHd := ActSymDef; symName := GetSDName(symHd); { your routine won?t run without selecting a symbol first, so I added this to prompt you. } if (SymName='') then begin ClrMessage; Message ('No Symbol is selected'); SysBeep; end else begin { start poly, acquire mouse click location, place vertex and insert symbol instance } OpenPoly; BeginPoly; GetPt(pX, pY); AddPoint(pX, pY); Symbol(symName, pX, pY, 0); GetPt(pX, pY); AddPoint(pX, pY); Symbol(symName, pX, pY, 0); {repeats as long as the shift key is held down} while Shift do begin GetPt(pX, pY); AddPoint(pX, pY); Symbol(symName, pX, pY, 0); end; EndPoly; {set poly fill and line wt} h := LNewObj; { h points to the new polygon } SetFPat(h, 0); SetLW(h, 6); MoveFront; { probably not needed } SetDSelect(h); {duplicate symbols and select only the duplication. for some reason the duplicate command leaves the original selected, unlike the in-document duplicate} Group; Duplicate(0, 0); g := LActLayer; { Points to duplicated group of Symbols sans Poly } DSelectAll; { the following can probably be done with less code, but sometimes brute force works as fast, and as well as finesse. } { g already points to the duplicated group. Go inside the group and decompose your symbols first. } k := FInGroup(g); while (k<>nil) do begin SymbolToGroup(k, 2); k := NextObj(k); end; { while } { second pass, go back inside and ungroup everything. } k := FInGroup(g); while (k<>nil) do begin j := NextObj(k); { save the next object before ungrouping this one } hUngroup(k); k := j; end; { while } { third pass, go back inside and delete all text objects } k := FInGroup(g); while (k<>nil) do begin j := NextObj(k); { save the next object before deleting this one } if (GetType(k)=10) then { type 10 = text } DelObject (k); k := j; end; { while } { end of brute force } SetSelect(h); { poly } SetSelect(g); { duplicated and decomposed group, sans text } HUngroup(g); { Disolve the group of duplicated and decomposed symbols } { add surfaces and set line wt } DoMenuTextByName('Add Surface', 0); L := LActLayer; { Points to the original group of symbols. } g := prevObj(L); { Points to the new AddSurface object (i.e., polyline). } SetLW(g, 24); SetSelect(g); MoveFront; end; { if/else SymName } END; Run (PolyLn);[/code]
  12. If you can program a button on your mouse to type the characters XX (the shortcut for the 2D selection cursor), it should work everywhere except in a text edit window. At least I'd like to think that it would. Worth a try. Raymond
  13. I believe the double parens are there in case two, or more, search criteria are selected. eg. SelectObj((T=21) & (LS=2) & (FF=0)); Read this as "Select all objects that are Type=21 (polygon) AND Line Style=2 (solid foreground color) AND Foreground Fill=0 (None)." One set of parens is all that is needed, but duplicates don't hurt the compiler. The programmers didn't write code that would adjust for the special case of one selection criteria using one set of parens. It's been like this for a very long time, and it is confusing for new programmers. HTH, Raymond
  14. LObject points to the last object in the drawing (i.e., the last object to redraw if all layers are visible), and is not necessarily on the active layer. L:=LObject; SetLW(L,24); SetDSelect(L); Unless you are on the top layer of the drawing, this will usually NOT do what you want. I am not sure where your object lies in the stacking order, but I have not tried your code yet. I will look more closely at it later. Raymond
  15. There is a Schematic Pipe PIO at VS Example page. It is the 2D Path Object, second from the bottom. HTH, Raymond
  16. If you duplicate objects with a script and LNewObj doesn't work for you, try LActLayer. A newly duplicated object will be on top of the stacking order on the Active layer until it is moved or another object is created/moved on top of it. Good luck, Raymond
  17. Hi Nicholas, 1) The script is written to be compiled as a PIO, not a stand alone VectorScript executed from a command palette. Select the "Create Plug-In?" menu. Press New. Give it a name and select "2D Path". Press the Script button and paste the script there. Close this window. 2) The "PPipe_Type" variable is not declared in the script but in the Plug-In Editor and made available to the script. The parameter Pipe_Type will be made available to the script as PPipe_Type, a String variable. Notice the extra "P" in the name. Press the Parameters button and ADD "Pipe_Type" as your one and only PIO parameter. This will later appear in the Object Info Palette (OIP) as an editable parameter. For its type, choose Pop-Up. You can copy or type the values from the top of the program into the list window provided: Hot Water Cold Water Chilled Water, etc. You can close the editor now and open the Workspace Editor to add the new PIO to your active workspace. It should work, at least it did for me. 3) Whenever you get "Error: Did not expect this after end of statement - missing ;?", check the previous line. The ";" is usually missing from there. 4) Yes, {$DEBUG} only works after a program compiles. Meaning it is syntactically correct, but not necessarily logically correct. 5) The debugger jumped to the last line because "result" was FALSE. "result" would have to be TRUE to step into the code. I believe GetCustomObjectInfo should only be used in code that creates a PIO, therefore it probably won't work in a stand alone script. If you get confused again on anything, please write back. Raymond
  18. You're welcome, Juno. One thing to note, when spreadsheets are placed in the drawing, the object type is 56 (Worksheet Image). It's a different beast from the Spreadsheet of type 18. Raymond
  19. Hi Juno, Your criteria doesn't work because Worksheets are not objects that are placed in the drawing. They hang off to the side, so to speak. If you need to get a handle to your Worksheets, try the following script. I modified it from one I wrote a while back to get handles to Saved Sheets. You can call your procedure from inside the IF statement in the WHILE loop. The IF statement is necessary to filter out unwanted objects because there is more than one object type in the WS list. HTH, Raymond code: PROCEDURE WkSheets; { Raymond Mullin - 28 April 2004 } { Get a handle to each Worksheet in drawing and display name in Message window. } CONST WorksheetType = 18; TmpWSName = 'WS Tmp'; VAR WSHnd, hndDummyWS :Handle; BEGIN { Get handle to a Dummy Sheet which gives you a handle in the Sheet list. } NewSprdSheet(TmpWSName, 1, 1, 5, 3, False, False) ; hndDummyWS := GetObject(TmpWSName); { Get handle to the new sheet } WSHnd := PrevObj(hndDummyWS); { Get handle to previous object on List } DelObject(hndDummyWS); { Not needed any more } Message(''); Wait(1); { Clear Message Window, but leave open } while (WSHnd <>nil) do begin { Traverse the WkSheet List } if (GetType(WSHnd) = WorksheetType) then begin Message(GetName(WSHnd)); Wait(1); end; { if } WSHnd := PrevObj(WSHnd); { Previous Obj on WkSheet List } end; { while } END; Run(WkSheets);[/code]
  20. Hi Mat, If you use an external editor, set the point size high enough to read. Then you can copy and paste to the VS Edit window, or use {$INCLUDE } in your script to pull in the latest edited version. Good luck, Raymond
  21. Hi Mat, quote: How do you comment out a whole block of code easily?You can comment out multiple lines of code with { }, but you are right about embedded comments, they will kick an error on the first unintentional }. If there aren't many comments in your block, you can remove all the }'s and retype them when you reinstate your code block. If there are a lot, you can replace the }'s with another character [i.e., an !], then replace the ! with } when you remove the outer { }. This assumes you are using an editor with search and replace features. Next question. quote: Why does "if Selected(H)" not simply return "true" if an object on any layer is selected? It would, but getting the handle to an object not on the Active Layer is not as easy as getting one ON the Active Layer. Unlike the standard suite of handle retrieving functions* (FSActLayer, FActLayer, LSActLayer, LActLayer, LnewObj), which is set up to work on the active layer, ForEachObjectInLayer() steps through EVERY object in the DRAWING. It's scope can be limited with the three integer option variables in its definition, which is defined in the VS 10.5 Function Reference as: code: Procedure ForEachObjectInLayer( actionFunc : PROCEDURE; { should say FUNCTION, not PROCEDURE } objOptions : INTEGER; travOptions : INTEGER; layerOptions : INTEGER );[/code] The handle of each object retrieved is passed to a user defined FUNCTION which can do anything you like. The actionFunc is defined as: code: Function actionFunc(objHand :Handle) :Boolean;[/code][/indent] As long as this function returns a value of FALSE, ForEachObjectInLayer will continue stepping through the objects in the drawing. When, or if, the function returns a value of TRUE, ForEachObjectInLayer will stop. If you want to examine every object in the drawing, then never return a TRUE value. In my code, I have my actionFunc, FSVisObj(), return TRUE when an object is SELECTED. I know it is also visible because I set the first parameter (objOptions) to 1, which restricts ForEachObjectInLayer to only examine visible objects, and the fourth parameter (layerOptions) to 2, which further restricts it to only examine visible layers. The handle to the object in question is passed back through the locally global variable, ObjHnd. If this does not clarify your question, ask again. Maybe I can be more succinct next time. HTH, Raymond * FInLayer(), FSObject() will return handles to objects on other layers, but you have to know which layer you want first. An outer loop could be implemented to step through every layer in the drawing, and an inner loop to step through each object on a layer, but ForEachObjectInLayer does that for you now. [ 04-04-2004, 01:13 AM: Message edited by: MullinRJ ]
  22. Hi Katie, Two of your three questions are answered, hiding for all to see. They are in your quote. OS9.2 & 1.25GB w/ 164MB allocated. Only the VW version is missing. Six thirty-eight on Saturday evening. Your diligence is admirable, and appreciated. Thanks, Katie. Raymond
  23. Hi Stefan, Open the Resource Browser (RB) from the main menu bar - Palettes>Resource Browser. At the top of the RB window, the fourth line down, is a button labeled "Resources". Click it and a pop-up menu will appear with "New resource in your_VW_file_name...". It, too, is the fourth selection down. Select it, and a dialog window will open with all the resource types you can create, eight types in all. "Symbol Folder" is the one you want. Raymond [ 03-24-2004, 08:24 PM: Message edited by: MullinRJ ]
  24. The "tree like structure" that Katie refers to also includes branches for VectorScript Palettes (which are like sub-folders for scripts) and the scripts they contain, in addition to the branch for Symbols and their sub-folders. Clicking on Symbol sub-folders or VS Palettes, opens them to display their contents. It is then that you will see more than "Top Level" displayed in the document folder list. As you add these items to your file, the document folder list shows the hierarchy of your position within the Resource Browser. Also, if you have multiple files open, the display also reflects your position in the particular file you are browsing through. HTH, Raymond
  25. Hi Zero, Here's a VS function that should do as you wish: code: function FSVObj :Handle; { Return a handle to the First_Selected_Visible_OBJect. } Var ObjHnd :Handle; Function FSVisObj(H :Handle) :Boolean; Begin if Selected(H) then ObjHnd := H; FSVisObj := Selected(H); End; { FSVisObj } Begin ObjHnd := nil; ForEachObjectInLayer(FSVisObj , 1, 0, 2); FSVObj := ObjHnd; End; { FSVObj }[/code] Use it as you would FSActLayer. Raymond [ 03-22-2004, 05:28 PM: Message edited by: MullinRJ ]
×
×
  • Create New...