jes notes Index Gallery . Signed Distance Functions Shaft passers Snap issues

2025-04-03

Last modified: 2025-04-03 21:14:25

< 2025-04-02 2025-04-04 >

Volume, mass, centre of mass

Today I had some thoughts on calculating volume, mass, and centre of mass of SDFs:

Apparently it is not easy to do automatic integration analytically.

ChatGPT says that if we have automatic integration then we can compute the centre of mass in each axis directly, as the integral of "the coordinate in that axis multiplied by the density at that point", and then dividing by the overall mass.

COM_x = integral(integral(integral(x * density(x,y,z) dx)dy)dz) / mass

I guess we have to do integrals with numerical methods. You can use interval arithmetic to easily classify large volumes as inside or outside, and then recursive subdivision to work out how much is actually in or out, and stop when enough significant figures seem stable.

Surface queries

Work out what types of object you might want to query (primitives, sub-primitive surfaces, sub-root objects in tree, only modifiers, etc.), and tag each struct with ids for all of those things, and let users choose their selection mode. Also allow fillets between any pair of things (so you could do a fillet between "Sphere001" and "Box001_Surface002" for example).

The only combinator that needs to know about the fillet is the most recent common ancestor of the selected surfaces.

The plan is to work out what types of object you might want to query, which could be "primitives" (Box, Sphere), "basic surfaces" (6 surfaces of a box), "top-level objects" (everything immediately under Document), "modifiers", "combinators", some special type of tagged objects?

And then the expression tree needs to propagate a separate id for each type of thing you might want to query.

And then by changing your "selection mode" (is there a better way?) you can do surface queries by clicking on the object, and then apply fillets between any 2 selected things - and they wouldn't even have to be of the same type. You could easily fillet between a particular surface and a particular top-level object.

And although we obviously could build up a massive expression to calculate all possible combinations of object to find the blend radius... we actually only need to put the interaction between 2 objects in their first common ancestor. Because that is the only node that can see surfaces of both types.

Because in order to get an interaction between 2 surfaces in a min/max, you need to have one surface on one side and one surface on the other.

I guess you can always add different "query types" later on, so to start with just do it for primitives since we already have the uniqueId in the struct. I will quite quickly want to fillet against cube faces, but can add that after. And we could add a bool to each node that tells it to re-label its distances, so then if you click on a surface that went through one of those nodes then it gets selected instead of its (grand-grand-grand-)child.

Clockwatcher

Not sure what has happened, but it has some datapoints showing absolutely enormous period, even with other datapoints either side showing really short periods:

And that's with moving average turned on!

How can there be a 15k second period and yet it took less than 15k seconds until the next sample?

Some massive timestamp drift here. 100B microseconds is a jump of 100k seconds? Which is more than a day. So what happened there?

Has my Raspberry Pi just had bad timestamps due to being turned off for too long, and it gave up on trying to smudge it and instead just did a couple of step changes? I don't really understand.

At about the same timestamps there are also discontinuities in the pressure and humidity readings, and to a lesser extent in the temperature:

That the problem afflicts some sensors apart from the balance wheel position sensor suggests that the timestamp problem is inside the Pi and not the ESP32 (because the environmental sensors are connected directly to the Pi).

OK, I think it is a data loading problem of some sort!

If you draw a straight line through the timestamp drift points:

You can see it intersects the origin!

That suggests that at those points we got a timestamp of 0?

And the values in the pressure, temperature, and humidity charts also show the same value as the value at timestamp 0.

So that is very interesting.

For some reason we're inserting duplicate copies of the very first datapoint, either in the database or in the chart. Potentially the database is getting NULLs inserted and the AI JavaScript trash code is copying the first datapoint in that case?

Selection

I have made it so that instead of drawing the "secondary object" as its own shader, we just highlight its surfaces.

I definitely want back the ability to draw the original object, maybe on some separate toggle.

Releasing a grab handle needs to not trigger a click on the canvas.

And I think I want Ctrl-scroll or something to move up/down the selection tree while hovering, and then you click to pick. That is a much better interaction model than "manually say whether you want surfaces, primitives, modifiers, combinators, or top-level objects".

But in order to show it highlighted I need to somehow have the shader know the id of every node in the chain, rather than just the deepest one. Hmm.

What if we give every node in the tree its own bit, and then for each pixel we get a bitmask saying which nodes were on the path.

Or, for each min or max we say whether it went left or right, and then we can address 64 levels deep instead of only 64 individual objects. And the mask becomes a prefix?

Or, for each min and max we say "is the current node's uniqueId the same as the selected node? if so, propagate our own uniqueId instead of that of the selected child".

Or, we add a struct field saying "is selected" or "is preselected", which becomes true if the node is the selected/hovered one.

Well I now have a dashed outline in the tree for preselect.

So I am actually pretty pleased with how selection works now, except that the preselection surface highlight disappears when you scroll away. Need to ruminate on that overnight. So far I think the best idea is to add a field to the struct that says "am I preselected" and "am I selected", and have each structmin or structmax set it to true if the selected uniqueId matches the preselection id or the selection id.

< 2025-04-02 2025-04-04 >