Day 15: Between the landscape and the tree
Part of the Advent of Grok {Shan, Shui}*. See blog post for intro and table of contents.
These last days I’ve looked into how the overall picture got planned by mountplanner
in a series of objects consisting of a {tag, x, y}
, now let’s see how those large objects (features of the landscape) are actually drawn. This will hopefully cover the entire process from the whole picture to a singular stick on it—at least, some paths (mountains with some houses and some trees), assuming others have more or less the same logic.
You see, I am already starting to consider how I’ll sum it all up for publishing: probably the series of daily diary entries as I write them, but also some digestible high-level retelling of the whole picture. Looking into some of the lately rewritten methods with a fresh eye, I still see that it wouldn’t be that digestible for those just wanting a quick overview of the juiciest and the most important… But we’ll see.
Philosophy aside, to the Mount.mountain
!
As always I am starting with a mechanical cleanup of the attributes and such…
this.mountain = function(xoff, yoff, seed = 0,
{height = rand(100, 500), width = rand(400, 600), tex = 200, veg = true, ret = 0, color}
) {
tex
, veg
and ret
are a bit of a mystery, let’s see later. (I also was curious when the defaults are calculated—if it would be like in Python, once calculated on definition, those randomness in height/width would be totally screwed. Fortunately, in JS it is like in Ruby, on every call.)
Now, shallow view on the method shows that it calculates some list of points, and then calls internal function vegetate
many times to, probably, fill up the space for the mountain with various features.
On the road, as per habit, a way to screw things up (less appealing than usual…)
…but actually me changing reso = [10, 50]
to resolution = {x: 10, y: 50}
(and then using resolution.x
instead of reso[0]
) helped me to quickly find the hole in my mental model. According to usage, it was actually other way round, and reso[0]
meant “resolution for y
”.
The first working attempt for the point list calculation gives this:
var ptlist = range(resolution.y).
map( yi => {
hoff += rand(yoff / 100)
return range(resolution.x).map( xi => {
var x = (xi / resolution.x - 0.5) * Math.PI;
var y = Math.cos(x) * Noise.noise(x + 10, yi * 0.15, seed);
var p = 1 - yi / resolution.y;
return [(x / Math.PI) * w * p, -y * h * p + hoff]
})
})
But being bad at math (I used to love trigonometry so much 20 years ago… and now I can’t even for sure say “oh, of course it calculates an angle of that!”) I am still kinda lost in all that. Nevertheless, I am almost sure the names should change somehow: even with my rudimentary trigonometry leftovers, I see that x
and y
seem to be some angles, not coordinates.
But I’ll move forward for now, to the vegetate
method and further—and then we’ll see where it all leads in general.
That’s what I did to vegetate
:
function vegetate(treeFunc, growthRule, proofRule) {
canv += ptlist.
flatMap( (points, xi) => points.filter( (point, yi) => growthRule(xi, yi) ) ).
and_then( veglist => veglist.filter( (_, i) => proofRule(veglist, i) ) ).
map( ([x, y]) => treeFunc(x, y) ).
join()
}
So, it receives three functions:
- what to draw (named
treeFunc
, but actually the method code calls it for all picture features, architecture as lik as trees) - how to choose “whether to draw at this point of the grid” (
growthRule
) - how to decide “whether to really draw at this point, considering the list of points choosen” (
proofRule
)
It then filters through the grid twice with growthRule
, then proofRule
, and then draws! Simple.
Some observations:
- I half-suspect my names for
xi
andyi
(coordinates of the grid) are in the wrong order, considering we saw above thatptlist
was generatedy
-first (so the outer iteration is actually byy
s); but not sure yet, and not even sure it matters… - I suspect we might make
growsRule
s’ code simpler if we’ll passpoint
to them, too—most of the time they do something likeptlist[i][j]
somewhere inside - The
growthRule
more complicated thanreturn true
is used exactly once, so it might be a special occasion? But we’ll see.
In general, “we’ll see” is the mood of the day: once I’ll reiterate on all the real usages of this vegetate
, I expect at least some amount of insights into the way the filtering/deciding what to draw is performed.