PDA

View Full Version : Cinema 4d Scripts


JoelOtron
10-28-2005, 04:15 PM
Users--please post your scripts here


--------------------------------------
From c)hri:
UserScript: AO multipass helper

http://forums.cgsociety.org/showthread.php?t=289429




-----------------

hi folks,

I played around with the new script manager and wrote a short script which should help to improve the AO multipass workflow a bit.
The script walks through all materials in the scene, disables all channels except of the luminance channel. The luminance channel is filled with a plain white color.
So the multipass workflow looks like that:
* run the script
* disable all lights in the scene

copy-paste the script code into the script manager, assign a script name. save it. script can be called via the Plugin menu -> user scripts

Be aware that previous material settings will be lost, its a one-way-ticket. It don't works for the old shaders like danel, etc.
Material updates are'nt displayed immediately (coders: help!)

I know the script is far from being perfect, but hey: it's my first one (for c4d)



---------------------------------
vistitMaterial(op) {
if (op == null) return;
// enable luminance
var lum = op->GetChannel(CHANNEL_LUMINANCE);
if (lum) {
var bc = new(BaseContainer);
bc->SetData(CH_BRIGHTNESS,1);
bc->SetData(CH_COLOR, vector(1.0,1.0,1.0));
bc->SetData(CH_MIXMODE,0);
bc->SetData(CH_MIXSTRENGTH,0);
lum->SetContainer(bc);
op->SetChannelState(CHANNEL_LUMINANCE, true);
}
// disable other channels
op->SetChannelState(CHANNEL_COLOR, false);
op->SetChannelState(CHANNEL_TRANSPARENCY, false);
op->SetChannelState(CHANNEL_REFLECTION, false);
op->SetChannelState(CHANNEL_ENVIRONMENT, false);
op->SetChannelState(CHANNEL_FOG, false);
op->SetChannelState(CHANNEL_SPECULAR, false);
op->SetChannelState(CHANNEL_SPECULARCOLOR, false);
op->SetChannelState(CHANNEL_GLOW, false);
op->SetChannelState(CHANNEL_DIFFUSION, false);
op->Update();
vistitMaterial(op->GetNext());
}

main(doc, op){
vistitMaterial(doc->GetFirstMaterial());
}
---------------------------------

JoelOtron
10-28-2005, 04:17 PM
http://forums.cgsociety.org/showthread.php?t=288976

From Mdme sadie

Use the attached Script (just unzip it in your library/scripts folder, then drag & drop it into your interface/assign it a keyboard shortcut, or access it via the plugins->Scripts menu).

To use : select the object that will be instanced, then run the script. Enter the starting part of the objects names that will be turned into instances, e.g. if you have a bunch of objects called Screw_1 Screw_2 Screw_3... etc then just enter Screw in the dialog. if the object you've got selected is the first name you want to use then just click ok with an empty text box.

Attachment below

http://forums.cgsociety.org/attachment.php?attachmentid=83476

JoelOtron
10-28-2005, 04:21 PM
From Geespot:

Here's a simple 9.5 script

Just add it to the Script Manager, select a parent object and execute the script the usual method.

// Get the active object
var op = doc->GetActiveObject();
if(!op) return;

// De-select all objects first
CallCommand(12113);

// Percentage 0.0 = 0%, 1.0 is 100%
var perc = 0.5;

// Get te first child object of active object
var child = op->GetDown();

// Start random generator
var r = new(Random);
r->Init(GeGetSysTime()->second);
var n;

// Count the children
while(child)
{
// Generate a number between 0.0 and 1.0
n = r->Get01();

// Is this number less than our percentage?
if(n < perc)
{
// Select object
child->SetBit(BIT_AOBJ);
// Update object
child->Message(MSG_UPDATE);
}

// Move onto next object
child = child->GetNext();

}

// Update document
doc->Message(MSG_UPDATE);

JoelOtron
10-28-2005, 04:22 PM
//--------------------------
//recursive select routine
Rselect(op,rnd) {
//randomly select (make active or not)
if (rnd->Get11()>0.0) op->SetBit(BIT_AOBJ);
else op->DelBit(BIT_AOBJ);

//recurse through hierarchy
var nchild=op;
for (nchild=nchild->GetDown();nchild;nchild=nchild->GetNext()) Rselect(nchild,rnd);
}

//--------------------------
//main function routine
main(doc,op) {
var child=op->GetDown();
var random_seed=123456;
var rnd=new(Random);
//init random number generator with seed
rnd->Init(random_seed);

for (child=op->GetDown();child;child=child->GetNext()) Rselect(child,rnd);

return TRUE;
}

c-hri
10-29-2005, 01:39 PM
ok, here's my next.

inspired by the boring clean up and grouping process after importing a 3ds files. I don't know about the other apps, but for instance ArchiCad creates kinda cryptic object names without any hierarchy.

The script is called TidyUp:
It groups root level objects by their texture tags. I have successfully tested it with several archicad generated 3ds files.
Example: all objects with a brick material applied get grouped together in a new top-level-group called 'brick' (group name = material name).

Unzip the file into your library/scripts directory.

cheers,
c)hri

c-hri
11-01-2005, 02:59 PM
hi all,

here's my new one, it's called: RenameChildren. I wrote it because I had troubles using mdm_ sadies fine Convert To Instance script in a recent project (unsorted, cryptic object names everywhere; again a .3ds import).

The attached script renames all children of the selected parent object:
Eg. Parent is called Wall => the children will be renamed to wall_1, wall_2 etc etc

There's also an updated version of my TidyUp script attached. Both scripts take care of undo/redo commands now.

cheers
c)hri

Neldor
11-15-2005, 06:58 AM
Hi! This is my simple script.


var bc=new(BaseContainer);
bc->SetData(MDATA_EXTRUDE_OFFSET, 0);
bc->SetData(MDATA_EXTRUDE_SUBDIVISION, 0);
bc->SetData(MDATA_EXTRUDE_PRESERVEGROUPS, TRUE);
bc->SetData(MDATA_EXTRUDE_CREATECAPS, FALSE);
SendModelingCommand(ID_MODELING_EXTRUDE_TOOL, doc, op, bc, MODIFY_POLYGONSELECTION);


Works only witn poly at this moment.

c-hri
12-30-2005, 09:11 AM
hi folks,

here's a simple 'material replacer' user script. Unzip the file into your library/scripts directory.

Usage:
*Activate exactly one material (this will gonna be the new material)
*Select one or more objects
* Run the script: all texture tags of the selected objects (including all children) will have the new material applied.


cheers
c)hri

Per-Anders
01-19-2006, 05:04 AM
Script for setting a texture tag on a spotlight to teh right size/projection to cover the spotlight itself (just place in a coffee tag on a spotlight)


GetTextureTag(op)
{
if (!op) return NULL;

var tag=op->GetFirstTag();
if (!tag) return NULL;

while (tag) {
if (tag->IsInstanceOf(Ttexture)) return tag;
tag=tag->GetNext();
}

return NULL;
}


main(doc,op)
{
var tag=GetTextureTag(op);
if (!tag) return FALSE;

var lang=op#LIGHT_DETAILS_OUTERANGLE;

var coveragey=(lang/PI2);
var coveragex=coveragey*0.5;

var offx=0.25+coveragex;
var offy=0.5-coveragey;

var leny=coveragey*2;
var lenx=-coveragex*2;

tag#TEXTURETAG_OFFSETX=offx;
tag#TEXTURETAG_OFFSETY=offy;
tag#TEXTURETAG_LENGTHX=lenx;
tag#TEXTURETAG_LENGTHY=leny;
}

Sneaker
03-08-2006, 11:33 AM
Hi,

I just played arround with user scripts and want to offer my result.

FullSplit performs a split, deletes the selected polygons and removes
unnesessary points using optimize.



-Sneaker

Per-Anders
03-15-2006, 08:27 PM
Rhis is a useful little script to allow you to lock out objects from being selectable in the OM. Just put this in a COFFEE tag on the object you want to protect. All it does is check the objects selected bit(GetBit), then if it's set it switches it off (DelBit) it and forces cinema to redraw it's interface (EventAdd).


main(doc,op)
{
if(op->GetBit(BIT_AOBJ))
{
op->DelBit(BIT_AOBJ);
EventAdd();
}
}

tcastudios
06-14-2006, 09:52 PM
Gathered 20 of my scripts for checking out. They all only make sense if placed in your layout to speed many things up.

Dload here (http://homepage.mac.com/tcastudios/xfiles.html)
http://homepage.mac.com/tcastudios/tcaxpresso/20scripts.jpg

Cheers
Lennart

otomo
08-15-2006, 09:16 AM
this is a little script written by Frank Berg and me which saves you a few mouseclicks.

it will connect the selected objects, using the connect command, put the result in the same branch, just above the first selected object and delete the original objects.


http://forums.cgsociety.org/showthread.php?t=393322



edit: uploaded an updated version, fixed some issues, like deleting didnt work if not in object mode and other minor things. only thing left: undo the script actions in one step.

Geespot
10-13-2006, 01:13 PM
Group Connect
---------------

Group Connect is a script that will convert an object and all its children into a single polygon mesh.


// Group Connect v1.0
// -------------------
// Group Connect is a script that will convert a grouped selection
// of objects into a single polygon mesh including materials
// using Selection Tags to assign each polygon a seperate texture.
//
// Created by Ian Gorse 12 October 2006
// http://www.iangorse.co.uk/
// Recursive method to create a selection tag for each object
// ==========================================================
// child: The current object in hiearchy
CreateSelection(child)
{

while(child)
{
child->SetBit(BIT_AOBJ); // Select the object
CallCommand(13323); // Select All polygons
// Only create a selection tag if this object has polygons
if(child->GetType()==Opolygon)
{
// Creates a selection tag for this object
// It names the selection tag the same name as the object
var selection = new(BaseSelect);
selection = child->GetPolygonSelection();
var tag = new(PolygonSelectionTag);
tag->SetSelection(selection);
tag->SetName(child->GetName());
child->InsertTag(tag);
}
CallCommand(13324); // Deselect all polygons
child->DelBit(BIT_AOBJ); // Deselect the object
CreateSelection(child->GetDown());
child=child->GetNext();
}
}
// Just a method to start the selection creation process
// Its on its own function because I had other plans, but I made a workaround with a Hack (below)
StartSelectionProcess(op)
{
CreateSelection(op);
}
// Attempts to find a texture tag on the passed object
// If it doesn't find one, it will check its parents object
// and use that instead
// ==========================================================
// op: The object to check for a texture tag
FindTextureTag(op)
{
if(!op) return NULL;
// Search for a texture tag on this object
var tag = op->GetFirstTag();
var searching = TRUE;
var returntag;
while(tag && searching)
{
if(tag->GetType()==Ttexture)
{
// Found a texture tag
returntag = tag;
searching=FALSE;
}
tag=tag->GetNext();
}
// Could not find Texture Tag, attempt to find inherited texture tag
if(!returntag)
{
returntag = FindTextureTag(op->GetUp());
}
return returntag;
}
// Recursive method to find texture tags on each object
// =====================================================
// op: The object to apply the texture onto
// child: The selected object and its children
CreateMaterial(op,child)
{
while(child)
{

// Search for a texture tag on this object
var tag = FindTextureTag(child);

if(tag)
{
// Make a copy
var newtag = tag->GetClone();
newtag#TEXTURETAG_RESTRICTION=child->GetName();
op->InsertTag(newtag);
}
CreateMaterial(op,child->GetDown());
child=child->GetNext();
}
}
main(doc,op)
{
// Cals the Current State To Object command on the selected object
var bc = new(BaseContainer);
SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT, doc, op, bc, MODIFY_ALL);
// The new editable object is automatically added to the document.
// Keep track of it here so I can remove it later
var newop = doc->GetActiveObject();
// Make sure the polygon tool is selected
CallCommand(12187);
// Start the polygon selection process
newop->DelBit(BIT_AOBJ); // De-select the cloned object first
StartSelectionProcess(newop);
newop->SetBit(BIT_AOBJ);
// HACK -- To avoid any hierarchy issues, Im just grouping everything up
// -- I'm taking advantage that the Connect command returns a polygon object only
var nullop = new(NullObject);
nullop->SetName(newop->GetName());
doc->InsertObject(nullop,NULL,NULL);

// Move the current state to object under the null objet
newop->Remove();
newop->InsertUnder(nullop);
// Select the nullobject
nullop->SetBit(BIT_AOBJ);

// Creates a texture tag for each polygon selection
CreateMaterial(nullop,op);
CallCommand(16388); // Select Children
CallCommand(12144); // Connect
// Remove the new grouped object
nullop->Remove();
}


Example:
Original model
http://i6.photobucket.com/albums/y211/Unigee/groupconnect_orig.jpg

GroupConnected object
http://i6.photobucket.com/albums/y211/Unigee/groupconnect_result.jpg

Download the Instructions (http://www.iangorse.co.uk/scripts/groupconnect/groupconnect.pdf) for its installation usage

Geespot
10-27-2006, 03:46 PM
AngleSelect is a script that will select all polygons within an user defined angle. With it, its possible to select all polygons above/below and between two set angles.

Click the attachment to download.

How to install:
Extract the zip file into your Cinema4D/library/scripts folder

The script will then be available in the C4D Script Manager

Per-Anders
01-17-2007, 09:21 PM
FindActiveType(doc, op, type)
{
while (op)
{
if (op->GetBit(BIT_ACTIVE))
if (op->IsInstanceOf(type)) return op;

if (op->GetDown())
{
op = op->GetDown();
}
else
{
while (!op->GetNext())
{
op = op->GetUp();
}
if (op) op = op->GetNext();
}
}
return NULL;
}

main(doc, op)
{
var data = new(BaseContainer);
data->SetData(MDATA_CURRENTSTATETOOBJECT_INHERITANCE, TRUE);

var spline = FindActiveType(doc, doc->GetFirstObject(), Ospline);
if (spline == NULL) return;
var poly = FindActiveType(doc, doc->GetFirstObject(), Opolygon);
if (poly == NULL) return;

var pspline = spline->GetPrev();
var uspline = spline->GetUp();
var ppoly = poly->GetPrev();
var upoly = poly->GetUp();

doc->StartUndo();

var boole =AllocObject(Oboole);
doc->InsertObject(boole, NULL, NULL);
if (!boole) return;
doc->AddUndo(UNDO_NEW, boole);

var extrude = AllocObject(Oextrude);
if (!extrude) return;
doc->InsertObject(extrude, boole, NULL);
doc->AddUndo(UNDO_NEW, extrude);

var cam = doc->GetActiveBaseDraw()#BASEDRAW_DATA_CAMERA;
if (!cam) return;

var smg = spline->GetMg();
extrude->SetMg(smg);

doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
spline->InsertUnder(extrude);

spline->SetPosition(vector(0.0,0.0,0.0));
spline->SetRotation(vector(0.0,0.0,0.0));
spline->SetScale(vector(1.0,1.0,1.0));

extrude#EXTRUDEOBJECT_MOVE:VECTOR_Z = 100000.0;
extrude#CAP_START = 0;
extrude#CAP_END = 0;

boole#BOOLEOBJECT_TYPE = BOOLEOBJECT_TYPE_WITHOUT;
boole#BOOLEOBJECT_HIGHQUALiTY = TRUE;
boole#BOOLEOBJECT_HIDE_NEW_EDGES = TRUE;

doc->AddUndo(UNDO_CHANGE, poly);
poly->Remove();
poly->InsertUnder(boole);

if ( !SendModelingCommand( MCOMMAND_CURRENTSTATETOOBJEC T, doc, boole, data, MODIFY_ALL)) return;

var newobj = doc->GetActiveObject();
var newchl = newobj->GetDown();

doc->AddUndo(UNDO_NEW, newobj);
if (uspline == poly) uspline = newchl;
if (pspline == poly) pspline = newchl;
if (upoly == spline || ppoly == spline)
{
doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
doc->InsertObject(spline, uspline, pspline);
doc->AddUndo(UNDO_CHANGE, newchl);
newchl->Remove();
doc->InsertObject(newchl, upoly, ppoly);
}
else
{
doc->AddUndo(UNDO_CHANGE, newchl);
newchl->Remove();
doc->InsertObject(newchl, upoly, ppoly);
doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
doc->InsertObject(spline, uspline, pspline);
}
doc->AddUndo(UNDO_CHANGE, spline);
spline->SetMg(smg);

doc->AddUndo(UNDO_DELETE, poly);
poly->Remove();
doc->AddUndo(UNDO_DELETE, extrude);
extrude->Remove();
doc->AddUndo(UNDO_DELETE, boole);
boole->Remove();
doc->AddUndo(UNDO_DELETE, newobj);
newobj->Remove();

doc->EndUndo();
}

Simply allows you to project cut an editiable polygonal mesh using a spline. Select both the spline and the polygonal object and run this script. Make sure that the spline is betwene your obejct and the camera as it cuts in a projection from the splines current position, so everything behind the spline will get cut, but nothing in front of the spline.

Per-Anders
01-17-2007, 10:09 PM
And here's a version that projects along the camera normal rather than the splines own axis :

FindActiveType(doc, op, type)
{
while (op)
{
if (op->GetBit(BIT_ACTIVE))
if (op->IsInstanceOf(type)) return op;

if (op->GetDown())
{
op = op->GetDown();
}
else
{
while (!op->GetNext())
{
op = op->GetUp();
}
if (op) op = op->GetNext();
}
}
return NULL;
}

main(doc, op)
{
var data = new(BaseContainer);
data->SetData(MDATA_CURRENTSTATETOOBJECT_INHERITANCE, TRUE);

var spline = FindActiveType(doc, doc->GetFirstObject(), Ospline);
if (spline == NULL) return;
var poly = FindActiveType(doc, doc->GetFirstObject(), Opolygon);
if (poly == NULL) return;

var pspline = spline->GetPrev();
var uspline = spline->GetUp();
var ppoly = poly->GetPrev();
var upoly = poly->GetUp();

doc->StartUndo();

var boole =AllocObject(Oboole);
doc->InsertObject(boole, NULL, NULL);
if (!boole) return;
doc->AddUndo(UNDO_NEW, boole);

var extrude = AllocObject(Oextrude);
if (!extrude) return;
doc->InsertObject(extrude, boole, NULL);
doc->AddUndo(UNDO_NEW, extrude);

var cam = doc->GetActiveBaseDraw()#BASEDRAW_DATA_CAMERA;
if (!cam) return;

var smg = spline->GetMg();
extrude->SetMg(cam->GetMg());

doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
spline->InsertUnder(extrude);

spline->SetMg(smg);

extrude#EXTRUDEOBJECT_MOVE:VECTOR_Z = 100000.0;
extrude#CAP_START = 0;
extrude#CAP_END = 0;

boole#BOOLEOBJECT_TYPE = BOOLEOBJECT_TYPE_WITHOUT;
boole#BOOLEOBJECT_HIGHQUALiTY = TRUE;
boole#BOOLEOBJECT_HIDE_NEW_EDGES = TRUE;

doc->AddUndo(UNDO_CHANGE, poly);
poly->Remove();
poly->InsertUnder(boole);

if ( !SendModelingCommand( MCOMMAND_CURRENTSTATETOOBJECT, doc, boole, data, MODIFY_ALL)) return;

var newobj = doc->GetActiveObject();
var newchl = newobj->GetDown();

doc->AddUndo(UNDO_NEW, newobj);
if (uspline == poly) uspline = newchl;
if (pspline == poly) pspline = newchl;
if (upoly == spline || ppoly == spline)
{
doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
doc->InsertObject(spline, uspline, pspline);
doc->AddUndo(UNDO_CHANGE, newchl);
newchl->Remove();
doc->InsertObject(newchl, upoly, ppoly);
}
else
{
doc->AddUndo(UNDO_CHANGE, newchl);
newchl->Remove();
doc->InsertObject(newchl, upoly, ppoly);
doc->AddUndo(UNDO_CHANGE, spline);
spline->Remove();
doc->InsertObject(spline, uspline, pspline);
}
doc->AddUndo(UNDO_CHANGE, spline);
spline->SetMg(smg);

doc->AddUndo(UNDO_DELETE, poly);
poly->Remove();
doc->AddUndo(UNDO_DELETE, extrude);
extrude->Remove();
doc->AddUndo(UNDO_DELETE, boole);
boole->Remove();
doc->AddUndo(UNDO_DELETE, newobj);
newobj->Remove();

doc->EndUndo();
}

Per-Anders
04-01-2007, 09:03 PM
This script allows you to select selection tags if their selection overlaps the selection you have made. Works on polygon selection tags only (can be modified to work on point selection tags too).

Use in the Script Manager.

To use : Make a polygon selection, then execute the script to select any polygon selection tags on your object that overlap your selection (quick way to find the right polygon selection tag on an object for a specific area).

var sel = op->GetPolygonSelection();
var cnt = sel->GetCount();
var ar = new(array, cnt);
var vcnt = op->GetPolygonCount();
var i = 0, o = 0;
for (i = 0; i < vcnt ; i++)
{
if (sel->IsSelected(i))
{
ar[o] = i;
o++;
}
}

var tag = op->GetFirstTag();
while (tag)
{
tag->DelBit(BIT_ACTIVE);
if (tag->IsInstanceOf(Tpolygonselection))
{
var tsel = tag->GetSelection();
for (i = 0; i < cnt ; i++)
{
if (tsel->IsSelected(ar[i]))
{
tag->SetBit(BIT_ACTIVE);
break;
}
}
}
tag = tag->GetNext();
}

Per-Anders
04-02-2007, 07:31 PM
Just select several objects and this will instance them all in one go.

op = doc->GetFirstObject();
var instance = op;
var mynull = AllocObject(Onull);
while (op)
{
if (op->GetBit(BIT_ACTIVE))
{
instance = AllocObject(Oinstance);
instance#INSTANCEOBJECT_LINK = op;
instance->InsertUnder(mynull);
instance->SetMg(op->GetMg());
op->DelBit(BIT_ACTIVE);
}

if (op->GetDown())
{
op = op->GetDown();
}
else
{
while (!op->GetNext() && op->GetUp())
{
op = op->GetUp();
}
op = op->GetNext();
}
}

op = mynull->GetDown();

while(op)
{
instance = op;
op = op->GetNext();
instance->Remove();
doc->InsertObject(instance, NULL, NULL);
instance->SetBit(BIT_ACTIVE);
}

marcorabellini
04-07-2007, 02:56 AM
I modified this script to add the name of the original plus a "[i]" to the end of the name. I actually didn't do to much coding myself but used a couple scripts I downloaded from here. One was from Per and I don't know who did the other one. (Sorry). I've commented the two lines I added. I'm not a coder by any stretch so if there's a way to make this any better I have no idea. It seems to be working for me in 10.1.
Select an object and run this script. That's it.

op = doc->GetFirstObject();
var instance = op;
var mynull = AllocObject(Onull);
var objectname=GetActiveDocument()->GetActiveObject()->GetName(); //get the original object name
while (op)
{
if (op->GetBit(BIT_ACTIVE))
{
instance = AllocObject(Oinstance);
instance#INSTANCEOBJECT_LINK = op;
instance->InsertUnder(mynull);
instance->SetMg(op->GetMg());
op->DelBit(BIT_ACTIVE);
}

if (op->GetDown())
{
op = op->GetDown();
}
else
{
while (!op->GetNext() && op->GetUp())
{
op = op->GetUp();
}
op = op->GetNext();
}
}

op = mynull->GetDown();

while(op)
{
instance = op;
op = op->GetNext();
instance->Remove();
doc->InsertObject(instance, NULL, NULL);
instance->SetBit(BIT_ACTIVE);
instance->SetName(objectname + " [i]"); //set the instance name to original +[i]
}

LucentDreams
04-11-2007, 07:39 AM
theres almost 30 here http://www.cineversity.com/tutorials/index.asp?cid=21

Two packages,

GRIP, camera and light management scripts
CONscripts, constraint creation and defaults scripts.

Darter
01-01-2008, 05:51 AM
This script randomly applies materials to a polygon object. For each Texture Tag on the object, a Polygon Selection Tag is created and assigned a random selection of polygons.

Each tag has a unique selection, so no overlapping of textures occurs.

If you find this script useful, its companion Update Selection Tags (http://forums.cgsociety.org/showthread.php?f=182&t=576712) may also be of interest.

tcastudios
01-02-2008, 11:40 PM
Speedo prints the Velocity(Units and degrees per second) of a selected object.
To get velocity of other parameters use SetDriver/Driven to a Dummy Null
and use the script on the Null.
Velocity is calculated between the Start and End Frame of the Preview Range.

Cheers
Lennart

// Speedo by tcastudios©2008. For commercial and personal use.
// Re-distribution in any form is not allowed,
// but feel free to use any part of it for your own stuff.
// (If notonly to make it better:) )
// Speedo comes "as is" with no warranty in any form and without any
// personal support.
//
// Speedo is a script for Cinema4D versions having a scriptmanager and/or
// to be used in a Menu COFFEE setup.
// Copy and paste -all- text from top to bottom into the ScriptManager.
// Select an Object and run the SpeedoScript.
// Speedo prints the velocity of the active object in the Console.
// The average velocity is calcultated between the Start- and End Frame
// of the documents PreviewRange.
// For "One Frame" velocity, set Preview Range to two frames.
//
// Enjoy! Lennart Wåhlin tcastudios


var op = doc->GetActiveObject();
if(!op) return;

var a;
var ax;
var ay;
var az;
var ah;
var ap;
var ab;

var b;
var bx;
var by;
var bz;
var bh;
var bp;
var bb;

var fps = doc->GetFps();
var first = doc->GetLoopMinTime()->GetSecond()*fps;
var last = doc->GetLoopMaxTime()->GetSecond()*fps;
var keytokey = last-first;

var TimeNow = new(BaseTime);
TimeNow->SetFrame(first,fps);
doc->SetTime(TimeNow);
doc->AnimateDocument(ALL);
doc->Message(MSG_UPDATE);
a = op->GetMg()->GetV0();
var apos = op->GetPosition();
var arot = op->GetRotation();
ax = apos.x;
ay = apos.y;
az = apos.z;
ah = arot.x;
ap = arot.y;
ab = arot.z;

var TimeThen = new(BaseTime);
TimeThen->SetFrame(first+(last-first),fps);
doc->SetTime(TimeThen);
doc->AnimateDocument(ALL);
doc->Message(MSG_UPDATE);
b = op->GetMg()->GetV0();
var bpos = op->GetPosition();
var brot = op->GetRotation();
bx = bpos.x;
by = bpos.y;
bz = bpos.z;
bh = brot.x;
bp = brot.y;
bb = brot.z;

var dist = vlen(a-b);
var x = bx-ax;
var y = by-ay;
var z = bz-az;
var h = bh-ah;
var p = bp-ap;
var b = bb-ab;

TimeNow->SetFrame(first,fps);
doc->SetTime(TimeNow);
doc->AnimateDocument(ALL);
doc->MultiMessage(MSG_UPDATE);
var distsec = dist/(keytokey/fps);
var xsec = x /(keytokey/fps);
var ysec = y /(keytokey/fps);
var zsec = z /(keytokey/fps);
var hsec = Degree(h /(keytokey/fps));
var psec = Degree(p /(keytokey/fps));
var bsec = Degree(b /(keytokey/fps));
println("__________________________________________________");
println("Speed Between Frame ",int(first)," and ",int(last));
println("Velocity ",tostring(distsec,".2f")," Units/Sec");
println("X-Velocity ",tostring(xsec,".2f")," Units/Sec");
println("Y-Velocity ",tostring(ysec,".2f")," Units/Sec");
println("Z-Velocity ",tostring(zsec,".2f")," Units/Sec");
println("H-Rotation ",tostring(hsec,".2f")," Degrees/Sec");
println("P-Rotation ",tostring(psec,".2f")," Degrees/Sec");
println("B-Rotation ",tostring(bsec,".2f")," Degrees/Sec");
println("__________________________________________________");

Per-Anders
04-20-2008, 05:09 AM
Cinema normally only allows you to scale multiple objects with x+ whatever, this script allows you to size multiple selected objects with units, percent (relative to the largest object), and relative units (to the largest object).


getSize(op, dir, global)
{
var min = MAXREAL, max = MINREAL;

var i = 0;
var mg = op->GetMg();
if (!global) mg = new(Matrix);
var pcnt = op->GetPointCount();
var padr = op->GetPoints(), p, pv;
if (!padr) return 0.0;

switch (dir)
{
case 0: //x
{
for (i = pcnt - 1 ; i >= 0; --i)
{
pv = mg->GetMulP(padr[i]);
p = pv.x;
if (p < min) min = p;
if (p > max) max = p;
}
} break;
case 1: //y
{
for (i = pcnt - 1 ; i >= 0; --i)
{
pv = mg->GetMulP(padr[i]);
p = pv.y;
if (p < min) min = p;
if (p > max) max = p;
}
} break;
case 2: //z
{
for (i = pcnt - 1 ; i >= 0; --i)
{
pv = mg->GetMulP(padr[i]);
p = pv.z;
if (p < min) min = p;
if (p > max) max = p;
}
} break;
default: return FALSE; break;
}

return max - min;
}

scaleObject(op, amt, dir, scalepoints, global)
{
if (amt == 0.0) return FALSE;

var dist = getSize(op, dir, global);
if (dist == 0.0) return FALSE;

var ratio = (dist + amt) / dist;
if (!scalepoints) ratio = (dist * amt) / dist;

if (scalepoints)
{
//rescale all points
var i = 0;
var pcnt = op->GetPointCount();
var padr = op->GetPoints();
if (!padr) return FALSE;

switch (dir)
{
case 0:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].x *= ratio;
} break;
case 1:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].y *= ratio;
} break;
case 2:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].z *= ratio;
} break;
default: return FALSE; break;
}

op->SetPoints(padr);
}
else
{
//set objects scale
var scl = op->GetScale();
switch (dir)
{
case 0: scl.x *= ratio; break;
case 1: scl.y *= ratio; break;
case 2: scl.z *= ratio; break;
default: return FALSE; break;
}

op->SetScale(scl);
}

return TRUE;
}

class ScaleAllDlg : GeModalDialog
{
public:
ScaleAllDlg();

var stored_x, stored_y, stored_z;

CreateLayout();
Command(id, msg);
}

ScaleAllDlg::ScaleAllDlg()
{
super();
}

ScaleAllDlg::CreateLayout()
{
SetTitle("Scale Units");

AddGroupBeginV(1000, BFH_SCALE|BFV_SCALE, 1, "", 0);
{
AddGroupBorder(BORDER_GROUP_IN);
AddGroupBorderSpace(4,4,4,4);
AddGroupSpace(4,4);

AddGroupBeginV(1001, BFH_SCALE|BFV_SCALE, 2, "", 0);
{
AddStaticText(1002, BFH_LEFT, 0,0, "X", 0);
AddEditNumberArrows(2000, BFH_SCALE, 80, 0);

AddStaticText(1003, BFH_LEFT, 0,0, "Y", 0);
AddEditNumberArrows(2001, BFH_SCALE, 80, 0);

AddStaticText(1004, BFH_LEFT, 0,0, "Z", 0);
AddEditNumberArrows(2002, BFH_SCALE, 80, 0);
}
AddGroupEnd();

AddComboBox(2005, BFH_SCALE|BFH_FIT, 0, 0);
AddItem(2005, 0, "Global");
AddItem(2005, 1, "Local");

AddComboBox(2003, BFH_SCALE|BFH_FIT, 0, 0);
AddItem(2003, 0, "Scale");
AddItem(2003, 1, "Size");
AddItem(2003, 2, "Size+");

AddButton(2004, BFH_SCALE|BFH_FIT, 0, 0, "Apply");

AddDlgGroup(DR_DLGGROUP_OK);
}
AddGroupEnd();

SetInt(2003, 0, 0, 3, 1);
SetPercent(2000, 100.0, MINREAL, MAXREAL, 0.01);
SetPercent(2001, 100.0, MINREAL, MAXREAL, 0.01);
SetPercent(2002, 100.0, MINREAL, MAXREAL, 0.01);

return;
}

ScaleAllDlg::Command(id, msg)
{
switch (id)
{
case 2005:
case 2003:
{
switch (GetInt(2003))
{
case 0:
{
SetPercent(2000, 100.0, MINREAL, MAXREAL, 0.01);
SetPercent(2001, 100.0, MINREAL, MAXREAL, 0.01);
SetPercent(2002, 100.0, MINREAL, MAXREAL, 0.01);
} break;
case 1:
{
var doc = GetActiveDocument(); if (!doc) return;
var op = doc->GetFirstObject(); if (!op) return;
var global = !GetInt(2005);
var xwid = 0.0, ywid = 0.0, zwid = 0.0;
while (op)
{
if (op->GetBit(BIT_ACTIVE))
{
var wid = getSize(op, 0, global);
if (wid > xwid) xwid = wid;
wid = getSize(op, 1, global);
if (wid > ywid) ywid = wid;
wid = getSize(op, 2, global);
if (wid > zwid) zwid = wid;
}

if (op->GetDown()) op = op->GetDown();
else
{
while (!op->GetNext() && op->GetUp()) op = op->GetUp();
op = op->GetNext();
}
}
SetMeter(2000, xwid, MINREAL, MAXREAL, 0.01);
SetMeter(2001, ywid, MINREAL, MAXREAL, 0.01);
SetMeter(2002, zwid, MINREAL, MAXREAL, 0.01);

stored_x = xwid;
stored_y = ywid;
stored_z = zwid;
} break;
case 2:
{
SetMeter(2000, 0.0, MINREAL, MAXREAL, 0.01);
SetMeter(2001, 0.0, MINREAL, MAXREAL, 0.01);
SetMeter(2002, 0.0, MINREAL, MAXREAL, 0.01);
} break;
default: break;
}
} break;
case 2004:
{
var doc = GetActiveDocument();
if (!doc) return;
var op = doc->GetFirstObject();
if (!op) return;

var global = !GetInt(2005);

var scl = vector(0.0, 0.0, 0.0);
var smode = FALSE;

switch (GetInt(2003))
{
case 0:
{
scl.x = GetFloat(2000);
scl.y = GetFloat(2001);
scl.z = GetFloat(2002);
smode = FALSE;
} break;
case 1:
{
scl.x = GetMeter(2000) - stored_x;
scl.y = GetMeter(2001) - stored_y;
scl.z = GetMeter(2002) - stored_z;
smode = TRUE;
} break;
case 2:
{
scl.x = GetMeter(2000);
scl.y = GetMeter(2001);
scl.z = GetMeter(2002);
smode = TRUE;
} break;
default: break;
}

while (op)
{
if (op->GetBit(BIT_ACTIVE))
{
doc->AddUndo(UNDO_CHANGE, op);
if ((smode && scl.x != 0.0) || (!smode && scl.x != 1.0)) scaleObject(op, scl.x, 0, smode, global);
if ((smode && scl.y != 0.0) || (!smode && scl.y != 1.0)) scaleObject(op, scl.y, 1, smode, global);
if ((smode && scl.z != 0.0) || (!smode && scl.z != 1.0)) scaleObject(op, scl.z, 2, smode, global);
op->Message(MSG_UPDATE);
}

if (op->GetDown()) op = op->GetDown();
else
{
while (!op->GetNext() && op->GetUp()) op = op->GetUp();
op = op->GetNext();
}
}
EventAdd();
DrawViews(DA_NO_THREAD);
} break;
default: break;
}
}


main(doc, op)
{
var dlg = new(ScaleAllDlg);
var result = dlg->Open(-1, -1);
}

bellaLugosi
07-06-2008, 02:59 PM
Hi,

I made this to speed up my deformer workflow, maybe some of ya'll find it useful as well.
I dock it in my layout to have one-click-deformers appear in place :)

The script inserts deformers at position of currently active object, as child of active object. Deformer also assumes same rotation and size as active object.

Upon invocation, a dialog appears that lets one select which type of deformer to create.
Supported are 5 most basic deformers (bend,shear and so on..)
other deforemers like formula are not supported atm.

works on polyObjects and all primitives except figure.
polyObjects should have their axis centered before using the script, else deformer size may be a little off.


hf,
BellaLugosi



//---------------------------------------
// EasyDeformer
//
// Inserts basic Deformers at position of selected object.
// Also inherits rotation and scale, by computing bounding box.
// Works for poly-Objects and all primitives except Figure.
// If used on poly-Objects, objects should have their axis centered before,
// else deformer dimensions may be off.
//
// by BellaLugosi
//---------------------------------------


// returns bounding box size vector of given object
GetBoundingBox(obj){
var count = obj->GetPointCount();
var points = (obj->GetPoints());
var maxPoint = vector(0,0,0);
var i;
for (i = 0; i < count; i++) {
var x = abs(int(points[i].x + 0.5)); if(x > maxPoint.x) maxPoint.x = x;
var y = abs(int(points[i].y + 0.5)); if(y > maxPoint.y) maxPoint.y = y;
var z = abs(int(points[i].z + 0.5)); if(z > maxPoint.z) maxPoint.z = z;
}
return maxPoint*2; // dist from center times two equals size
}

// type of deformer to put around the active object
var deformerType;

//The dialog
class InstanceDialog : GeModalDialog {
public:
CreateLayout();
Command(id,msg);
};

InstanceDialog::CreateLayout() {
SetTitle("EasyDeformer");

AddGroupBeginH(0,BFH_SCALEFIT,3,"",0);
AddStaticText(0,BFH_SCALEFIT,0,0,"Select Deformer to use:",0);
AddComboBox(1000,BFH_SCALEFIT, 80, 12);
AddItem(1000, obend, "Bend");
AddItem(1000, otwist, "Twist");
AddItem(1000, obulge, "Bulge");
AddItem(1000, oshear, "Shear");
AddItem(1000, otaper, "Taper");

AddDlgGroup(DR_DLGGROUP_OK|DR_DLGGROUP_CANCEL);
AddGroupEnd();
}

InstanceDialog::Command(id,msg) {
deformerType=GetInt(1000);
// use default deformer
if(deformerType==0) deformerType=obend;
}

main(doc,op)
{

// Get the active object
var op = doc->GetActiveObject();
if(!op) return;

// open Dialog
var dlg=new(InstanceDialog);
//dlg->SetDimensions();
dlg->Open(NOTOK,NOTOK);
if (!dlg->GetResult()) return FALSE;

var size = vector(0,0,0);
var type = op->GetType();

// is it a poly object ?
if(op->IsInstanceOf(opolygon))
size = GetBoundingBox(op);
else if(type>5153 && type<5174) // or a primitive ?
{
// create polyobject from input object
var bc = new(BaseContainer);
SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT, doc, op, bc, MODIFY_ALL);
//doc->Message(MSG_UPDATE);
var clone = doc->GetActiveObject();
clone->SetName("copy");

//compute bounding box
size = GetBoundingBox(clone);
// remove poly object
clone->Remove();
}
else return; // else incompatible object (like spline or array or sth)

// compute some deformer offset from the average size of the objects sides
var _offset = int((size.x+size.y+size.z) / 100 + 0.5);
// apply offset
size+=_offset;

// insert deformer object as child of selected object
var deformer = AllocObject(deformerType);
// align deformer to parent obbject
var zeroVec = vector(0,0,0);
deformer->SetPosition(zeroVec);
deformer->SetRotation(zeroVec);
// resize deformer
var deformer_bc = deformer->GetContainer();
deformer_bc->SetData(DEFORMOBJECT_SIZE,size);
deformer->SetContainer(deformer_bc);

// add deformer as child of selected object
deformer->InsertUnder(op);
// add undo
doc->AddUndo(UNDO_OBJECT_NEW,deformer);
// De-select all objects
CallCommand(12113);
// select Deformer
op->GetDown()->SetBit(BIT_AOBJ);
// Update document
doc->Message(MSG_UPDATE);
}

HolgerBiebrach
08-23-2008, 01:01 PM
"GetNameFromChild" is my very first Script. It´s small but fine and does what the name says.

Enjoy it!!

http://www.holgerbiebrach.de/files/getnamefromchild.zip (http://www.holgerbiebrach.de/files/getnamefromchild.zip)

otomo
01-24-2009, 01:09 PM
this script is a detector if your current poly selection contains polygons which are
already part of another selection tag. If so then the according selection tags are selected.
Works only with one selected object at a time.


/*
OVERLAP DETECTOR

this script is a detector if your current poly selection contains polygons which are
already part of another selection tag. If so then the according selection tags are selected.
Works only with one selected object at a time.
*/


var polySelection = op->GetPolygonSelection();//get the selected polygons of the currently selected object
var polycountOfSel = polySelection->GetCount();//how many polygons are selected?
var arSelPolys = new(array, polycountOfSel);//create array for selected polygons
var polycountOfObject = op->GetPolygonCount();//how many polygons does the object have in total?

var i = 0, o = 0;
for (i = 0; i < polycountOfObject ; i++)//iterate through all polygons of the object
{
if (polySelection->IsSelected(i))//writes every selected polygon(index) into an array
{
arSelPolys[o] = i;
o++;
}
}

var tag = op->GetFirstTag();
while (tag)//iterates through all tags of the object
{
tag->DelBit(BIT_ATAG);//deselect the tag
if (tag->IsInstanceOf(Tpolygonselection))//check if the tag is a Polygonselection tag
{
var tagSelection = tag->GetSelection();//what are the polygons in the selection tag?
for (i = 0; i < polycountOfSel ; i++)//iterates trhroug all currently selected polygons
{
if (tagSelection->IsSelected(arSelPolys[i]))//if a currently selected polygon is also part of the selection tag, then mark it as selected
{
tag->SetBit(BIT_ATAG);
break;
}
}
}
tag = tag->GetNext();
}

tcastudios
03-26-2009, 01:17 AM
Two scripts that might come in handy.
DIVIDE_SELECT: Selects the new points.
SELECT_NTH_POINT: Select nth number of points.

(Both only tested in R11)

In ScriptManager go File->Import and navigate to the dloaded files.

Cheers
Lennart

ecore
04-26-2009, 03:01 PM
2 simple scripts to adjust select tools/brushes radius with your own assigned hotkey, as the same as bodypaint brush hotkeys use "." and ",".

support commands:

Live Selection (Soft Selection)
Modeling Brush
Modeling Magnet
CA Paint Tool
CA Morph Brush
CA Weight Tool
MoGraph Selection
Hair Live Selection
Hair Brush
Hair Cut

04.27.09 modified:
1 unit increase/decrease per click when radius<=50;
2 units increase/decrease per click when radius>50.

Per-Anders
11-09-2009, 10:55 PM
Mirror Vice in COFFEE form. Keeps points at zero and kills extra polygons

Must be placed on the symmetry object itself rather than the polygonal geometry under it, and you should enable "Camera Dependent" on the COFFEE tag for the camera flipping to work (also make sure when you apply the tag that your camera is facing the side of the object that your geometry is on).

var clamp_pnts, clamp_flags, clamp_cnt, cur_pcnt, cur_vcnt, clamp_dir, tolerance, camera_dir;

GetCameraDirection(doc, symmetry_object)
{
var bd = doc->GetActiveBaseDraw();
if (!bd) return FALSE;

var cam = bd#BASEDRAW_DATA_CAMERA;
if (!cam) return FALSE;

var dir = cam->GetMg()->GetV3();
var mg = symmetry_object->GetMg();

dir = mg->GetMulV(dir);

switch (clamp_dir)
{
case SYMMETRYOBJECT_PLANE_XY: return dir.z > 0; break;
case SYMMETRYOBJECT_PLANE_XZ: return dir.y > 0; break;
case SYMMETRYOBJECT_PLANE_YZ: return dir.x > 0; break;
default: break;
}

return FALSE;
}

Init(doc, op, symmetry_object)
{
var padr = op->GetPoints();
var pcnt = op->GetPointCount();
var i = 0, cnt = 0;

tolerance = symmetry_object#SYMMETRYOBJECT_TOLERANCE;
clamp_dir = symmetry_object#SYMMETRYOBJECT_PLANE;

if (!symmetry_object#SYMMETRYOBJECT_WELD) tolerance = 0.0;

//Iterate through points and work out which need to be flagged
if (!clamp_pnts)
{
clamp_pnts = new(BaseSelect);
camera_dir = GetCameraDirection(doc, symmetry_object);
}

clamp_pnts->DeselectAll();

switch(clamp_dir)
{
case SYMMETRYOBJECT_PLANE_XY:
{
for (i = pcnt - 1; i >= 0; --i)
{
if (padr[i].z > -tolerance && padr[i].z < tolerance)
{
//Point within range
clamp_pnts->Select(i);
}
}
} break;
case SYMMETRYOBJECT_PLANE_XZ:
{
for (i = pcnt - 1; i >= 0; --i)
{
if (padr[i].y > -tolerance && padr[i].y < tolerance)
{
//Point within range
clamp_pnts->Select(i);
}
}
} break;
case SYMMETRYOBJECT_PLANE_YZ:
{
for (i = pcnt - 1; i >= 0; --i)
{
if (padr[i].x > -tolerance && padr[i].x < tolerance)
{
//Point within range
clamp_pnts->Select(i);
}
}
} break;
}

cnt = clamp_pnts->GetCount();

if (!clamp_cnt || clamp_cnt != cnt)
{
//Convert selection to short array for faster get/set access
//No BaseSelect::GetRange in COFFEE unfortunately
clamp_cnt = cnt;
clamp_flags = new(array,cnt);
if (!clamp_flags) return FALSE; //Memory Error

cnt = 0;

for (i = pcnt - 1; i >= 0; --i)
{
if (clamp_pnts->IsSelected(i))
{
clamp_flags[cnt++] = i;
}
}
}

cur_pcnt = pcnt;

return TRUE;
}

RemoveZeroPolygons(doc, op)
{
var padr = op->GetPoints();
var pcnt = op->GetPointCount();
var vadr = op->GetPolygons();
var vcnt = op->GetPolygonCount();
var i = 0, cnt = 0, ind = 0;

var vc = new(VariableChanged);
var map = new(array, vcnt);
if (!vc || !map) return FALSE;

if (!cur_vcnt || cur_vcnt > vcnt) cur_vcnt = 0;

for (i = cur_vcnt - 1; i >= 0; --i)
{
map[i] = i;
}

//New polygons are always added at the end, so this makes this much quicker
for (i = cur_vcnt, ind = cur_vcnt; i < vcnt && ind < vcnt; ++i, ++ind)
{
cnt = clamp_pnts->IsSelected(vadr[i * 4 + 0]);
cnt += clamp_pnts->IsSelected(vadr[i * 4 + 1]);
cnt += clamp_pnts->IsSelected(vadr[i * 4 + 2]);
cnt += clamp_pnts->IsSelected(vadr[i * 4 + 3]);

if (cnt == 4)
{
//All points are clamped, therefore we need to cull this polygon
map[i] = NOTOK;
ind--;
continue;
}

map[i] = ind;
}

if (ind != vcnt)
{
//Update the polygon count using the map
vc->Init(vcnt, ind, map);
op->MultiMessage(MSG_POLYGONS_CHANGED, vc);
op->Message(MSG_CHANGE);
} else cur_vcnt = vcnt;

return TRUE;
}

ClampPoints(op)
{
var padr = op->GetPoints();
var pcnt = op->GetPointCount();
var i = 0, ind = 0, changed = FALSE;

for (i = clamp_cnt - 1; i >= 0; --i)
{
ind = clamp_flags[i];
if (ind > pcnt) continue;

if (padr[ind].x != 0.0)
{
padr[ind].x = 0.0;
changed = TRUE;
}
}

if (changed)
{
op->SetPoints(padr);
op->Message(MSG_UPDATE);
}
}

CameraFlip(doc, op, symmetry_object)
{
var dir = GetCameraDirection(doc, symmetry_object);

var i = 0;
var pcnt = op->GetPointCount();
var padr = op->GetPoints();
var bc = new(BaseContainer);

if (camera_dir == dir) return; //Nothing changed
camera_dir = dir;

switch (clamp_dir)
{
case SYMMETRYOBJECT_PLANE_XY:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].z = -padr[i].z;
} break;
case SYMMETRYOBJECT_PLANE_XZ:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].y = -padr[i].y;
} break;
case SYMMETRYOBJECT_PLANE_YZ:
{
for (i = pcnt - 1; i >= 0; --i) padr[i].x = -padr[i].x;
} break;
default: break;
}

op->SetPoints(padr);
SendModelingCommand(MCOMMAND_REVERSENORMALS, NULL, op, bc, MODIFY_ALL);
op->Message(MSG_UPDATE);
}

//Main function routine, called each pass
main(doc,op)
{
//Get the active symmetry object involved here
var symmetry_object = op;
while (symmetry_object)
{
if (symmetry_object->IsInstanceOf(Osymmetry)) break;
symmetry_object = symmetry_object->GetUp();
}

if (!symmetry_object || !symmetry_object->IsInstanceOf(Osymmetry) || !symmetry_object#ID_BASEOBJECT_GENERATOR_FLAG) return TRUE; //No active symmetry object

//We only adjust the first child of the symmetry object
op = symmetry_object->GetDown();

if (!op->IsInstanceOf(Opoint)) return TRUE; //Not a points object

var pcnt = op->GetPointCount();
var vcnt = op->GetPolygonCount();

//Check for any new points that need clamping
if (!clamp_pnts || pcnt != cur_pcnt || symmetry_object#SYMMETRYOBJECT_TOLERANCE != tolerance || symmetry_object#SYMMETRYOBJECT_PLANE != clamp_dir)
{
if (!Init(doc, op, symmetry_object)) return FALSE;
}

ClampPoints(op);

//Check for any new polygons that might need culling
if (symmetry_object#SYMMETRYOBJECT_WELD && vcnt != cur_vcnt)
{
if (!RemoveZeroPolygons(doc, op)) return FALSE;
}

CameraFlip(doc, op, symmetry_object);

return TRUE;
}

abdelouahabb
12-19-2009, 06:43 PM
hi
sorry if it was already posted, this script is really simple, it can replace Split function, because Split function dont change the name of the resulted object,

var miaw = doc -> GetActiveObject();
doc -> AddUndo(UNDO_OBJECT, miaw);
CallCommand(14046); //split
miaw = miaw->GetNext();
miaw = miaw->SetName("MiawClone");

ok, as you can see the script is from a beginner and maybe it's full of errors, but it worked :D
Tip: sadly i dident knew how to select the resulted object (the clone) but there is a tip, when you use only one object in all the scene, add this:
CallCommand(100004794);
this simply will invert the object selection in the object manager :D
hope it will help :hmm:

Scott Ayers
12-19-2009, 07:14 PM
Here's how you can select and de-select objects rather than de-selecting everything.

var miaw = doc -> GetActiveObject();
doc -> AddUndo(UNDO_OBJECT, miaw);
CallCommand(14046); //split
miaw = miaw->GetNext();
miaw = miaw->SetName("MiawClone");
op->DelBit(BIT_ACTIVE); //de-select the first object
op = doc->FindObject("MiawClone");
op->SetBit(BIT_ACTIVE);// select the object named "MiawClone"

Take a look at my COFFEE Bible.
I'm still working on it. But it has a lot of things that newbies should find very helpful.

Edit* Removed outdated version.

-ScottA

Scott Ayers
12-27-2009, 07:20 PM
The Coffee Bible (https://sites.google.com/site/scottayersmedia/CoffeeBible_Updated11-13-10.zip) - Last Updated 11-13-10


-ScottA

mogh
03-20-2010, 11:15 PM
http://www.defcon-x.de/wp-content/uploads/2008/08/cad_clean.png (http://www.defcon-x.de/c4d/c4d-scripts)

The Dialog says it all i guess, feel free to report any bugs.

Scriptsite from mogh (http://www.defcon-x.de/c4d/c4d-scripts)

regards mogh

Scott Ayers
04-18-2010, 11:37 PM
Here's a list of most of the view settings.
Since they aren't echoed through the Script log. I thought this might come in handy.

//These are the default viewport settings you can set with coffee scripts.
//You can simply copy and paste any, or all of these into a script and it will change your view settings when you run it.
//These are the settings found when you select Edit->Configure above the main scene window.

//Most are simple on(1) off(0) options. But a few items have multiple choices or color values.
//If an option has multiple choices. Type a higher number to get to the next choice in the list.



//Display Tab
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SDISPLAYACTIVE = 0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_WDISPLAYACTIVE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_USEPROPERTIESACTIVE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SELECTED_NORMALS = 0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SHOWPATH=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_XRAY=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_STACKEDMATERIALS=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TINT_POLYGON_SELECTION=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SDSEDIT=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDGE_POINTS=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ACTIVE_STEMS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_BOUNDINGBOXSELECTION=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_WIREFRAMESELECTION=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_USE_LAYERCOLOR=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TINT_POLYGON_NORMALS=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_DEFORMEDEDIT=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SHADE_HANDLES=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ROTATION_BANDS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_BOUNDINGBOXSELECTION_CHILDREN=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_WIREFRAMESELECTION_CHILDREN=1;


//Filter Tab
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_NULL=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_SPLINE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HYPERNURBS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_JOINT=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_CAMERA=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_SCENE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_OTHER=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_GRID=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_WORLDAXIS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HUD=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HIGHLIGHTING=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_MULTIAXIS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HANDLEBANDS=0;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_NGONLINES=0;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_POLYGON=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_GENERATOR=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_BONE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_DEFORMER=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_LIGHT=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_PARTICLE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_NULLBONES=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HORIZON=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_BOUNDS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_SDS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_HIGHLIGHTING_HANDLES=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_OBJECTHANDLES=1;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_SDSCAGE=0;
doc->GetActiveBaseDraw()#BASEDRAW_DISPLAYFILTER_ONION=1;

//View Tab
doc->GetActiveBaseDraw()#BASEDRAW_DATA_PROJECTION=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TEXTURES=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_BACKCULL=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SHOWSAFEFRAME=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_RENDERSAFE=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TITLESAFE=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TINTBORDER=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TINTBORDER_COLOR= vector(0,0,0);//<--Black
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ACTIONSAFE=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TRANSAXES=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_OBJECTAXIS_OBJECTSCALE=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_NORMALS_SCALE=1;//<--100%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_BAND_POSITION=.25;//<--25%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_POINT_HANDLE_SIZE= 3;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_POINT_SELECTED_SIZE= 5;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TITLESAFE_SIZE= .8;//<--80%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TINTBORDER_OPACITY=.1;//<--10%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ACTIONSAFE_SIZE= .9; //<--90%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_TRANSAXES_OPACITY= .8;//<--80%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_OBJECTAXIS_SCALE= 1; //<--100%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ROTBAND_SCALE= 1; //<--100%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_BAND_SIZE= .1; //<--10%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_ROTATION_CIRCLE=.75; //<--75%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDGE_SELECTED_SIZE= 2;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDITOR_AXIS_POS=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDITOR_AXIS_TYPE=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDIT_AXIS_SCALE= 1;//<--100%
doc->GetActiveBaseDraw()#BASEDRAW_DATA_EDIT_AXIS_TEXT=1;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_HQ_OPENGL=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_HQ_SHADOWS=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_HQ_NOISES=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_HQ_TRANSPARENCY=0;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_HQ_POST_EFFECTS=0;

//Back Tab
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SNAP_PLANE_SPACING= 100;//<--100m
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SNAP_PLANE_SUB= 100;
doc->GetActiveBaseDraw()#BASEDRAW_DATA_SNAP_PLANE_ROUGHSUB= 10;

//HUD TAB
doc->GetActiveBaseDraw()#BASEDRAW_HUD_CAMERADISTANCE=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_FRAMETIME=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_PROJECTION_NAME=1;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_ROOT_OBJECT=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOTAL_OBJECTS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOTAL_POINTS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOTAL_EDGES=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOTAL_POLYGONS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOTAL_NGONS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_FPS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_FRAME=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_CAMERA_NAME=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_ACTIVE_OBJECT=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_PARENT_OBJECT=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTED_OBJECTS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTED_POINTS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTED_EDGES=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTED_POLYGONS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTED_NGONS=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TOOL=0;
doc->GetActiveBaseDraw()#BASEDRAW_HUD_BACKCOLOR= vector(number,number,number);//add your own color numbers
doc->GetActiveBaseDraw()#BASEDRAW_HUD_BACKOPACITY= .4;//<--40%
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TEXTCOLOR=vector(number,number,number);//add your own color numbers
doc->GetActiveBaseDraw()#BASEDRAW_HUD_TEXTOPACITY=1;//<--100%
doc->GetActiveBaseDraw()#BASEDRAW_HUD_SELECTCOLOR=vector(number,number,number);//add your own color numbers
doc->GetActiveBaseDraw()#BASEDRAW_HUD_ALWAYSACTIVE=1;


*Edit- Hmm. There seems to be a formatting issue creating empty spaces.
This might be too big for the forum's code tag . So I'll attach the text file to this post.

-ScottA

andreberg
05-10-2010, 09:22 AM
Hi All,

Here's a script that converts the layer color of an object, creates a new material with the same color (if non existant) and assigns it to the object.

This makes it possible to fully render the model as if the display effect "layer color" was enabled. I find it especially useful for imported CAD files.

Here's the original thread (http://forums.cgsociety.org/showthread.php?f=182&t=880407) that started it. Thanks a lot to Cairyn and Lennart for the pointers and help.

Here's the script in plain sight for your viewing pleasure.
Or download the script complete with its own icon from the attachment below.

//
// Layer Color to Material
// CINEMA 4D User Scripts
//
// Created by Andre Berg on 2010-05-10.
// Copyright 2010 Berg Media. All rights reserved.
//
// Version 0.1
//
// Summary: Convert an object's layer color to a newly
// assigned material with the same color.
//
// Modus Operandi:
// First, loop through all the objects that are selected
// in the object manager and get the layer the object belongs to.
// Then, create a new material and set the material's color channel to
// the same RGB color as the color of the layer.
// Create a new texture tag on the object and assign the corresponding
// material.
// Do not create a new material if a material with name "RGB x,y,z"
// already exists. Use existing material instead.
//
// Tip: before you run the script, make sure you really select all the
// objects you want examined and not just their parents. You can do this
// easily by selecting the parent, then choosing Select children from
// the OM's edit menu.
//
// Also, if you want all the new materials that will be created added to
// an existing material layer, in the Material Manager switch to that layer
// before running the script. Any materials created will by assigned to this
// layer automatically.
//

// --------------------------------------
const var RGB_8BIT_MULT = 255;
const var TARGET_CHANNEL = 0; // 0 = CHANNEL_COLOR, 1 = CHANNEL_LUMINANCE
// --------------------------------------

PrintLayerNameAndColor(layer) {
var lname = layer->GetName();
var lcol = layer#ID_LAYER_COLOR;
println("layer '" + lname + "' has color: RGB("
+ tostring(lcol.x * RGB_8BIT_MULT) + ","
+ tostring(lcol.y * RGB_8BIT_MULT) + ","
+ tostring(lcol.z * RGB_8BIT_MULT) + ")");
}

ColorToString(col) {
return "RGB "
+ tostring(int(floor(col.x * RGB_8BIT_MULT))) + ","
+ tostring(int(floor(col.y * RGB_8BIT_MULT))) + ","
+ tostring(int(floor(col.z * RGB_8BIT_MULT)));
}

FindLastTag(op) {
var ttag = op->GetFirstTag();
var ttag1;

while(ttag)
{
ttag1 = ttag;
ttag = ttag->GetNext();
}
if(ttag1) return ttag1;
else return NULL;
}

OpHasTextureTagWithName(op, str) {
var ttag = op->GetFirstTag();
while (ttag) {
if (ttag->GetType() == Ttexture &&
ttag#TEXTURETAG_MATERIAL->GetName() == str) {
return true;
}
ttag = ttag->GetNext();
}
return false;
}

main(doc,op) {
var i;
doc->StartUndo();
for(i = 0; object(i); i++) {
var op = object(i);
var lay = op#ID_LAYER_LINK;
if (lay) {
var col = lay#ID_LAYER_COLOR;
var layname = lay->GetName();
var colstr = ColorToString(col);
//println(colstr);

// see if a material with name "RGB x,y,z" already exists
var mat = doc->FindMaterial(colstr);
if (!mat) {
// if not create a new material
StopAllThreads();
CallCommand(13015);
mat = doc->GetFirstMaterial();
if (!mat) return;
doc->AddUndo(UNDO_MATERIAL_NEW , mat);
}

// set material name to "RGB x,y,z"
mat->SetName(colstr);

// set the color channel to the RGB values of the layer
var mchan = mat->GetChannel(TARGET_CHANNEL);
if (!mchan) return;
var mchanbc = mchan->GetContainer();
if (!mchanbc) return;
mchanbc->SetData(CH_COLOR, col);
mchan->SetContainer(mchanbc);

// find out if the object already has a tag which references the proper layer material
if (!OpHasTextureTagWithName(op, colstr)) {
var textag = AllocTag(Ttexture);
if (!textag) return;
StopAllThreads();
op->InsertTag(textag, FindLastTag(op));
doc->AddUndo(UNDO_TAG_NEW, textag);
var tagbc = textag->GetContainer();
doc->AddUndo(UNDO_TAG_DATA, textag);
tagbc->SetData(TEXTURETAG_MATERIAL , mat); // Load the new Mat into the Container
//tagbc->SetData(TEXTURETAG_PROJECTION , 6); // Set projection to UVW
textag->SetContainer(tagbc);
}
}
op->MultiMessage(MSG_UPDATE);
}
doc->EndUndo();
}

I am also trying to create a Python version of this script and I have it converted about 3/4 but I am stuck at the point where I created the new material and need to adjust the color channel's RGB vector.

EDIT: Python version finished. Download attachment in this post (http://forums.cgsociety.org/showpost.php?p=6506208&postcount=13) from the original thread.

Enjoy!

André

Per-Anders
05-19-2010, 11:33 PM
Select degenerate polygons. This script allows you to select polygons around an edge shared by more than 2 polygons (illegal when dealing with many operators).

getInd(vadr, polyIndex, pointIndex)
{
return vadr[polyIndex * 4 + ((pointIndex + 4)%4)];
}

main(doc, op)
{
var vadr = op->GetPolygons(),
vcnt = op->GetPolygonCount(),
i = 0,
o = o,
u = 0,
p = 0,
cnt = 0,
p1 = 0, p2 = 0,
firstpol = 0,
hit = FALSE,
sel = op->GetPolygonSelection();

doc->StartUndo();
doc->AddUndo(UNDO_CHANGE, op);
sel->DeselectAll();

for (u = vcnt - 1; u >= 0; --u)
{
for (o = 3; o >= 0; --o)
{
p1 = getInd(vadr, u, o);
p2 = getInd(vadr, u, o+1);

if (p1 == p2) continue;

cnt = 0;

for (i = u - 1; i >= 0; --i)
{
hit = FALSE;
for (p = 3; p >= 0 && !hit; --p)
{
if (getInd(vadr, i, p) == p1)
{
if (getInd(vadr, i, p - 1) == p2) hit = TRUE;
}
else if (getInd(vadr, i, p) == p2)
{
if (getInd(vadr, i, p - 1) == p1) hit = TRUE;
}
}

if (hit)
{
cnt++;
if (cnt == 1) firstpol = i;
else if (cnt == 2)
{
sel->Select(u);
sel->Select(firstpol);
sel->Select(i);
}
else if (cnt > 2) sel->Select(i);
}
}
}
}
op->SetPolygonSelection(sel);
op->Message(MSG_UPDATE);
doc->EndUndo();
}

Scott Ayers
09-10-2010, 04:59 PM
Here's a Coffee Effector example that allows you to have clones interact with other non cloned objects in your scene. Based on how far apart they are.
I used a light in this example. But you can use anything else you like. And instead of triggering a light's intensity. You can trigger any attribute you want.
//This script is to be used inside of a Mograph Coffee Effector. NOT a coffee tag!
//This script makes a light turn on when any clone gets near it. And also works combined with other effectors
//Make sure you put this code in the "Full Control" mode in the coffee effector
//If used with other effectors;
//*Make sure the coffee effector is *last* in the list of effectors in your clone's effectors list

main(doc,op)
{
var md = GeGetMoData(op);
if (!md) return false;
var cnt = md->GetCount();
var marr = md->GetArray(MODATA_MATRIX);
var fall = md->GetFalloffs();
var L = doc->FindObject("Light"); //<--- Insert your light's name here
var Lpos = L->GetPosition();
L#LIGHT_BRIGHTNESS=0;// change light intesity to Zero

var distance = 30; //<--- Edit the distance value here
var intensity = .7;//<---Edit the light's intensity value here


var i;
for(i = cnt-1; i >= 0; --i) // Loop through the available clones
{
var pos = marr[i]->GetV0();// Get their global positions
var dist = vlen(pos - Lpos);//the clone's position minus the light's position
if (dist < distance)
{
//println(pos);
//println("true");
L#LIGHT_BRIGHTNESS=intensity; // change light's intensity
}
}

md->SetArray(MODATA_MATRIX, marr, true);
return true;
}

Don't forget that you can combine this with other effectors which is one of the really cool things about the Coffee Effector.
Just make sure the Coffee Effector is listed last in your cloner's effector list or it won't work.

-ScottA

tcastudios
09-22-2010, 12:41 AM
A little Target Length setter brought up at the Vray forum
meant to "spot" a DOF distance.

Copy all into your script manager, make sure to make
a short cut for it!


// dangTARGET tcastudios.com 2010
//
// Make sure to make a ShortCut for this to work. (In example Shift+Tab)
// Set the target length of current Camera View by
// using the short cut and mouse pointer position (not clicking!)
// Tested in R11 and R11.5

var acam = doc->GetActiveBaseDraw()#BASEDRAW_DATA_CAMERA; // Get activ View (Camera)
var rottype = acam#CAMERAOBJECT_MODE; // Get Current Camera Mode
var prepivpos = acam#CAMERAOBJECT_PIVOT_POSITION; // Get Current Pivot position

CallCommand(1021420); // Set a temporal Camera Pivot Point
var acampos = acam->GetMg()->GetV0(); // Get View Matrix
var pivpos = acam#CAMERAOBJECT_PIVOT_POSITION; // Get New Pivot position

acam#CAMERAOBJECT_TARGETDISTANCE = vlen(pivpos-acampos); // The Simple non trigometric target distance
acam#CAMERAOBJECT_PIVOT_POSITION = prepivpos; // Reset Pivot position
acam#CAMERAOBJECT_MODE = rottype; // Reset Camera Mode


Cheers
Lennart

Per-Anders
09-29-2010, 09:30 PM
A simple Effector to avoid overlapped clones.

Set up the COFFEE Effector with the following UserData entries:

1 - Float - Name : Radius, Units: Meter, Min : 0.0, No Max, Default 10.0
2 - Integer - Name : Iterations, Min : 1, No Max, Default : 10
3 - Integer - Name : Method, Interface :Cycle, options

0;Hide
1;Offset along Z
2;Push Apart


Set the COFFEE Effector Mode to Full Control enter the following code:

main(doc,op)
{
var md = GeGetMoData(op);
if (!md) return false;
var cnt = md->GetCount();
var marr = md->GetArray(MODATA_MATRIX);
var farr = md->GetArray(MODATA_FLAGS);

var hide = op#ID_USERDATA:3;
var radius = op#ID_USERDATA:1;
var iterations = op#ID_USERDATA:2;
var separation = (1.0 / float(iterations)) * 0.5;

var i = 0, o = 0, u = ((hide == 0)?iterations - 1:0);

while (u++ < iterations)
{
for (i = cnt - 1; i >= 0; --i)
{
if ((farr[i]&(1<<0)) && !(farr[i]&(1<<1))) //Only if the clone is visible
{
for (o = i - 1; o >= 0; --o)
{
if ((farr[o]&(1<<0)) && !(farr[o]&(1<<1)) && vlen(marr[i]->GetV0() - marr[o]->GetV0()) < radius)
{
if (hide == 0)
{
//Hide the clone
farr[i] &= ~(1<<0);
break;
}
else if (hide == 1)
{
//Move the clone along it's z direction by 100
marr[i]->SetV0(marr[i]->GetV0() + (marr[i]->GetV3() * radius));
break;
}
else if (hide == 2)
{
var delta = vnorm(marr[i]->GetV0() - marr[o]->GetV0()) * radius * separation;

marr[i]->SetV0(marr[i]->GetV0() + delta);
marr[o]->SetV0(marr[o]->GetV0() - delta);
}
}
}
}
}
}

md->SetArray(MODATA_FLAGS, farr, true);
md->SetArray(MODATA_MATRIX, marr, true);
return true;
}


Store and reuse as required.

Control description :

Radius - The minimum radius clones can be before they are pushed apart/deleted

Method -
- Hide - Hides the clones that overlap
- Offset along Z - Pushes clones out form the surface when they voerlap creating stacked clones
- Push Apart - Pushes the clones apart from each other

Iterations - Repeats the process this number of times to help avoid overlaps as much as possible.

Example R12 file attached.

berandogan
12-17-2010, 10:44 AM
Hi, I am new to py4d.
I wrote a script which i think would be useful. But There is a problem I couldn't make the undo work. Is there anybody who can help?

#This script Runs the "Group Objects" command for all selected Objects.
#This is useful when you are changing lots of objects' pivots, used in a Fracture Object to work while using effectors.
import c4d
from c4d import documents

selection = doc.GetOrderedActiveObjects()
c4d.CallCommand(12113) # Deselect All
for each in selection:
each.SetBit(c4d.BIT_ACTIVE) # Select Single Object
c4d.CallCommand(100004772) # Group Objects
c4d.CallCommand(12113) # Deselect All

rsquires
01-11-2011, 01:19 PM
Just got into scripts for improving workflow and like how easy it is, using the script log, to create quite complex little helpers. But I have a question.

Is it possible to return the attributes of say the modelling axis back to it's default settings once the script I have initiated is dropped for another tool. My script is for using a normal rotation along normals for selected polys to rotate them. Didn't realise you could do this but very happy to have found that it's possible. So I have a script that instigates the rotate tool and then sets the modelling axis to normal etc, and ticks the along normals check box. But after I have finished with it how can I return the modelling axis back to what it was before.

all the best

Richard

oliveoyle
01-25-2011, 05:34 PM
I am very new to c4d scripting. I have trying to learn from seeing other scripts and the script log. I made two simple scripts fro Tweak and Auto switch modes. When I use the default icon for these modes, I constantly needed to switch other things, like how axis off, move tool and so on. These two simple scripts do what I need, but I need some help to add a little more to them and I lack the knowledge.

// Selects Tweak mode with additional selections

CallCommand(1016114); // Tweak mode
CallCommand(200000088); // Move tool
CallCommand(12139); // Point tool
CallCommand(1016176); // Show Axis Tool


second script

// Selects Auto Switch Mode with additional selections
CallCommand(1016118); // Auto Switch mode
CallCommand(200000083); //Live Selection
CallCommand(12139); // Point tool
CallCommand(1016176); // Show Axis Tool



I would like the Tweak script to make sure that the Show Axis is always off. Currently, it flip flops the previous state. I need it to see if the Show Axis is off and to leave it off. Same thing for the Auto Switch script, except the opposite. I need the Auto Switch script to always make sure it will have Show Axis on.

The other problem I have is the Icon images I made. I need them to show they are active when selected. How can I make icon images that change to show which one is selected like all the other icons that show my Preference Theme Colors Pallette Background Active Color? Or even better for me, to make two Icon Images for each script that toggles between them when I select that script icon in the palette. Like one image with a gray background and then shows a red background when it is selected in the palette so it is different looking then the Pallette Background Active Color.


Thanks for any help,
Olive

andreberg
03-26-2011, 07:19 PM
Hi,

I want to share a Helpers class for Python with you.

The Helpers class is collection of reusable methods from here, the Plugin Café and from my own scripts.

I would like to thank the authors (where applicable) for making their code available and often taking the time to answer questions about it too.
In no apparent order I would like to thank: Per-Anders Edwards, Scott Ayers, Robert Grünweiss, nux95, Lennart from tcastudios, Mikael Sterner and anyone I forgot.

Also, don't forget the old forum post archive (http://www.plugincafe.com/forum_search.asp) over at the Plugin Café - a valuable resource of information, since many question have been asked before.


class Helpers(object):
"""Contains various helper methods."""
def __init__(self, arg):
super(Helpers, self).__init__()

@staticmethod
def readConfig(filepath=None):
"""
Read settings from a configuration file.

Returns None if config file at filepath doesn't exist.
Returns the config object on success.
"""
result = None
if filepath is None:
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "res/", "config.ini")
if os.path.exists(filepath):
config = ConfigParser.ConfigParser()
config.read(filepath)
result = config
return result

@staticmethod
def saveConfig(config, filepath=None):
"""
Save settings to a configuration file.

If filepath is None, it will be assumed to point to res/config.ini.
Returns True if successful, False otherwise.
"""
result = False
if filepath is None:
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "res/", "config.ini")
try:
with open(filepath, 'wb') as configfile:
config.write(configfile)
result = True
except Exception, e:
print "*** Caught Exception: %r ***" % e
return result

@staticmethod
def initConfig(defaults, filepath=None):
"""
Initialize configuration file by writing the defaults.

Returns True if config file was created,
False if config file already exists or otherwise.
"""
result = False
if filepath is None:
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "res/", "config.ini")
if not os.path.exists(filepath):
config = ConfigParser.ConfigParser(defaults)
result = Helpers.saveConfig(config, filepath)
return result

@staticmethod
def vDeg(v, ishpb=False):
"""Convert each component of vector v to degrees"""
if v is None:
raise ValueError("v can't be None")
if not isinstance(v, c4d.Vector):
raise TypeError("Expected vector, got %s" % type(v))
if ishpb:
res = c4d.Vector(0,0,0)
res.x = Deg(v.x)
res.y = Deg(v.y)
res.z = Deg(v.z)
if res.x >= 180:
res.x -= 360
if res.y >= 180:
res.y -= 360
if res.z >= 180:
res.z -= 360
return res
else:
return c4d.Vector(Deg(v.x), Deg(v.y), Deg(v.z))

@staticmethod
def vRad(v, ishpb=False):
"""Convert each component of vector v to radians"""
if v is None:
raise ValueError("v can't be None")
if not isinstance(v, c4d.Vector):
raise TypeError("Expected vector, got %s" % type(v))
if ishpb:
if v.x >= 180:
v.x -= 360
if v.y >= 180:
v.y -= 360
if v.z >= 180:
v.z -= 360
return c4d.Vector(Rad(v.x), Rad(v.y), Rad(v.z))

@staticmethod
def vAvg(lst):
"""Calculate the average of a list of vectors"""
if lst is None:
raise ValueError("List lst can't be None")
if not isinstance(lst, list):
raise TypeError("Expected list of vectors, got %s" % type(lst))
lstlen = len(lst)
res = c4d.Vector(0,0,0)
if lstlen == 0: return res
for l in lst:
res.x += l.x
res.y += l.y
res.z += l.z
res.x = res.x / float(lstlen)
res.y = res.y / float(lstlen)
res.z = res.z / float(lstlen)
return res

@staticmethod
def select(op):
if not op.GetBit(c4d.BIT_ACTIVE):
op.ToggleBit(c4d.BIT_ACTIVE)
return op.GetBit(c4d.BIT_ACTIVE)

@staticmethod
def selectAdd(op):
"""
Same as select(op) but uses a slightly different mechanism.

See also BaseDocument.SetSelection(sel, mode).
"""
doc = op.GetDocument()
doc.SetActiveObject(op, c4d.SELECTION_ADD)

@staticmethod
def selectGroupMembers(grp):
doc = documents.GetActiveDocument()
for obj in grp:
# add each group member to the selection
# so we can group them in the object manager
#doc.AddUndo(UNDO_BITS, obj)
doc.SetActiveObject(obj, c4d.SELECTION_ADD)

@staticmethod
def selectObjects(objs):
for op in objs:
Helpers.select(op)

@staticmethod
def deselectAll(inObjMngr=False):
"""
Not the same as BaseSelect.DeselectAll().

inObjMngr bool if True, run the deselect command from Object Manager,
else the general one for editor viewport
"""
if inObjMngr is True:
c4d.CallCommand(100004767) # deselect all (Object Manager)
else:
c4d.CallCommand(12113) # deselect all

@staticmethod
def groupObjects(objs, name="Group"):
"""
CallCommand based grouping of objects from a list.

Generally unreliable, because selection state matters.
Use insertUnderNull for better effect.
"""
Helpers.deselectAll(True)
result = None
if objs is None:
return result
if not isinstance(objs, list):
objs = [objs]
else:
return result
for o in objs:
Helpers.select(o)
if DEBUG: print "creating group %s" % name
c4d.CallCommand(100004772) # group objects
doc = documents.GetActiveDocument()
grp = doc.GetActiveObject()
grp.SetName(name)
result = grp
return result

@staticmethod
def groupSelected(name="Group"):
"""
CallCommand based grouping of selected objects.

Generally unreliable, because selection state matters.
Use insertUnderNull for better effect.
"""
result = None
if DEBUG: print "creating group %s" % name
c4d.CallCommand(100004772) # group objects
doc = documents.GetActiveDocument()
grp = doc.GetActiveObject()
grp.SetName(name)
result = grp
return result

@staticmethod
def recurseBranch(obj):
child = obj.GetDown()
while child:
child = child.GetNext()
return Helpers.recurseBranch(child)

@staticmethod
def getNextObject(op, stopobj=None):
if op == None: return None
if op.GetDown(): return op.GetDown()
if stopobj is None:
while not op.GetNext() and op.GetUp():
op = op.GetUp()
else:
while (not op.GetNext() and
op.GetUp() and
op.GetUp() != stopobj):
op = op.GetUp()
return op.GetNext()

@staticmethod
def getActiveObjects(doc):
"""
Same as BaseDocument.GetSelection(), where GetSelection also selects tags and materials.
"""
lst = list()
op = doc.GetFirstObject()
while op:
if op.GetBit(c4d.BIT_ACTIVE) == True:
lst.append(op)
op = Helpers.getNextObject(op)
return lst

@staticmethod
def findObject(name):
"""Find object with name 'name'"""
if name is None: return None
if not isinstance(name, basestring):
raise TypeError("Expected string, got %s" % type(name))
doc = documents.GetActiveDocument()
if not doc: return None
result = None
op = doc.GetFirstObject()
curname = op.GetName()
if curname == name: return op
op = Helpers.getNextObject(op)
while op:
curname = op.GetName()
if curname == name:
return op
else:
op = Helpers.getNextObject(op)
return result

@staticmethod
def createObject(typ, name, undo=True):
obj = None
try:
doc = documents.GetActiveDocument()
obj = c4d.BaseObject(typ)
obj.SetName(name)
doc.InsertObject(obj)
if undo is True:
doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
c4d.EventAdd()
except Exception, e:
print "*** Caught Exception: %r ***" % e
return obj

@staticmethod
def insertUnderNull(objs, grp=None, name="Group", copy=False):
"""
Inserts objects under a group (null) object, optionally creating the group.

objs BaseObject can be a single object or a list of objects
grp BaseObject the group to place the objects under
(if None a new null object will be created)
name str name for the new group
copy bool copy the objects if True

Returns the modyfied/created group on success, None on failure.
"""
if grp is None:
grp = Helpers.createObject(c4d.Onull, name)
if copy == True:
objs = [i.GetClone() for i in objs]
if DEBUG: print "inserting objs into group '%s'" % grp.GetName()
if isinstance(objs, list):
for obj in objs:
obj.Remove()
obj.InsertUnder(grp)
else:
objs.Remove()
objs.InsertUnder(grp)
c4d.EventAdd()
return grp

@staticmethod
def togglePolySelection(op):
result = False
totalpolys = op.GetPolygonCount()
psel = op.GetPolygonS()
while psel.HostAlive() == 1:
for poly in xrange(totalpolys):
psel.Toggle(poly)
result = True
break
return result

@staticmethod
def selectAllPolys(op):
result = False
totalpolys = op.GetPolygonCount()
psel = op.GetPolygonS()
while psel.HostAlive() == 1:
for poly in xrange(totalpolys):
psel.Select(poly)
result = True
break
return result

@staticmethod
def polyToList(p):
if not isinstance(p,c4d.CPolygon):
raise TypeError, "CPolygon expected"
if p.c == p.d: return [p.a,p.b,p.c]
return [p.a,p.b,p.c,p.d]

@staticmethod
def listToPoly(l):
if not isinstance(l, list):
raise TypeError, "list or dict expected"
ln = len(l)
if ln < 3:
raise IndexError, "lst must have at least 3 indieces"
elif ln == 3:
return c4d.CPolygon(l[0],l[1],l[2])
else:
return c4d.CPolygon(l[0],l[1],l[2],l[3])

@staticmethod
def calcPolyNormal(p, op):
"""
Calculate the orientation of face normal by using Newell's method.
See calcVertexNormal for an example of usage within the calling context.
"""
if not p: raise ValueError("p can't be None")
if not isinstance(p, c4d.CPolygon):
raise TypeError("Expected CPolygon, got %s" % type(p))
N = c4d.Vector(0,0,0)
lst = Helpers.polyToList(p)
llen = len(lst)
#print "lst = %r" % lst
allp = op.GetAllPoints()
for i in range(llen):
x = i
n = ((i+1) % llen)
#print x, n
vtx = allp[lst[x]]
vtn = allp[lst[n]]
#print "vtx%d = %r (%s)" % (x, vtx, type(vtx))
#print "vtn%d = %r (%s)" % (n, vtn, type(vtn))
N.x += (vtx.y - vtn.y) * (vtx.z + vtn.z)
N.y += (vtx.z - vtn.z) * (vtx.x + vtn.x)
N.z += (vtx.x - vtn.x) * (vtx.y + vtn.y)
return N.GetNormalized()

@staticmethod
def calcVertexNormal(v, idx, op):
"""
Calculate the vertex normal by averaging surrounding face normals.
Usually called from a construct like the following:

for i, point in enumerate(op.GetAllPoints()):
vn = calcVertexNormal(point, i, op):
"""
if not v: raise ValueError("v can't be None")
if not isinstance(v, c4d.Vector):
raise TypeError("Expected Vector, got %s" % type(v))
N = c4d.Vector(0,0,0)
nb = Neighbor()
nb.Init(op)
pntpolys = nb.GetPointPolys(idx)
polys = []
normals = []
allp = op.GetAllPolygons()
for poly in pntpolys:
x = poly
poly = allp[poly]
#print "poly %d = %r (%s)" % (x, poly, type(poly))
polys.append(poly)
normal = Helpers.calcPolyNormal(poly, op)
normals.append(normal)
ln = len(normals)
if ln == 0: return N # beware of div by zero
for n in normals:
N += n
N = c4d.Vector(N.x/ln, N.y/ln, N.z/ln)
return N.GetNormalized()

@staticmethod
def getGlobalPosition(obj):
return obj.GetMg().off

@staticmethod
def getGlobalRotation(obj):
return MatrixToHPB(obj.GetMg())

@staticmethod
def getGlobalScale(obj):
m = obj.GetMg()
return c4d.Vector(m.v1.GetLength(),
m.v2.GetLength(),
m.v3.GetLength())

@staticmethod
def setGlobalPosition(obj, pos):
m = obj.GetMg()
m.off = pos
obj.SetMg(m)

@staticmethod
def setGlobalRotation(obj, rot):
"""
Please remember, CINEMA 4D handles rotation in radians.

Example for H=10, P=20, B=30:

import c4d
from c4d import utils
#...
hpb = c4d.Vector(utils.Rad(10), utils.Rad(20), utils.Rad(30))
SetGlobalRotation(obj, hpb) #object's rotation is 10, 20, 30
"""
m = obj.GetMg()
pos = m.off
scale = c4d.Vector( m.v1.GetLength(),
m.v2.GetLength(),
m.v3.GetLength())

m = HPBToMatrix(rot)

m.off = pos
m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

obj.SetMg(m)

@staticmethod
def setGlobalScale(obj, scale):
m = obj.GetMg()

m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

obj.SetMg(m)

@staticmethod
def setObjectAxisRotation(obj, rot, local=False, iterations=15, depth=0):
"""
Set the rotation of the object axis (i.e. keeping points in place).

obj object
rot vector
local bool if True, work with the local matrix instead of global
iterations int number of recursive steps taken to find a solution
normally 15 appears to be generous enough while not
being excessive.
depth int leave at 0
"""
# unfortunately tail recursion and depth guard
# seem needed because of the MatrixToHPB(HPBToMatrix(Rad(angle))
# roundtrip round-off error, so we need to improve
# our solution with each recursion level
depth += 1
if obj is None: return False
if not isinstance(rot, c4d.Vector):
raise TypeError("expected c4d.Vector, got %s" % type(rot))
if local is False:
getfn = obj.GetMg
setfn = obj.SetMg
else:
getfn = obj.GetMl
setfn = obj.SetMl
mo = getfn()
# calc difference to current orientation
# (we want absolute value opposed to relative increment)
currot = MatrixToHPB(mo)
diff = rot-currot
if VectorEqual(rot, currot) or depth >= iterations:
return False
else:
if DEBUG:
print "%d: rot = %s, currot = %s, diff = %s" % (depth, rot, currot, diff)
mat = HPBToMatrix(diff)
# orient whole object (axis + points)
setfn(mo * mat)
# get inverse rotation matrix for the points
pntsrm = mat.__invert__()
allpnts = obj.GetAllPoints()
newpnts = []
for pnt in allpnts:
# write back points to previous positions
# by applying the inverse matrix
newpnts.append(pntsrm * pnt)
obj.SetAllPoints(newpnts)
obj.Message(c4d.MSG_UPDATE)
if DEBUG:
currot = MatrixToHPB(getfn())
diff = rot-currot
print "%d: rot = %s, currot = %s, diff = %s" % (depth, rot, currot, diff)
return Helpers.setObjectAxisRotation(obj, rot, local, iterations, depth)

@staticmethod
def centerObjectAxis(obj):
# check object type
if obj is None or not isinstance(obj, c4d.PointObject):
return True

maxpoints = obj.GetPointCount()
if maxpoints == 0:
return False

# get center of gravity of object vertices in parent's coordinates
cg = c4d.Vector(0,0,0)
scale = 1.0 / maxpoints
for c in xrange(0, maxpoints):
cg += (obj.GetPoint(c) * scale)
ml = obj.GetMl()
cg = ml * cg # GetMulP

# get inverse of matrix of object and the translation vector to new position
inv = ml.__invert__()
trans = inv * (cg - obj.GetRelPos()) # GetMulV

# move object to new position and compensate vertex positions
obj.SetRelPos(cg)
for c in xrange(0, maxpoints):
obj.SetPoint(c, obj.GetPoint(c) - trans)
obj.Message(c4d.MSG_UPDATE)

# compensate positions of child objects
child = obj.GetDown()
while child:
child = child.GetNext()
child.SetRelPos(child.GetRelPos() - trans)

return True





(and here's a syntax highlighted gist (https://gist.github.com/888507) - may be easier to read)

Last but not least thanks to S. Rath for creating Py4D and subsequently having Python integrated into CINEMA 4D.

I'm in scripting heaven :)

Andre

andreberg
03-30-2011, 11:34 AM
Here's two more Python classes:

Plane - contains methods for calculating the distance to a point and the intersection of a plane and a point with a direction vector.

(syntax highlighted gist (https://gist.github.com/894257))


class Plane(object):
"""Represents a plane defined by position and normal vector"""
def __init__(self, pos, n):
super(Plane, self).__init__()
self.pos = pos
self.n = n.GetNormalized()
if DEBUG: print "self.pos = %r, self.n = %r" % (pos, n)

def setN(self, newn):
self.n = newn.GetNormalized()

def setPos(self, newpos):
self.pos = newpos

def sideAsString(self, d):
if d < 0:
res = "back"
elif d == 0:
res = "onplane"
else:
res = "front"
return res

def pointResidence(self, p):
"""
Define the resident direction of a point with respect
to the plane.

The point can be either in front of the plane (+1), on the
plane (0) or on the back of the plane (-1).
"""
d = self.pointDistance(p)
eps = 0.000001
if d <= eps:
d = -1
elif abs(d) < eps:
d = 0
else:
d = 1
if DEBUG: "point residence = %r" % d
return d

def pointDistance(self, p, getsigned=True):
"""
Calculate distance from a point p to the plane.

getsigned bool set to True if you want a signed distance.
This can be useful to determine if the point
is located in the half space from the backside
of the plane or in the half space on the front.
"""
if p is None:
raise ValueError("Point p can't be None")
if not isinstance(p, c4d.Vector):
raise TypeError("Expected Vector, got %s" % type(p))
if DEBUG: print "pos = %r, n = %r, p = %r" % (self.pos, self.n, p)
if not getsigned:
projp = self.lineIntersection(p)
if projp is None:
raise ValueError("dist can't be None when projected along plane normal!")
dist = (p - projp).GetLength()
else:
pos = self.pos
n = self.n
d = -n * pos
nx2 = n.x * n.x
ny2 = n.y * n.y
nz2 = n.z * n.z
dist = (n.x * p.x + n.y * p.y + n.z * p.z + d)
if DEBUG:
s = ""
if getsigned is True:
s = " (signed)"
print "dist = %r%s" % (dist, s)
return dist

def lineIntersection(self, p, d=None):
"""
Calculate intersection point with a line starting at position p
and pointing in the direction d. May return None if an intersection
isn't possible (parallel directions).

d vector direction of the line. If None, the normal of the
plane will be used instead.
"""
if p is None:
raise ValueError("Point p can't be None")
if not isinstance(p, c4d.Vector):
raise TypeError("Expected Vector, got %s" % type(p))
if not isinstance(d, (type(None), c4d.Vector)):
raise TypeError("Expected Vector or None, got %s" % type(p))
pos = self.pos
n = self.n
if d is None:
d = n
else:
d.Normalize()
ddn = d.Dot(n)
if abs(ddn) < 0.000001:
return None
mu = (pos - p).Dot(n)/ddn
pisect = p + mu * d
return pisect




MinMax - after a class from a COFFEE snippet I recieved eons ago. It gives you the min, max, midpoint, radius and size of a list of vectors.

(syntax highlighted gist (https://gist.github.com/894259))

class MinMax(object):
"""
Calculate various area metrics from a list of points,
such as min, max, midpoint, radius and size.
"""
def __init__(self):
super(MinMax, self).__init__()
FLOATMIN = sys.float_info[3]-1000 # workaround for underflow error
FLOATMAX = sys.float_info[0]
self.min = c4d.Vector(FLOATMAX, FLOATMAX, FLOATMAX)
self.max = c4d.Vector(FLOATMIN, FLOATMIN, FLOATMIN)

def __str__(self):
return "%r\n size = %s\n mp = %s\n min = %s\n max = %s" % (
self, self.getSize(), self.getMp(), self.min, self.max
)

def addPoint(self, p):
if p.x < self.min.x: self.min.x = p.x
if p.x > self.max.x: self.max.x = p.x
if p.y < self.min.y: self.min.y = p.y
if p.y > self.max.y: self.max.y = p.y
if p.z < self.min.z: self.min.z = p.z
if p.z > self.max.z: self.max.z = p.z

def addPoints(self, lst):
for p in lst:
self.addPoint(p)

def addSelectedPoints(self, op):
"""
Add selected points from object 'op'.

Returns number of points added, or
False if there are no points or op
doesn't exist.
"""
if op is None: return False
allpnts = op.GetAllPoints()
if len(allpnts) == 0: return False
pntsel = op.GetPointS()
pntcnt = op.GetPointCount()
n = 0
if pntsel.HostAlive():
for i, p in enumerate(allpnts):
if pntsel.IsSelected(i):
self.addPoint(op.GetPoint(i))
n += 1
else:
return False
return n

def getMax(self):
return self.max

def getMin(self):
return self.min

def getMp(self):
return (self.min + self.max) * 0.5

def getRad(self):
return (self.max - self.min) * 0.5

def getSize(self):
return self.max - self.min





Cheers

Andre

andreberg
04-02-2011, 03:12 AM
Here's a Python script that will create a construction plane from three selected vertices.
It will create multiple planes if you have three points selected each on multiple polygon objects.

Just remember to have exactly three points selected per object, as everything else is ambiguous and cannot always be solved.

I have attached a version of the script with CINEMA's construction plane icon to this post (http://forums.cgsociety.org/showpost.php?p=6929699&postcount=7), but for a quick read here it is in CODE tags:


# -*- coding: MacRoman -*-
#
# Three Point Plane
# CINEMA 4D Python Scripts
#
# Created by André Berg on 2011-04-01.
# Copyright 2011 Berg Media. All rights reserved.
#
# Version 0.4
# Updated: 2011-04-10
#
# Summary: Create a construction plane from three
# selected vertices (for each selected poly object).
#
#
"""
Name-US:Three Point Plane
Description-US:Create a plane from three selected vertices
"""

import sys
import c4d
from c4d import gui
from c4d import documents
from c4d.utils import *

DEBUG = False

if DEBUG:
import pprint
pp = pprint.PrettyPrinter(width=200)
PP = pp.pprint
PF = pp.pformat

def createObject(typ, name=None, undo=True):
obj = None
try:
doc = documents.GetActiveDocument()
obj = c4d.BaseObject(typ)
if name is not None:
obj.SetName(name)
doc.InsertObject(obj)
if undo is True:
doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
c4d.EventAdd()
except Exception, e:
print "*** Caught Exception: %r ***" % e
return obj

def setGlobalRotation(obj, rot):
"""
Please remember, CINEMA 4D handles rotation in radians.

Example for H=10, P=20, B=30:

import c4d
from c4d import utils
#...
hpb = c4d.Vector(utils.Rad(10), utils.Rad(20), utils.Rad(30))
SetGlobalRotation(obj, hpb) #object's rotation is 10, 20, 30
"""
m = obj.GetMg()
pos = m.off
scale = c4d.Vector( m.v1.GetLength(),
m.v2.GetLength(),
m.v3.GetLength())

m = HPBToMatrix(rot)

m.off = pos
m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

obj.SetMg(m)

def getGlobalRotation(obj):
return MatrixToHPB(obj.GetMg())

def setGlobalPosition(obj, pos):
m = obj.GetMg()
m.off = pos
obj.SetMg(m)

def objectAxisFromVector(v):
return HPBToMatrix(VectorToHPB(v))

def main(doc):
doc.StartUndo()

sel = doc.GetSelection()
if sel is None: return False

c4d.StopAllThreads()

# loop through all objects
for op in sel:
mg = op.GetMg()
relrot = op.GetRelRot()
isrotated = not VectorEqual(relrot, c4d.Vector(0,0,0))

pntsel = op.GetPointS()
pntcnt = op.GetPointCount()
allpnts = op.GetAllPoints()

# get selected points as c4d.Vector
points = []
for i, point in enumerate(allpnts):
if pntsel.IsSelected(i):
points.append(point)

if len(points) != 3:
# we really need exactly three points,
# everything else is ambiguous
print "Three Point Plane.py: please select exactly three points to create a plane..."
continue

p1 = points[0]
p2 = points[1]
p3 = points[2]

pd21 = p2 - p1
pd23 = p2 - p3
pd21.Normalize()
pd23.Normalize()

if DEBUG:
print "pd21 = %r, pd23 = %r" % (pd21, pd23)

plane = createObject(c4d.Oconplane)
if plane is None: continue


#newmgz = (pd21.Cross(pd31)).GetNormalized() * HPBToMatrix(relrot)
#newmgy = (newmgz.Cross(c4d.Vector(1,0,0))).GetNormalized()
#newmgx = newmgy.Cross(newmgz).GetNormalized()

#newmg = c4d.Matrix()
#newmg.off = mg * p1
#newmg.v1 = newmgx
#newmg.v2 = newmgy
#newmg.v3 = newmgz

newmg = objectAxisFromVector( ~pd21.Cross(pd23) * HPBToMatrix(relrot) )
newmg.off = p1 * mg

if DEBUG:
print "newmg = %r" % newmg

plane.SetMg(newmg)
plane[c4d.CONSTRUCTIONPLANE_TYPE] = 0
plane[c4d.CONSTRUCTIONPLANE_SPACING] = 10
plane.Message(c4d.MSG_UPDATE)

# tell C4D to update internal state
doc.EndUndo()
c4d.EventAdd()

if __name__ == '__main__':
doc = documents.GetActiveDocument()
main(doc)

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.



Enjoy!

Andre

HolgerBiebrach
05-17-2011, 08:28 AM
Here is a new script-set I made.
cheers, Holger

http://www.holgerbiebrach.com/?p=1285

HolgerBiebrach
05-17-2011, 08:28 AM
Great script-set for retopology. Check it out:

http://www.holgerbiebrach.com/?p=1272

tcastudios
07-22-2011, 07:48 PM
RePathTex, re-pathing script

Info at:
http://forums.cgsociety.org/showthread.php?f=47&t=995873

Cheers
Lennart

xfon5168
07-28-2011, 04:34 PM
Open Source B3 Auto-Rigger:

http://bretbays.com/2011/07/13/b3-auto-rigger/

tcastudios
09-17-2011, 04:29 PM
dangCAM R13Py

Navigation helper for R13.
(Updated with dolly function)

Cheers
Lennart



# dangCAM_Py R13 tcastudios.com©2011
#
# Make sure to make a ShortCut for this to work. (In example Tab)
# Aim Camera/Light View by placing the mouse pointer on an object
# then run the short cut (not clicking the mouse!)
#
# If any Cameras and Lights are selected, they will be aimed instead of Active View.
# "dolly" sets the dolly factor for active view.

import c4d
from c4d import gui, Vector, utils

def main():
dolly = 0.75 # 0.0 = No Dolly, 1.0 = Full Dolly
scam = doc.GetActiveObjects(True) # Get Selected Object(s)
adraw = doc.GetActiveBaseDraw() # Active View

#Get Scene or Editor Camera
acam = adraw.GetSceneCamera(doc) if adraw.GetSceneCamera(doc) else adraw.GetEditorCamera(doc)
c4d.CallCommand(1021420) # Toggle Camera Pivot Point
acamm = acam.GetMg() # Get View Matrix
acampos = acamm.off # Get current View position
newbc = acam.GetDataInstance() # Get updated Container
poi = newbc.GetVector(c4d.ID_CAMERA_POINT_OF_INTEREST) # Toggle Camera Pivot Point
if poi == Vector(0):
return True
sel = False

if scam: # if Selected is/are not acam and not active View
for so in scam:
if (so.GetType() == c4d.Ocamera or so.GetType() == c4d.Olight):
sel = True
sopos = so.GetMg().off # Get current View position
newrot = utils.VectorToHPB(poi-sopos) # The new rotation (Targeting)
som = utils.HPBToMatrix(newrot, c4d.ROTATIONORDER_HPB) # New rotation into View Matrix
dollypos = utils.MixVec(sopos , poi , utils.Clamp(0.0 , 0.95 ,dolly)) # dolly
som.off = dollypos if so == acam else sopos # Position into View Matrix
so.SetMg(som) # Load Matrix into View

if sel == True:
c4d.EventAdd()
c4d.CallCommand(1021420) # Toggle Camera Pivot Point
return True

newrot = utils.VectorToHPB(poi-acampos) # The new rotation (Targeting)
dollypos = utils.MixVec(acampos , poi , utils.Clamp(0.0 , 0.95 ,dolly)) # 0.95 max dolly
acamm = utils.HPBToMatrix(newrot, c4d.ROTATIONORDER_HPB) # New rotation into View Matrix
acamm.off = dollypos # Position into View Matrix
acam.SetMg(acamm) # Load Matrix into View
c4d.CallCommand(1021420) # Toggle Camera Pivot Point

if __name__=='__main__':
main()

tcastudios
09-17-2011, 04:30 PM
dangTARGET R13 Py

Set Focus Helper for R13

Cheers
Lennart



# dangTARGET_Py [R13] tcastudios.com©2010-2011
#
# Make sure to make a ShortCut for this to work. (In example Shift+Tab)
# Set the target length (Focus) for current Camera/Light View by placing the mouse pointer on an object
# then run the short cut (not clicking the mouse!)
#
# If any Cameras and Lights are selected, their focus will be set intstead of Active View

import c4d
from c4d import gui, Vector

def main():
scam = doc.GetActiveObjects(True) # Get Selected Object(s)
adraw = doc.GetActiveBaseDraw() # Active View

#Get Scene or Editor Camera
acam = adraw.GetSceneCamera(doc) if adraw.GetSceneCamera(doc) else adraw.GetEditorCamera(doc)

c4d.CallCommand(1021420); # Toggle Camera Pivot Point
bc = acam.GetDataInstance() # Get Container
poi = bc.GetVector(c4d.ID_CAMERA_POINT_OF_INTEREST) # Get new POI position R13

sel = False

if scam: # if Selected is/are not acam and not active View
for so in scam:
if (so.GetType() == c4d.Ocamera or so.GetType() == c4d.Olight):
sel = True
poiz = ~(so.GetMg())*poi # paralel z distance
if so.GetType() == c4d.Ocamera:
so[c4d.CAMERAOBJECT_TARGETDISTANCE] = poiz.z # Set Calculated TargetLength for Selected Camera
if so.GetType() == c4d.Olight:
so[c4d.LIGHT_DETAILS_OUTERDISTANCE] = poiz.z # Set Calculated TargetLength for Selected Light

if sel == True:
c4d.EventAdd()
c4d.CallCommand(1021420) # Toggle Camera Pivot Point
return True

poiz = ~(acam.GetMg())*poi # paralel z distance
if acam.GetType() == c4d.Ocamera:
acam[c4d.CAMERAOBJECT_TARGETDISTANCE] = poiz.z # Set Calculated TargetLength for Active Camera View
if acam.GetType() == c4d.Olight:
acam[c4d.LIGHT_DETAILS_OUTERDISTANCE] = poiz.z # Set Calculated TargetLength for Active Light View
c4d.EventAdd()
c4d.CallCommand(1021420); # Toggle Camera Pivot Point

if __name__=='__main__':
main()

tcastudios
09-17-2011, 04:31 PM
ToggleCAMROTATION R13 Py

Toggle Camera and Cursor Mode

Cheers
Lennart



# Toggle Camera Rotation_Py [R13] www.tcastudios.com©2011
# Toggles between "Camera" and "Cursor" Mode
# Short cut example: Shift + <

import c4d

def main():
if c4d.IsCommandChecked(440000092): # If Cursor Mode switch to..
c4d.CallCommand(440000095) # Camera Mode
if c4d.IsCommandChecked(1021420): # If Pivot is locked
c4d.CallCommand(1021420) # Release Pivot Pos

else: c4d.CallCommand(440000092) # Else switch to Cursor Mode

if __name__=='__main__':
main()

tcastudios
09-17-2011, 09:20 PM
camPLANE [R13]Py
This is a simple camPLANEv2 idea using
the Python Generator Object.
Copy and paste this into a Python Generator Object
and save it to the Content Browser for later use.
To be used as a child of a Camera Object.

Cheers
Lennart



# camPLANEv2 [R13] tcastudios.com © 2011
#
# Copy all into a Python Generator Object.
# Save to the Content Browser for later use.
# Use as a Child of a Camera Object.

import c4d
import math

def psize(r,z):
return math.tan(r/2.0)*z*2.0

def main():
op[c4d.OPYTHON_OPTIMIZE] = False
plane = c4d.BaseObject(c4d.Oplane)
plane[c4d.PRIM_AXIS] = 5
plane[c4d.PRIM_PLANE_SUBW] = 2
plane[c4d.PRIM_PLANE_SUBH] = 2

cam = op.GetUp()

if cam is None or cam.GetType() != c4d.Ocamera:
#print 'Parent Not a Camera'
#Just return the plane object
return plane

planeZ = cam[c4d.CAMERAOBJECT_TARGETDISTANCE]
op[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector(0,0,planeZ)
op[c4d.ID_BASEOBJECT_ABS_ROTATION] = c4d.Vector(0)

camV = cam[c4d.CAMERAOBJECT_FOV_VERTICAL]
camH = cam[c4d.CAMERAOBJECT_FOV]
plane[c4d.PRIM_PLANE_HEIGHT] = psize(camV,planeZ)
plane[c4d.PRIM_PLANE_WIDTH] = psize(camH,planeZ)

return plane

SilverCity
09-18-2011, 07:47 AM
dangCAM R13Py

Navigation helper for R13.

Cheers
Lennart

Thanks for this script! Is it possible to add a zoom in option, as well? I made good use out of another script you posted which set the camera pivot point and zoomed to that object. Unfortunately, that script is not working in R13. Navicam has the same function but is not available yet for R13.

Navigation is so much better in R13, but the ability to set the pivot and zoom to the object in one keystroke is such a time saver, especially when working with large scenes and many objects.

tcastudios
09-18-2011, 01:09 PM
Updated the dangCAM_Py post with dolly option.


Cheers
Lennart

NiklasR
09-30-2011, 04:06 PM
Hello,

have you ever wished to have a List class in Coffee ? Some set of data that size you can change, add items to it ? Here it is ;)
The clList class is a single linked list. It's implemented mostly recursively and very fast. The acess time of an item is O(n).
You can create a new list from an array or from scratch.
The code is Open Source, the class is documented within the class declaration.

How to use it:

include "clList.coh";
var arr = new(array, 21);
var list = new(clList, arr);
// or
var list = new(clList, NULL);

list->append(32);
list->append(99.03);
list->append("hello world !");
list->insert(0, "Ha, I have jostled to index 0 !");
list->remove(32); // removes '32'
list->pop(); // removes the last item, 'hello world'
list->pop2(1); // removes '99.03'
println(list->getLength());
println(list->toString());
// 3
// L[Ha, I have jostled to index 0 !]



You may use this software in private and commercial projects for free.
Download: clList10.zip (http://www.mediafire.com/?gan80c4gg4623cc)

Cheers,
Niklas Rosenstein

ccross
10-12-2011, 07:04 PM
Duplicates to instances.

This python code will take duplicated objects and turn them into instances. Select all the duplicated objects, run the script. It will keep all the objects in their current positions and with their current names.


import c4d
from c4d import gui

def main():
objList = doc.GetActiveObjects(False)

reference = objList.pop()

for element in objList:

newInst = c4d.BaseObject(c4d.Oinstance)
newInst[c4d.INSTANCEOBJECT_LINK] = reference

newInst.SetMg(element.GetMg())
newInst.SetMl(element.GetMl())
newInst.SetName(element.GetName())
doc.AddUndo(c4d.UNDO_DELETE, element)
doc.InsertObject(newInst, pred=element)
element.Remove()

doc.AddUndo(c4d.UNDO_NEW, newInst)

doc.EndUndo()
c4d.EventAdd()

if __name__=='__main__':
main()

ccross
10-12-2011, 07:13 PM
Clean up Nulls:

This python script is useful for working with CAD data. It goes through the scene and removes any empty groups or groups with only one child.



import c4d
import sys
from c4d import gui
#Removes empty groups and groups with only one child


def main():
sys.setrecursionlimit(50000)
RecursiveSearch(doc.GetFirstObject())
c4d.EventAdd()

def RecursiveSearch(obj):

if not obj.IsAlive():
return


next = obj.GetNext()
down = obj.GetDown()

EvalObject(obj)

if not obj:
down = None

if down:
RecursiveSearch(down)


if next:
RecursiveSearch(next)


def EvalObject(obj):

# remove empty groups
if len(obj.GetChildren())<1 and obj.GetType() == c4d.Onull:
obj.Remove()

# tweak groups to remove groups with just one child
if len(obj.GetChildren())==1 and obj.GetType() == c4d.Onull:

next = obj.GetNext()
down = obj.GetDown()
Mg = down.GetMg()
doc.InsertObject(down,pred=obj)
down.SetMg(Mg)

# use the name from the deleted group
down.SetName(obj.GetName())
obj.Remove()

if __name__=='__main__':

Scott Ayers
01-07-2012, 07:12 PM
Admins--Please delete this post

douwe
01-16-2012, 03:40 AM
Scales MoGraph clones that are being cloned onto a Polygonal Object, based on the surface area of the individual Polygons.

Requires a MoGraph Cloner Object in Object Mode, Distribution set to Polygon Center.

Requires a Coffee Effector set to Full Control, with 3 User Data Sliders :
1: "Scale Factor" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Max: 1.99 / Default: 1
2: "Scale Minimum" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Max: 1.99 / Default: 0.01
3: "Scale Maximum" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Slider Max: 1.99 / No Max Limit / Default: 1.99

///////////////////////////////////////////////////////////////////////////////
// d_PolySize Effector
//
// Coffee Effector by douwe - 2012 - http://vimeo.com/douwe4d
//
// Scales MoGraph clones that are being cloned onto a Polygonal Object,
// based on the size of the respective polygons.
//
// Requires a MoGraph Cloner Object in Object Mode, Distribution set to Polygon Center.
//
// Works with other Effectors;
// just make sure d_PolySize appears last in the Effectors list
// of the Effector Tab on your Cloner.
//
// Requires a Coffee Effector set to Full Control, with 3 User Data Sliders :
// 1: "Scale Factor" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Max: 1.99 / Default: 1
// 2: "Scale Minimum" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Max: 1.99 / Default: 0.01
// 3: "Scale Maximum" - Float Slider / Real / Step: 0.01 / Min: 0.01 / Slider Max: 1.99 / No Max Limit / Default: 1.99
//
//
// I patched together homemade solutions for a few obstacles I bumped into.
// If you find any bugs, or come up with ways to make this better or more efficient,
// or if you add new functionality --->
// Make me a happy camper, and please let me know, so I can learn..
//
// cheers,
// d
//
// credits to Sandi Dolšak and Nick Woolridge for the Surface Calculation Formulas
// and to Sataneev for the challenge.
///////////////////////////////////////////////////////////////////////////////


map(input, inMin, inMax, outMin, outMax)
{
var inrange;
if((inMax-inMin) != 0) { inrange = (input-inMin)/(inMax-inMin); }
else inrange = 0;
return inrange * (outMax-outMin) + outMin;
}

main(doc,op)
{
var md = GeGetMoData(op);
if (!md) return false;
var cnt = md->GetCount();
var marr = md->GetArray(MODATA_MATRIX);
var fall = md->GetFalloffs();
var cloner = md->GetGenerator();
var obj = cloner#MG_OBJECT_LINK;
var polycount = obj -> GetPolygonCount();
var poly = obj -> GetPolygons();
var points = obj -> GetPoints();
var ud_scale_factor = op#ID_USERDATA:1;
var ud_min_scale = op#ID_USERDATA:2;
var ud_max_scale = op#ID_USERDATA:3;
var i, scale, map_surface;
var hi_pol_size = 0;
var lo_pol_size = 9999999999999999999999999999;
var part_1,part_2,a,b,c,d,e,f,s;
var area = new(array,100000);
var arr_A = new(array,100000);
var arr_B = new(array,100000);
var arr_C = new(array,100000);
var arr_D = new(array,100000);

for (i = 0; i < (polycount*4); i++) {
if (i % 4 == 0) arr_A[i/4] = points[poly[i]];
if (i % 4 == 1) arr_B[i/4] = points[poly[i]];
if (i % 4 == 2) arr_C[i/4] = points[poly[i]];
if (i % 4 == 3) arr_D[i/4] = points[poly[i]];
}

for (i = 0; i < polycount; i++) {
a = vlen(arr_A[i] - arr_B[i]);
b = vlen(arr_B[i] - arr_C[i]);
c = vlen(arr_A[i] - arr_C[i]);
s = (a+b+c)/2;
part_1 = sqrt (s*(s-a)*(s-b)*(s-c));
d = vlen(arr_A[i] - arr_C[i]);
e = vlen(arr_A[i] - arr_D[i]);
f = vlen(arr_D[i] - arr_C[i]);
s = (d+e+f)/2;
part_2 = sqrt (s*(s-d)*(s-e)*(s-f));
area[i] = part_1 + part_2;

if (area[i]< lo_pol_size){ lo_pol_size = area[i]; }
if (area[i]> hi_pol_size){ hi_pol_size = area[i]; }
}

for (i = cnt - 1; i >= 0; --i)
{
if (!area[i]){ area[i]= lo_pol_size; } // line for yader. in surface mode if clones > polys
map_surface = map(area[i], lo_pol_size, hi_pol_size, ud_min_scale, ud_max_scale);
scale = map_surface * (ud_scale_factor) ;

marr[i]->SetV1(marr[i]->GetV1()*scale);
marr[i]->SetV2(marr[i]->GetV2()*scale);
marr[i]->SetV3(marr[i]->GetV3()*scale);
}
md->SetArray(MODATA_MATRIX, marr, true);
return true;
}

Here's a link to an example c4d-file to play with : http://www.mediafire.com/file/gcu9ouwk9eiz2nv/d_PolySize-Effector-1.c4d

I patched together homemade solutions for a few obstacles I bumped into.
If you see any bugs, or know of ways to make this better or more efficient,
or if you add new functionality, please let me know, so I can learn.

credits to Sandi Dolšak and Nick Woolridge for the Surface Calculation Formulas and to Sataneev for the challenge.

d

tcastudios
04-01-2012, 12:12 AM
Two Stop Motion expressions, xSTOPMO_FIX and xSTOPMO_VAR.
Click my sign for xfiles.

Cheers
Lennart

tcastudios
04-03-2012, 09:49 PM
lineREADER is an expression for direct reading of Simple Text Files (.txt).
The expression controls the text on a Text- or MoText object.

Download lineREADER at http://tcastudios.com -> xfiles.

Per-Anders
05-10-2012, 04:37 AM
Find and select holes in a mesh.

import c4d
from c4d import gui
from c4d import utils

def main():
doc.SetMode(c4d.Medges)
nbr = utils.Neighbor()
nbr.Init(op)
vcnt = op.GetPolygonCount()
vadr = op.GetAllPolygons()
sel = op.GetEdgeS()
sel.DeselectAll()
for i in range(0,vcnt):
pa = vadr[i].a
pb = vadr[i].b
pc = vadr[i].c
pd = vadr[i].d
if nbr.GetNeighbor(pa, pb, i) == c4d.NOTOK:
sel.Select(i * 4)
if nbr.GetNeighbor(pb, pc, i) == c4d.NOTOK:
sel.Select(i * 4 + 1)
if pc != pd and nbr.GetNeighbor(pc, pd, i) == c4d.NOTOK:
sel.Select(i * 4 + 2)
if nbr.GetNeighbor(pd, pa, i) == c4d.NOTOK:
sel.Select(i * 4 + 3)
c4d.DrawViews()


if __name__=='__main__':
main()

Per-Anders
05-10-2012, 04:55 AM
And this will close all the holes in a mesh

import c4d
from c4d import gui
from c4d import utils

def main():
nbr = utils.Neighbor()
nbr.Init(op)
vcnt = op.GetPolygonCount()
settings = c4d.BaseContainer()
settings[c4d.MDATA_CLOSEHOLE_INDEX] = op
doc.AddUndo(c4d.UNDO_CHANGE,op)

for i in range(0,vcnt):
vadr = op.GetPolygon(i)
pinf = nbr.GetPolyInfo(i)
if nbr.GetNeighbor(vadr.a, vadr.b, i) == c4d.NOTOK:
settings[c4d.MDATA_CLOSEHOLE_EDGE] = pinf["edge"][0]
utils.SendModelingCommand(command = c4d.ID_MODELING_CLOSEHOLE_TOOL, list = [op], mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION, bc = settings, doc = doc)
nbr.Init(op)
if nbr.GetNeighbor(vadr.b, vadr.c, i) == c4d.NOTOK:
settings[c4d.MDATA_CLOSEHOLE_EDGE] = pinf["edge"][1]
utils.SendModelingCommand(command = c4d.ID_MODELING_CLOSEHOLE_TOOL, list = [op], mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION, bc = settings, doc = doc)
nbr.Init(op)
if vadr.c != vadr.d and nbr.GetNeighbor(vadr.c, vadr.d, i) == c4d.NOTOK:
settings[c4d.MDATA_CLOSEHOLE_EDGE] = pinf["edge"][2]
utils.SendModelingCommand(command = c4d.ID_MODELING_CLOSEHOLE_TOOL, list = [op], mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION, bc = settings, doc = doc)
nbr.Init(op)
if nbr.GetNeighbor(vadr.d, vadr.a, i) == c4d.NOTOK:
settings[c4d.MDATA_CLOSEHOLE_EDGE] = pinf["edge"][3]
utils.SendModelingCommand(command = c4d.ID_MODELING_CLOSEHOLE_TOOL, list = [op], mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION, bc = settings, doc = doc)
nbr.Init(op)

doc.SetMode(c4d.Mpolygons)
#select the new polygons
sel = op.GetPolygonS()
for i in range(vcnt, op.GetPolygonCount()):
sel.Select(i)
c4d.EventAdd()


if __name__=='__main__':
main()

art3D
05-17-2012, 11:27 AM
"ShowWeights" is a script to show the weight for each selected point of the selected vertex maps in editor view.

You can find it at my website http://www.art3d.de -> scripts (navigation button top right)

(Yes, i should update my website to get rid of frames and being able to post direct links, sorry.)

Knut

HolgerBiebrach
05-18-2012, 07:51 AM
Hi Per. I can't copy paste the script correctly to my script manager. I guess there are Format problems. Would you be so kind and attach the Script as a File?
I could use this script quite a lot. Thank you.

tcastudios
07-14-2012, 02:26 AM
Global Tag renamer. See info in script

Cheers
Lennart

# tagRENAMER tcastudios.com©2012
# Select any Tag(s) in ObjectManager.
#
# NOTE: If no Objects are selected, ALL Tags of selected type in document will be renamed
# To only rename tags of same type on selected Objects:
# Select BOTH the Object(s) and Tag(s) of type to be renamed
#
# Run the tagRENAMER script and all tags of the same type(s)
# in document as selected will be renamed as : "ObjectName:TagType:Count"
# If only one tag of same type on Object no Count is added.
# Tag types in the "StopList" will not be renamed

import c4d
from c4d import gui

def checktype(tags): # List of current Tag Types on Object
checktypes = []
for tag in tags:
checktypes.append(tag.GetType())
return checktypes

def scantags(obj,tagtypes): # Scan Tags on Object
n = 1
tags = obj.GetTags()
objname = obj.GetName()
for tag in tags:
tagtype = tag.GetType()
count = checktype(tags).count(tagtype)

if tagtype in tagtypes:
newname = objname + ':' + tag.GetTypeName()

if count > 1:# Only add count if more than one tag of same type found on Object
newname = newname + ':'+ str(n).zfill(2)
n += 1

doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL,tag)
tag.SetName(newname)

def scandoc(doc,obj,tagtypes): # Scan doc obj hierarchy
while obj:
scantags(obj,tagtypes)
scandoc(doc,obj.GetDown(),tagtypes)
obj = obj.GetNext()

def main():
# List of tags not to be renamed
stoplist = [c4d.Tpolygonselection,
c4d.Tpointselection ,
c4d.Tedgeselection ]

tagtypes = [] # The list of selected Tags Types
for tag in doc.GetActiveTags():
tagtype = tag.GetType()
if tagtype not in stoplist:
tagtypes.append(tagtype)
if not len(tagtypes):
print 'No Tag(s) of Correct Type Selected'
gui.MessageDialog('No Tag(s) of Correct Type Selected')
return True

doc.StartUndo()
# Run the renaming based on selected Tag Type(s)
activeobjects = doc.GetActiveObjects(True)
if len(activeobjects):
for obj in activeobjects:
scantags(obj,tagtypes)
else:
obj = doc.GetFirstObject()
scandoc(doc,obj,tagtypes)
doc.EndUndo()
c4d.EventAdd()

if __name__=='__main__':
main()

kaggen
08-16-2012, 12:44 AM
Hi!

I use the jMc2Obj to export Minecraft meshes to .obj files for import to Cinema4d. jMc2Obj can also export texturefiles for color and alpha. Unfortunatly Cinema doesn't import/link the texturemaps.

Fortunatly jMc2Obj uses the same name for the material as the filename for the texture. So i made a Coffee script that go through all materials and try to find the corresponding color and alpha file. You have to select the directory where the teturefiles is.

//
// Script to load PNG textures (color and alpha) into materials from imported .obj files
// especially from the jMc2Obj export tool which converts Minecraft objects
// to ".obj" format and saves textures as PNG files.
//
// Usage:
// 1. Import your minecraft .obj file. The materials will be created by Cinema without textures.
// 2. Execute the script and choose the folder which contains the texturefiles (PNG)
// Done!
// If textures is blurry, select all the materials and go to the color channel and select Sampling = "none"
//

main(doc,op)
{
var dir = GeGetStartupPath();

// Select dialog for path to texture files
if(dir->PathSelect("Choose path for minecraft textures"))
{
var TexDir = dir->GetFullString();
println ("Texture directory: ", TexDir);
var mat = doc->GetFirstMaterial();

if(mat == NULL)
{
println("No materials");
return;
}


// Go through all materials in the document and
// try to find matches with filenames in texture dir
do
{
var material_name = mat->GetName();

// Add .png extension
var file_color = stradd(material_name,".png");

// Alpha files have a "_a" after material name
var file_alpha = stradd(material_name,"_a.png");

// Check for color texture file
dir->AddLast(file_color);
if(GeFileExist(dir, FALSE)) {
mat->SetChannelState(CHANNEL_COLOR, TRUE);
var chColor = mat->GetChannel(CHANNEL_COLOR);
var contColor = chColor->GetContainer();
contColor->SetData(CH_TEXTURE, file_color);
chColor->SetContainer(contColor);
} else {
println("No color texturefile found for material '", material_name,"'");
}
dir->RemoveLast();

// Check for alpha map file
dir->AddLast(file_alpha);
if(GeFileExist(dir, FALSE)) {
mat->SetChannelState(CHANNEL_ALPHA, TRUE);
var chColor = mat->GetChannel(CHANNEL_ALPHA);
var contColor = chColor->GetContainer();
contColor->SetData(CH_TEXTURE, file_color);
chColor->SetContainer(contColor);
} else {
println("No alpha texturefile found for material '", material_name,"'");
}
dir->RemoveLast();


} while ((mat = mat->GetNext()) != NULL);

}
}

NiklasR
09-22-2012, 10:13 AM
Hi,

I made this script for dirtyharry here on the CGSociety forum. It imports textures from a directory matching a glob-pattern, adds them to the color and alpha channel and creates a plane object with the texture on it and adjusts the planes dimensions to match the texture.

Flow:
When you run it, you wil be asked to select a directory. After that, another window opens, asking you for a glob-patterns. You may know this from Unix systems. Here (http://en.wikipedia.org/wiki/Glob_%28programming%29)'s more about it. You can seperate multiple glob-patterns with a semi-colon (as well as leading and trailing spaces to make it more readable).
The default glob-pattern matches all *.tif and *.tiff files. Note that passing the same pattern two times will import the files matching the pattern two times.

The script can be found on pastebin (http://pastebin.com/WxG6YDA6). Here (http://forums.cgsociety.org/showthread.php?p=7421171#post7421171)'s the original thread in the forums.

-Niklas

angeljk
01-27-2013, 03:44 AM
Hi everybody..I really hate split my edges using knife tool with loop options, it's tricky and many times it doesn't result ok (if the mesh isn't close it only cut in a side)...my workflow is this..I select a edge then I select ring selection..when all the edges in my loop are selected I press connect and now I've my nice loop...now I use kyama slide for positionate my cut...

this is a lot of steps...would be possible create a plugin or script for doing this??...thanks

NiklasR
06-01-2013, 11:49 AM
This is a small script that will set up a Pyrocluster scene.

http://gyazo.com/19c5b86027bc979ee5fd752a59b6dae1.png http://gyazo.com/97048086cdc38da3587f88329080bccd.png

# Copyright (C) 2013, Niklas Rosenstein
# All rights reserved.
#
# Free for private and commercial use. The copyright holder
# does not give ANY WARRANTY in MERCHANTIBILITY of this software.
# The copyright notice may not be removed nor modified.
# Modifications of this software is allowed only with the
# explicit notice of the origin of this software, naming the
# original author.

import c4d

ID_PC_MATERIAL = 1001005
ID_PC_VOLUMETRACER = 1001006

def create(type_id, parent=None, pred=None):
obj = c4d.BaseList2D(type_id)
if obj.CheckType(c4d.Obase):
doc.InsertObject(obj, parent, pred)
elif obj.CheckType(c4d.Mbase):
doc.InsertMaterial(obj, pred)
if not parent:
parent = ()
elif not isinstance(parent, (tuple, list)):
parent = (parent,)

for p in parent:
tag = p.MakeTag(c4d.Ttexture)
tag[c4d.TEXTURETAG_MATERIAL] = obj
doc.AddUndo(c4d.UNDOTYPE_NEW, tag)

elif obj.CheckType(c4d.Tbase):
parent.InsertTag(obj, pred)
else:
raise ValueError('incompatible base type for %d' % type_id)

doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
return obj

def main():
emitter = create(c4d.Oparticle)
p_geom = create(c4d.ID_TP_PARTICLEGEOMETRY)
env = create(c4d.Oenvironment)
null = create(c4d.Onull)
xpresso = create(c4d.Texpresso, null)
mat = create(ID_PC_MATERIAL, [emitter, p_geom])
vtracer = create(ID_PC_VOLUMETRACER, env)

c4d.EventAdd()

main()

Or on pastebin (in case the forum software messes up the indentation): http://pastebin.com/SPtkRZvd

Per-Anders
11-27-2013, 07:41 PM
Here you chaps go, I've not done extensive testing, but this script is a slightly tarted up version of my old euler filter script. It's a python script, the attached zip also contains a small icon if you fancy it. Simply select an object, it's tracks or even just specific keys and hit the command to apply. It is set to only work with the first timeline window (so if you make use of four timeline windows be aware of this), this is simply a limitation due to python not being able to determine which is the active window, but apart from that you should be good to go. It should also work with the f-curve mode of the timeline, and in theory it should adjust the f-curve tangents for you too.

Have fun, happy thanksgiving.

import c4d
import math
from c4d import gui

#Cinema 4D Euler Fiter Command
#Select an object, it's tracks, or keys and run to apply the filter
#Have no selection to apply the filter to the entire scene!
#Per-Anders Edwards 2013
#Happy Thanksgiving!

#check for selection, limited to just the first timeline in order to keep thigns simple
#it could be possible to extend this to cover all four timelines
#but determining the active f-curve/key window between all four isn't possible in python currently
def checkSelect(obj):
#Check selection within all four timelines
if c4d.IsCommandChecked(456001191):
if obj.GetNBit(c4d.NBIT_TL1_SELECT):
return True

#Check selection within all four timelines
if obj.GetNBit(c4d.NBIT_TL1_SELECT2):
return True

#Check selection within all four fcurve managers
if c4d.IsCommandChecked(465001190):
if obj.GetNBit(c4d.NBIT_TL1_FCSELECT):
return True


#Key specific check
if obj.GetNBit(c4d.NBIT_CKEY_ACTIVE):
return True

#No selection
return False

#main euler filter function
def main():
arr = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if len(arr) == 0:
op = doc.GetFirstObject()
while op:
arr.append(op)
if op.GetDown():
op = op.GetDown()
else:
while (not op.GetNext()) and op.GetUp():
op = op.GetUp()
op = op.GetNext()

hasSelectedTracks = False
hasSelectedKeys = False

#find out if there's a selection to use
for op in arr:
track = op.GetFirstCTrack()

while track is not None and not hasSelectedTracks and not hasSelectedKeys:
if track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_REL_ROTATION or track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_ABS_ROTATION:

if checkSelect(track):
hasSelectedTracks = True
break

curve = track.GetCurve()
while curve is not None and not hasSelectedKeys:
keyCount = curve.GetKeyCount()
for i in range(0, keyCount):
key = curve.GetKey(i)
if checkSelect(key):
hasSelectedKeys = True
break

curve = curve.GetNext()

track = track.GetNext()

#Filter the keys to be within 180 degrees of their previous neighbors
for op in arr:
track = op.GetFirstCTrack()

while track is not None:
lastValue = 0.0
if track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_REL_ROTATION or track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_ABS_ROTATION:
if not hasSelectedTracks or checkSelect(track):
curve = track.GetCurve()
while curve is not None:
keyCount = curve.GetKeyCount()
for i in range(0,keyCount):
key = curve.GetKey(i)
kval = key.GetValue()

if hasSelectedKeys and not checkSelect(key):
lastValue = kval
continue

if i != 0:
#Start an undo for the change made
doc.AddUndo(c4d.UNDO_CHANGE, key)

#Calculate the modulo key offset
mval = math.fmod((kval - lastValue), math.pi * 2.0)
delta = (lastValue + mval) - kval

#Now handle the key tangents to maintain a nice predictable effect
if i > 0:
#left tangent
leftKey = curve.GetKey(i - 1)
leftKVal = leftKey.GetValue()
dif = kval - leftKVal
if dif != 0.0:
doc.AddUndo(c4d.UNDO_CHANGE, leftKey)
kLeftVal = key.GetValueLeft()
leftKRightVal = leftKey.GetValueRight()

proportion = (delta + dif) / dif

kLeftVal = kLeftVal * proportion
leftKRightVal = leftKRightVal * proportion
leftKey.SetValueRight(curve, leftKRightVal)
key.SetValueLeft(curve, kLeftVal)

if i < keyCount - 1:
#right tangent
rightKey = curve.GetKey(i + 1)
rightKVal = rightKey.GetValue()
dif = kval - rightKVal
if dif != 0.0:
doc.AddUndo(c4d.UNDO_CHANGE, rightKey)
kRightVal = key.GetValueRight()
rightKLeftVal = rightKey.GetValueLeft()

proportion = (delta + dif) / dif

kRightVal = kRightVal * proportion
rightKLeftVal = rightKLeftVal * proportion
rightKey.SetValueLeft(curve, rightKLeftVal)
key.SetValueRight(curve, kRightVal)

#finally set the key value itself
kval = lastValue + mval
key.SetValue(curve, kval)


lastValue = kval

curve = curve.GetNext()

track = track.GetNext()

c4d.EventAdd()

if __name__=='__main__':
main()

Per-Anders
11-27-2013, 11:12 PM
A slightly improved version that minimizes angular differences in a cleaner fashion

import c4d
import math
from c4d import gui

#Cinema 4D Euler Fiter Command
#Select an object, it's tracks, or keys and run to apply the filter
#Have no selection to apply the filter to the entire scene!
#Per-Anders Edwards 2013
#Happy Thanksgiving!

#check for selection, limited to just the first timeline in order to keep thigns simple
#it could be possible to extend this to cover all four timelines
#but determining the active f-curve/key window between all four isn't possible in python currently
def checkSelect(obj):
#Check selection in timeline
if c4d.IsCommandChecked(465001191) is True:
if obj.GetNBit(c4d.NBIT_TL1_SELECT):
return True

if obj.GetNBit(c4d.NBIT_TL1_SELECT2):
return True

#Check selection in fcurve manager
if c4d.IsCommandChecked(465001190) is True:
if obj.GetNBit(c4d.NBIT_TL1_FCSELECT):
return True


#Key specific check
if obj.GetNBit(c4d.NBIT_CKEY_ACTIVE):
return True

#No selection
return False

def shiftKey(doc, key, keyIndex, curve, newValue):
keyCount = curve.GetKeyCount()
kval = key.GetValue()

if kval == newValue:
return

delta = newValue - kval

if keyIndex > 0:
#left tangent
leftKey = curve.GetKey(keyIndex - 1)
leftKVal = leftKey.GetValue()
dif = kval - leftKVal
if dif != 0.0:
doc.AddUndo(c4d.UNDO_CHANGE, leftKey)
kLeftVal = key.GetValueLeft()
leftKRightVal = leftKey.GetValueRight()

proportion = (delta + dif) / dif

kLeftVal = kLeftVal * proportion
leftKRightVal = leftKRightVal * proportion
leftKey.SetValueRight(curve, leftKRightVal)
key.SetValueLeft(curve, kLeftVal)

if keyIndex < keyCount - 1:
#right tangent
rightKey = curve.GetKey(keyIndex + 1)
rightKVal = rightKey.GetValue()
dif = kval - rightKVal
if dif != 0.0:
doc.AddUndo(c4d.UNDO_CHANGE, rightKey)
kRightVal = key.GetValueRight()
rightKLeftVal = rightKey.GetValueLeft()

proportion = (delta + dif) / dif

kRightVal = kRightVal * proportion
rightKLeftVal = rightKLeftVal * proportion
rightKey.SetValueLeft(curve, rightKLeftVal)
key.SetValueRight(curve, kRightVal)

#finally set the key value itself
key.SetValue(curve, newValue)

#main euler filter function
def main():
arr = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if len(arr) == 0:
op = doc.GetFirstObject()
while op:
arr.append(op)
if op.GetDown():
op = op.GetDown()
else:
while (not op.GetNext()) and op.GetUp():
op = op.GetUp()
op = op.GetNext()

hasSelectedTracks = False
hasSelectedKeys = False

#find out if there's a selection to use
for op in arr:
track = op.GetFirstCTrack()

while track is not None and not hasSelectedTracks and not hasSelectedKeys:
if track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_REL_ROTATION or track.GetDescriptionID()[0].id == c4d.ID_BASEOBJECT_ABS_ROTATION:

if checkSelect(track):
hasSelectedTracks = True
break

curve = track.GetCurve()
while curve is not None and not hasSelectedKeys:
keyCount = curve.GetKeyCount()
for i in range(0, keyCount):
key = curve.GetKey(i)
if checkSelect(key):
hasSelectedKeys = True
break

curve = curve.GetNext()

track = track.GetNext()

#Filter the keys to be within 180 degrees of their previous neighbors
for op in arr:
trackH = op.FindCTrack([c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_X])
trackP = op.FindCTrack([c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Y])
trackB = op.FindCTrack([c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z])

if hasSelectedTracks and not (checkSelect(trackH) or checkSelect(trackP) or checkSelect(trackB)):
continue

curveH = trackH.GetCurve() if trackH is not None else None
curveP = trackP.GetCurve() if trackP is not None else None
curveB = trackB.GetCurve() if trackB is not None else None

keyTimeList = []

for curve in [curveH, curveP, curveB]:
if curve is None:
continue
keyCount = curve.GetKeyCount()
for i in range(0, keyCount):
key = curve.GetKey(i)
if not hasSelectedKeys or checkSelect(key):
doc.AddUndo(c4d.UNDO_CHANGE, key)
keyTimeList.append([key.GetTime().Get(), key.GetTime()])

if len(keyTimeList) == 0:
continue

keyTimeList.sort()
lastKey = keyTimeList[-1]
for i in range(len(keyTimeList) - 2, -1, -1):
if lastKey == keyTimeList[i]:
del(keyTimeList[i])
else:
lastKey = keyTimeList[i]

#doing this four iterations seems to solve the whole thing in the cleanest way
lastKeyVal = c4d.Vector(0.0, 0.0, 0.0)
for keyTimeEntry in keyTimeList:
keyTime = keyTimeEntry[1]
valH = trackH.GetValue(doc, keyTime, doc.GetFps()) if trackH is not None else op[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_X]
valP = trackP.GetValue(doc, keyTime, doc.GetFps()) if trackP is not None else op[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Y]
valB = trackB.GetValue(doc, keyTime, doc.GetFps()) if trackB is not None else op[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z]

valVector = c4d.Vector(valH, valP, valB)

if keyTime == keyTimeList[0][1]:
lastKeyVal = valVector
continue

hpb = c4d.utils.GetOptimalAngle(lastKeyVal, valVector, op[c4d.ID_BASEOBJECT_ROTATION_ORDER])

for curve, val, lastValue in [[curveH, hpb.x, lastKeyVal.x], [curveP, hpb.y, lastKeyVal.y], [curveB, hpb.z, lastKeyVal.z]]:
if curve is None:
continue

if hasSelectedTracks and not checkSelect(curve.GetTrack()):
continue

try:
key, index = curve.FindKey(keyTime).values()
except:
try:
index, key = curve.AddKey(keyTime).values()
doc.AddUndo(c4d.UNDO_NEW, key)
if hasSelectedKeys:
key.ChangeNBit(c4d.NBIT_TL1_SELECT, True)
except:
continue

if not hasSelectedKeys or checkSelect(key):
shiftKey(doc, key, index, curve, val)

lastKeyVal = hpb

c4d.EventAdd()

if __name__=='__main__':
main()