Rhino Viewport-like CPlanes in GrassHopper?

Is it possible to set a temporary construction plane in GrassHopper like we do manually in Rhino?

I’m currently spending some learning hours on a organic model (a shoulder) with “lesser than distinct” inclination angles of local CPlanes. I would like to navigate in World at times, and in (model) local CPlanes at times, due to the fact that the real world “problem domain” uses both World for the overall orientation, and local CPlanes for detail specifications of rotation angles etc (for example, the arm’s movement limits and angles are defined in World, while details about the shoulder joint (humeral head and glenoid socket) is specified in a local CPlane being aligned with the (joint’s) socket, etc.

The model will probably be animated and simulated as well, and movement patterns will be defined both World and in locally aligned Plane(s). I know there are plenty of Plane components, but it seem to me that they are meant to be used or translating objects rather than Planes being used as reference planes as when manually modelling in Rhino.

What strategies are you guys using for handling alike ‘CPlane cases’ when working with GrassHopper?

// Rolf

No, all Grasshopper geometry is in World XYZ coordinates. This is a feature request which occasionally comes up, but I don’t really have any good ideas on how to implement it. Any suggestions?

what’s with the cake?

1 Like

seems 4 years anniversary :smiley:

1 Like

One more year and I get a set-of-steak-knives-icon.


something worth remembering :smile: but maybe a cake knife icon would seem more reasonable,
as long as the knife does not look like a shoe :wink: happy anniversary in that case.


Hm. Got the cold fish right in my lap… But perhaps the following could give some ideas about how to implement something that would also stay within, or at least stay near the current paradigm.

First of all, CPlanes needs a context. GrassHopper has no natural context since everything is a process (a “time lapse”) rather than something happening in 3D space. In manual Rhino you can have unlimited “local” CPlanes in 3D space, at all times, without the CPlanes affecting any unwanted parts. The user decides WHEN and WHERE a certain CPlane is to be used, and actions taken while CPLane is active is picked in detail by the user.

In GrassHopper on the other hand, the “when” is always present, and an activated CPlane would potentially affect everything in the model with unpredictable results. So, since the process in GrassHopper changing the model proceeds along data flows, the CPlanes must be part of and limited to that flow.

So we need to eliminate time out of the problem. From this follows, I do believe, that the options left are space. Two dimensional space.

Groups. Groups may do the trick. If Grouping the parts of a GH model that is affected by a CPlane definition, then time is out and the effective transformations are constrained to a limited visual area of components. I’m thinking in terms of CPlaneGroups.

Today Groups are only visual adornments. But they could be enhanced into providing with just that context which is needed for applying CPlanes to parts of a geometry. For this reason I think that the standard groups should be enhanced with the ability to - implicitly - define the Plane for any components inside of it : CPlaneGroups.

Scope - The default Plane in any CPlaneGroup would of course be World, but if the CPlane is transformed, either by property settings (see text about “radio buttons” in Fig1.) or by transformations inside or from outside the CPlaneGroup, then all the components inside should be translated as well.

External Ports - CPlaneGroups should have connectors (ports) just like any other Gh Component, and thus a CPlaneGroup can have a rotated Plane as it’s input as well as its output, thus enabling “chaining” of CPlane transformations from one CPlaneGroup to another CPlaneGroup, including any geometry contents (see external ports in Fig1. below).

Internal Ports - The Plane related logic (dark area in Fig.1.) of a CPlaneGroup should of course not be visible, but the ports involved should be. This is what the transparent panels intends to indicate. In the frame of the CPlanGroup the ports of all possible Plane transformation schemes should be available, directed INWARDS from the frame border (only the port icons, the white “bumps”, that is). In my opinion the actual Plane rotations doesn’t have to be part of the visible component layout, unless the user specifies a plane transformation on his own. When he specifies hiw own rotation, then he can feed the CPlaneGroup with that Plane transformation in order to make the whole group become affected. Plane components would therefore be “immune” from the influence of the CPlaneGroup context and must always explicitly have their input ports feed connected (except for possibly the ConstructPlane component).

Fig.1 Two connected (chained) CPlaneGroups where local CPlane definition affects only components inside the group, unless that very CPlane transformation is “exported” as well, as it is in this case (default Plane input value is World, of course).

So what do you think?

One more thing - a CPlaneGroup would normaly, in order to be meaningful, have to be populated by components while designing the Gh network meant to be affected by the CPlane. But the group area canvas isn’t a very forgiving canvas to work on, so perhaps CPlaneGroups should be drag-transparent, meaning that it only has a frame, and so one can pick and drag things inside like if it was on the regular canvas. A checkbox at the border, or in a corner could make the Group area “filled” again like regular groups and at the same time, include any components (and subgroups) inside.

Notice also that in this context, if missing that a component may not be “attached” to a group (while still inside of it), then it is no longer only a “layout bug” (like now) but a logical bug, and most likely a very serious one at that. (The very idea with being inside (not “attached to”) the group is in this context that it should be influenced by the Plane transformation. This must be visualized very clearly, by “being inside”).

In short: Anything inside the CPlaneGroup frame should be “infested” by any active Plane transformations for that CPlaneGroup.


Unique Icon’s in the corners, and perhaps even the frame, could indicate if the CPlaneGroup has deviated its plane from World. A lit moon icon replaces an earth icon in the corners? :slight_smile:

// Rolf

1 Like

I agree that a solution would ideally be found within the existing UI paradigm of objects and wires. And indeed chaining would be a vital feature, without which it would be very cumbersome to manage these relationships.

There’s basically four levels on which a custom CPlane could be assigned:

  1. The document level (this would be exceedingly awkward in my opinion).
  2. The collection level (as per your CPlaneGroup suggestion).
  3. The component level (CPlaneGroups would allow for this, but there are more elegant solutions for this case).
  4. The datum level (sounds like it would be really complicated, but very flexible).

These levels are not mutually exclusive, but there are always ambiguities that arise when more than one solution is provided.

A mechanism for adding additional inputs to components (not just CPlanes, but also Tolerance, Preview Colour, Preview Dash Pattern, Warning/Error Modifiers, … list goes on pretty much indefinitely) which has been discussed for a while is what’s called ‘leech objects’. These are basically free floating parameters that can be attached to those components that understand what they are for:

This is primarily a component-level solution, but I guess leeches could be attached to groups as well, allowing groups to take on this additional function as you proposed.

There are three problems with the collection-level approach with respect to the component-level approach:

  1. It is possible that a component is part of more than one collection. Could be either nested collections of intersecting collections. In such cases, is there an error? Does one collection win? Are the collection transformations combined? If so, in what order?
  2. If a component is copy-pasted, it will lose the associated CPlane it was given via membership of some collection.
  3. It is not always easy to see whether or not a component actually is part of a group. It could be within the group boundaries, yet still not be part of it. This is a problem with groups in general, but it gets extra serious when groups become functional objects in addition to ‘visual adornments’.

On the whole I’m fairly optimistic about such an approach, I think it would solve a lot of problems without being difficult to understand. the one remaining issue though is datum-level modifiers. Is it important to be able to specify modifiers such as CPlanes to individual objects? If so, are leeches/CPlaneGroups flexible enough to do it, or are they only able to set a single CPlane?

[quote=“DavidRutten, post:8, topic:44538”]
There are three problems with the collection-level approach with respect to the component-level approach:

  1. It is possible that a component is part of more than one collection. Could be either nested collections of intersecting collections. In such cases, is there an error? Does one collection win? Are the collection transformations combined? If so, in what order? [/quote]

I think that if a component is “within” the area of one or more CPlaneGroups, then it is infested. If it is within two CPlaneGroups (that both have their CPlane modified) then it is affected by both - in z-order. This seems to me to be the most intuitive.

But for obvious reasons I would avoid stacking CPlaneGroups…

If it is deemed to risky to allow implicitly chained overlapping CPGs then one could require that the one on top (in z order) is explicitly connected - via it’s input connector - in order to avoid ambiguity.

But I think that one rule is better than two. “Anything within” is implicitly infested, except for possibly the Plane components themself which needs to be explicitly connected. But for example a ConstructPlane should take on the CPlane transform it’s introduced within[*], just like it takes on World as default outside a CPG. One rule is simpler than two. :slight_smile:

[*] - “within” as opposed to “member of” (which is not visibly obvious)

[quote=“DavidRutten, post:8, topic:44538”]
If a component is copy-pasted, it will lose the associated CPlane it was given via membership of some collection.[/quote]

Yes. I think that a component must be explicitly within a CPlaneGroup for the geometry to be affected by it.

Most important should be that it is always obvious to the user what’s happening in the model. But if the same CPlaneGroup transform is to be used elsewhere in the same GH model, then one can connect the new CPlaneGroup to the first one (with the std wires) and so propagate the CPlane to any number of other CPlaneGroups.

[quote=“DavidRutten, post:8, topic:44538”]
It is not always easy to see whether or not a component actually is part of a group. It could be within the group boundaries, yet still not be part of it. This is a problem with groups in general, but it gets extra serious when groups become functional objects in addition to ‘visual adornments’.[/quote]
Yes. In my post I addressed that problem by making a distinction between being “within” (visually within the borders of a CPG) and being “part of” a group.

I think that CPlaneGroups should be very “poisonous” or “radiant” in that any component or group being visibly within its borders (even touched by a CPG border) should be affected. Then no ambiguity is possible.

The idea that a CPlaneGroup should be component-like, in that it has in-ports and out-ports, allows for propagating its particular magic in the same manner as any other component. This would be necessary since further processing of the geometry may take place elsewhere (outside a specific CPG), only to be further processed again within the same “CPG transform” so to speak. Then one can just make a new CPG and plug in a wire from the first CPG and continue. Aso.


Edit 2:
The way I think of it is that there’s a one to many relation of the implicit Plane from a CPlaneGroup to objects ( [Plane]-1----*-[Object] ) while keeping existing behavior for objects, that is, feeding a component with a Plane component should behave as they do now - only difference would be that the components would - already- have been implicitly transformed by the underlaying CPlaneGroup before any further Plane manipulations by Plane components inside the CPG would take place. So implicit (group-) and explicit (component-) Plane transformations should add up.

Gh Components and the CPlaneGroup should have type compatible in-ports from exclusively one (1) other plane component or CPlaneGroup (recursive relation; [Plane]1-in------out-*[Plane] ).
(/End of edit 2)

All in all, components could be affected by one implicit Pane (from a CPlaneGroup) and/or one Plane component (only adding to the currently existing Plane concept).

This should be no absolute limitation since CPlaneGroup transforms will “add up” if chained, and so any object being plane-transformed on Plane A can be further Plane-transformed on Plane B, provided that Plane A propagates its Plane to the in-port of Plane B. Keeping this visible is important, I do believe.

BTW, if subclassing CPlaneGroup from the existing Group class, even making ALL groups into type CPlaneGroups, and defaulting to World, would that allow for existing groups being compatible with such an upcoming version?

I thought of CPlaneGroups in this way from start (as an extension of the Group class), and that CPGs could have a state (like Enabled and Preview states) that activates/deactivates the specific CPlaneBehavior.

Having a CPlaneEnabled property would make it easy to enhance existing models without braking them, and no need for regrouping components, just activate CPlaneEnabled on the upgraded ol’ group. And even then nothing bad would happen since groups with its inmate components would still default to World as they are in the current Gh versions. Only when manipulating the CPlane orientation of a group things would start to happen…

// Rolf

Wow when I think of this in context of GrassHopper, a CPlaneGroup can in effect be used as a “hinge” in complex animation sets. And each part (placed on individual CPGs) is then dead simple to control. Controlling a 6-axle robot? A piece of cake.

// Rolf

I tried to study the relational problems between the existing group concept and the potential new CPlaneGroup concept in the following “conceptual class” diagram (the existing class inheritance hierarchy I have no knowledge about, of course).

By drawing the diagram I realized that backwards compatibility is at risk if not only adding the functionality of the concept of “Implicit Planes” instead of trying to replace the current membership.

Fig.1. A pseudo-class diagram demonstrating the component relationships with existing groups and wannabe CPlaneGroups :

In the current concept, depicted as the role “explicitMemberOf” of a group including its multiplicity, is depicted in the upper left corner, Gh Components can “explictly” belong to none or to many groups (0…1). Explicit means here that the user have to explicitly add a component to a Group.

I would love to see a CPlaneGroup trapping its components implicitly if a component is located within the area of the group. But even if skipping this way of “becoming-a-member”-idea in the Plane concept, (staying only with the old explicit membership), there is still the concept of components being implicitly affected by the Plane aspect (apart from becoming members, that is).

And this aspect of implicitly inheriting the CPlaneGroup’s Plane can’t be a many-relation on par with the group membership(s). Instead it has to be limited to one (1) implicit Plane per CPlaneGroup and Component. This limited multiplicity (“1…n” instead of “n…n”) is depicted with the other link called “ImplicitPlaneInfo”, with the role name “implicitPlane” (located below the GhComponent class).

CPlaneGroups and its Components may share the transformation of a common ImplicitPlane, but CPlaneGroups being members of another CPlaneGroup have their own relation (via the role “affectedGroups”) See Fig.1.

I fear the situation in which a component, or CPlaneGroup appears to be members while not actually being attached to the CPlaneGroup, thus deceiving the user into thinking that any Plane manipulations actually affects the component or subgroup (because that would be a serious logical bug). It is for this reason I was thinking in terms of implicit membership (by its location withing the framed area of a group).

But “implicit membership” doesn’t play well with the current concept of explicitly assigned group membership, so the logical-bug-risk-problem perhaps should be addressed by other means. One solution would be if each component have a symbol indicating which group it is member of.

A solution for group-membership could start from the level of the Group itself. Each Group could have a Z-order indicator in the upper left corner (the z-order number from 0…+) and each member group on the next z-level would have the indicator saying 1:0 and 1:1 for the second group on the same first z-level. A group within one of those groups would be labeled 2:0 , meaning the first (0) group on the third (2) z-level. A level-n component inside the area of a group with the level<>n (not the same level number) would be flashing in red, meaning, “isn’t something wrong here?” (yes, the component or group isn’t assigned, or it’s on the wrong z-level). And so on.

In any case, the logical-bug-problem must be addressed since it’s much more serious than in the current version where non-assigned components, while visibly within the area of a group, only causes annoyance when trying to move the group (which btw also should be fixed, in my opinion).

For now I have no good idea about how to handle the compatibility problem of (current) groups and components being part of multiple groups. Perhaps it simply should not be allowed - under certain conditions. The compatibility problem could be reduced if the rule of “One Implicit Plane Only” (implies membership of only one CPlaneGroup as well) is enforced when, and only when, a CPlaneGroup has its Plane capability switched on, but not when its switched off (default).

And when the user attempts to switch on the property “CPlaneEnabled” (off by default), then the conflicting items could start flashing, prompting for the user to resolve the conflict.

In 100 out of 100 version upgrades from Gh1 to Gh2 this would work without hassle, simply because no one has ever designed Gh defs using CPlaneGroups before, so only the component layout would have to change a little bit if introducing this concept into an old Gh definition.

Or, was it the other way around? Anyway, the Gh Canvas should be perceived as a CPlaneGroup as well, defaulting to World. Anything on top of it, or “within” it is implicitly affected by its Plane. The Canvas only has no in-port and out-port.

So while we do not think of it, any components on the Gh Canvas actually has an “implict Plane” already now, because they think they reside in World, although no one knows why and how… (the blessings of zeros may play a role here). Anyway, for the above reason I let the Canvas inherit from CPlaneGroup in the diagram, meaning that Components always belong to at least one CPlaneGroup (the World Canvas). Therefore a component’s basic behavior doesn’t actually change if being placed inside another CPlaneGroup, it’s just being affected by a different transformation.

// Rolf

If by ‘upcoming version’ you mean Grasshopper 2.0, then hopefully yes. Although I am not interesting in adding a feature like this purely for local CPlanes. It needs to be something that allows assignment of all kinds of overrides.

Support for custom C-Planes (and indeed support for any kind of override) needs to be provided by the components. Furthermore these components must also signal to GH that they support a specific override. This sort of thing will put additional burden on component developers, so it is something that needs to be implemented at a very low level in the SDK or it will simply not be adopted.

There are plenty of open questions about implementation, but it’s my job to worry about that. Here I’d like to focus on how features like this should appear to the user.

Yes, I assumed that it’s a bit “too much” for Gh1.

Am I correct in understanding that you meant that Gh1 would not be updated “purely for local CPlanes”?

// Rolf

Grasshopper 1.0 is officially no longer being developed. We’re only fixing serious bugs. I occasionally do some minor new stuff just to keep sane, but this would be far too big a project that would even involve huge changes/additions to the SDK.


Sorry for bumping up this thread again, but I woke up this morning and couldn’t rid myself of the idea that Groups could be used for defining scope of concurrency as well. The concept of PlaneGroups perhaps would work also for ThreadGroups?

I didn’t analyse this very deeply, but at first thought it seems to me that Planes and Threads shares some data conflict risks - because the basic problem with a Plane is that of conflicting threads - one must restrict the scope of a Plane’s influence. In short, GH definitions must be “Plane Safe”, as well as Thread Safe.

Which is what lead to the idea that Groups could be a way to manage also thread safety. With the additional benefit of making the scope of separated threads visible.

Threads being one of them? :thinking:

// Rolf

I don’t think it would be a good idea to shift thread-safety responsibility to the end user. It’s just too easy to make a mistake.