edit 29/04/14 - Here is a new collection of more than 80 example files, organized by category:
KangarooExamples.zip
This zip is the most up to date collection of examples at the moment, and collects t
bi-directional link, the link is unidirectional (downflow only), because of the use of proxies.
Matrix transforms and persistent constraints: I don't think this is true. The parts can have mates to other parts that preserve geometric relationships like 'coincident' , 'aligned' etc. These are essentially bi-directional. GH's algorithmic approach does not do relationships in the same / flexible way. In GH, the 'relationship' has to be part of the generation method that dependent on the creation sequence. I.e. draw line 2 perpendicularly from the end of point of line 1. If you are thinking about parts or assemblies sharing, or referencing parameters as part of the regen process, this is also possible. iLogic does this, and adds scripting. So does Catia. Inventor/iLogic can also access Excel and have all the parameter processing done centrally, if required.
Consequently, scripting the placement of components is irrelevant in GH, unless you decide that each component needs to be contained in its own separate file.
I wouldn't be too hasty here. Yes, you are right about compartmentalisation. I think this needs to happen with GH, in order to deal with scalability/everyday interoperability requirements. Confining projects to one script is not sustainable. MCAD apps have been doing this for ages with 'Relational Modeling'.The Adaptive Components placement example illustrates that it is beneficial to be able to script some 'hints' that can be used on placement of the component. Say, if your component requires points as inputs, then its should be able to find the nearest points to the cursor as it moves around. I think Aish's D# / DesignScript demo'd this kind of behaviour a few years ago. Similarly, Modo Toolpipe reminds me how a lot of UI based transactions can be captured as scripts (macro recorder etc). Allowing this input to be mixed in and/or extended by GH I think will yield a lot of 'modeling efficiency' around the edges. This is a (mis)using GH as an user-programmable 'jig' for placing/manipulating 'dumb' elements in Rhino. It may even give the 'dumb elements' a bit more 'intelligence' by leaving behind embedded attributes, like links to particular construction planes etc.Even if we confine ourselves to scripting. GH is a visual or graphic programming interface. A lot of 'insert and connect' tasks can be done more easily using graphic methods. If we need to select certain vertices on a mesh as inputs for, say, a facade panel, its going to be quicker to do this 'graphically' (like the AC example), then ferreting out the relevant indices in the data tree et al. The 'facade panel' script would then have some coding to filter/prompt the user as to what inputs were acceptable, and so on.
This also brings up the point that generating components and assemblies in MCAD is not as straightforward. In iParts and iAssemblies, each configuration needs to be generated as a "child" (the individual file needs to be created for each child) before those children can be used elsewhere.
Not sure what you mean here. If the i-parts are built up using sketches /profiles or other more rudimentary features (like Revits' profile/face etc family templates) then reuse should be fairly straight forward. I suppose you could make it like GH scripting, if you cut and paste or include script snippets that generate the desired Inventor features.
One of the reasons why the distributed file approach makes perfect sense in MCAD, is that in industry you deal with a finite set of objects. Generative tools are usually not a requirement. Most mechanical engineers, product engineers and machinists would never have any use for that.
I don't think this is true. Look at the automotive body design apps, which are mostly Catia based. All of the body parts are pretty much 'generative' and generated from splines, in a procedural way, using very similar approaches to GH. Or sheet metal design. It's not always about configuration of off-the-shelf items like bolts. And, the constraints manager is available to arbitrate which bit of script fires first, and your mundane workaday associative dimensions etc can update without getting run over by the DAG(s) :-)
…
Introduction to Grasshopper Videos by David Rutten.
Wondering how to get started with Grasshopper? Look no further. Spend an some time with the creator of Grasshopper, David Rutten, to learn the
.
Things have been working swimmingly in many areas of the plugin, but one particular problem has been tough to solve. I have two components that are trying to read/write to the same memory at the same time, causing Rhino exceptions and crashes.
The conflicts appear to be happening between two components -- one is a "Layer Events Listener" that reports essentially what type of layer event just happened. The other is a "Set Layer Visibility" component that toggles the visibility of a list of layers.
The code:
public class LayerTools_LayerEventsListener : GH_Component { /// <summary> /// Initializes a new instance of the LayerTools_LayerListener class. /// </summary> public LayerTools_LayerEventsListener() : base("Layer Events Listener", "Layer Listener", "Get granular information about the layer events happening in the Rhino document.", "Squirrel", "Layer Tools") { }
/// <summary> /// Registers all the input parameters for this component. /// </summary> protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { pManager.AddBooleanParameter("Active", "A", "Set to true to listen to layer events in the Rhino document.", GH_ParamAccess.item, false); pManager.AddTextParameter("Exclusions", "E", "Provide a list of exclusions to stop reading specific events (Added, Deleted, Moved, Renamed, Locked, Visibility, Color, Active).", GH_ParamAccess.list); pManager[1].Optional = true; }
/// <summary> /// Registers all the output parameters for this component. /// </summary> protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { pManager.AddBooleanParameter("Initialized", "I", "Whether the listener changed from passive to active.", GH_ParamAccess.item); pManager.AddTextParameter("Document Name", "doc", "Name of the Rhino document that is changing.", GH_ParamAccess.item); pManager.AddTextParameter("Layer Path", "path", "Path of the modifed layer.", GH_ParamAccess.item); pManager.AddIntegerParameter("Layer Index", "ID", "Index of the modified layer.", GH_ParamAccess.item); pManager.AddIntegerParameter("Sort Index", "SID", "Sort index of the modified layer.", GH_ParamAccess.item); pManager.AddTextParameter("Event Type", "T", "Type of the modification.", GH_ParamAccess.item); pManager.AddBooleanParameter("Added", "A", "If the layer has been added.", GH_ParamAccess.item); pManager.AddBooleanParameter("Deleted", "D", "If the layer has been deleted.", GH_ParamAccess.item); pManager.AddBooleanParameter("Moved", "M", "If the layer has been moved.", GH_ParamAccess.item); pManager.AddBooleanParameter("Renamed", "R", "If the layer has been renamed.", GH_ParamAccess.item); pManager.AddBooleanParameter("Locked", "L", "If the layer locked setting has changed.", GH_ParamAccess.item); pManager.AddBooleanParameter("Visibility", "V", "If the layer's visibility has changed.", GH_ParamAccess.item); pManager.AddBooleanParameter("Color", "C", "If the layer's color has changed.", GH_ParamAccess.item); pManager.AddBooleanParameter("Active", "Act", "If the active layer has changed.", GH_ParamAccess.item); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { bool active = false; List<string> exclusions = new List<string>();
DA.GetData(0, ref active); DA.GetDataList(1, exclusions);
RhinoDoc thisDoc = null;
bool initialize = false;
string dName = null; string activePath = null; int layerIndex = -1; int sortIndex = -1; string eventType = null; bool added = false; bool deleted = false; bool moved = false; bool renamed = false; bool locked = false; bool visibility = false; bool color = false; bool current = false;
if (active) { thisDoc = RhinoDoc.ActiveDoc;
initialize = (!previouslyActive) ? true : false;
RhinoDoc.LayerTableEvent -= RhinoDoc_LayerTableEvent; RhinoDoc.LayerTableEvent += RhinoDoc_LayerTableEvent; previouslyActive = true;
} else {
RhinoDoc.LayerTableEvent -= RhinoDoc_LayerTableEvent; previouslyActive = false; }
if (ev != null) { dName = ev.Document.Name; layerIndex = ev.LayerIndex; eventType = ev.EventType.ToString();
if (!exclusions.Contains("Active")) { if (ev.EventType.ToString() == "Current") { // active layer has just been changed current = true; }
}
if (!exclusions.Contains("Moved")) { if (ev.EventType.ToString() == "Sorted") { // active layer has just been changed moved = true; }
}
if (!exclusions.Contains("Added")) { if (ev.EventType.ToString() == "Added") { // layer has just been added activePath = ev.NewState.FullPath; added = true; }
}
if (!exclusions.Contains("Active")) { if (ev.EventType.ToString() == "Deleted") { // layer has just been added
deleted = true; } }
if (ev.EventType.ToString() == "Modified") { // layer has been modified activePath = ev.NewState.FullPath;
//skip sortindex eventType = ev.EventType.ToString();
if (ev.OldState != null && ev.NewState != null) { if (!exclusions.Contains("Locked")) { if (ev.OldState.IsLocked != ev.NewState.IsLocked) locked = true;
} if (!exclusions.Contains("Visibility")) { if (ev.OldState.IsVisible != ev.NewState.IsVisible) visibility = true; }
if (!exclusions.Contains("Moved")) { if (ev.OldState.ParentLayerId != ev.NewState.ParentLayerId) moved = true; }
//if (ev.OldState.SortIndex != ev.NewState.SortIndex) moved = true; if (!exclusions.Contains("Renamed")) { if (ev.OldState.Name != ev.NewState.Name) renamed = true; }
if (!exclusions.Contains("Color")) { if (ev.OldState.Color != ev.NewState.Color) color = true; } }
} }
DA.SetData(0, initialize); DA.SetData(1, dName); DA.SetData(2, activePath); DA.SetData(3, layerIndex); DA.SetData(4, sortIndex); DA.SetData(5, eventType); DA.SetData(6, added); DA.SetData(7, deleted); DA.SetData(8, moved); DA.SetData(9, renamed); DA.SetData(10, locked); DA.SetData(11, visibility); DA.SetData(12, color); DA.SetData(13, current);
}
static bool previouslyActive = false; Rhino.DocObjects.Tables.LayerTableEventArgs ev = null;
void RhinoDoc_LayerTableEvent(object sender, Rhino.DocObjects.Tables.LayerTableEventArgs e) { ev = e;this.ExpireSolution(true); }
And for the layer visibility component:
public LayerTools_SetActiveLayer() : base("Set Active Layer", "SetActiveLayer", "Set the active layer in the Rhino document.", "Squirrel", "Layer Tools") { }
/// <summary> /// Registers all the input parameters for this component. /// </summary> protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { pManager.AddBooleanParameter("Active", "A", "Set to true to change the active layer in Rhino.", GH_ParamAccess.item, false); pManager.AddTextParameter("Path", "P", "Full path of the layer to be activated.", GH_ParamAccess.item); }
/// <summary> /// Registers all the output parameters for this component. /// </summary> protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { pManager.AddIntegerParameter("Layer ID", "ID", "Index of layer that has been activated.", GH_ParamAccess.item); pManager.AddBooleanParameter("Status", "St", "True when the layer has been activated.", GH_ParamAccess.item); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { bool active = false; string path = "";
if (!DA.GetData(0, ref active)) return; if (!DA.GetData(1, ref path)) return;
int layer_index = -1; bool status = false;
if (path != null) {
Rhino.RhinoDoc doc = Rhino.RhinoDoc.ActiveDoc; Rhino.DocObjects.Tables.LayerTable layertable = doc.Layers;
layer_index = layertable.FindByFullPath(path, true);
if (layer_index > 0) { // if exists RhinoDoc.ActiveDoc.Layers.SetCurrentLayerIndex(layer_index, true); status = true; } }
DA.SetData(0, layer_index); DA.SetData(1, status); }
Now originally I was getting exceptions when changing multiple layers' visibility properties, which would cause the Event Listener to fire and try to read the Visibility property before the memory has been released by the Set Layer Visibility component. That led me to add an "Exceptions" input, that would allow me to disable the reading of Visibility events at the source in the Layer Events listener. That helped me manage about 95% of the crashes I was getting, but I still get strange crashes in other event properties, even when that property shouldn't be affected. For instance, I am getting a crash here on the Name property in the event from the delegate function, even though I am only changing Visibility at any one time:
I have a few ideas but they all seem pretty hacky. One is to try to set a flag that is readable by any component in the plugin -- so that the event listener can see if a "set" component is currently running and abort before causing an exception. The other is creating a delay in the event listener, somthing like 200ms, to allow any set components to finish what they are doing before reading the event. Neither seems super ideal.
Any ideas?
Thanks,
Marc
…
currently within a fake euphoria framework - blame China/UAE) and a potential decision about doing/developing this or doing that … well …anyway … read and enjoy.
AEC matters: The good, the bad and the ugly.
The bad news: Rhino is NOT suitable for the job (although some use it … but only in the sense that people use Modo for the so called “hard modeling”). By job I mean things up to shop drawing level + specs + you and me (we call it Final level) – nothing to do with sketches and outlines of some abstract “schematic” topology.
The ugly news: The so called Design-Construct approach gains exponentially momentum especially in countries the likes of China/UAE/BRICS (95% of the whole AEC activity worldwide happens there). DeCo means: AEC engineers deliver some kind of study in a preliminary level and the main contractor splits (outsourcers) the job and assigns the study completion AND the construction to various sup-constructors. That thing appeared first – in a large scale - in Dubai 15 years ago. This means that the era of Sergio Pininfarina is over and out: welcome anonymous Toyota designer. In plain English: days of construction corporations fast replacing practices. Dead men walking.
The good news: All AEC related apps (Revit, AECOsim, Allplan and the likes) are in a lethargic state as regards the brave new world (based on the archaic level driven organization schemas etc etc). Of course they all claim the exact opposite and point that support BIM (nobody mention PLM) better than the other guy. But the 21st century – helped by 2 forthcoming unavoidable crisis (a) about shortage of water (b) about transition from carbon to hydrogen economy – isn’t about bureaucracy: think cost/resources optimization and “fitness” rather than China/UAE type of liquid trend. Days of euphoria fast approaching the Wall.
Top to bottom and visa versa.
Old days Titans (Oscar, Mies, Walter, Pierre Luigi, Frank, Eero, blah blah) outlined things (mostly using crayons) and the rest were struggling to translate these in reality in an one way vector like process : Top to bottom that is. These days the inverse gains momentum : when in the whole consider the part … validate … redo … validate … redo. This means bottom to top geared with top-to-bottom. In plain English : child imposes rules to parent and parent imposes rules to child. This means classic MCAD feature/history modeling (CATIA/NX/MS). This is something that Rhino can’t do (not to mention that Rhino is a surface modeler – a rather critical fact).
The parts that are bigger than the whole.
Go there ( http://www.behance.net/gallery/2885057/a-myriad-of-cables) are inspect the whole thing: it’s a parametric nightmare made with the other guy (Generative Components – slower than a Skoda + bugs + why bother?). But the whole (masts and membranes and the likes) means nothing here: focus to the details that are critical for connecting this with that. Complex feature driven solids that are made with internal (on a per se basis) parameters (like fillets required for casting or radius for cable anchoring) whilst they comply with external rules/parameters (cable angles, topology clash issues etc etc). So the whole outlines possibilities … and the part either can follow…or the part must change…or the whole must change. Can you do that with GH/Rhino? And if not what’s missing? (lot’s of things to be honest).
Some other "similar" things:
The narrow picture.
I agree with what others already said and with pretty much all Ola’s points – especially the visual drag-and-drop path mapper (i.e. a visual data manipulator so to speak) and the enable/disable components in groups capability.
Some other suggestions:
A multi canvas capability. As things are right now…it’s like working in Rhino in one view (rather unsuitable I guess). In fact …since overlapping views they don’t work in Rhino…well…you know, he he.
A working auto profile arrangement capability (non twisted Loft/Sweep and the likes). Worth 1Bn dollars that one.
Ability to locate components that caused this or that in the Rhino view: meaning a 2 way communication approach : GH makes things happen in Rhino and things can indicate their cause in the GH canvas.
A robust collection of components that bake stuff in nested blocks (emulating some primitive assembly/component way of thinking). Why may you ask? Well … the whole objective is to talk to CATIA (via STEP) don’t you agree? CATIA makes things happen in real-life not Rhino.
A robust collection of components that can create real-life parametric tensile membrane solutions (get some inspiration from FormFinder: useless because it’s academic but good to point the way). Membranes (and geodesics) are the future.
I could continue at infinitum but IMHO the big picture is worth 12345,67 “focused” GH improvements.
May the Force (the dark option) be with us all.
…