Grasshopper

algorithmic modeling for Rhino

Hi Grasshopper community,

I have been using a great C# script that takes geometry in Grasshopper and bakes it into Rhino as blocks. It's helpful for organizing geometry (one bake contains everything plugged into the component as one block), but I need the script to do one more thing for a specific project...

I am plugging in a series of identical geometries into the component (let's say five identical rectangular surfaces) and would like it to bake each plane as a duplicate of the same block (one block, repeated 5 times). Right now, it bakes one block that contains five rectangular surfaces. I am hoping to get it to bake in such a way that I can pull the model into SketchUp and I can have five identical components - I can edit one and all of them change. I'm replacing the simple planes with a more complex model. I have already verified blocks work in SketchUp, so I'm thinking the change would be within the C# component, something about the way it looks at the geometry and groups it.

Was wondering if I can post the script itself here and ask if anyone knows how to tweak it to accomplish what I'm hoping?

I know baking blocks isn't officially supported in GH, and I don't need to be reminded of this, but I am hoping for some constructive help on this particular component, which is so close to what I need.

Many thanks.

Views: 5446

Replies to This Discussion

here is the script currently:

using Rhino;
using Rhino.Geometry;
using Rhino.DocObjects;
using Rhino.Collections;

using GH_IO;
using GH_IO.Serialization;
using Grasshopper;
using Grasshopper.Kernel;
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>
}

Hi Josh,

just because GH doesn't have native support for blocks doesn't mean you can't use them in C#. It's your code so you can pretty much do whatever you want in it.

I'm not an expert on blocks in Rhino, but my understanding is as follows:

  • There are objects in the 3dm file which have been tagged as part of a block. These are not visible/selectable under normal circumstances.
  • There are block definitions, which basically determine which objects in the 3dm file belong to a single block. The definitions also specify the block name etc.
  • Then there are block instances which are actually Rhino objects that you can see and select. An instance specifies which block definition it wraps and it also provides a local transformation for that block, along with layer, object name etc. etc.

It sounds that what you need to do is add some geometry that is block content, then create a definition from this geometry (just a single plane by the sound of it) and then add a bunch of block instances of that definition. To accomplish this you need to figure out what the transform is for each of your planes.

Can you post the simplest possible GH/GHX file that shows the question? I'd rather not spend my time trying to reverse engineer the script code and inputs from plain text.

--

David Rutten

david@mcneel.com

Tirol, Austria

Thank you for the quick response David.

I have attached the 3DM and GH files for reference. Essentially I am placing colored planes with unique numbers in parking lot bays to automatically populate parking lots for large renderings. I would be pulling the baked model into SketchUp and replacing the colored planes with particular vehicles.

The cars are placed on randomly reduced points within the bays. Each car type has a color and unique name (ie Car 24) that is intended to be baked. Basically, I am looking for that C# bake component in the "car" section to bake each car type as a series of identical blocks. So if there are 4 pink Car 1s in the model, baking would result in 4 instances of the block that is a pink plane that says Car 1.

Hope this makes sense. Thanks for taking a look.

Attachments:

Wow....is all that stuff just to place some random cars in a parking lot?

It's closing in on midnight here, but from my brief foray into your file it seems like you have a bunch of bay center lines that intersect a collection of curves that represent the parking plan. Then these intersections eventually have to create random cars right?

I think I can probably create a script which generates planes for all possible car locations (with randomness if you want) in the entire lot with a lot fewer components. If you really want population density control on a per-bay basis it's something you can probably add later. Does that sound ok?

--

David Rutten

david@mcneel.com

Tirol, Austria

Yes, you are correct in your understanding of the file and its intentions. I'm creating it so that when my firm does aerial renderings of large shopping centers, we don't have to spend two days manually placing cars randomly in a parking lot.

Again, my biggest concern right now is ensuring that each car type can be baked as a series of block instances so all Car 23s can become Land Rovers, etc.

Yes, if you want to take a shot at simplifying this I would be grateful. I am always working to improve the script. I appreciate you responding so late in the night.

I'm going to have to go to bed soon, but I attached a medium sized C# script which computes all possible car positions based on two sets of curves. One containing all the plan curves and the other all the centre lines.

Next step is to remove some percentage of these planes and then figure out which blocks to bake at which plane. That'll be a different script which will do all the block baking.

--

David Rutten

david@mcneel.com

Tirol, Austria

Attachments:

Quick update, added randomness controls. Motion along both principal directions and rotation can now be controlled.

--

David Rutten

david@mcneel.com

Tirol, Austria

Attachments:

I'm blown away by how easy this seems when you do it. Nice work. Love the added random positioning features.

With block insertion script. The blocks are defined in the file (which is probably not what you're after, but I hope you can change that yourself).

The blocks I add all have a user string that is associated with the script component ID. That allows me to delete the blocks the next time the script runs.

--

David Rutten

david@mcneel.com

Tirol, Austria

Attachments:

Thank you again David.

I'm exploring the script. Forgive me for my oblivion, but three questions:

1. How might I edit that last C# component to include a bake/boolean toggle? That was helpful for me in my last script.
2. Other than the baked planes that came with the .3DM file, I do not see any outputs from the script itself. I looked in the C# code to see if there was anything amiss, but I don't know what to look for. I saw your helpful notes though.
3. Since I can't see any GH outputs from the script, I may be misled here, but could the C# script at the end also apply colors to the planes similar to my old scripts? That was great to have - you could quickly see the placement of similar cars, making sure they aren't too near, etc.

Thanks again - I did not create the original C# script so I am very new to the C# coding language in GH.

I see. I thought you wrote the original. 

If you assign a colour to the original block then the result will be coloured as well.

The script outputs the IDs of all the block instances it adds to the file. I'm not really sure what you can do with these IDs, but I figured I might as well output them.

I noticed that my script doesn't erase the shapes the first time it runs. This is a bug that is very hard to fix without releasing an update of Grasshopper.

As for the boolean toggle, add another input, name it 'Enable' or something, set the Type Hint to bool, and then add:

if (!Enable)

  return;

To the top of the script. It will still erase the shapes, regardless of the value of Enable though. However the fix for that is actually also the fix for the first-time-bug I mentioned before. I'll upload a fixed script shortly.

--

David Rutten

david@mcneel.com

Tirol, Austria

Updated script and file with an additional, coloured block.

--

David Rutten

david@mcneel.com

Tirol, Austria

Attachments:

RSS

About

Translate

Search

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service