Hi everyone- I have a herringbone paving field and I would like to use GH to separate these into different types to make it look like a gradient. I looked at a few old tutorials like this one and figured out how to make this happen at a small scale using closest points, consec domain, and jitter.
Trial 2 (closer to what I want):
fyi: As you can see in the 2nd trial, the ‘centerline’ isn’t truly center so I used “point in curve” to cull which ones are on the bottom VS upper side.
I am trying this one more time to fit a different urban condition. While this is still dividing the pavers according to their distance away from the ‘center line,’ when I apply jitter, it doesn’t “jitter” evenly anymore like the previous two screenshots.
Paving divided into 4 types
Jitter 0.001 applied – instead of a even jitter, pattern emerges
Jitter 0.1 applied
What’s going on here? Besides the different inputs, I haven’t changed anything on the script. How can I make my jitters seem more even like it did before? Something must be out of order or sequenced weird, but I can’t figure out where that’s happening.
Attached is the script with internalized data. The center line is really long because I want to do this to a large area (computer performance willing) - but wanted to make sure it worked at this scale first.
choi-paver-gradient.gh (6.2 MB)
Off hand, it looks like a data tree issue. Your “INPUT lower half boundary” curve is not internalized so not much I can do?
59,840 “paving pattern curves”! Wow.
Oops! All I did was draw a rectangle that started at the centerline and encapsulated all of the “lower half” curves. Should be corrected in this attachment.
Yeah… a LOT of pavers, yes. Totally agreed. Part of this operation is trying to prove to people who pay me that 1000s and 100s of curves bog down performance… But automating this in GH is a lot easier than drawing this by hand in CAD as they were doing prior to my studies.
choi-paver-gradient.gh (6.2 MB)
I was in the process of doing that, thanks for saving me the trouble. However, it appears to me that the “curve to affect gradient” is not really in the center of your pavers pattern. Consequently, the “lower half boundary” curve causes Dispatch to place 27,456 pavers in one “half” (‘A’) and 32,38 in the other “half” (‘B’).
That aside, it’s an “interesting” approach. I would think that distance from the centerline alone would be all you need to know to assign colors without any need to treat them as two groups.
Skipping the slow (in this case) Boundary component, one can see the assigned colors this way:
I would change your “distance bt paver and curve” group as follows:
It looks like you want the Jitter swap to be limited to adjacent distance/color domains?
I’ll have to give it a little more thought…
choi-paver-gradient_2020Aug27a.gh (6.2 MB)
Here is a hasty adaptation (simplification?) that avoids splitting the pavers into two groups. My instinct is to think about it this way.
Hey @Joseph_Oster! Thanks for taking the time to look through this. Yes, the centerline is not actually centered. The study that we’re doing includes an intersection, and one side of the road has a wider sidewalk than the other. So entwine/bang based on which side they’re on was a quick idea I had… I had just learned about entwine so I’m probably overusing it.
This method worked in the “trial 2” version which also didn’t have a true centerline. I guess I’m trying to figure out why it’s not working exactly in this version.
And thanks for showing me closest curve… d’oh!
Just a thought. Does the order of the curves have to do with anything? It seems awfully haphazard. Would reordering this to some kind of logic make the jitter work?
FYI I created this paving pattern by arraying a group of these herringbones. I thought I did the same thing for the previous version too, so again I’m not sure what the difference is in this file.
It would change the outcome but I’m not sure how Jitter would be affected. I’m grasping for ideas but haven’t got a breakthrough yet to match your “closer to what I want” image, which suggests a semi-orderly exchange of pavers along the boundaries of each domain/branch.
My inclination is to defer Jitter (and possible sorting?) until after the pavers are sifted into their respective domain/branches, possibly replacing Jitter with a different random method, but that might be nothing more than a mental convenience. It’s easy to bypass Jitter by connecting ReMap ‘R’ output directly to Includes ‘V’ input.
Here is a version that is simplified further:
P.S. Oh look, a quick addition of Sort Points (yellow group) with a dramatic outcome, though skewed from the centerline.
GIGO, not really helpful even when I connect the sorted points to Crv CP…
Oh gosh, seriously thanks for spending time to work through this. I’m gonna experiment with the sort points. The visual impact matters most, rather than the perfect script, and the sort points is bringing out the intended effect. I wonder if the cplane/ the way the pavers are oriented has to do with some of the issues.
Ultimately the fate of this outcome is… for it to be brought back in CAD for construction documents haha. So an imperfect pattern is still OK since we’ll be working on it more.
Yes, sorting the pavers would be easier if the grid were square with the ‘World XY’ axes. Whether or not it makes a difference depends on what the “final” algorithim turns out to be.
Just FYI, I compared my latest simplified version (without sorting) to your original, being careful to match the Jitter and seed values in both. At first, I was disappointed to notice a slight difference in results until I realized why. Two differences in the code:
- By splitting the pavers into two groups as you did, you got two different domain bounds where I have only one. So my domains are the same on both sides, yours are not.
- Your distance values are the result of measuring to the closest point in a cloud (Divide Curve) whereas mine are from the distance to the “centerline” (Crv CP).
I’m still not sure what to do next but am happy with the simplified code.
Here’s a thing that looks pretty good? I rotated the paver curves, their center points and the centerline, sorted the pavers as before, reduced the jitter factor (a lot!) and voila.
The Boundary surface component takes more than 13 minutes for ~60K surfaces so I’ll add an image to this post when it finishes.
P.S. Here is the same model with Boundary enabled (13.7m) and connected to Preview:
Sorting the pavers was indeed the key insight that makes this work. More on that below.
First though, this post adds refinements including separating the ~60K paver geometry from the GH code, something I wish I had done at the very beginning. That data is now in a separate file that uses Data Output to pass the paver curve geometry to the small piece of code that uses it. The geometry doesn’t need to be re-posted each time the code changes - a Rhino file would work as well.
choi-pavers_2020Aug28a.gh (6.2 MB)
The code that sorts the pavers and creates the gradient is now quite small. It uses Data Input to read the pavers passed from the choi-pavers_2020Aug28a.gh file (which must be opened first).
Notice that I added two more Rotate components to restore the pavers and their center points to the original orientation after sorting them.
As to sorting, this image shows the result (using only the first 1000 points because Point List is painfully slow with 60K points!). The sequence starts at the bottom left and proceeds vertically, sorting all the points with the same X value by Y. Then the next X value to the right is sorted by Y, and so on.
The very small value required by Jitter is to minimize the vertical swapping of adjacent pavers in this sorted list. Pretty cool and simpler than I expected!
I think there’s a somewhat simpler technique that will help you here. Jitter is very dependent on list order — in this case we’d probably prefer to preserve the order of the original list. This way we also no longer need to do any rotating or make any other assumptions about the shape of the curve or the arrangement of the pavers — it will work with any set of curves and any attractor.
The tactic I use is this:
- find the distance from every paver to the attractor curve. I’d use Curve Closest Point for this, using a point for the center of each paver.
- Add some random noise to the distance value itself. The larger this value, the greater the “blur” between color zones.
- Remap the Distance+noise values to be between 0-1
- find the domain each remapped value fits within with Find Domain.
- The index of the “found domain” is now the index for your paver.
- Use Member Index to get the counts of each paver color.
The other thing I’d suggest is to treat your pavers as Meshes rather than creating Boundary Surfaces in order to visualize them. Using that in tandem with Mesh Color will be much faster.
choi-paver-gradient.gh (344.3 KB)
Here is the same code with Boundary enabled and using a Jitter ‘S’ (Seed) value of 132. I can see anomalies in the pattern due to gaps in the sorted pavers, which are caused by the zig-zag pattern that displaces their center points, which in turn affects Sort Points. A better sorting algorithm would avoid these anomalies.
OH!!! I just noticed that these center points have a range of Z values!? 16.530204 To 17.708645
And the centerline is sloped and slightly below all of them. Arrgh…
I like this approach VERY MUCH Andrew! (@andheum) Way better. It’s easy to get fixated on a particular path and stop looking for a better approach. Using a mesh is much faster too, though I adapted it to use Boundary surface. Much simpler and without the anomalies caused by Sort Points and Jitter.
I prefer your use of Find Domain to get the appropriate color too but didn’t go quite that far (yet) in changing my code.
You didn’t internalize the paver curves but can use the same Data Input from my earlier post to read them from the choi-pavers_2020Aug28a.gh Data Output.
This is what I was actually looking for! Thank you for seeing through my “ooh look at jitter it’s a shiny toy!” and providing the better solution to this.
Thanks @Joseph_Oster for your time as well! I learned a lot from both of you.