Pat Stanford Posted November 18, 2008 Share Posted November 18, 2008 (edited) This script will replace every selected object with the active symbol definition. It was designed to replace circles with a symbol located at their center. Check carefully for other objects before depending on it. Use in Good Health, Pat (*********** Copy between Here ************) Procedure ReplaceWithSymbol; {Replaces every selected object with the active symbol definition} {Displays a message if no symbol definition is active.} {November 17, 2008} {? 2008, Coviana, Inc - Pat Stanford pat@coviana.com} {Licensed under the GNU Lesser General Public License} Var X1, Y1: Real; Procedure ReplaceObject(H1:Handle); Begin Get2DPt(H1,1,X1,Y1); Symbol(GetSDName(ActSymDef),X1,Y1,0); SetDSelect(LNewObj); DelObject(H1); End; Begin If ActSymDef<>Nil then ForEachObject(ReplaceObject,SEL=True) Else Message('No Symbol Definition Selected.'); End; Run(ReplaceWithSymbol); (********** And Here ***********) Edited November 18, 2008 by Pat Stanford Quote Link to comment
shorter Posted February 18, 2009 Share Posted February 18, 2009 Dear Pat Could this script be amended to replace any object with a symbol but with the center of the selected object(s) as the insertion point of the symbol? Regards Steven Shorter Quote Link to comment
Pat Stanford Posted February 18, 2009 Author Share Posted February 18, 2009 It probably could be modified to do that, but might it not be easier to modify the symbols so that their insertion point is at the center of the symbol? What exactly are you trying to do and why? Quote Link to comment
Heath Posted February 26, 2009 Share Posted February 26, 2009 Pat, This is great. I will use it often. Is it possible to have the inserted symbol be selected after replacement? Thanks again for sharing your knowledge. Heath Quote Link to comment
Pat Stanford Posted February 26, 2009 Author Share Posted February 26, 2009 You can't leave them selected based on the way it is currently written. It replaces the selected objects one at a time and then deselects each as it is done. If you were to select the new objects, the script would just continue to churn forever. It could easily be modified to go back and select every instance of the given symbol, but there is no easy way to select just the ones that have be replaced. This one does just that. Procedure ReplaceWithSymbol; {Replaces every selected object with the active symbol definition} {Displays a message if no symbol definition is active.} {November 17, 2008} {? 2008, Coviana, Inc - Pat Stanford pat@coviana.com} {Licensed under the GNU Lesser General Public License} {February 26, 2009} {modified to select all symbols of the type used in the replace} Var X1, Y1: Real; S1 : String; Procedure ReplaceObject(H1:Handle); Begin Get2DPt(H1,1,X1,Y1); Symbol(GetSDName(ActSymDef),X1,Y1,0); SetDSelect(LNewObj); DelObject(H1); End; Begin If ActSymDef<>Nil then begin ForEachObject(ReplaceObject,SEL=True); S1:=concat('S=',CHR(39),GetSDName(ActSymDef),CHR(39)); SelectObj(S1) end Else Message('No Symbol Definition Selected.'); End; Run(ReplaceWithSymbol); Quote Link to comment
Heath Posted February 27, 2009 Share Posted February 27, 2009 Thanks again Pat! Heath Quote Link to comment
panta rhei Posted February 27, 2009 Share Posted February 27, 2009 It could easily be modified to go back and select every instance of the given symbol, but there is no easy way to select just the ones that have be replaced. This one does just that. Depends on the definition of easy. One could read the locations into an array while deleting the selected items, then place the symbols to these stored locations. Quote Link to comment
Pat Stanford Posted February 27, 2009 Author Share Posted February 27, 2009 easy - adjective Requiring less than the 10 minutes I have to spend on this today. ;-) Quote Link to comment
panta rhei Posted February 27, 2009 Share Posted February 27, 2009 Of course it's an adjective, but I didn't know that it is measurable in time. In an easy-chair, is one supposed to sit only less than 10 minutes? Quote Link to comment
MullinRJ Posted February 28, 2009 Share Posted February 28, 2009 So, how long is easy-as-pie? My guess is 2+ hours. OK, this appeared easier that it was, but with a little bit of effort, you can have your cake ? I mean pie ? and eat it, too. I think Petri's suggestion of using an array would have been easier, but we hates arrayssss. Raymond Procedure ReplaceWithSymbol; {Replaces every selected object with the active symbol definition} {Displays a message if no symbol definition is active.} {November 17, 2008} {? 2008, Coviana, Inc - Pat Stanford pat@coviana.com} {Licensed under the GNU Lesser General Public License} {February 26, 2009} {modified to select all symbols of the type used in the replace} {February 27, 2009 - RJM} {Move new symbols to back, so they stay selected.} {Uses HCenter to place symbol at center of selected object.} {Optionally, move symbols to front, so they keep relative stacking order.} Const ???SQ = chr(39);??????{ Single Quote } Var ???H, Hfo : Handle; ???X1, Y1 : Real; ???S1 : String; ???Procedure ReplaceObject(H1:Handle); ???Begin ??????HCenter(H1, X1, Y1); ??????Symbol(S1, X1, Y1, 0); ??????HMoveBackward(LNewObj, True);????????????{ move to back instead of deselect } ??????DelObject(H1); ???End;??????{ ReplaceObject } Begin ???if (ActSymDef <> nil) then begin ??????Hfo := FActLayer;??????????????????????????????{ handle to first object on layer } ??????if Selected(Hfo) then Hfo := nil; ??????S1 := GetSDName(ActSymDef); ??????ForEachObject(ReplaceObject, SEL); ??????{ omit the following if stacking order is not important, } ??????{ otherwise this moves all new symbols to the front. } ??????if (FSActLayer <> nil) then begin????????????{ there were selected objects converted } ?????????if (Hfo = nil) then Hfo := NextDObj(FActLayer);???{ first deselected obj } ?????????if (Hfo = nil) then Hfo := LActLayer;??????{ top selected symbol } ?????????H := PrevObj(Hfo); ?????????while (H <> nil) do begin ????????????HMoveForward(H, True); ????????????H := PrevObj(Hfo); ?????????end;??????{ while } ??????end;??????{ if (FSActLayer <> nil) } ???end ???else Message('No Symbol Definition Selected.'); End; Run(ReplaceWithSymbol); Quote Link to comment
panta rhei Posted February 28, 2009 Share Posted February 28, 2009 Well, here's another take on the subject. I've totally forgotten the circumstances, but obviously the 3D & rotation aspects are there for a reason. PROCEDURE Sel2Syms; { ? Petri Sakkinen 1998-2009 } { This macro replaces selected objects on the active layer with instances of the active symbol } VAR i, n, objType : INTEGER; x, y, z, a : REAL; xi, yi, zi, ai: ARRAY[1..1000] OF REAL; theSymbol : STRING; obHd, sdHd : HANDLE; BEGIN theSymbol := GETSDNAME(ACTSYMDEF); IF (theSymbol > '') THEN BEGIN obHd := FSACTLAYER; WHILE obHd <> NIL DO BEGIN i := i+1; x := 0; y := 0; a := 0; z := 0; objType := GETTYPE(obHd); CASE objType OF 9 : GETLOCUS3D(obHd, x, y, z); { found a 3D locus } 15 : BEGIN { found a symbol } GETSYMLOC3D(obHd, x, y, z); a := GETSYMROT(obHd); END; 17 : GETLOCPT(obHd, x, y); { found a 2D locus } OTHERWISE HCENTER(obHd, x, y); { found something else} END; { case } xi := x; yi := y; zi := z; ai := a; obHd := NEXTSOBJ(obHd); END; IF YNDIALOG('Delete selected objects?') THEN DELETEOBJS; FOR n := 1 TO i DO BEGIN SYMBOL(theSymbol, xi[n], yi[n], ai[n]); IF (zi[n] <> 0) THEN MOVE3DOBJ(LNEWOBJ, 0, 0, zi[n]); END; END ELSE ALRTDIALOG('You must have an active symbol'); END; RUN(Sel2Syms); Quote Link to comment
ccroft Posted March 1, 2009 Share Posted March 1, 2009 This is an interesting thread. I always enjoy seeing how different minds come up with different means to the same end. Myself, I've had selection status get in my way a few times before. What's served me well is to build an array of the selected object's handles, and then make the procedures handle based instead of selection based. So here's yet another take on it: PROCEDURE replace_it; ???VAR ??????objX,objY,symX,symY:REAL; ??????index:INTEGER; ??????handleBin:ARRAY[1..1000] of HANDLE; FUNCTION loadBin(h:HANDLE): BOOLEAN; ???Begin ??????index:=index+1; ??????handleBin[index]:=h; ???End; PROCEDURE change_it(objectHand:HANDLE); ???Begin ??????HCenter(objectHand, objX, objY); ??????Symbol(GetSDName(ActSymDef), objX, objY, 0); ??????HCenter(LNewObj, symX, symY); ??????HMove(LNewObj, objX-symX, objY-symY); ??? ??????DelObject(objectHand); ???End;?????? BEGIN ???IF (ActSymDef <> nil) THEN ??????Begin ?????????index:=0; ?????????ForEachObjectInLayer(loadBin,2,0,2); ?????????index:=1; ??????WHILE handleBin[index]<>NIL ?????????Begin ?????????change_it(handleBin[index]); ?????????index:=index+1; ?????????End; ??????End ???Else AlrtDialog('Make a Symbol Active, DUMB-ASS!'); END; RUN(replace_it); If anyone wants to actually use this script, you might want to edit the alert message depending on the work environment. This is my standard alert, cause the only time I get it is when I'm pushing hard on a deadline and it usually lightens my mood a bit. As per an early request, I added a couple lines to move the symbol center to the old objects center. Works great in my drawing environment, but I'm quessing there might be situations where it fails. Seems too simple to be correct. I'd like to thank everyone who asked or answered in this thread. Contrary to what I thought when I first read it, the end result is actually gonna be very useful to me. (I wish you could cut and paste a script in here without messing up the formatting) Quote Link to comment
MullinRJ Posted March 1, 2009 Share Posted March 1, 2009 (I wish you could cut and paste a script in here without messing up the formatting) Hi Charles, ???You can, if you indent your source code with tabs. First, replace all tabs with three option-space (NBS = non-breaking space) characters, select all and copy, then undo (to restore your tabs). You can then paste on the tech-board and your indents remain. If you indent with spaces, it will be a bit trickier. (It appears you indented some of your code this way, just not all of it. I used NBS characters in my pasted code above and in my paragraph indents here.) ???The only issue I have with using arrays, especially static arrays, is that the code is not general enough. It will fail at the 1001'st object (citing yours and Petri's examples.) This is easy to adjust for us programmer types, but there are a lot of people who cringe at thought of modifying a script. ???The use of dynamic arrays can get around the static array limit, but you have to count everything first then declare your array size, and even then you are limited to 32K elements, which should be enough for most everything, but it's still not bullet proof. ???The method I used does not have a well defined upper limit, but speed may be the limiting factor for it. Remove the italicized lines and it will run faster, but then the replaced objects will be on the bottom of the stacking order instead of on the top. This may or may not be an issue. Tagging everything with a record for reselection is another way to tackle this problem, but it's also cumbersome to write and debug. ???The best part of this thread is there are four examples (actually five with Pat's two posts) of the same idea that a beginning scripter can compare. Happy scripting, y'all. Raymond Quote Link to comment
panta rhei Posted March 1, 2009 Share Posted March 1, 2009 ???You can, if you indent your source code with tabs. First, replace all tabs with three option-space (NBS = non-breaking space) characters, Nice! Have to try... The use of dynamic arrays can get around the static array limit, but you have to count everything first then declare your array size, and even then you are limited to 32K elements, which should be enough for most everything, but it's still not bullet proof. Duly noted, but I think we can quite safely assume that few scripts need to handle more than 32K elements. Counting is not that bad. In my example this would have been the better approach: VAR i, n, objType : INTEGER; x, y, z, a : REAL; xi, yi, zi, ai: DYNARRAY[] OF REAL; theSymbol, lName : STRING; obHd, sdHd : HANDLE; ???? BEGIN ????????????theSymbol := GETSDNAME(ACTSYMDEF); ????????????IF (theSymbol > '') THEN BEGIN ???????????? lName := GETLNAME(ACTLAYER); ???????????? n := COUNT(SEL & (L=lName)); ???????????? ALLOCATE xi[1..n]; ??????????? ?ALLOCATE yi[1..n]; ???????????? ALLOCATE zi[1..n]; ??????????? ?ALLOCATE ai[1..n]; ???????????? obHd := FSACTLAYER; etc. Quote Link to comment
ccroft Posted March 1, 2009 Share Posted March 1, 2009 ???The only issue I have with using arrays, especially static arrays, is that the code is not general enough. It will fail at the 1001'st object (citing yours and Petri's examples.) This is easy to adjust for us programmer types, but there are a lot of people who cringe at thought of modifying a script. Hello Ray, Very true, but that's the beauty of the programmer and end-user being the same person! I've always just created an array sufficiently over-size for my own purposes. In fact I'll never use it on more than 100 objects, so I just forgo the dynamic. I guess I'm not a good vScript citizen... It's very good that you pointed this out for the benefit of others. I thought your approach was most interesting. I never would have thought of doing this by manipulating the stacking order, and it took me quite a while to see how this works. Somehow arrays just make a lot of sense to me. (My mind must resemble an old time post-office sort station or something....lots of little boxes in a grid.) And thanks for the formatting tip. I think you mentioned that before, but I couldn't remember the correct key stroke. BTW, you can also go back and edit using option/space to get indents as I did. (hope I didn't accidently erase a semi-colon or something) So to sum it all up, we have three ways to get around the infinite loop of selection. One is stacking order based, one is position based, and one is handle based. Carry on! Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.