PDA

View Full Version : drop cube to the floor


Jannis
09-15-2009, 10:37 AM
I have for years resisted learning coffee though I am quite capable with mel and javascript and some other bits and pieces. I find coffee syntax too... Anyway, I am starting small to see if I can get into it at last with the view of recreating an autorigger set up that I have made in Maya. If I get there I would like to share it with the community but need loads of help to get on with coffee.

So here is the first litttle script for making primitives being dropped on the floor after their hight has been modified. It is very simple but something that I find useful:

var myFloor = object()#PRIM_CUBE_LEN:VECTOR_Y;

object()#ID_BASEOBJECT_POSITION:VECTOR_Y = myFloor/2;

At the moment it works only with primitive cubes but it should be very easy to apply to any object if I knew how to access the active object in the scene.
I found out about getActiveObject command but don't know how to write it correctly.
If anyone can help this might be a handy little script.

donelgreeko
09-15-2009, 01:42 PM
Hi, try:

var op;
op = doc->GetActiveObject();

tcastudios
09-15-2009, 02:37 PM
In a Script (ScriptManager):
op is the single selected object (more than one object selected return an error).
In a CoffeeTag, op is the object that the tag is attached to.


if(!op) {println("No Object or more than one Object is selected");return;}
op->SetName("Hey");


In both a script and a coffeTag (CinemaR11+):
object() is the first selected object found.
tag() is the first selected Tag found.

if(!object()) {println("No Object Selected");return;}
object()->SetName("Hey");

Cheers
Lennart

Jannis
09-15-2009, 04:24 PM
Thank you both.

donelgreeko
09-18-2009, 12:44 PM
more than one object selected return an error

Oh, really? Good to know. I thought the first object from a multi-selection returns.
You live and learn. :)

Jannis
09-18-2009, 06:42 PM
Hi, I am still trying to refine this little script and learn on the way,

I have found how to change scale by the SetScale command,

object()->SetScale (vector (1,1,1));

what is the command for changing size?

Also another question, does the -> sign work the same as dot notation in mel script?

For example in mel you would write,

setAttr "pCube1.translateX" 0;

How would I write this with dot notation in coffee?

Thanks in advance for any help.

By the way, I bought Rui's coffee book, just waiting to be delivered and hope that it will shed some light in the peculiarities of coffee ;o)

tcastudios
09-18-2009, 08:56 PM
"Size" is different depending on what kind of object it is.
A Cube has, as in your first script, PRIM_CUBE_LEN:VECTOR_Y
A Sphere has PRIM_SPHERE_RAD.
So for primitives you need to check what kind it is and then call
the correct value to set.
Such as;

if(op->IsInstanceOf(Ocube))
if(op->IsInstanceOf(Osphere)) // etc

For point objects ( Objects being editable ) you have to run thru
all points and check the size that way.

As you are looking into COFFEE, there are two main ways of
setting and getting values. (Thou both do it sort of the same internally I suppose).

-1 Using Containers.

ex of adding to an existing value:

var bc = op->GetContainer();
var old_value = bc->GetData(someparameter_ID); // <- Only if you want to get it.
var myvalue = x;
bc->SetData(someparameter_ID , old_value + myvalue);
op->SetContainer(bc);

ex of simply set a new value (old value is over written):

var bc = op->GetContainer();
var myvalue = x;
bc->SetData(someparameter_ID , myvalue);
op->SetContainer(bc);

"someparameter_ID" is an ID you need to poke around in Cinema ref files to find.
Either by it's name or number.

-2 Using Operators. (Since R9.102 I think)
The operator " sign" is #.

ex of adding to an existing value:

var old_value = op#ID_SOMEPARAMETER;
var myvalue = x;
op#ID_SOMEPARAMETER = old_value + myvalue;

or more direct.

var myvalue = x;
op#ID_SOMEPARAMETER = op#ID_SOMEPARAMETER + myvalue;


Using the operator method is in most cases the more straight forward.
9 of 10 times it's all you need.
For scripting it is also very convenient since you only need to drag any parameter
from the AM direct into the COFFEE editor or Script Manager and you get the correct ID!
The operator , # , is added automatically.

I hope I don't confuse more than help :)
You -do- need to download the COFFEE SDK 9.5 (currently the latest sdk for COFFEE)
from Maxon. Once you get the basics it is very good.
I really hope any new SDK is as thorough.
And Rui's book is a very good starter/add on!

Cheers
Lennart

Jannis
09-18-2009, 09:19 PM
Lennart thank you very much, I do appreciate your help.

I will try to implement your pointers and see if can get it to work better.

tcastudios
09-18-2009, 09:29 PM
I'm happy to help as time permits.
I remember when I started (and with no programming
experience to talk about) and most of the "in between lines"
info I got from the folks here, too many to mention (so I don't
forget anyone:) )

Cheers
Lennart

Jannis
09-19-2009, 08:02 AM
ok, here is the script and it works with all primitives. Now I need to learn how
to access the points of polygons and it should work with editable objects.

If you want to use it, just copy and paste it in your script editor.

I don't know if this is the most elegant way of writing this, I am sure it is not ;o)
But it is a start.

Thanks for your help again lennart.

ps,

I did get Rui's book and going through it, very good! Hope he
brings out some more educational material.

//cube

if(op->IsInstanceOf(Ocube)){

var cb_grid = op#PRIM_CUBE_LEN:VECTOR_Y;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cb_grid/2;

}


//sphere

if(op->IsInstanceOf(Osphere)){

var sp_grid = op#PRIM_SPHERE_RAD;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = sp_grid;

}

//cone

if(op->IsInstanceOf(Ocone)){

var cn_grid = op#PRIM_CONE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cn_grid/2;

}

//cone

if(op->IsInstanceOf(Ocylinder)){

var cl_grid = op#PRIM_CYLINDER_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cl_grid/2;

}

//capsule

if(op->IsInstanceOf(Ocapsule)){

var caps_grid = op#PRIM_CAPSULE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = caps_grid/2;

}

//oiltank

if(op->IsInstanceOf(Ooiltank)){

var oil_grid = op#PRIM_OILTANK_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = oil_grid/2;

}

//torus

if(op->IsInstanceOf(Otorus)){

var tor_grid = op#PRIM_TORUS_INNERRAD;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = tor_grid;

}

//tube

if(op->IsInstanceOf(Otube)){

var tub_grid = op#PRIM_TUBE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = tub_grid/2;

}

//figure

if(op->IsInstanceOf(Ofigure)){

var fig_grid = op#PRIM_FIGURE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = fig_grid/2;

}

//pyramid

if(op->IsInstanceOf(Opyramid)){

var pyr_grid = op#PRIM_PYRAMID_LEN;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = pyr_grid.y/2;

}

tcastudios
09-19-2009, 07:38 PM
For PointObjects (anything with points) you would check:

if(op->IsInstanceOf(Opoint))

Then you need to use: (For details check the SDK)

var opm = op->GetMg(); // The objects matrix
var oppos = op->GetV0(); // The objects global position
var pc = op->GetPointCount(); //How many points in the object
var pointpos = op->GetPoint(n); //The point (n) local position as a vector
pointpos = opm->GetMulP(pointpos); // The point (n) global position as a vector

Store the first pointposition.y
var lowestpoint = op->GetPoint(0);
before a "for" or "while" loop.
Compare the stored point with the next point, over writing the
stored if the next is lower in space.

And then move the object (oppos.y - lowestpoint.y) units

While more involved, the upside is that you can use the same
code for almost any object by cloning it, make it editable, then
do the calculation on the clone and finally just move the original object.
And then deleting the clone when it's done, clone->Remove().

Have a go at it and then ask:)

Cheers
Lennart

Jannis
09-20-2009, 02:24 PM
Thanks Lennart!

I got it working and it works now pretty well with all polygonal objects with a limitation that
in order for the object to drop on the grid it has to be symmetrical in Y size. I am happy with that though, as it is my first script in coffee and it does meet the task I se it out to do.

So the script now will drop to the grid all primitives and all polygon objects immidietly after they have been made editable.

Here is the polygon part of the script:

if(op->IsInstanceOf(Opoint)){

var n =0;
var i;
var opm = op->GetMg(); // The objects matrix
//var oppos = op->GetV0(); // The objects global position
var pc = op->GetPointCount(); //How many points in the object
var pointpos = op->GetPoint(n); //The point (n) local position as a vector
pointpos = opm->GetMulP(pointpos); // The point (n) global position as a vector

var lowestpoint = op->GetPoint(0);

var lowestpoint_pos = op->GetPoint(n);

for(i=0;i<pc;i++) ;

if(pointpos.y < lowestpoint_pos.y ){ lowestpoint_pos.y = pointpos.y; }

println(lowestpoint_pos.y);

op#ID_BASEOBJECT_POSITION:VECTOR_Y = -lowestpoint_pos.y;

}


Now a couple of things,

Lennart the line to get the objects gloabal position,

var oppos = op->GetV0(); // The objects global position

returns,

Member not found

in the console, so I used instead I used

op#ID_BASEOBJECT_POSITION:VECTOR_Y

to get the object's position. Is there something in the syntax I am missing?

The other thing is a general observation. I am simply amazed that you have to run such convoluted routines in Coffee to simply get the position of a polygonal object, something that you can achieve in mel simply by writing, setAttr "object.translateX" 0;

Though I am now commited to learn coffee and very thankful of all the help it seems to me like a very unfriendly language to start with and this is why despite the fact that I am long time user and have scripted several tools in other landuages I have been relactant to take the plunge.

Anyway, enough with the ranting ;o). Thanks again. My next step is to clean up the code and make this into a simple plugin and then I will start on the autorigger which from the looks of the complexity in coffee will be an uphill struggle ;o)

Jannis
09-20-2009, 03:19 PM
ok, here is the cleaned up code for the polugon object dropped on the
grid, I give it here seperatelly because it was the hardest part of this
script and maybe someone else may bennefit from my straggles ;o)



//polygon object dropped on the grid

if(op->IsInstanceOf(Opoint)){

//counters

var n =0;//counter to set the points of the object
var i;// counter to use in the for loop to cycle through the points of the object

//variables to get position of points

var opm = op->GetMg(); // The objects matrix
var pc = op->GetPointCount(); //How many points in the object
var pointpos = op->GetPoint(n); //The point (n) local position as a vector
pointpos = opm->GetMulP(pointpos); // The point (n) global position as a vector

//variables that points to the first point of the object and gets its position
var lowestpoint = op->GetPoint(0);
var lowestpoint_pos = op->GetPoint(n);

//loop that moves through the pointcount of the object

for(i=0;i<pc;i++) ;

//comparing all points for the one with the lowest Y position

if(pointpos.y < lowestpoint_pos.y )
{
lowestpoint_pos.y = pointpos.y;
}

//passing the lowest Y point position - which sets the object on the grid

op#ID_BASEOBJECT_POSITION:VECTOR_Y = -lowestpoint_pos.y;

}

Jannis
09-20-2009, 03:23 PM
And here is the whole script. Any commends regarding
my sloppiness or otherwise are wellcome ;o)



///////////Jannis Labelle////////////
//Script that sets primitive objects on the grid
//Thanks to Lennart 'tcastudios' without whom I wouldn't have a clue
//how to get started with this

//cube

if(op->IsInstanceOf(Ocube)){

var cb_grid = op#PRIM_CUBE_LEN:VECTOR_Y;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cb_grid/2;

}


//sphere

if(op->IsInstanceOf(Osphere)){

var sp_grid = op#PRIM_SPHERE_RAD;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = sp_grid;

}

//cone

if(op->IsInstanceOf(Ocone)){

var cn_grid = op#PRIM_CONE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cn_grid/2;

}

//cone

if(op->IsInstanceOf(Ocylinder)){

var cl_grid = op#PRIM_CYLINDER_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = cl_grid/2;

}

//capsule

if(op->IsInstanceOf(Ocapsule)){

var caps_grid = op#PRIM_CAPSULE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = caps_grid/2;

}

//oiltank

if(op->IsInstanceOf(Ooiltank)){

var oil_grid = op#PRIM_OILTANK_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = oil_grid/2;

}

//torus

if(op->IsInstanceOf(Otorus)){

var tor_grid = op#PRIM_TORUS_INNERRAD;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = tor_grid;

}

//tube

if(op->IsInstanceOf(Otube)){

var tub_grid = op#PRIM_TUBE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = tub_grid/2;

}

//figure

if(op->IsInstanceOf(Ofigure)){

var fig_grid = op#PRIM_FIGURE_HEIGHT;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = fig_grid/2;

}

//pyrqmid

if(op->IsInstanceOf(Opyramid)){

var pyr_grid = op#PRIM_PYRAMID_LEN;
op#ID_BASEOBJECT_POSITION:VECTOR_Y = pyr_grid.y/2;

}

//polygon object dropped on the grid

if(op->IsInstanceOf(Opoint)){

//counters

var n =0;//counter to set the points of the object
var i;// counter to use in the for loop to cycle through the points of the object

//variables to get position of points

var opm = op->GetMg(); // The objects matrix
var pc = op->GetPointCount(); //How many points in the object
var pointpos = op->GetPoint(n); //The point (n) local position as a vector
pointpos = opm->GetMulP(pointpos); // The point (n) global position as a vector

//variables that points to the first point of the object and gets its position
var lowestpoint = op->GetPoint(0);
var lowestpoint_pos = op->GetPoint(n);

//loop that moves through the pointcount of the object

for(i=0;i<pc;i++) ;

//comparing all points for the one with the lowest Y position

if(pointpos.y < lowestpoint_pos.y )
{
lowestpoint_pos.y = pointpos.y;
}

//passing the lowest Y point position - which sets the object on the grid

op#ID_BASEOBJECT_POSITION:VECTOR_Y = -lowestpoint_pos.y;

}

tcastudios
09-20-2009, 04:44 PM
I was typing fast and it should of coarse be:
var oppose = opm->GetV0();
since we already got the global matrix by;
var opm = op->GetMg();

You need to use the global position ,V(0), to get the
correct calculation.
Using the operator method returns the local position of the object.
(As if it was a child of another object).

You can also see each point (vertex) as a child of it's own object.
That is the local position you get with;
var pointpos = op->GetPoint(n);
And to get it's global position you run the;
pointpos = opm->GetMulP(pointpos);

Also I think you need to look t the "for" loop….
First, no semicolon after a for, while if etc….

Then you need to store the compared points in the loop.
I took the liberty to clutter a bit in your polygon code and
maybe you can see the changes and what they do,
(I hope :) )

Cheers
Lennart

if(!op) return;
if(op->IsInstanceOf(Opoint)){

//var n = 0;

var opm = op->GetMg(); // The objects matrix
var oppos = opm->GetV0(); // The objects global position
var pc = op->GetPointCount(); //How many points in the object NOTE: it's "one more" than the point number

var pointpos = op->GetPoint(0); //The first point (n) local position as a vector
pointpos = opm->GetMulP(pointpos); // The point (n) global position as a vector

var i;
//var lowestpoint_pos = op->GetPoint(0);

for(i=0;i<(pc-1);i++) //;
{
var nextpoint = op->GetPoint(i+1);
nextpoint = opm->GetMulP(nextpoint);
if(nextpoint.y < pointpos.y) // Compare the next point
pointpos = nextpoint; // Store the new lowest point
else pointpos = pointpos; // Store the still lowest point
}

var ypos = oppos.y - pointpos.y;
opm->SetV0(vector(oppos.x , ypos , oppos.z));
op->SetMg(opm);


//if(pointpos.y < lowestpoint_pos.y ){ lowestpoint_pos.y = pointpos.y; }
//println(lowestpoint_pos.y);
//op#ID_BASEOBJECT_POSITION:VECTOR_Y = -lowestpoint_pos.y;

}

Jannis
09-20-2009, 05:53 PM
Thanks Lennart!

I can see that your way of doing it is much more elegant.

I will study your corrections a bit more in depth and I will impliment them
in my code. I did realise I was getting the local position of the points
but didnt know how to access their global position. Thats why I ended
setting the Y position of the lowest point to a negative value, it was the only
way of making sure the object would be set on the grid.

Also, if I may ask you a question about syntax,
if the code still executes when you add a semicolon ;
after the for loop and the if statement, but also
executes without it, what is the advantage or writing
them without the semicolon?

Thanks for all your help once again.

tcastudios
09-20-2009, 07:05 PM
I don't know what shape of polygon object you are testing with
but if you try (with your code) a Platonic Object made editable,
you'll see that it only jumps up and down for each execution.

As for the semicolon.
Since your for loop as actually not doing anything other than
count the " i ", nothing dangerous is happening.
The code still doesn't "see" what it is and simply executes
the lines after it swapping the two .y positions back and forth for each
execution of the script.


So for example using a if like:

if(object()) // there is a selected object
println("It's a Selected object"); // Only prints this if there is a selected object.

if you put a semicolon there like

if(object()); // there is a selected object
println("It's a Selected object"); // Prints this in any case even if nothing selected


These examples are not "dangerous" but if you are searching things with for
example obj->GetNext(), it could lead not only to a faulty code
but a code that goes into an infinite search and memory error/crash.

Cheers
Lennart

Jannis
09-20-2009, 08:20 PM
I don't know what shape of polygon object you are testing with
but if you try (with your code) a Platonic Object made editable,
you'll see that it only jumps up and down for each execution.


true, I tried 'my code' (really it is all your code! ;o) ) with every other object other than the platonic. The platonic gave me problems as a primitive also so I left it out ;o)

Thanks for the clarification of the semicolon.

By mistake I wrote,

if (object())
println ("object selected")

without the semicolon for the prinln()

and I got a warning saying,

Syntax error[expected ';' found '}' ]

even though the curly brackets are not writen. Which means that cinema puts the curly brackets there whether you write them or not and perhaps if you end an if statement with
a semicolon it searches for the argument in the whole document, puting the whole document in the curly brackets, without it applies on a limited scope? Maybe?

tcastudios
09-20-2009, 08:48 PM
It's not my code if it doesn't run ! :)

Regarding semi colons.
Simply put, in general.
Conditions (for, while, try etc) - no semicolon.
Functions ( var = x; , op->GetMg(); etc ) semicolons.

So in reality in you for loop you count "i" and while you
count them the code executes the simple function ";" (Your lonely semicolon)
that does nothing since there is nothing in front of it.

Similar to your if(object()) you code is probably looking at a "open curly bracket"
from earlier in the code.(Maybe)

Never the less, you idea of starting to learn COFFEE using a Drop functionality is
very wise, since it involves most of the basic stuff to get grip of.

Now some homework for you :)
When you get the code to work correct you will notice that it works for
Spline Objects (Editable splines with points) as well.
However, if you take a circle object, make it editable, you see it has
four point.
Now rotate the Circle (banking it)Running the script will then place
the circle spline at the lowest point (vertex) but that isn't the lowest -part- of the spline.
What to do ?! :)
A SplineObject is a PointObject as well!

So look up:
SplineObject
GetSplineObject(),
Ospline
spline->InitLength();
GetSplinePoint(x,x);
UniformToNatural
And then the same local to global issues.

Ok? :)

Cheers
Lennart

Kuroyume0161
09-20-2009, 10:03 PM
Still not completely perfect, but you could reference (or use) my DropToFloor COFFEE plugin. It is not an active script but works well. It is open source so you can examine/use the code as you like.

DropToFloor (http://www.kuroyumes-developmentzone.com/c4d/drop_plugins/DropToFloor.zip)

Robert

tcastudios
09-20-2009, 10:12 PM
I use it daily :)
It's also a very good reference for checking out COFFEE!

(That spline issue, lowest part, could be added maybe at some point :) )

Cheers
Lennart

Kuroyume0161
09-21-2009, 06:26 AM
Thanks, Lennart.

Interestingly, issues with things like Mograph Cloner objects just made known caused me to spend the day updating DropIt and, just now, DropToFloor. Instead of using MCOMMAND_MAKEEDITABLE, the code is using MCOMMAND_CURRENTSTATETOOBJECT and MCOMMAND_JOIN for more consistent results. DropIt! now uses the same basic ray-triangle intersection code as DropIt! Pro for accurate object-object drops. Both have been streamlined for faster processing.

DropToFloor (http://www.kuroyumes-developmentzone.com/c4d/drop_plugins/DropToFloor_0.8.zip)

DropIt (http://www.kuroyumes-developmentzone.com/c4d/drop_plugins/DropIt_0.5.zip)

Again, feel free to examine the DropToFloor code to see how it works.

Robert

Jannis
09-21-2009, 10:30 AM
Thanks guys.

Lennart, thanks for the homework ;o)
Learning about splines will be an important part for developing my autorigger and another
plugin I have created in maya regarding character animation, so I might as well start now.

Robert thanks for pointing me towards your plugin, as soon as I get a little more confident with coffee syntax so that I can understand what I am looking at I will have a thorough look,
I am sure I can learn alot from it.

Ok, back in the sdk to see if I can make any sense of it ;o)

Jannis
09-21-2009, 12:24 PM
While looking for all the hints regarding the spline object in the sdk, I came along the fallowing command which sounds interesting,

GetRad(void)

This is the bounding box radius (x/y/z) of the object, this works for all objects and is faster than manually finding the bounds of even polygon objects, the radius is internally cached.

Vector
The bounding box width, height and depth.

SInce all the primitives are symmetrical and remain so after they are made editable, getting their dimension in Y of their bounding box seems to me ideal and alot faster as the sdk suggests to drop them on the grid. I am thinking that since that can be accomplished
easily with the bounding box expresso tag that in effect gives you the size of the object
the GetRad() command seems to promise to do the same thing?




though writing,

op->GetRad();

Gives a Fail script incompatible values.

tcastudios
09-21-2009, 03:08 PM
I think you are looking at the "Main" SDK for C.
You need to go to Maxon ->Support -> Older SDK Documents

and then get the
"COFFE SDK 95 zip/chm".

All C stuff is not implemented in COFFEE.
And I don't think GetRad() is. (Never used it)

Cheers
Lennart

Jannis
09-21-2009, 04:54 PM
Thanks once again Lennart, you are right I have been using the version 11 sdk. It does make now so much more sense looking at the right sdk ;o)

I can now understand why so many people are using C++ to code in Cinema, it seems to
be alot more powerful. Still, I am sticking to Coffee for the time being until I get the hang of it.

Jannis
09-21-2009, 07:35 PM
Ok, I am struggling with the spline, the sdk is not realy that clear, or at
least I don't understand. How can you access the shape of the spline?
What does the UniformToNatural do? I mean it says it
Returns the natural position along the spline. Meaning?

I managed to make a hack at this by using some of the erlier
techniques to get the lowest point and the highest point,
turn them both to absolute and devide it by 2 to ged the radius
and set this as Y position. So far I only tested this with a circle
spline made editable


if (op->IsInstanceOf(Ospline)){

var opm = op->GetMg();
var p_count = op->GetPointCount();
var L_pos = op->GetPoint(0);
var H_pos = op->GetPoint(0);
var oppos = opm->GetV0();

var i;

for(i=0;i<(p_count-1);i++)
{
var low_point = op->GetPoint(i+1);

if (low_point.y<L_pos.y)
{
L_pos.y = low_point.y;
}

var Hi_point = op->GetPoint(i+1);

if (Hi_point.y>H_pos.y)
{
H_pos.y = Hi_point.y;
}


}

var rad = (abs(L_pos.y) + abs(H_pos.y))/2;

op#ID_BASEOBJECT_POSITION:VECTOR_Y=rad;

}

tcastudios
09-22-2009, 01:11 AM
That will only work for an unedited perfect circle spline.
Pretty narrow use :)
Think of it, the objects position could be anywhere in relation to its
own points (vertexes). It's rarely exactly halfway in-between the highest
and lowest points.

The only two values that are of interest (for dropping point objects)are:
The lowest points global position:

var pointpos = op->GetPoint(n);
pointpos = opm->GetMulP(pointpos);
and the objects global position.

var oppose = op->GetMg()->GetV0();

Then:

var distance = oppos.y - pointpos.y
will give us the distance.

And finally reload the op's matrix and reload the matrix back in the op:

opm->SetV0(vector(oppos.x , distance , oppos.z));
op->SetMg(opm);

So for now, just stop using the op#BASEOBJECT_POSITION:VECTOR etc.
Ok? :) It's not helping us here!

Also in your "for" loop, you are still not storing the lowest value if the "if" condition is not fulfiled!
When you are doing:
if(low_point.y < L_pos.y) L_pos.y = low_point.y;
You need to add "else" to keep your still lowest point in memory.
else L_pos.y = L_pos.y;

Other wise you will only compare with the -original- first point (op->GetPoint(0); )
thru out the iteration.

As for a SplineObject I should not do your homework, should I ? :)
(Skip the UniformToNatural at this stage...)
But, the very same rules apply. Lowest point and objects position (both global).
But instead of iterating the points (vertex's) we need to iterate the position along the
spline in tiny small steps.

op is the spline object (again an editable spline with vertexes, a point object)

var position = op->GetSplinePoint( x , 0);
This will give you the position along the spline at x.
x is a value between 0 and 1. The start and end of the spline.
The zero after the x means that we are using the first -segment- of the spline.
For example the letter "O" have two segments, the inner and the outer part.

Then it's back to get the global value of the position.
It's the same as before:

position = op->GetMg()->GetMulP(position);

Then the for loop. It's the same idea as before but
the "i" in a for iteration is an integer.
And the position along the spline is from 0 to 1.
So we can then do:

var i; // the integer
for(i = 1; i < 1000; i++)
Having "i" count to 1000.
And to get the small steps along the spline.

var position = op->GetSplinePoint( i * 0.001 , 0);
position = opm->GetMulP(position);


Compare and store as before.

Now, keep at it ! :)

Cheers
Lennart

Jannis
09-22-2009, 10:57 AM
Man, I dont know if we ever meet, but I do owe you a drink or two or three if we do ;o)

If there is ever anything I can help you with, regarding bits that I do well, just let me know
I would love to have to opportunity to repay you for your generosity.

Just one question, if I may, to clarify it in my mind,

The, GetSplinePoint( x , 0); command, is it the command that calculates the position of
a point along the length of a spline form 0 to 1, like the position value in the align to spline
tag and the position port of the expresso spline node?

tcastudios
09-22-2009, 11:16 AM
yes, the local position along the spline.

Cheers
Lennart

Rantin Al
09-22-2009, 11:48 AM
Thanks Lennart. A few more beers from me too. :beer:

I've been following this thread and your coffee explanations have been very helpful.

Another snippet added to the collection.

Cheers, Alan.

tcastudios
09-22-2009, 01:20 PM
Looks like as if I at some point will be totally waisted :)
Looking forward to that…….I think….

Anyway, I'm glad to make some input as I remember I needed
and got the initial "push" from the forums , esp. CGTalk, how things connect.

Once over that first bump, reading the SDK starts to make sense.
It's a bit of Catch22, you need to know what your are looking for
before you know what you are looking for.

I have no intention to become a "real" programmer but so far
COFFEE is very much the perfect vehicle for most thing I need
making things easier and reusable ( in scripts, CoffeeTags and Coffee Nodes).

The inclusion of the Script Manager a few versions back of Cinema
was a -big- help to try things out.

But always keep in mind, any examples I and others give are most
often "snippets", not actually working code.
While "copy and paste" -might- work, the idea is to show a principle.


Cheers
Lennart

Jannis
09-23-2009, 09:45 AM
Ok, before I move any further I want to recap what I have learned from Lennart so far. Perhaps that might be of interest to others who are thinking of learning coffee. Because I am a visual person I broke the 'polygon' code into five steps explaining to myself the principles and here are my notes


http://www.labelleart.com/temp/poly_point_001.jpg



http://www.labelleart.com/temp/poly_point_002.jpg



http://www.labelleart.com/temp/poly_point_003.jpg



http://www.labelleart.com/temp/poly_point_004.jpg



http://www.labelleart.com/temp/poly_point_005.jpg


and here is the whole code





if(!op)return;
if(op->IsInstanceOf(Opoint))
{
//////////////////object's global position//////////////////

var mtx = op->GetMg();//the object's matrix
var oppos = mtx->GetV0();//object's global position

//////////////////first point's global position//////////////////

var L_pn = op->GetPoint(0);//the first point's local position
var G_pn = mtx->GetMulP(L_pn);//the point's global posiionn inside its matrix
var pcount =op->GetPointCount();
var i;

for(i=0;i<(pcount-1);i++)
{
var nextpoint = op->GetPoint(i+1);
nextpoint = mtx->GetMulP(nextpoint);
if(nextpoint.y < G_pn.y) // Compare the next point
G_pn = nextpoint; // Store the new lowest point
else G_pn = G_pn; // Store the still lowest point
}


var ypos = oppos.y -G_pn.y;
mtx->SetV0(vector(oppos.x , ypos , oppos.z));
op->SetMg(mtx);
}
http://www.labelleart.com/temp/rpoly_point_001.jpg

tcastudios
09-23-2009, 01:13 PM
There you go!
For some fun, copy and paste that into a COFFEE Tag
inside the main(doc,op)


main(doc,op)
{
> here <
}


Click Compile and move the lowest point down :)

Cheers
Lennart

Rantin Al
09-23-2009, 01:45 PM
Thanks Jannis.

How many words to a picture?
Nice way of illustrating and explaining the function of the coffee. :thumbsup:

Alan.

Jannis
09-25-2009, 11:38 AM
Ok, I have been trying for a couple of days with the code for the spline but all it does is jumping up and down, here is the break down of the code


var mtx =op->GetMg();
var oppos = mtx->GetV0();



gives me the objec's global position

var P_pos = op->GetSplinePoint( 0 , 0);
P_pos = mtx->GetMulP(P_pos);

gives me the 0 position as a global vector of the spline position from 0 to 1


var i;

sets the counter variable


for (i=0;i<1000;i++){
var newposition = mtx->GetMulP(P_pos);
newposition = op->GetSplinePoint((i * 0.001) , 0);

if(newposition.y<P_pos.y)
P_pos.y=newposition.y;
else
P_pos.y=P_pos.y;


}

for loop. Loops for thousand, sets a new variable newposition that returns the 0 position of the spline position from 0 to 1. It than gets mutliplied by .001 to return incriments from
0 to 1 at the end of the loop.

the if statement within the loop checks if the newposition.y is smaller than the 0 position of the spline as a vector v(0-1) and sets the P_pos to that value, else the P_pos
stays unchanged.


var ypos = -oppos.y -P_pos.y;
mtx->SetV0(vector (oppos.x, ypos, oppos.z));
op->SetMg(mtx);

finally we subtract the new P_pos.y from the original oppos.y (the object's global position) in the new variable ypos

we reset the object's global postion with this new ypos value and resset the matix.

So what am I doing wrong?

Jannis
09-25-2009, 02:35 PM
Ok this code now works, I was using previously the variable oppos.y as a negative
value out of desperation to get it to work like,

var ypos = -oppos.y -P_pos.y;

but it should be like this.

var ypos = oppos.y -P_pos.y;

After quite a bit of testing and testing the setup with expresso I now see what is happening. The code is executed correctly the first time if the object is on the 0 world space but then it is added every time it is executed. I think my problem is in the last part of the expression. I need to think about this a bit longer...hm...


var mtx =op->GetMg();
var oppos = mtx->GetV0();
var P_pos = op->GetSplinePoint( 0 , 0);
P_pos = mtx->GetMulP(P_pos);
var i;



for (i=0;i<1000;i++){
var newposition = mtx->GetMulP(P_pos);
newposition = op->GetSplinePoint((i * 0.001) , 0);

if(newposition.y<P_pos.y)
P_pos.y = newposition.y;



else
P_pos=P_pos;
P_pos.y=P_pos.y;




}


var ypos = oppos.y -P_pos.y;

mtx->SetV0(vector (oppos.x, ypos, oppos.z));

op->SetMg(mtx);

Jannis
09-25-2009, 02:58 PM
Ok I solved it!! And there is no better feeling than solving it. I had the variables the wrong way it should be like this,


var mtx =op->GetMg();
var oppos = mtx->GetV0();
var P_pos = op->GetSplinePoint( 0 , 0);
P_pos = mtx->GetMulP(P_pos);
var i;



for (i=0;i<1000;i++){

var newposition = op->GetSplinePoint((i * 0.001) , 0);

newposition = mtx->GetMulP(newposition);

if(newposition.y<P_pos.y)
P_pos.y = newposition.y;



else
P_pos=P_pos;
println (P_pos.y);




}


var ypos = oppos.y -P_pos.y;

mtx->SetV0(vector (oppos.x, ypos, oppos.z));

op->SetMg(mtx);




It was this part that was upside down, this is the right way. first declaire the variable newposition and set it to the local position of the position value of the spline (0 to 1).
Than set it to the global position with the GetMulP () command.



var newposition = op->GetSplinePoint((i * 0.001) , 0);

newposition = mtx->GetMulP(newposition);

What I was doing wrong was declaring the position variable in the global position of the first point of the position value (0-1) and then set it to return its local value, this is why it was jumping, because the local value was added time after time. Also since the iteration in the loop starts from 0 the GetMulP(); command doesn't need to point to the 0 point of the spline position (0-1), since the iteration begins with 0. Still, you can only learn from your mistakes and by struggling with this I have learned alot.

var newposition = mtx->GetMulP(P_pos);
newposition = op->GetSplinePoint((i * 0.001) , 0);

tcastudios
09-25-2009, 03:05 PM
Tops!
I was just about to point that out :)

Detail: You can start the iteration with "1" (instead of "0").
You don't need to compare the same (first) position with itself.

Cheers
Lennart

Jannis
09-25-2009, 03:27 PM
Thanks Lennart! I am so glad I did solve this myself;o)
Though I look forward to all your advice!

It was such a stupid oversight but you need to get an intuitive feeling for a language before you can feel confident and I am a long way from it.

If I may ask for your advice once more, do you think there is anymore functionality I can add to this before I put it to sleep?

The things I can add would be to make it work with Platonic objects. The problem with the Platonic is that it seems to have a bounding box that works for the biggest shape it can produce, that is the Bucky and all the other objects are smaller then the bounding box. Do you have any suggestions?

The other thing would be to include all primitive spline objects. What do you think? Would this be worth the learning curve or should I move on?

ANyway, here is the finished code with Lennart's correction of starting the iteration from 1 and the usual initial checks for object selection and object type

if(!op) return;
if(op->IsInstanceOf(Opoint)){


var mtx =op->GetMg();
var oppos = mtx->GetV0();
var P_pos = op->GetSplinePoint( 0 , 0);
P_pos = mtx->GetMulP(P_pos);
var i;

for (i=1;i<1000;i++){

var newposition = op->GetSplinePoint((i * 0.001) , 0);

newposition = mtx->GetMulP(newposition);

if(newposition.y<P_pos.y)
P_pos.y = newposition.y;

else
P_pos=P_pos;
println (P_pos.y);

}


var ypos = oppos.y -P_pos.y;
mtx->SetV0(vector (oppos.x, ypos, oppos.z));
op->SetMg(mtx);

}

Jannis
09-25-2009, 05:28 PM
Ok, continuing with my notes here are the ones for the editable spline droped on the grid.
Again, thanks to Lennart. The complete code is above, just copy and paste it in the script manager as usual.




http://www.labelleart.com/temp/spline_point_001.jpg



http://www.labelleart.com/temp/spline_point_002.jpg




http://www.labelleart.com/temp/spline_point_003.jpg



http://www.labelleart.com/temp/spline_point_004.jpg

CGTalk Moderation
09-25-2009, 05:28 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.