using Grasshopper.Kernel.Data; using Grasshopper.Kernel.Types;
using System; using System.IO; using System.Xml; using System.Xml.Linq; using System.Linq; using System.Data; using System.Drawing; using System.Reflection; using System.Collections; using System.Windows.Forms; using System.Collections.Generic; using System.Runtime.InteropServices;
/// <summary> /// This class will be instantiated on demand by the Script component. /// </summary> public class Script_Instance : GH_ScriptInstance { #region Utility functions /// <summary>Print a String to the [Out] Parameter of the Script component.</summary> /// <param name="text">String to print.</param> private void Print(string text) { /* Implementation hidden. */ } /// <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary> /// <param name="format">String format.</param> /// <param name="args">Formatting parameters.</param> private void Print(string format, params object[] args) { /* Implementation hidden. */ } /// <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary> /// <param name="obj">Object instance to parse.</param> private void Reflect(object obj) { /* Implementation hidden. */ } /// <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary> /// <param name="obj">Object instance to parse.</param> private void Reflect(object obj, string method_name) { /* Implementation hidden. */ } #endregion
#region Members /// <summary>Gets the current Rhino document.</summary> private readonly RhinoDoc RhinoDocument; /// <summary>Gets the Grasshopper document that owns this script.</summary> private readonly GH_Document GrasshopperDocument; /// <summary>Gets the Grasshopper script component that owns this script.</summary> private readonly IGH_Component Component; /// <summary> /// Gets the current iteration count. The first call to RunScript() is associated with Iteration==0. /// Any subsequent call within the same solution will increment the Iteration count. /// </summary> private readonly int Iteration; #endregion
/// <summary> /// This procedure contains the user code. Input parameters are provided as regular arguments, /// Output parameters as ref arguments. You don't have to assign output parameters, /// they will have a default value. /// </summary> private void RunScript(bool bake, List<GeometryBase> G, Point3d L, Color C) { COL = C; LOCATION = L; NAME = ""; pnts.Clear(); crvs.Clear(); breps.Clear();
foreach(GeometryBase geom in G){ switch(geom.GetType().Name){ case "Point": pnts.Add(((Rhino.Geometry.Point) geom).Location); break; case "Curve": //create a new geometry list for display break; case "PolyCurve": crvs.Add((PolyCurve) geom); break; case "Brep": breps.Add((Brep) geom); break; default: Print("Add a new case for this type: " + geom.GetType().Name); break; } }
if(bake){ Rhino.DocObjects.InstanceDefinition I = doc.InstanceDefinitions.Find(NAME, false);
if(I != null) doc.InstanceDefinitions.Delete(I.Index, true, true);
int index = doc.InstanceDefinitions.Add(NAME, "description", Point3d.Origin, G); doc.Objects.AddInstanceObject(index, Transform.Scale(L, 1)); } }
// <Custom additional code> //GEOMETRY Lists to display
List<Point3d> pnts = new List<Point3d>(); List<PolyCurve> crvs = new List<PolyCurve>(); List<Brep> breps = new List<Brep>();
string NAME; Point3d LOCATION; int THICKNESS = 2; Color COL;
//Return a BoundingBox that contains all the geometry you are about to draw. public override BoundingBox ClippingBox { get { return BoundingBox.Empty; } } //Draw all meshes in this method. public override void DrawViewportMeshes(IGH_PreviewArgs args) {
}
//Draw all wires and points in this method. public override void DrawViewportWires(IGH_PreviewArgs args) { foreach(Point3d p in pnts) args.Display.DrawPoint(p, Rhino.Display.PointStyle.ControlPoint, THICKNESS, COL);
foreach(PolyCurve c in crvs) args.Display.DrawCurve(c, COL, THICKNESS);
foreach(Brep b in breps) args.Display.DrawBrepShaded(b, new Rhino.Display.DisplayMaterial(COL));
args.Display.DrawPoint(LOCATION, Rhino.Display.PointStyle.ActivePoint, 3, Color.Black); args.Display.Draw3dText(NAME, Color.Gray, new Plane(LOCATION, Vector3d.ZAxis), THICKNESS / 3, "Arial"); }
// </Custom additional code> }…
C# only).
We've switched UI toolkits from winforms to Eto (which has much better cross platform support) so GH2 will run on both Mac and Windows. The developer of Eto now works part-time at McNeel so I'm pretty confident any problems that come up can be solved the proper way.
We're working on complete documentation. Glossaries, explanations of core-concepts, example files for all components, etc. etc. All fully editable and extensible by third party content providers, be they plugin developers, teachers, translators, or whatever.
This time around I'm designing the SDK with multi-threading in mind, so a lot of types have become immutable. I'm also adding multi-threading wherever it makes sense in the core classes.
This time around I'm adhering to .NET guidelines for the SDK.
There will also be much deeper and better support for data trees (they were introduced only halfway through GH1 development). The same goes for data conversion.
There is support for user data on each and every data type. So you can assign custom data to curves, numbers, breps, whatever and it will piggy back along as that data flows through the network. This user data will also serve as the basis for custom settings. For example you could assign the user data "BakeLayer = Building A" to some geometry and when that geometry gets baked, GH will figure out in what layer it is supposed to end up. Or you can assign "DisplayColor = Orange" and that geometry will appear orange in the viewports.
Expressions have been extended to be any chunk of VB or C# code (support for python will probably be added at some point). They can be far more intricate (but they don't have to be) and they will be run as compiled code, rather than interpreted code. Expressions also have ways to access data that is defined elsewhere in the document. So if there's a slider somewhere called "Thickness" then an expression in a number input parameter could look like "Min(x * 2, Thickness)".
--------------------------------------------------------------------------------------------
I am doing or have done the above. I'm hoping to get around to the items below.
--------------------------------------------------------------------------------------------
The interface will be simplified. I'm planning to remove a lot of options and settings and replace them with smarter code. If that ultimately fails options and settings can always be brought back.
There will be a lot more zoom aware UI, so if you want details about some component or parameter, you'll no longer have to dig through a gazillion menu items, you just zoom in on that object.
There will be better tools to document, debug and manage large files. This is a huge area of R&D but it is one of the major weaknesses of GH1 in my opinion.
Solutions will be multi-threaded, and hopefully also run in the background.
As part of a general effort within McNeel, I'm hopeful there will be a reliable way to explore, install, and uninstall plugins for Grasshopper directly from the Grasshopper interface. No need to go to some webpage, no need to register, no need to log in, no need to enter captchas or having a new password emailed to you because you can't remember the old one. It's ridiculous how difficult this appears to be in 2015, but we now have someone at McNeel who's really good at this stuff and I'm pretty confident they'll make it awesome.
There'll be a lot more types of data to work with (sub-d geometry, extrusions, polylines, spheres, graphs, bitmaps, better support for fields, ...). The aim here is both to reduce memory overhead by providing light-weight types and to provide more functionality.
There will be more ways to organise and display data, both on the canvas and in the viewports. Better bar graphs, better pie charts, better and more everything.
The default preview materials will be grey and yellow, not red and green.
--------------------------------------------------------------------------------------------
As you can see there's a lot of work to be done, for sure the first alpha release will be as soon as possible, but I've been focusing on core classes only so far. There's no working prototype, there's no working UI, there's no document class yet that actually runs solutions. We're a long way from the first alpha.
Right now I'm mostly acquainting myself with Eto (YouTube video if you want to know what that means) and I'm working on data type conversions and preview materials.
--------------------------------------------------------------------------------------------…
.
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
…
with the core McNeel team in Seattle for about 2 months tomorrow and I wanted to release this before I left. It's a bit rushed, clusters are definitely not as 'finished' as I'd like them to be, but there should be enough there for some good old customer feedback at least.
Just in case I horked something up, you can still download 0.7.0057 here.
Download 0.8.0001 from the usual location.
First a basic new features and bug list, then the warning section. If you don't read the warning section you forfeit any rights to complain about this new release.
● Added a new Cluster Object. This is very young code, expect big (quite possibly breaking) changes in the future.
● Added auto-panning to Drag Object and Draw Wire interactions.
● Added canvas curl UI for drag+drop options.
● Added default values to the Quad-Face and Tri-Face components.
● Added a Tree Split component for separating out branches.
● Drag+Drop with text content now creates a new Panel.
● Curve data can now convert from a Surface/Brep with a single closed edge loop.
● Added runtime message balloon feedback.
● VB and C# script components now update immediately when typehints are changed.
● VB and C# script components now update immediately when input parameter access is changed.
● MoveForward and MoveBackwards arrange options are now available.
● Added a Grasshopper Version field to the status bar.
● GraphMapper can now adjust intervals, points and vectors in addition to just numbers.
● Parameter disconnection menu items now highlight the connection in question on mouse-over.
○ The menu short-cuts for Find and Move Forward were both Ctrl+F. Find is now F3.
○ Any Undo operation would wreck the Redo stack, this no longer happens.
○ Fixed a bug with automatic tooltip resizing.
○ Fixed an erroneous "app" autocomplete member in the C# and VB script members.
○ Fixed a bug in the CurveCurve intersection SDK code that occured with overlaps.
○ Fixed a bug in the PointList display component with stale point data.
○ Fixed a nasty bug with stale document caches and undo/redo.
○ Custom Preview Meshes would always draw wires regardless of the Grasshopper view setting. This is fixed.
The Aforementioned Warning Section
This pertains mostly to clusters. At present there's no way yet to edit the contents of a cluster. You can make clusters from a selection by clicking on the toolbar cluster button (selected objects remain on the canvas, this will change), or by drag+dropping ghx files onto the canvas and selecting the Cluster Insert mode from behind the curl.
Clusters contents can be opened as new documents via the Cluster object menu, but this code is very icky still. You can edit cluster properties by double clicking on one.
It is entirely possible that clusters will change so much in the near future that old clusters might not read correctly from 0.8.0001 files. Do not use them yet on production work and always make backups.
That's it. Enjoy,
David
--
David Rutten
david@mcneel.com
Poprad, Slovakia…
Added by David Rutten at 4:27pm on October 22, 2010
or GH with: 1. Animation Timeline 2. Rendering 3. API
Summary:
Animation Timeline: Smooth animation system that plays at the real-world speed; so you know the robot will run just right when you upload the code.
Rendering: Extensive options and outputs; so you can generate amazing videos.
API: Access our functions through Python and C# scripting; so you can manage parameters and actions for complex processes for each target.
More info:
Animation Timeline:
Build an animation from a list of Planes, it's that easy! Get these from points, curves or surfaces. Download the example files with the trial and test it yourself.
The unique Timeline component displays all the important robot warnings and the digital Input/Ouput:
RED – clash detection BLUE - singularities YELLOW – over rotation ORANGE – out of reach Digital Inut/Output: red=off, green=on
Rendering:
IO smoothly interpolates between all the Planes you set. This means you can generate keyframes for positions between Planes too e.g. you have two planes defining a tool path, IO can generate 2000 keyframes. Smooooth!
Rendered in full colour as standard, not GH red :-)
LiveBaking - let's you use Rhino render settings in real-time (can be a bit slow!)
Slider animation - use the native 'Animate' option to export hi-res images and create videos easily. Just set the number of frames you need (hint: divide total time in seconds by the frames-per-second rate)
Bake unlimited meshes as keyframes for export to render-pipelines in 3DS etc.
API
Accessing the IO functions through Python and C# let's you build more powerful definitions. You can assign data to every position the robot reaches, allowing you to control speed, acceleration, wait-times, actions and more. Examples comparing C# with Python are included in the examples files.
You can also use teh API build your own plugins that use the IO timeline to do all the hard work like IK and creating valid code, while you enjoy developing your new process...
Check out the website for more features and videos of the example definitions: www.robots.io
Download the PDF guide: 150314_IO_Primer_v1.pdf.
See www.robots.io for more info and pricing.
Developed by RoboFold Ltd. Used by leading academics, researchers and professionals.
…
Added by Gregory Epps at 10:15am on November 7, 2014
tput parameters.
Besides adding resizing functionality, I'm interested in changing the default color. I've done this for other components by deriving from GH_ComponentAttributes, and creating a capsule of the appropriate shade, then calling base.RenderComponentCapsule(canvas, graphics, false, true, true, true, true, true). I'd also like to draw vector shapes, and I'm assuming I would just call 'graphics.DrawXYZ' during the appropriate channel.
Below is the current Render method in my GH_ResizableAttributes<GH_Component> class. It will draw a component, with grip circles, but the parameters aren't included with my component, so no wires can be attached.
What am I missing in my derived class?
protected override void Render(GH_Canvas canvas, System.Drawing.Graphics graphics, GH_CanvasChannel channel) { if (channel == GH_CanvasChannel.Objects) { GH_Palette palette = GH_Palette.Normal;
// Adjust palette based on the Owner's worst case messaging level. switch (Owner.RuntimeMessageLevel) { case GH_RuntimeMessageLevel.Warning: palette = GH_Palette.Warning; break;
case GH_RuntimeMessageLevel.Error: palette = GH_Palette.Error; break; }
RectangleF capsuleBox = new RectangleF(this.Bounds.Location, this.Bounds.Size); GH_Capsule capsule = GH_Capsule.CreateCapsule(capsuleBox, palette); float inputGripSeparation = this.Bounds.Height / Owner.Params.Input.Count; float outputGripSeparation = this.Bounds.Height / Owner.Params.Output.Count;
float inputOffset = inputGripSeparation / 2; float outputOffset = outputGripSeparation / 2;
for (int i = 0; i < Owner.Params.Input.Count; ++i) {
float y = i * inputGripSeparation + inputOffset; capsule.AddInputGrip(this.Bounds.Y + y); } for (int i = 0; i < Owner.Params.Output.Count; ++i) {
float y = i * outputGripSeparation + outputOffset; capsule.AddOutputGrip(this.Bounds.Y + y); }
if (Owner.RuntimeMessageLevel == GH_RuntimeMessageLevel.Error || Owner.RuntimeMessageLevel == GH_RuntimeMessageLevel.Warning) { capsule.Render(graphics, this.Selected, Owner.Locked, true); } else {
capsule.Render(graphics, Color.FromArgb(188, 157, 202)); }
capsule.Dispose(); base.Render(canvas, graphics, channel); } else {
base.Render(canvas, graphics, channel); } }…
I'm going to post here some examples of writing simple C# scripts which use the Kangaroo library for custom iterative behaviour. While I have posted a number of examples of custom goals before, so far
n fact) according a vast variety of "modes" PLUS the required clash detection (ALWAYS via trigonometry). In plain English: outline any collection of Breps and "apply" a truss that is topologically sound (planarization in case of quads etc is an added constrain). PLUS outline/solve what comes "next" after that truss (like the planar glazing "add-on" brackets of yours [ the ones that need redesign, he he], or some roofing/facade skin system [secondary supports, corrugated sheet metal, insulation, final cladding, dogs and cats])
2. Imaging doing this in real life (nothing to do with "abstract" formations of "lines" or "shapes" or whatever). This means primarily adopting a BIM umbrella: in plain English AECOSim, Revit or Allplan (I'm a Bentley man so I use AECOSim + Generative Components). This also means using "in-parallel" a top MCAD app for 1:1 details, FEA/FIM and the vast paraphernalia required for real-life studies destined for real-life projects (made with real-life money by real-life people). My choice: CATIA/Siemens NX.
3. What to send to Microstation (if not using Generative Components, that is) and/or CATIA? In what "state"? To do what exactly? For instance even if you could design this feature driven tensile membrane anchor custom node in Rhino (you can't) it could be 100% useless in CATIA:
4. Imaging masterminding ways to send them nested instance definitions of ... er ... a coordinate system (all what you need). In plain English: since is utterly pointless to send them nested blocks that can't been parametrically controlled (variations/modifications/PLM management/BOM/specs etc etc)... send them simply the "instructions" to place coordinate systems of components that ARE parametrically designed within Microstation and/or CATIA (classic feature driven design approach blah blah). So GH solves topology et all (working on data imported via, say, Excel sheets related with sizes of components etc etc) and sends to Microstation simply this (a myriad of "this" actually):
I do hope that the gist of the "method" (the ONLY way to invite GH to the party) is clear.
best, Peter…
cause you are not saying what you want inside the second tree. You say this is not important, ok... then just take the first tree as it is and there you have it! Two trees with the same structure!....
Of course I am guessing the above answer will not satisfy you, so let's take it in your case:
You want to move 1458 lines on Z axis.
The question is: How high do you want to move each line?
A. You want to move them all 1 unit high? then do this:
B. You want to move eash of the 54 lines of every list by the corresponding 54 Y values? Then do this:
C. You want to do tha same as (B) but with the 2 trees having the exact same structure? There is absolutely no point in that but if you are obsessed about it you could do this:
What I am trying to say is that the structure of a tree is irelevant if you don't know what you want to have inside it.
And the method to create a tree with the desired structure depends again on what you want to have inside the tree....…
st shortest path. The guiding splines would work like a forcefield so that paths are "drawn" towards them with a user defined strength and radius of influence.Since each path is basically independent, it should be relatively straight forward to multithread. I downloaded the C# code for the pathfinding node and have to see if I'm up to it.
Would also be interesting to know how far away the first beta of a multithreaded GH 2 is.
I also had some hopes when "Fabric Engine" showed a demo of a Rhino exporter, since its "Canvas" is an extremely optimized node system that's fully multithreaded and optionally uses the GPU, which could be interesting to explore for some heavy lifting if they for instance would attach it to GH. But I guess it does not make much sense for them as a target.
Above image uses 20000 random points. In Softimage XSI ICE this would not be much, since it's nodes are fully multithreaded and optimized for huge numbers of particles and point deformation. In GH, with anything above 500 points, things get rather "meditative".
Illustrator takes up to half an hour after each and every change to colour, line style, blending mode etc. I have one even more complex file with over 3 GB size and there Illustrator (CS6 x64) goes into some kind of trance and after some hours of thinking moves on to some advanced psychotic, catatonic state to never fully return... ;-)So usually I run it in the background while doing something else...
I recently tried different other vector graphics apps (Inkscape, Affinity Designer, Xara) but they were even worse if they were able to open the files at all. Maybe I should give Corel a try too.
Cheers and thanks for your offer! Your work is a major inspiration for me while learning Grasshopper!
Tom…