.
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
…
ed!!! :)
It's a bout motion of some points, lines and circles ... After the motion my supervisor would be very glad, if this is possible:
t=0 ... the motion begins to start ... t=1 ... the motion is finished ... Animate => virtualdub => gif animation ...
I need to highlight these points ... but not all at the same time ...
To be honest it's not really about highlighting the points, but it's the same thing I guess ...
I need to show, that these three lines are parallel to each other ...
So I construct 2 lines with a distance for example 1 cm and each has the length of 2 cm and they make a 60° angle with the x-axis. Then I group them in a group component. So this is the problem ...
I could do that: when t happens to be 1, then I could show all the lines at the same time ... But this is not, what my supervisor is asking me to do ... he is asking me to let them show slowly one after another ...
If it gets too complicated, I'll jump in :D ... So I appreciate any help with this ... Thanks again :)
…
he arc distance.
(The distance difference/error between an arc and a chord is lesser if the segments are small compared to local curvature, as is your case. This is just a technicality...)
You also missed the advantage of use Grasshopper.
GH works with lists and trees of objects! You worked almost with only 1 value/object at time.
In my definition make a "Panel" component and link it step by step at outputs of every component I've used.
Try to understand the logic of the components:
every component have inputs and outputs "slots", if you move the mouse over them, a small bubble comment will come out telling:
1 What type of element should it be linked (symbol), like "number", "points", "curve", "surface", or "boolean"...
2 A short description
3 The current values or the current tree structure
By following the "flow" of the definition, try to also follow the values, and see how the components manage them.
(is this correct?? :D )
…
icosecond laser. In their wisdom the manufacturers of the laser have paired a cutting edge laser with an ancient CNC. The machine requires straight cut lines only (it doesn't handle curves) so these have to be converted from the original design, for which I'm using Grasshopper. Also, it requires multiple passes at a slight offset each time in order to ablate the silver successfully, generated again using Grasshopper.
So far so good. The machine controller is very picky about the format of Gcode it accepts, and it will only accept Gcode. So I am currently exporting the Grasshopper processed design as a dxf and running it through a dxf2gcode converter. This must then be manually processed (I use vi!) to change x references to c, y references to d and remove any references to z. Precision must be to 3 decimal places.
Silkworm is of course ideal for creating Gcode but is pretty specifically written for 3D printing I think? How configurable would it be with the config file to produce what I've described above, even if it's raw gcode which could then be wrapped manually with a header and footer? I'm thinking you'd have to rewrite portions of the module which is of course a bit pointless for such a specific task. Thought I'd ask anyway!
Cheers,
Simon
…
o I can apply your color gradient code (not shown but in GH file, off screen) after the Z sort:170316_SpheresStandardizer_2017Mar16b.gh
The fact that sphere 'Volume' is required a second time, after 'Pull' to wires, reminds me of a similar issue we dealt with last week: http://www.grasshopper3d.com/forum/topics/trimming-points-pulled-fr...
Seems to me that 'Pull Point' has a serious defect that requires extraordinary effort and/or kludgy code to remedy. If you don't graft the curves, 'Pull' returns each point pulled to it's nearest curve - exactly what you want, except without knowing which curve puled it?
In this code (above), you are using 'Pull D (Distance)', 'Smaller' with an arbitrary value as 'B' and 'Cull' to associate the closest curve with each point. In the other thread, I ended up creating brep cylinders around the curves to get the correct result. Ridiculous!!
I've spent a lot of time trying and utterly failing to find a truly proper solution. Is there one? (see "AHA!!!!" below!)
Searching the forum, I quickly found a couple old posts referring to the same problem:
pull point (bug?) May 27, 2009http://www.grasshopper3d.com/forum/topics/pull-point-bug
Small request April 18, 2013http://www.grasshopper3d.com/forum/topics/small-request
=========================
AHA!!!! I had given up and was about to post the above when I finally solved it. Created a cluster called 'PullT' that does the job, sorting by 'D (Distance)'. Here's the cluster:
And here's how it's used: 170316_SpheresStandardizer_2017Mar16c.gh
Notice that 'PullT' emits a cull pattern ('Pc') that can be used on related data to structure it into the same tree pattern - 'Volume (V)' in this case, so it's only used once. Could do the same with the original mesh spheres if there was reason to do so.
I've tested it on last week's code in the other thread and it seems to work fine; will post it there shortly.…
S of elements (chain links in this case), work first at low resolution to reduce compute time and avoid freeze-ups! When the model looks right you can increase resolution (i.e., the number of contours/links in this case).
The first effort (chainmail_2017Jan18b.gh) is getting points at the intersection of contour lines from two planes, XY and YZ, then getting surface normals for those points to 'Orient' the pair of links. This required ignoring all the extraneous points (due to multiple surfaces making up the "polysurface") returned by 'Srf CP (Surface Closest Point)' using two criteria: the 'D (Distance)' value and the 'uvP' coordinates that indicate an edge point (x=0 or 1, y=0 or 1).
Using the YZ plane worked well for the front and back surfaces but results in sparse points on the sides. Using the XZ plane instead has the opposite effect. Would be great if they could be blended somehow (animated gif):
Ultimately, it would probably work best to treat the body section and the arm as two different cylinders with contours conforming better to each surface separately.
The second method (chainmail_2017Jan18c.gh) uses only XY contours and 'DivLength' (divided by length), similar to a brick wall:
…
Added by Joseph Oster at 2:34pm on January 18, 2017
ood Samaritan) said: well ... since the Ducati won't start (not my fault officer) help that girl.
Good news: Almost ready, well for a pair of curves ... but the rest are bureaucracy than any(?) intelligence(?). Took me 27 minutes, 23 seconds and 45,78 milliseconds using the famous cut and paste method of mine - US patent pending (from other C# stuff, that is).
I hear you: but the planes don't rotate. Well, that's exactly "almost" is used: the rotation logic IS NOT that simple (can you guess the reason?).
How to use it (up to that point - FULL detail Louvers used, he he):
(a) Load the Rhino file first. It doesn't display anything but the Block Manager can tell you a different story.
(b) Load the definition (it doesn't look that impressive at least as regards the graphics, he he) AND read all the comments.
(c) Go there and enable the second script (turn false to true, DO NOT turn false the second boolean flag because the simplified Louver is not yet imported).
(d) Prior changing the geometry via the first C#, disable the script (or keep it active if your computer is fast). But ... if you change the widthOfPanel value ... you'll need CATIA for that I'm afraid (create on the fly the parametric Louver assembly in full detail, in REAL-TIME).
I hear you: where are the wooden things? Well ... that's kid's stuff my dear just extruding a BrepFace both sides (V2 does this).
I hear you: are you saying that you'll make ALL the curves with C# (control their shape individually PER pair) and not just place the louvers into the existing curves provided? Yes that is what V3 does (it's ready but some minor things remain).
I hear you: and what V4 does then? Well ... have faith, he he
All that provided that ... that |$@%@$ Ducati could start (what's wrong with this thing? that's the 1M question).
best, The Troll…
occur more than once in the same list, and different elements with identical values can occur more than once. Also, a list may contain lack of elements, referred to as "nulls".
Sets. Strictly speaking a Set is a mathematical construct which adheres to a strict collection of rules and limitations. Basically, a Set is the same as a List, with the exception that it cannot contain the same element more than once, or indeed two or more different elements with the same values. You see, in mathematics there is no difference between a value and an instance of that value, they are the same thing. In programming however it is possible to store the number 7 in more than one spot in the RAM. Grasshopper does not enforce this rule very strongly though, you can use a lot of Set components on lists that have multiple occurrences of the same value. The big difference between Lists and Sets in Grasshopper is that Sets are only defined for simple data types that have trivial equality comparisons. Basically: booleans, integers, numbers, complex numbers, strings, points, vectors, colours and intervals. Lists can contain all kinds of data.
Strings. Strings are text. There's nothing more to it. I don't know why early programmers chose to call them strings, but I suppose it's a better description of the memory representation of them. Strings are essentially sequences of individual characters.
Trees. Trees are the way all data is stored in Grasshopper. Even when you only have a single item, it will still be stored in a tree. A tree is a sorted collection of lists, where each list is identified by a path. A specific path can only occur once in a tree, when you merge two trees together, lists with identical paths are appended to each other. Trees are an attempt to losslessly represent not just the data itself, but also the history of that data. Imagine you have 4 curves {A,B,C,D} and you divide each into 3 points {X,Y,Z}. Then, for each of those points you create a new line segment {X',Y',Z'} and then divide each of those line segments again into 5 points each {K,L,M,N,O}. The way data is stored in trees, it should be possible to figure out whether a point M belongs to X' or to Z', and whether that X' or Z' came from A, B, C or D. This is why paths are often quite long after a while, because they encode a lot of history.
Paths. A Path is nothing more than a list of integers. It's denoted using curly brackets and semi-colons: {A;B;...;Z}. A Path should never be empty {} or have negative integers {0;-1}, but it is certainly possible to create a path like this and it probably won't even crash Grasshopper. Paths are 'grown' by components that (potentially) create more than one output value for a single input value. For example Divide Curve. It creates N points for every single input curve. In cases like this a new integer is appended to the end of the path.
In the next release the Path logic in Grasshopper is somewhat different. I fixed a number of obscure bugs (hopefully without introducing new fresh bugs) and special cased certain operations to somewhat reduce the speed at which paths grow. This may well break files that rely on a specific tree layout, but I hope the temporary sacrifice will be worth the long-term benefits.
--
David Rutten
david@mcneel.com
Poprad, Slovakia…
ficiently learn concepts and features of Grasshopper at an accelerated pace in an instructor-led hands-on instruction environment. The advantages of using Grasshopper in preliminary design and concept development come to life since the students will be able to create their models on TROTEC Lasers machine. Participants should have basic knowledge of Rhino 5. Details...
Location:TROTEC - Laser (map)7610 Market DriveCanton, MI 48187United States
Instructor:
Andres Gonzalez, ART, McNeel Miami
RhinoFabStudio
To Register:e-mail: Jackie@mcneel.comphone: 305-513-4445http://mcneelmiami.com/training1…
generate a triangle mesh from your set of points using Delaunay Algorithm (than may leave some long thin triangles at the border, that may need to be filtered)
b) use Weaverbirds Constant Quad subdivision to get your undeformed base unit
c) adjust each faces border, so the border polygon starts (and ends) at one of the original generating points. (might do this differenly. It's just so i know the position of each edge or vertex relative to the given original corner of the base unit)
d) move the original corners of the base unit according to the attractor point
Now to simulate your sinusoidal shape:
I use edgeSrf to create a patch from four non planar edge curve.
Two of those are the unmodfied subdivision edges.
The other two are nurbs curves made from four Points:
1) the end point that at the center of the base units edge.
2) one Point somewhere along the edge
those two will ensure continuity between the adjacent subdivision quads.
3) that intermediate Point projected to a plane that is normal to the direction of movement of the final end point
4) the original element Corner, after moving.
the last two will make the curve round out and make sure that all other adjacent curves will join somewhat continously. you may change that to whatever suits you.…