View Full Version : Can't get my Polygons to update
Scott Ayers 07-22-2010, 04:27 PM Can anyone tell me why my selected polygon won't move even though it's been moved in memory?
Here's the code: var bs = new(BaseSelect); // holds the polygon data
var select = bs->Select(4); //Select polygon#4 in the object's available array of polygons
select = vector(0,0,0);// Move it to these coordinates in memory
println(select);// Check to see if it was really moved-->Checks out fine
op->SetPolygonSelection(bs);//Execute the changes-->DOES NOT WORK!!
op->Message(MSG_UPDATE);
-ScottA
|
|
Cairyn
07-22-2010, 05:12 PM
Can anyone tell me why my selected polygon won't move even though it's been moved in memory?
Here's the code: var bs = new(BaseSelect); // holds the polygon data
var select = bs->Select(4); //Select polygon#4 in the object's available array of polygons
select = vector(0,0,0);// Move it to these coordinates in memory
println(select);// Check to see if it was really moved-->Checks out fine
op->SetPolygonSelection(bs);//Execute the changes-->DOES NOT WORK!!
op->Message(MSG_UPDATE);
Because you're not doing with this code what you think you're doing... :-)
A BaseSelect does not hold copies of the polygons or their position. It just lists all the selected polygons. It is a list of indices. So, what you are doing here, is:
var bs = new(BaseSelect); // you create a new, empty selection
var select = bs->Select(4); // you select the fourth polygon
This will NOT return the fourth polygon. Instead, the return value is a Boolean that tells you whether the call to Select() worked. (note: "select" is now Boolean)
select = vector(0,0,0); // overwrite the boolean with a vector
This will NOT set any polygon to any value (even considering that you can't assign a single vector to a full polygon - you need to move its points). Instead, it overwrites the current content of the variable "select" with the null vector. (note: "select" is now a vector)
println(select); // this will output the null vector.
This null vector does nothing, since you never use it anywhere. "select" is a variable that has nothing to do with the polygons of your object, or with the selection. It has absolutely no effect on the result.
op->SetPolygonSelection(bs); // Set a new selection, in this case the fourth polygon
This does NOT move anything. The variable "bs" is now a BaseSelect that tells the object "op" that its fourth polygon is supposed to be selected. Because that's how you set up your BaseSelect with the second line.
When the code is done, and you are in polygon mode, you will notice that the fourth polygon is selected, indeed. And that's what your code does.
If you want to move a polygon, you need to:
- Access the actual polygon array
- Find the vertices of that polygon
- Change the coordinates of those vertices
- Notify the object of polygon change.
A BaseSelect will help you only with selections, not with the actual coordinates.
Scott Ayers
07-22-2010, 05:35 PM
I was afraid of that.
I took a look through my notes. And it occurred to me that I was only grabbing the polygon and I would have to write more code to do something with it. But I wasn't sure.
I always get confused when it comes to polygons as opposed to dealing with vertices.
Every time I try to use the built in functions in C4D. I always end up not being able to use them. And end up having to resort back to manipulating the vertices themselves.
I think it was JDP that once told me that those polygon functions can only be used for getting them and information about them. And that they can't be used to actually manipulate them.
But I could have misunderstood that.
In my head. When I see a selected polygon I think to myself "I've got the thing selected. So why can't I just move it to a different vector position?"
If I wanted to move a selected polygon as a whole. Rather than moving each point of the polygon individually. Could I somehow create a new array, or possibly a new matrix for it. And then use that to move it?
-ScottA
Cairyn
07-22-2010, 06:25 PM
I was afraid of that.
I took a look through my notes. And it occurred to me that I was only grabbing the polygon and I would have to write more code to do something with it. But I wasn't sure.
I always get confused when it comes to polygons as opposed to dealing with vertices.
Every time I try to use the built in functions in C4D. I always end up not being able to use them. And end up having to resort back to manipulating the vertices themselves.
I think it was JDP that once told me that those polygon functions can only be used for getting them and information about them. And that they can't be used to actually manipulate them.
But I could have misunderstood that.
In my head. When I see a selected polygon I think to myself "I've got the thing selected. So why can't I just move it to a different vector position?"
If I wanted to move a selected polygon as a whole. Rather than moving each point of the polygon individually. Could I somehow create a new array, or possibly a new matrix for it. And then use that to move it?
-ScottA
Well, let's go back one step. First, you may have the wrong concept of a polygon. A polygon is a set of vertex references, nothing more. It's not an object that you can grab and handle. To get the full benefit of C4D programming, you must get used to the idea that some things are just referencing other things, which may be referencing third things, which link to fourth things, which then can be handled in some way. The polygon is a lie. You cannot take it and handle it programmatically, as you can do it through the user interface.
Let's start with a simple code example.
movePolygon(obj,p,vec) {
println(obj, " ", p, " ", vec);
var point = obj->GetPoint(p->a);
obj->SetPoint(p->a, point + vec);
point = obj->GetPoint(p->b);
obj->SetPoint(p->b, point + vec);
point = obj->GetPoint(p->c);
obj->SetPoint(p->c, point + vec);
point = obj->GetPoint(p->d);
obj->SetPoint(p->d, point + vec);
}
main(doc,op){
var poly = op->GetPolygon(4);
movePolygon(op,poly,vector(0.0,10.0,0.0));
op->Message(MSG_UPDATE);
}
The function movePolygon() may be what you want. It takes a polygon (needs the object reference too, to access the points) and moves it by a vector. This is done by adding the vector to all points of the polygon.
The main program extracts the fourth polygon and passes it to this function. And lo!, the polygon moves. (Provided you have a polygon object selected, and that object has at least 4 polygons, otherwise the whole thing crashes, because I'm too lazy to include the absolutely necessary safety checks.)
Now, this function gives you the power to manipulate polys. You can pass other vectors, or write methods to transform these polygons in some other way. But... it is too simple!
What happens if you call the function on adjacent polygons?
var poly = op->GetPolygon(4);
movePolygon(op,poly,vector(0.0,10.0,0.0));
poly = op->GetPolygon(3);
movePolygon(op,poly,vector(0.0,10.0,0.0));
Let's assume that the polys 3 and 4 are adjacent.
Now, the polys may not move in the way you expect. They don't behave as a group, preserving the angle between them, like they would have done if you had selected them in the GUI and moved them. Instead, they actually move as if you had first selected one manually, moved it, then selected the other, moved it as well. The points that are common to both polygons have been moved twice.
As you see, it's not easy to get a special effect. If you want to move polygons as a group, so that each vertex is transformed only once, you would need to build up a list of points that contain each polygon's point exactly once, then transform all vertices in that list. (You can use a BaseSelect for that, if you don't mind that it will change your vertex selection.)
Also note: In my examples, there is no BaseSelect, and it does not matter what polys are really selected! Since I address only the 4th poly by index, I don't refer to any selection at all. If you want to affect the user's selection only (instead of using a fixed index), then you will need to get the object's BaseSelect and extract the polygon indices from there.
Cairyn
07-22-2010, 06:59 PM
Now for the tricky part: complete selections. Here's some code:
moveSelection(obj,vec) {
var bs = obj->GetPolygonSelection();
var ptbs = new(BaseSelect);
var poly;
var point;
var i;
for (i = 0; i < obj->GetPolygonCount(); i++) {
if (bs->IsSelected(i)) {
poly = obj->GetPolygon(i);
ptbs->Select(poly->a);
ptbs->Select(poly->b);
ptbs->Select(poly->c);
ptbs->Select(poly->d);
}
}
for (i = 0; i < obj->GetPointCount(); i++) {
if (ptbs->IsSelected(i)) {
point = obj->GetPoint(i);
point = point + vec;
obj->SetPoint(i,point);
}
}
}
main(doc,op){
moveSelection(op,vector(0.0,-10.0,0.0));
op->Message(MSG_UPDATE);
}
The method moveSelection() will move a whole polygon selection at once by the vector vec. (As the main() program shows.)
How is this done?
First, we get the current polygon selection of the object. (Which hopefully is a polygon object... see my comment in the last post.)
Then, we create a new, empty BaseSelect (ptbs, as in point base select...).
Then in the first "for", we go through all the object's polygons and for each, ask the first base select (the user's selection), whether the polygon is selected. Yes? Then we need to pick each point of the polygon and put it into our second BaseSelect.
Note that we do not use an array to store these points, or any other user data structure, but a BaseSelect. Why? Because a BaseSelect already takes care of points that are part of several selected polygons. Or easier: If I add a "4" to a BaseSelect that already contains a "4", there will still be only one "4" in the BaseSelect. That's what BaseSelect does.
When we are done with this loop, we can forget about polygons and the user's selection. Our ptbs now contains all points of all selected polygons, and each point only once.
We enter the second "for" loop. This time, we iterate over the points of the object, since that is where the coordinates are. For each point, we ask our ptbs whether the point is selected. (Meaning: This point was part of a selected polygon.) If that is the case, we add the transformation vector to it and write it back.
And when we're done with this loop, we're done with the task. Each point belonging to any selected polygon has been transformed (moved by "vec"), and only once instead of "as often as polygons are using this point". Voila.
Scott Ayers
07-22-2010, 08:06 PM
Lol.
I swear you must have been reading my mind. Because I have been trying to get the GetPolygonSelection() function to work with your MovePolygon() method for the past 20 minutes and failing miserably.
These are really great examples and they will come in handy.
I've looked all over the place and these are the only Polygon manipulation examples I've seen.
One last simple thing I'm stuck on.
I can't figure out how to get (print) the polygon index numbers for an object.
Is there a built in function that will do this? Or do I have to loop through the object by hand to get that information?
-ScottA
Cairyn
07-23-2010, 08:18 AM
I've looked all over the place and these are the only Polygon manipulation examples I've seen.
One last simple thing I'm stuck on.
I can't figure out how to get (print) the polygon index numbers for an object.
Is there a built in function that will do this? Or do I have to loop through the object by hand to get that information?
Well, I think most experienced programmers find the actual vertex manipulation to be a simple thing, so no one bothers with writing it down (and since there is no way to make money with teaching COFFEE now, I doubt anyone ever will). Selections, on the other hand, are a bit more complicated - I still find it baffling that there is no method to get the "next selected index" from a BaseSelect, apparently. Such a method exists for Containers, which are still a bit more complicated - for the recent thread about UserData, I actually had to look things up.
Anyway. As for your question about the polygon index numbers, this would be 0, 1, 2, 3, 4 ... up to the number of polys-1. Yes, it's that simple. Look into the Structure manager, the indices are the rows. Since polys and points are arrays, they always start at 0 and are consecutely numbered. (Other than Containers, which are maps and therefore contain arbitrary "indices".)
Or do you mean the polygon indices for something else, like a selection?
Scott Ayers
07-23-2010, 02:32 PM
The numbers in the structure manager is what I meant. The ones listed under the word "Polygon".
I can't seem to find the right function that will display those numbers in the console for the entire object, and/or for any selected polygons.
Since they are always displayed in the structure manager. I thought there might be a built in function that will do that?
I was able to get close. But it was printing out the column values sequentially under the A,B,C D columns. Which isn't what I wanted.
-ScottA
Cairyn
07-23-2010, 03:08 PM
The numbers in the structure manager is what I meant. The ones listed under the word "Polygon".
I can't seem to find the right function that will display those numbers in the console for the entire object, and/or for any selected polygons.
Since they are always displayed in the structure manager. I thought there might be a built in function that will do that?
I was able to get close. But it was printing out the column values sequentially under the A,B,C D columns. Which isn't what I wanted.
As I said, it's simply 0, 1, 2, 3... The polygons are stored in an array, which always have consecutive indices. You actually do not need any functions to "get" those numbers, except GetPolygonCount() to determine the upper bound of the array.
Look at the first "for" loop in my code, the one over the polygons. That is how you get all polygons in the order (without the "if" inside). If you want to have the selected polygons only, get the BaseSelect and test each polygon index with IsSelected(), again, like in the first "for" loop.
The same is valid for the points. Array, consecutive indices, BaseSelect. You can address all data in a polygon or point object in this way.
As you will find out, there are no edge functions though. An edge is simply any of the connections p->a to p->b, p->b to p->c, p->c to p->d, p->d to p->a for any polygon p, and they are not stored separately. (I think there are no methods in COFFEE to address edges directly, but I may be mistaken.)
Scott Ayers
07-23-2010, 05:08 PM
Ok. Thanks.
I was just curious if there was already a built-in function that did that.
But I guess I'll have to do it by hand like this: var selected = op->GetPolygonSelection();
var i;
for(i = 0; i < op->GetPolygonCount(); i++)
{
println(i);// prints all the polygons
if(selected->IsSelected(i))
{
op->GetPolygon(i);
println(i);// prints any selected polygons
}
}
No biggie.
I was just thinking that this function might have already been buit by Maxon.:shrug:
As always. Thanks a ton for the help.
I can find lot's of good tutorials about coding strings, databases, and web sties. But I'm having a very hard time finding good tutorials about polygon and matrix manipulation that aren't written for someone with a PHD in math. So the advice you guys are giving me here is very helpful.
-ScottA
CGTalk Moderation
07-23-2010, 05:08 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
vBulletin v3.0.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.