Jump to content

Replace Selected Objects with Symbol


Recommended Posts

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 by Pat Stanford
Link to comment
  • 3 months later...

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);

Link to comment

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.

Link to comment

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);

Link to comment

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);

Link to comment

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)

Link to comment
(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

Link to comment

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

Link to comment

???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!

Link to comment

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...