PDA

View Full Version : Scaling individual "islands" of polygons?



MentalFish
07-24-2009, 09:53 AM
Is it possible to individually scale islands of polygons, based on each poly-island's own center, or does it have to be done manually? Select-scale-select-scale...?

In this case I wanted to scale the holes and nuts of a car rim, see attachment.

If not natively available in LightWave, is there any LScripts out there that does this?

archijam
07-24-2009, 10:44 AM
LWCAD 3.1 can do this, ie. scale objects on same layer about their own centres, but I'm not sure if that would work on this geometry ..

art
07-24-2009, 11:32 AM
Try this:


main
{
reqbegin("Scale");
amount_ctl = ctlnumber("Scale by (%)",50.0);
return if !reqpost();
amount = getvalue(amount_ctl) / 100;
reqend();

undogroupbegin();
selmode(USER);
selhide(UNSELECTED);
polys = polycount();
while(polys[1] >0)
{
selpolygon(CLEAR);
selpolygon(SET,POLYNDX,1);
selpolygon(SET,CONNECT);
center = center(boundingbox());
scale(amount,center);
selhide(SELECTED);
selmode(GLOBAL);
polys = polycount();
selmode(USER);
}
selunhide();
selpolygon(CLEAR);
undogroupend();
}

EDIT: I see there is a problem with scaling and computation of scale center for connected geometries. I'll see if it can be easily fixed. If not, well, at least I tried :)

MentalFish
07-24-2009, 08:13 PM
Thanks art, that got me going in the right direction, but I stranded when it came to retrieving/selecting from the VMSELECTs I created. Any ideas on how to get it across the finish line here? (See comments in code)


main
{
reqbegin("Scale");
amount_ctl = ctlnumber("Scale by (%)",50.0);
return if !reqpost();
amount = getvalue(amount_ctl) / 100;
reqend();

undogroupbegin();

selmode(USER);
var currLayer=lyrfg();
var emptyLayer;
emptyLayer = lyrempty();
cut();
lyrsetfg(emptyLayer);

// Move geometry to seperate layer so we can get to each "island" of polys
paste();

var selCounter = 1;
polys = polycount();
while(polys[1] >0)
{
selpolygon(CLEAR);
selpolygon(SET,POLYNDX,1);
selpolygon(SET,CONNECT);

// Create selection sets instead of scaling at this point
MakeSelSet("TempScaleSelection"+selCounter);
selCounter = selCounter + 1;

selhide(SELECTED);
selmode(GLOBAL);
polys = polycount();
selmode(USER);
}
selunhide();
cut();
lyrsetfg(currLayer);
paste();

// Merge the "islands" back with the rest of the geometry
mergepoints();

for(n=1;n<selCounter;n++)
{
// Next: How do we get/use a VMSELECT?
// PSEUDO: select points from VMSELECT where name = "TempScaleSelection"+n
// Then this should work:
/*
selhide(UNSELECTED);
center = center(boundingbox());
scale(amount,center);
selunhide();
*/
}
// Is it also possible to reselect all the originally selected polygons
// and then delete all the temp VMSELECTs?

undogroupend();
}

// Copy/paste from Dodgy in another thread on the forum:
MakeSelSet:pname
{
selmode(USER);
editbegin();
mygroup=VMap(VMSELECT,pname,1);
foreach(p,points)
{
mygroup.setValue(p,1);
}
editend();
return(mygroup);
}

MentalFish
07-24-2009, 11:07 PM
It works now :beerchug:
I ended up using parts to set and get my selections, so be warned this script removes all existing parts assignments you may have in the model!!! If I don't do that, the old selections come along for the ride and gets scaled too.

This script also keeps the polygon selection after it is done.


main
{
reqbegin("Scale");
amount_ctl = ctlnumber("Scale by (%)",50.0);
return if !reqpost();
amount = getvalue(amount_ctl) / 100;
reqend();

undogroupbegin(); // One undo for this whole operation

selmode(USER);

var currLayer=lyrfg();
var emptyLayer = lyrempty();

// Put the polygon island on a seperate layer
cut();
lyrsetfg(emptyLayer);
paste();

// ### DELETE ALL EXISTING PARTS ###
lyrsetfg(currLayer);
selpolygon(CLEAR);
changepart("");

// Iterate through each island to create parts
lyrsetfg(emptyLayer);
var selCounter = 1;
polys = polycount();
while(polys[1] >0)
{
selpolygon(CLEAR);
selpolygon(SET,POLYNDX,1);
selpolygon(SET,CONNECT);
changepart("TempScaleSelection"+selCounter);
selCounter = selCounter + 1;
selhide(SELECTED);
selmode(GLOBAL);
polys = polycount();
selmode(USER);
}
selunhide();

// Reconnect the islands with the rest of the mesh
cut();
lyrsetfg(currLayer);
paste();
mergepoints();

// Scale all polygon islands
for(n=1;n<selCounter;n++)
{
selpolygon(CLEAR);
selpolygon(SET,PART,"TempScaleSelection"+n);
selhide(UNSELECTED);
center = center(boundingbox());
scale(amount,center);
selunhide();
}

// Reselect all polygon islands
for(n=1;n<selCounter;n++)
{
selpolygon(SET,PART,"TempScaleSelection"+n);
}

undogroupend();
}

Thanks for the help, I wouldn't have got on the right track without it!

daforum
07-25-2009, 03:40 AM
So is this now available as a compiled script to download?

I needed to do something similar yesterday and had to end up scaling one, deleting the others and then arraying them again. A script like this would benifit not just me but the whole community.

dballesg
07-25-2009, 04:13 AM
So is this now available as a compiled script to download?

I needed to do something similar yesterday and had to end up scaling one, deleting the others and then arraying them again. A script like this would benifit not just me but the whole community.

Why you need a compiled script?

Copy the text on the window. Be sure you copy the whole text.
Paste it inside Notepad or your preferred text editor.
Save it as thenameyouwant.ls.

Use the LScript command button (not the LSCript/RT) in modeler to open and execute it.

David

daforum
07-25-2009, 02:47 PM
Thanks david, I will give that a go.

I just thought a script available for everyone would be a useful tool.

MentalFish
07-25-2009, 06:47 PM
I am adding rotate, bend, twist and so on to the script too, and then i will post it as a download, but it will still be a regular .ls script file so everyone can add to the code as they see fit. People shouldn't make .lsc files unless they plan to sell their script, it's quite annoying when an lscript breaks and I can't fix it or learn from it since it is an lsc file.

In the meantime you can do as dballesg said and copy-paste-save it as a text file with .ls extension, but I would suggest you add like any other plugin (Add Plugin F11). Then you can assign it to a key or menu item by pressing Alt+F9 or Alt+F10. The plugin will come up under Additional with the same name as the file you save it to, i.e. ScalePolyIslands.ls

Stay tuned for more.

evenflcw
07-25-2009, 09:08 PM
Clever use of cut, paste and select connected to avoid costly mesh parsing. But you probably don't have to mess with parts and layers. Instead of parts just grab the polyIDs, kinda like so:


editbegin();
mypolys = polygons; //polygons is an array created when editbegin is called.
editend();

and reselect each island for processing with the selpolygon(SET, POLYID,...) function.

I made a few edits to accommodate. Slightly cleaner output. I put selmode allover the place (for consistency) because I had an issue with Modeler counting polys that should've been hidden under USER selmode. Oddly, it did not have issues when debugging, so I suppose it some kind of refresh bug.



@version 2.7
@warnings
@script modeler

amount;
groups;
groupCnt = 0;

polygons {
editbegin();
polys = polygons;
editend();
return polys;
}

main
{
//interface
{
selmode(DIRECT);
(polyCnt) = polycount();
if(polyCnt<1) {
info("No polygons selected");
return;
}

reqbegin("Scale");
amount_ctl = ctlnumber("Scale by (%)",50.0);
return if !reqpost();
amount = getvalue(amount_ctl) / 100;
reqend();
}


//processing
undogroupbegin();
{
selmode(USER);

//hide non-island and disconnect islands for Select Connected to work.
selhide(UNSELECTED);
cut(); paste();

//extract polygon groups
(polyCnt) = polycount();
while(polyCnt) {
selmode(USER);
selpolygon(SET,POLYNDX,1);
selpolygon(SET,CONNECT);
groups[++groupCnt] = polygons();
selhide(SELECTED);
selmode(GLOBAL); //Bug workaround! USER selmode counts hidden polys. Hides to slow!?
//Oddly, USER mode works when debugging.
(polyCnt) = polycount();
}

//reconnect
selunhide();
mergepoints();

//process each group
for(i=1;i<=groupCnt;i++) {
selmode(USER);
selpolygon(CLEAR);
selpolygon(SET,POLYID,groups[i]);
center = center(boundingbox());
scale(amount,center);
}

//reselect
selmode(USER);
selpolygon(CLEAR);
for(i=1;i<=groupCnt;i++) {
selpolygon(SET,POLYID,groups[i]);
}
}
undogroupend();
}

MentalFish
07-26-2009, 08:53 PM
Thanks evenflcw! I took it one step further and made it interactive as well as adding rotation to it too.

I could not figure out a way to delete the morph map I use to enable the interactivity, perhaps you could take a look at it?

It would also be cool to make the rotation work around the averaged normal of the selected polygons, so we could rotate the islands around their own/local "up" axis (See attachment). Any ideas on how to do this?

I also tested some twist and bend, but found it troublesome with the autoflex and fixedflex. It seems it expects/demands having an easing effect applied to it, while i want a linear/constant twist effect across the selection. Also, it would be cool if the twist effect could happen on the selection's averaged normal.


@version 2.7
@warnings
@script modeler

groups;
groupCnt = 0;

scaleAmount = 100;

rotateXAmount = 0;
rotateYAmount = 0;
rotateZAmount = 0;

polygons {
editbegin();
polys = polygons;
editend();
return polys;
}

main
{
init();
interface();
}

init
{
selmode(DIRECT);
(polyCnt) = polycount();
if(polyCnt<1) {
info("No polygons selected");
return;
}
extractPolyGrp();

//createMorphMap();
reselect();
}

interface
{
reqbegin("Polygon Islands");
reqsize(200, 150);

amount_ctl = ctlminislider("Scale:",100,0,1000);
ctlrefresh(amount_ctl, "updateScale");

ctlsep();

rotateXAmount_ctl = ctlminislider("Rotate X:",0,-360,360);
ctlrefresh(rotateXAmount_ctl, "updateXRotate");
rotateYAmount_ctl = ctlminislider("Rotate Y:",0,-360,360);
ctlrefresh(rotateYAmount_ctl, "updateYRotate");
rotateZAmount_ctl = ctlminislider("Rotate Z:",0,-360,360);
ctlrefresh(rotateZAmount_ctl, "updateZRotate");

if(reqpost())
{
selectBaseVmap();
reselect();
confirmChanges();
}
else
{
selectBaseVmap();
reselect();
}
reqend();
}

confirmChanges
{
process();
}

updateScale: value
{
scaleAmount = value;
process();
}
updateXRotate: value
{
rotateXAmount = value;
process();
}
updateYRotate: value
{
rotateYAmount = value;
process();
}
updateZRotate: value
{
rotateZAmount = value;
process();
}

extractPolyGrp
{
undogroupbegin();

selmode(USER);

//hide non-island and disconnect islands for Select Connected to work.
selhide(UNSELECTED);
cut(); paste();

// extract polygon groups
(polyCnt) = polycount();
while(polyCnt) {
selmode(USER);
selpolygon(SET,POLYNDX,1);
selpolygon(SET,CONNECT);
groups[++groupCnt] = polygons();
selhide(SELECTED);
selmode(GLOBAL); //Bug workaround! USER selmode counts hidden polys. Hides to slow!?
//Oddly, USER mode works when debugging.
(polyCnt) = polycount();
}
// reconnect
selunhide();
mergepoints();

// show selection again
reselect();

undogroupend();
}

createMorphMap
{
selectBaseVmap();
editbegin();
morphTarget=VMap(VMMORPH,"_TempVMap",3);
if(!morphTarget) error("Could not create the VMap");
foreach(p,points)
{
values[1] = 0;
values[2] = 0;
values[3] = 0;
morphTarget.setValue(p,values);
}
editend();
}

process
{
createMorphMap();
undogroupbegin();
//process each group
for(i=1;i<=groupCnt;i++) {
selmode(USER);
selpolygon(CLEAR);
selpolygon(SET,POLYID,groups[i]);
center = center(boundingbox());

scale(scaleAmount/100,center);

rotate(rotateXAmount,X,center);
rotate(rotateYAmount,Y,center);
rotate(rotateZAmount,Z,center);
}
reselect();
undogroupend();
}

reselect
{
//reselect
selmode(USER);
selpolygon(CLEAR);
for(i=1;i<=groupCnt;i++)
{
selpolygon(SET,POLYID,groups[i]);
}
}

selectBaseVmap
{
new();
close();
}

art
07-27-2009, 07:24 AM
I was busy over the weekend and didn't have a chance to reply, but I see that the script grew quite nicely. :thumbsup:

evenflcw
07-27-2009, 01:48 PM
It's seems tough to take this much further. XY rotation seems totally arbitrary on anything but axially alinged pieces (=islands).


I could not figure out a way to delete the morph map I use to enable the interactivity, perhaps you could take a look at it?
Only way to delete is to set morph value to 0 for all points. You might have to switch back to base aswell (possible in lscript?) for it to disappear completely.

It seems to transform in interactively for me without using morphs (commented out createMorphMap() in process()). Didn't it by you?


It would also be cool to make the rotation work around the averaged normal of the selected polygons, so we could rotate the islands around their own/local "up" axis (See attachment). Any ideas on how to do this?
Determining the axis automatically seems tricky. Average normal is safe and easy, but will obviously only work for geometry that have total rotational symmetry. I think perhaps it would be better to only analyze the points inbetween the islands and the rest (like if each piece was just a single poly). That should define the local construction plane for each piece. But starting with the simplest is the best way forward. You have the ids of all polys in each groups and there is a polynormal() function and a normalize(). So that's not much trouble. What remains is what to do with it... (read on)


I also tested some twist and bend, but found it troublesome with the autoflex and fixedflex. It seems it expects/demands having an easing effect applied to it, while i want a linear/constant twist effect across the selection. Also, it would be cool if the twist effect could happen on the selection's averaged normal.
Indeed they seem to require falloff, something you can't set from code. And rotation around an arbitrary axis doesn't seem to be possible via preexisting functions. So if one wants anything usefull, one either has to write all functions oneself or completely redesign it to make better use of native tools. Similar to CPlane or JettoLocal one could center and align all selected pieces, allow user to transform via native tools, then return pieces to their original position and alignment. That totally screw the interactive in-place preview but you can use any deformation tool you like.

MentalFish
07-27-2009, 06:15 PM
I think I have managed to retrieve the average normal of the selected polys through this:



// storing the normals in an array that is equally long as the groups array
groupsNml[groupCnt]= getNormal();
....
getNormal
{
selmode(USER);
editbegin();
polies = polycount();
polcnt = polies[1];
averageNml;
for(i=1; i<=polcnt; i++)
{
pol = polygons[i];
nml = polynormal(pol);
if(i==1)
averageNml = nml;
else
averageNml = averageNml + nml;
}
averageNml = normalize(averageNml);
editend();
return averageNml;
}


Now the question is, how do I use this to create the rotation around the normal "axis" of each polygon-selection?

intssed
07-28-2009, 03:53 AM
Thanks, petterms! "Scale" code is very useful!!!

art
07-28-2009, 09:02 AM
Now the question is, how do I use this to create the rotation around the normal "axis" of each polygon-selection?

As Dan said, you would probably have to write your own functions. I am not sure if polygons could be rotated directly. Maybe you would have to switch to point selections for that

MentalFish
07-29-2009, 02:53 AM
I have managed to get the polygon-islands rotate:

- Around their own average normal (only works for "symmetrical" meshes)
- The islands's neighbor polygons average normal (expand selection, deselect island)
- And came up with a third solution I will have to implement tonight where it will rotate around the normal of its own "base" so to speak.
Similar to what evenflcw said:
I think perhaps it would be better to only analyze the points inbetween the islands and the rest (like if each piece was just a single poly).

If this last one works it will be used by default and the two others become pretty much useless, but I might keep them as options through checkboxes.

Stay tuned.

art
07-31-2009, 09:00 AM
so how did you end up doing the rotations?

MentalFish
07-31-2009, 06:42 PM
rotate((rotateAmount-rotateAmountPrev)*polyGroupsNml[i].x,X,center);
rotate((rotateAmount-rotateAmountPrev)*polyGroupsNml[i].y,Y,center);
rotate((rotateAmount-rotateAmountPrev)*polyGroupsNml[i].z,Z,center);I will post the full script later on, as I want to tweak it a bit more and add a bend feature too.

Check out a screencast of it here:
http://vimeo.com/5866693 (it said 20 mins left until converting when I post this)

The twist tool is very sluggish, but at least it is there :)

MentalFish
08-02-2009, 03:17 PM
http://mentalfish.com/uploads/lscripts/MFPolygonGroups.gif

MFPolygonGroup (http://mentalfish.com/uploads/lscripts/MFPolygonGroups.zip)

I had problems getting the undogroupbegin/end to work, so it applies the transformation to a morph map, so you can go back to the (base) to "undo".

If you want to apply the transformation to (base) you can go: Map -> More -> Morph -> Apply Morph

The twist feature is a bit on the heavy side, so typing in the values numerically might help instead of dragging the slider. Other features such as pinch and bend might come later.

The select (base) hack by using new(); close(); only works if you have one model open at a time. Any other ways of going back to the base morph map?

evenflcw
08-02-2009, 03:25 PM
That looks pretty snazzy! Well done. Thanks.

EDIT: And works damn well too!

colkai
08-03-2009, 05:25 AM
Very cool - many thanks.

probiner
08-03-2009, 05:58 AM
I was about o cross "Edit Selection and Connected Geometry by independent center and axis" of my list. But i did not quite understand wich kind of selection you have to set in order to work. Only extruded and equal sets of poly work?

Cheers

PS: It's lovely to see stuff like this growing in the forum. Good work guys =)

MentalFish
08-03-2009, 01:19 PM
The script is updated, new download url, now it manages to apply the transformation to the (base) if you press ok, and if you press cancel it goes back to the (base) without applying the transformation.

I also went back to the initial name for it, Polygon Islands, I have a logo/icon in mind for it :)
Download MentalFish Polygon Islands (http://bit.ly/2XbH21) v 2009.08.03

Not sure if I understand your question probiner, doesn't this LScript work on differently shaped polygon selections? It works on the various types of poly-island shapes and sizes I have tried so far.

probiner
08-03-2009, 03:28 PM
Line 313, invalid polygon dientifer provided by selpolygon()

i get this a lot of time if i dont do a straing selection like the ones you do in you images.

My question is whats the condition for such selections?

by "Edit Selection and Connected Geometry by independent center and axis" I meant something like in the image below. If i do apply the script to that. BOOM, Line 313, inval... (and so on)

I'm probably misunderstanding the whole point of the script, sorry

Cheers

MentalFish
08-03-2009, 03:54 PM
The problem is the selection on the left, the script does not find an opening or end of the selection and as such it is not an "island" of polygons. If you cut off the bottom polygon of the model it should work as an island (the script will "find" the hole and use it as the base/pivot for its transformation).

I will add proper methods and messages to display for these situations.

probiner
08-03-2009, 04:53 PM
Great i see my self using this a lot even for single islands too.
We have Cplane to make a construction plane like Modo, but this can do the trick.

Just have to erase one poly and that's it =) And the toggle Center works like i wanted.

Only problems seem to see is that that LScript + Many Geometry = slow and Twist takes long to compute and i have to shut down Modeler. Same like WedgeBevel with complex meshes. If i wait enought tough it will compute.

Good Job and thanks

adk
08-03-2009, 05:06 PM
Great work folks ... and many thanks for this very handy script petterms :thumbsup::thumbsup::thumbsup:

art
08-04-2009, 07:24 AM
Only problems seem to see is that that LScript + Many Geometry = slow

Unfortunately, that's a common issue with lscript.

JeffrySG
08-04-2009, 08:27 AM
All I have to say is .... WOW! you guys rock! Very cool LS there!

probiner
08-04-2009, 11:37 AM
.p ?
It would be cool.
:thumbsup:

JeffrySG
08-04-2009, 12:15 PM
but...

.plugin

would be cooler! ;)

Kuzey
08-04-2009, 12:23 PM
but...

.plugin

would be cooler! ;)

Haha............+1

:D

Kuzey

MentalFish
08-04-2009, 02:38 PM
if it turns into a .p / .plugin I am out of the game, no skills in that department :stumped: but sure, that would be brilliant if it improves performance. But remember, share the source, keep it open :thumbsup:

Although, if it turns into a .plugin and xcode project, I would love to check it out and perhaps learn a thing or two from it.

probiner
08-04-2009, 03:07 PM
You could poke a coder... ehehe =)

"Teach me" :twak:

MentalFish
08-05-2009, 01:01 PM
Hey probiner (and everyone else :)) now you can use enclosed selections that you had problems with earlier. Come and get it:
Download MentalFish Polygon Islands (http://bit.ly/2XbH21) v 2009.08.05

When having enclosed polygon selections without any openings, the twist feature is disabled as it is using the contract selection feature which obviously does not work on a selection like that.

Edit: it seems I have disabled the twist feature regardless of selection type. Looking into it. Brb.

Edit 2: the twist issue among others i came across has been fixed

probiner
08-07-2009, 11:05 AM
Nice one again petterms.

Working here =)
Thanks

dandod
09-16-2009, 10:03 AM
Is it possible to individually scale islands of polygons, based on each poly-island's own center, or does it have to be done manually?

My apologizes if someone already said this. Point Normal Move under the Modify Tab can scale polygon islands. I do like the extra features your plugin offers, though!

MentalFish
02-16-2010, 05:38 PM
Update, more goodies: http://mentalfish.com/2010/02/islands-update/

probiner
02-16-2010, 05:50 PM
Congratz, looking even better.

Exception
07-31-2012, 11:14 AM
My apologizes if someone already said this. Point Normal Move under the Modify Tab can scale polygon islands. I do like the extra features your plugin offers, though!

How's that? I tried it and doesn't seem to do that.

Congrats on the plugin! I've tried it and it works well. I do have a question though... what's the actual unit of measure the number you type in have? Like, when I put in '30' in the scale field, what does the '30' mean? It's not percentage, doesn't seem to be millimeters... i'm confused.

Also, does it help to compile the script to increase speed? It's so slow... trying it on a tree with 10.000 leaves, and it takes ages.

erikals
07-31-2012, 11:41 PM
that's right, Point Normal Move is hardly the same :]