helped to make grasshopper a great platform for research and design in parametric design and fabrication including, Andy Payne, Daniel Piker, and Ronnie Parsons and Gil Akos from Studio Mode. In addition, this is the first AA Summer program to happen in the US and will bring many faculty and students from the EmTech program to San Francisco.
Here is the whole description:
BIODYNAMIC STRUCTURES AA Visiting School @ CCA California College of the Art Monday 12 to Wednesday 21 July, 2010
Biodynamics is the study of the force and energy of dynamic processes on living organisms. Through simple mechanisms embedded within the material logic of natural systems, specific stimuli can activate a particular response. This response occurs in carnivorous plants such as the Venus fly-trap, which uses turgor pressure to trap small insects in order to feed, and worms, which by contracting differently oriented muscles, achieve movement. This ten-day intensive workshop, co-taught by the faculty of the Emergent Technologies and Design Programme at the AA and the faculty of Architecture and MEDIAlab at California College of the Arts, will explore active systems in nature, investigating biomimetic principles in order to analyze, design and fabricate prototypes that respond to electronic and environmental stimuli. Students will work in teams to research specific biological systems, extracting logics of organization, geometry, structure and mathematics. Advanced analysis, simulation, modeling and fabrication tools will be introduced in order to apply this information to the design of both passive and active responsive architectural systems. Investigation and application of robotics, sensors and actuators will be employed for the activation of the material system investigation through the construction of working responsive prototypes.
+ CONTENT TAGS: Biodynamic, Parametric, Scripted, Mimetic, Responsive, Interactive, Digitally Fabricated
+ SOFTWARE: Rhino, Grasshopper, Firefly, RhinoScript, Arduino, Processing
CORE FACULTY
Michael Weinstock (Academic Head, Director of Emergent Technologies Programme, AA London UK)
Christina Doumpioti, Evan Greenberg, Konstantinos Karatzas (Tutors, AA EmTech Programme, London UK)
Jason Kelly Johnson (Future Cities Lab), Andrew Kudless (Matsys) (CCA MediaLab Coordinators, SF CA)
ASSOCIATED FACULTY
George Jeronimidis (Director of Center for Biomimetics, University of Reading UK); Andrew Payne (LIFT Architects, Grasshopper Primer); Daniel Segraves (ASGG Adrian Smith + Gordon Gill Architecture); Ronnie Parsons + Gil Akos (Studio Mode, NY); Daniel Piker (Kangaroo Project Live Physics)
ASSOCIATED LECTURERS:
Thom Faulders (Faulders Studio, San Francisco CA); Lisa Iwamoto and Craig Scott (Iwamoto/Scott Architects, San Francisco CA); David Gissen (HTC Experiments/CCA); Ila Berman (CCA Director of Architecture); Wendy Ju (CCA/Stanford University); Andrew Sparks (CCA); Nataly Gattegno (Future Cities Lab, San Francisco CA);
ENROLLMENT INFORMATION:
http://sanfrancisco.aaschool.ac.uk/; or visit the CCA MEDIAlab website: http://mlab.cca.edu
(Workshops are non-credit. Enrollment is processed by the AA. Workshop will run the full 10 days.)
CCA Faculty Coordinators: Jason Kelly Johnson and Andrew Kudless
AA Microblog Site: http://sanfrancisco.aaschool.ac.uk/
twitter: bioworkshopsf
Contact
visitingschool@aaschool.ac.uk or mlab@cca.edu
Downloads
Application Form…
will work slightly different from before. Sorry about breaking this, but it proved impossible to improve the selection logic with the fairly ambiguous notation that was implemented already.
Not every change is breaking though and I hope that most simple matching rules will work as before. There will be a McNeel webinar on Wednesday the 6th of November where I discuss the new selection rules (as well as path mapping syntax and relative offsets within one or more data trees). This will be a pretty hard-core webinar aimed at expert users. The event will be recorded so you can always go and watch it later. I figured I'd briefly explain the new selection rules on Ning before I release the update though.
-------------------------------------------------------------------------------
Imagine we have the following data tree, containing a bunch of textual characters:
{0;0} = [a,e,i,o,u,y] {0;1} = [ä,ë,ê,ï,î,ö,ô,õ,ü,û,ÿ,ý] {1;0} = [b,c,d,f,g,h,j,k,l,m,n,p,q,r,s,t,v,w,x,z] {1;1} = [ç,ĉ,č,ĝ,ř,š,ş,ž]
There are a total of four branches {0;0}, {0;1}, {1;0} and {1;1}. The first branch contains all the vowels that are part of the standard English alphabet. The second branch contains all non-standard vowels and branches three and four contain the standard and non-standard consonants respectively.
So what if we want to select from this tree only the standard vowels? Basically include everything in the first branch and disregard everything else. We can use the [Tree Split] component with a selection rule to achieve this:
{0;0}
This selection rule hard-codes the number zero in both tree path locations. It doesn't define an item index rule, so all items in {0;0} will be selected.
If we want all the vowels (both standard and non-standard), then we have several options:
{0;?} = select all branches that start with 0
{0;(0,1)} = select all branches that start with 0 and end in either 0 or 1
{0;(0 to 1)} = ......................................... and end in the range 0 to 1.
Conversely, selecting all standard vowels and consonants while disregarding all non-standard character can be achieved with rules as follows:
{?;0}
{(0,1);0}
{(0 to 1);0}
It is also possible to select items from each branch in addition to limiting the selection to specific branches. In this case another rule stated in square brackets needs to be appended:
{0;?}[0 to 2]
The above rule will select the first three vowels from the standard and the non-standard lists.
Basically, rules work in a very consistent way, but there are some syntax conventions you need to know. The first thing to realize is that every individual piece of data in a data-tree can be uniquely and unambiguously identified by a collection of integers. One integer describes its index within the branch and the others are used to identify the branch within the tree. As a result a rule for selection items always looks the same:
{A;B;C;...;Z}[i] where A, B, C, Z and i represent rules.
It's very similar to the Path Mapper syntax except it uses square brackets instead of parenthesis for the index (the Path Mapper will follow suit soon, but that won't be a breaking change). You always have to define the path selector rule in between curly brackets. You can supply any number of rules as long as you separate them with semi-colons.
The index rule is optional, but -when provided- it has to be encased in square brackets after the path selection rule(s).
The following rule notations are allowed:
* Any number of integers in a path
? Any single integer
6 Any specific integer
!6 Anything except a specific integer
(2,6,7) Any one of the specific integers in this group.
!(2,6,7) Anything except one of the integers in this group.
(2 to 20) Any integer in this range (including both 2 and 20).
!(2 to 20) Any integer outside this range.
(0,2,...) Any integer part of this infinite sequence. Sequences have to be at least two integers long, and every subsequent integer has to be bigger than the previous one (sorry, that may be a temporary limitation, don't know yet).
(0,2,...,48) Any integer part of this finite sequence. You can optionally provide a single sequence limit after the three dots.
!(3,5,...) Any integer not part of this infinite sequence. The sequence doesn't extend to the left, only towards the right. So this rule would select the numbers 0, 1, 2, 4, 6, 8, 10, 12 and all remaining even numbers.
!(7,10,21,...,425) Any integer not part of this finite sequence.
Furthermore, it is possible to combine two or more rules using the boolean and/or operators. If you want to select the first five items in every list of a datatree and also the items 7, 12 and 42, then the selection rule would look as follows:
{*}[(0 to 4) or (6,11,41)]
The asterisk allows you to include all branches, no matter what their paths looks like.
It is at present not possible to use the parenthesis to define rule precedence, rules are always evaluated from left to right. It is at present also not possible to use negative integers to identify items from the end of a list.
If you want to know more, join the Webinar on Wednesday!
--
David Rutten
david@mcneel.com
Seattle, WA…
Added by David Rutten at 8:57pm on November 3, 2013
rring to the above image)
Area
effective
effective
Second
Elastic
Elastic
Plastic
Radius
Second
Elastic
Plastic
Radius
of
Vy shear
Vz shear
Moment
Modulus
Modulus
Modulus
of
Moment
Modulus
Modulus
of
Section
Area
Area
of Area
upper
lower
Gyration
of Area
Gyration
(strong axis)
(strong axis)
(strong axis)
(strong axis)
(strong axis)
(weak axis)
(weak axis)
(weak axis)
(weak axis)
A
Ay
Az
Iy
Wy
Wy
Wply
i_y
Iz
Wz
Wplz
i_z
cm2
cm2
cm2
cm4
cm3
cm3
cm3
cm
cm4
cm3
cm3
cm
I have a very similar table which I could import to the Karamba table. But I have i_v or i_u values as well as radius of inertia for instance.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dimensjon
Masse
Areal
akse
Ix
Wpx
ix
akse
Iy
Wpy
iy
akse
Iv
Wpv
iv
Width
Thickness
Radius R
[kg/m]
[mm2]
[mm4]
[mm3]
[mm]
[mm4]
[mm3]
[mm]
[mm4]
[mm3]
[mm]
[mm]
[mm]
[mm]
L 20x3
0.89
113
x-x
4,000
290
5.9
y-y
4,000
290
5.9
v-v
1,700
200
3.9
20
3
4
L 20x4
1.15
146
x-x
5,000
360
5.8
y-y
5,000
360
5.8
v-v
2,200
240
3.8
20
4
4
L 25x3
1.12
143
x-x
8,200
460
7.6
y-y
8,200
460
7.6
v-v
3,400
330
4.9
25
3
4
L 25x4
1.46
186
x-x
10,300
590
7.4
y-y
10,300
590
7.4
v-v
4,300
400
4.8
25
4
4
L 30x3
1.37
175
x-x
14,600
680
9.1
y-y
14,600
680
9.1
v-v
6,100
510
5.9
30
3
5
L 30x4
1.79
228
x-x
18,400
870
9.0
y-y
18,400
870
9.0
v-v
7,700
620
5.8
30
4
5
L 36x3
1.66
211
x-x
25,800
990
11.1
y-y
25,800
990
11.1
v-v
10,700
760
7.1
36
3
5
L 36x4
2.16
276
x-x
32,900
1,280
10.9
y-y
32,900
1,280
10.9
v-v
13,700
930
7.0
36
4
5
L 36x5
2.65
338
x-x
39,500
1,560
10.8
y-y
39,500
1,560
10.8
v-v
16,500
1,090
7.0
36
5
5
I have diagonals (bracings) which can buckle in these "non-regular" directions too, and they do. If I could add those values then in the Karamba model I could assign specific buckling scenarios..... I can see another challenge which will be at the ModifyElement component, I will not be able to choose these buckling lengths, in these directions.
Do you think this functionality can be added within short, or should I try to find another way to model these members?
Br, Balazs
…
ooking for an efficient way to perform glazing of complex shapes.
I've only followed the Energy modelling workshops so far so i may have missed some essential components or workflows to achieve my needs. But i've made an attached definition with all my current attempts to get a proper HBzone with the numerous windows faces i will always have to deal with in this project.
I first thought that i was not using the HBObjWGZ correctly, then after some readings it was maybe an upgrading issue, then effectively i had my Therm 7.5 that needed to be reinstaled, but then ... I must be missing an essential HB tricks or workflow i guess ...
So I divided my attempt in two series :
- The Serie 1 : is a simplier version of the project step i'm working on but i'd be glad to achieve it first !
- The Serie 2 : is the real final direction of the project, which consist in sorting/dispatch faces to windowon one side and to an other material on the other, according to the winter sun and a pourcentage param.
Despite it is more complicated than the Serie one, it seems seems to create the same diversity of issues.
Until now, with the 5 different combinations of Serie 1, and the 3 of Serie 2, with and without using the different Glazing/window components, here are the logs i got from both HBZone component or OpenStudio component:
From OpenStudio - "1. The simulation has not run correctly because of this severe error: ** Severe ** BuildingSurface:Detailed="00073E23257843B6A948", invalid Construction Name="ETFE" - has Window materials.">> Has to deal with the way i'm trying to assign too early a customized EPConstruction material ? Done it wrong ? I tried to reload it in the library but doesn't change anything...
From OpenStudio - "1. The simulation has not run correctly because of this severe error: ** Severe ** BuildingSurface:Detailed="000579CD749E46DFA5EA", invalid Construction Name="EXTERIOR WINDOW" - has Window materials.">> Is it an issue in the way i define my surfs both as "WINDOW" (5) for srfType and Outdoors on the same component ?
From Create HBZone -"1. Solution exception:'EPZone' object has no attribute 'shdCntrlZoneInstructs'"
>> Happens when i try to introduce my ETFE EpMaterial after creating my first HBZone, with a Set EP Zone Construction, so this material seems to be not working either before and after trying to create an HB Zone
From Create HBZone- "1. Solution exception: 73df51a3b2144b1e858b has been moved, scaled or rotated."If you need to move or rotate a Honeybee object you should use Honeybee move, rotate or mirror components. You can find them under 12|WIP tab.
>> >> wich seems to exist in some on other thread Here and was a coding bug supposed to be fixed.
And last but not least ...
From OpenStudio - "1. The simulation has not run correctly because of this severe error: ** Severe ** checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than 90.0 degrees from base surface.2. The simulation has failed because of this fatal error: ** Fatal ** GetSurfaceData: Errors discovered, program terminates" .
I'm attaching the file with each attempt in this post. The definitions are disabled and the log already copied separatly so there is no need to compute each of them to see what's wrong.
If someone from the beginner to one of the Kings of HoneyBee has any relevant answer/solution to this attempt with complex geometry Issue it will be really nice for me so i could to move forward !!
Thanks in advance guys and have a great day !
…
nts for Ladybug too. They are based on PVWatts v1 online calculator, supporting crystalline silicon fixed tilt photovoltaics.
You can download them from here, or use the Update Ladbybug component instead. If you take the first option, after downloading check if .ghuser files are blocked (right click -> "Properties" and select "Unblock").
You can download the example files from here.
Video tutorials will follow in the coming period.
In the very essence these components help you answer the question: "How much energy can my roof, building facade, solar parking... generate if I would populate them with PV panels"?
They allow definition of different types of losses (snow, age, shading...) which may affect your PV system:
And can find its optimal tilt and orientation:
Or analyse its performance, energy value, consumption, emissions...
By Djordje Spasic and Jason Sensibaugh, with invaluable support of Dr. Frank Vignola, Dr. Jason M. Keith, Paul Gilman, Chris Mackey, Mostapha Sadeghipour Roudsari, Niraj Palsule, Joseph Cunningham and Christopher Weiss.
Thank you for reading, and hope you will enjoy using the components!
EDIT: From march 27 2017, Ladybug Photovoltaics components support thin-film modules as well.
References:
1) System losses:
PVWatts v5 Manual, Dobos, NREL, 2014
2) Sun postion equations by Michalsky (1988):
SAM Photovoltaic Model Technical Reference, Gilman, NREL, 2014
edited by Jason Sensibaugh
3) Angle of incidence for fixed arrays:
PVWatts Version 1 Technical Reference, Dobos, NREL, 2013
4) Plane-of-Array diffuse irradiance by Perez 1990 algorithm:
PVPMC Sandia National Laboratories
SAM Photovoltaic Model Technical Reference, Gilman, NREL, 2014
5) Sandia PV Array Performance Module Cover:
PVWatts Version 1 Technical Reference, Dobos, NREL, 2013
6) Sandia Thermal Model, Module Temperature and Cell Temperature Models:
Photovoltaic Array Performance Model, King, Boys, Kratochvill, Sandia National Laboratories, 2004
7) CEC Module Model: Maximum power voltage and Maximum power current from:
Exact analytical solutions of the parameters of real solar cells using Lambert W-function, Jain, Kapoor, Solar Energy Materials and Solar Cells, V81 2004, P269–277
8) PVFORM version 3.3 adapted Module and Inverter Models:
PVWatts Version 1 Technical Reference, Dobos, NREL, 2013
9) Sunpath diagram shading:
Using sun path charts to estimate the effects of shading on PV arrays, Frank Vignola, University of Oregon, 2004
Instruction manual for the Solar Pathfinder, Solar Pathfinder TM, 2008
10) Tilt and orientation factor:
Application for Purchased Systems Oregon Department of Energy
solmetric.com
11) Photovoltaics performance metrics:
Solar PV system performance assessment guideline, Honda, Lechner, Raju, Tolich, Mokri, San Jose state university, 2012
CACHE Modules on Energy in the Curriculum Solar Energy, Keith, Palsule, Mississippi State University
Inventory of Carbon & Energy (ICE) Version 2.0, Hammond, Jones, SERT University of Bath, 2011
The Energy Return on Energy Investment (EROI) of Photovoltaics: Methodology and Comparisons with Fossil Fuel Life Cycles, Raugei, Fullana-i-Palmer, Fthenakis, Elsevier Vol 45, Jun 2012
12) Calculating albedo: Metenorm 6 Handbook part II: Theory, Meteotest 2007
13) Magnetic declination:
Geomag 0.9.2015, Christopher Weiss…
.
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
…
doing this with the current tools or a bit of scripting since the Flickr API allows you to make requests in a REST format, but utilizing the Flickr.net API library makes it much simpler.
First and foremost, you need a Flickr API key...do you have one of those?
A great way to get to know the Flickr API is with the API Explorer. Here is a link to the page for the flickr.photos.search method explorer: http://www.flickr.com/services/api/explore/flickr.photos.search
The cool thing about this page is that it generates the REST Http call towards the bottom. So, here is what I did:
1. Grab the coordinates of the bounding box per Flickr API request:
bbox (Optional)
A comma-delimited list of 4 values defining the Bounding Box of the area that will be searched. The 4 values represent the bottom-left corner of the box and the top-right corner, minimum_longitude, minimum_latitude, maximum_longitude, maximum_latitude. Longitude has a range of -180 to 180 , latitude of -90 to 90. Defaults to -180, -90, 180, 90 if not specified. Unlike standard photo queries, geo (or bounding box) queries will only return 250 results per page. Geo queries require some sort of limiting agent in order to prevent the database from crying. This is basically like the check against "parameterless searches" for queries without a geo component. A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters — If no limiting factor is passed we return only photos added in the last 12 hours (though we may extend the limit in the future).
So, I went to Google Earth, picked a city (London, UK) and dropped two pins:
This gave me two locations, which I can put into the Explorer Page next to the bbox option. Here is what I put for these two points: -0.155941,51.496768,-0.116783,51.511431
2. Check has_geo
3. In extras, type in geo
4. Make the call!
You will see a list of responses in an XML format, these responses will be from the first page. Geolocated photos are limited to 250 / page, so you will have to grab them page by page.
If you want to add more options (minimum upload date, maximum upload date, etc) you can do this as well)
The best is at the bottom, you get the full http call for this: http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=ffd44f601393a46e86aa3a5f8a013360&bbox=-0.155941%2C51.496768%2C-0.116783%2C51.511431&has_geo=&extras=geo&format=rest&api_sig=b42330e5d1523bd5fe60c2ad43acde99
Notice this call has some other api key, you should eventually replace this with your own.
You could copy and paste this into a browser and you will get the results with the latitude and longitude:
So this is really what you need to know to do this through GH. Since gHowl has an XML parser component that can access files on the web, you should be able to use the same http call into this component.
Eventually, we get a response, and we need to grab the lat and lon data. With gHowl we can map these to xyz coordinates, and generate the heatmap...this is just a linear mapping:
Attached are both the Rhino file and the Grasshopper file, as well as the image underlay.
I am working on a series of components that makes this more straightforward, but for now, this should get you started.
…
ng is deciding how and where to store your data. If you're writing textual code using any one of a huge number of programming languages there are a lot of different options, each with its own benefits and drawbacks. Sometimes you just need to store a single data point. At other times you may need a list of exactly one hundred data points. At other times still circumstances may demand a list of a variable number of data points.
In programming jargon, lists and arrays are typically used to store an ordered collection of data points, where each item is directly accessible. Bags and hash sets are examples of unordered data storage. These storage mechanisms do not have a concept of which data comes first and which next, but they are much better at searching the data set for specific values. Stacks and queues are ordered data structures where only the youngest or oldest data points are accessible respectively. These are popular structures for code designed to create and execute schedules. Linked lists are chains of consecutive data points, where each point knows only about its direct neighbours. As a result, it's a lot of work to find the one-millionth point in a linked list, but it's incredibly efficient to insert or remove points from the middle of the chain. Dictionaries store data in the form of key-value pairs, allowing one to index complicated data points using simple lookup codes.
The above is a just a small sampling of popular data storage mechanisms, there are many, many others. From multidimensional arrays to SQL databases. From readonly collections to concurrent k-dTrees. It takes a fair amount of knowledge and practice to be able to navigate this bewildering sea of options and pick the best suited storage mechanism for any particular problem. We did not wish to confront our users with this plethora of programmatic principles, and instead decided to offer only a single data storage mechanism.*
Data storage in Grasshopper
In order to see what mechanism would be optimal for Grasshopper, it is necessary to first list the different possible ways in which components may wish to access and store data, and also how families of data points flow through a Grasshopper network, often acquiring more complexity over time.
A lot of components operate on individual values and also output individual values as results. This is the simplest category, let's call it 1:1 (pronounced as "one to one", indicating a mapping from single inputs to single outputs). Two examples of 1:1 components are Subtraction and Construct Point. Subtraction takes two arguments on the left (A and B), and outputs the difference (A-B) to the right. Even when the component is called upon to calculate the difference between two collections of 12 million values each, at any one time it only cares about three values; A, B and the difference between the two. Similarly, Construct Point takes three separate numbers as input arguments and combines them to form a single xyz point.
Another common category of components create lists of data from single input values. We'll refer to these components as 1:N. Range and Divide Curve are oft used examples in this category. Range takes a single numeric domain and a single integer, but it outputs a list of numbers that divide the domain into the specified number of steps. Similarly, Divide Curve requires a single curve and a division count, but it outputs several lists of data, where the length of each list is a function of the division count.
The opposite behaviour also occurs. Common N:1 components are Polyline and Loft, both of which consume a list of points and curves respectively, yet output only a single curve or surface.
Lastly (in the list category), N:N components are also available. A fair number of components operate on lists of data and also output lists of data. Sort and Reverse List are examples of N:N components you will almost certainly encounter when using Grasshopper. It is true that N:N components mostly fall into the data management category, in the sense that they are mostly employed to change the way data is stored, rather than to create entirely new data, but they are common and important nonetheless.
A rare few components are even more complex than 1:N, N:1, or N:N, in that they are not content to operate on or output single lists of data points. The Divide Surface and Square Grid components want to output not just lists of points, but several lists of points, each of which represents a single row or column in a grid. We can refer to these components as 1:N' or N':1 or N:N' or ... depending on how the inputs and outputs are defined.
The above listing of data mapping categories encapsulate all components that ship with Grasshopper, though they do not necessarily minister to all imaginable mappings. However in the spirit of getting on with the software it was decided that a data structure that could handle individual values, lists of values, and lists of lists of values would solve at least 99% of the then existing problems and was thus considered to be a 'good thing'.
Data storage as the outcome of a process
If the problems of 1:N' mappings only occurred in those few components to do with grids, it would probably not warrant support for lists-of-lists in the core data structure. However, 1:N' or N:N' mappings can be the result of the concatenation of two or more 1:N components. Consider the following case: A collection of three polysurfaces (a box, a capped cylinder, and a triangular prism) is imported from Rhino into Grasshopper. The shapes are all exploded into their separate faces, resulting in 6 faces for the box, 3 for the cylinder, and 5 for the prism. Across each face, a collection of isocurves is drawn, resembling a hatching. Ultimately, each isocurve is divided into equally spaced points.
This is not an unreasonably elaborate case, but it already shows how shockingly quickly layers of complexity are introduced into the data as it flows from the left to the right side of the network.
It's no good ending up with a single huge list containing all the points. The data structure we use must be detailed enough to allow us to select from it any logical subset. This means that the ultimate data structure must contain a record of all the mappings that were applied from start to finish. It must be possible to select all the points that are associated with the second polysurface, but not the first or third. It must also be possible to select all points that are associated with the first face of each polysurface, but not any subsequent faces. Or a selection which includes only the fourth point of each division and no others.
The only way such selection sets can be defined, is if the data structure contains a record of the "history" of each data point. I.e. for every point we must be able to figure out which original shape it came from (the cube, the cylinder or the prism), which of the exploded faces it is associated with, which isocurve on that face was involved and the index of the point within the curve division family.
A flexible mechanism for variable history records.
The storage constraints mentioned so far (to wit, the requirement of storing individual values, lists of values, and lists of lists of values), combined with the relational constraints (to wit, the ability to measure the relatedness of various lists within the entire collection) lead us to Data Trees. The data structure we chose is certainly not the only imaginable solution to this problem, and due to its terse notation can appear fairly obtuse to the untrained eye. However since data trees only employ non-negative integers to identify both lists and items within lists, the structure is very amenable to simple arithmetic operations, which makes the structure very pliable from an algorithmic point of view.
A data tree is an ordered collection of lists. Each list is associated with a path, which serves as the identifier of that list. This means that two lists in the same tree cannot have the same path. A path is a collection of one or more non-negative integers. Path notation employs curly brackets and semi-colons as separators. The simplest path contains only the number zero and is written as: {0}. More complicated paths containing more elements are written as: {2;4;6}. Just as a path identifies a list within the tree, an index identifies a data point within a list. An index is always a single, non-negative integer. Indices are written inside square brackets and appended to path notation, in order to fully identify a single piece of data within an entire data tree: {2,4,6}[10].
Since both path elements and indices are zero-based (we start counting at zero, not one), there is a slight disconnect between the ordinality and the cardinality of numbers within data trees. The first element equals index 0, the second element can be found at index 1, the third element maps to index 2, and so on and so forth. This means that the "Eleventh point of the seventh isocurve of the fifth face of the third polysurface" will be written as {2;4;6}[10]. The first path element corresponds with the oldest mapping that occurred within the file, and each subsequent element represents a more recent operation. In this sense the path elements can be likened to taxonomic identifiers. The species {Animalia;Mammalia;Hominidea;Homo} and {Animalia;Mammalia;Hominidea;Pan} are more closely related to each other than to {Animalia;Mammalia; Cervidea;Rangifer}** because they share more codes at the start of their classification. Similarly, the paths {2;4;4} and {2;4;6} are more closely related to each other than they are to {2;3;5}.
The messy reality of data trees.
Although you may agree with me that in theory the data tree approach is solid, you may still get frustrated at the rate at which data trees grow more complex. Often Grasshopper will choose to add additional elements to the paths in a tree where none in fact is needed, resulting in paths that all share a lot of zeroes in certain places. For example a data tree might contain the paths:
{0;0;0;0;0}
{0;0;0;0;1}
{0;0;0;0;2}
{0;0;0;0;3}
{0;0;1;0;0}
{0;0;1;0;1}
{0;0;1;0;2}
{0;0;1;0;3}
instead of the far more economical:
{0;0}
{0;1}
{0;2}
{0;3}
{1;0}
{1;1}
{1;2}
{1;3}
The reason all these zeroes are added is because we value consistency over economics. It doesn't matter whether a component actually outputs more than one list, if the component belongs to the 1:N, 1:N', or N:N' groups, it will always add an extra integer to all the paths, because some day in the future, when the inputs change, it may need that extra integer to keep its lists untangled. We feel it's bad behaviour for the topology of a data tree to be subject to the topical values in that tree. Any component which relies on a specific topology will no longer work when that topology changes, and that should happen as seldom as possible.
Conclusion
Although data trees can be difficult to work with and probably cause more confusion than any other part of Grasshopper, they seem to work well in the majority of cases and we haven't been able to come up with a better solution. That's not to say we never will, but data trees are here to stay for the foreseeable future.
* This is not something we hit on immediately. The very first versions of Grasshopper only allowed for the storage of a single data point per parameter, making operations like [Loft] or [Divide Curve] impossible. Later versions allowed for a single list per parameter, which was still insufficient for all but the most simple algorithms.
** I'm skipping a lot of taxonometric classifications here to keep it simple.…
Added by David Rutten at 2:22pm on January 20, 2015