epony has quit [Remote host closed the connection]
aiyion1 has quit [Ping timeout: 258 seconds]
aiyion1 has joined #openscad
aiyion1 has quit [Remote host closed the connection]
aiyion1 has joined #openscad
fling has quit [Quit: ZNC 1.8.2+deb2+b1 - https://znc.in]
fling has joined #openscad
noonien has joined #openscad
la1yv_j has quit [Remote host closed the connection]
la1yv_j has joined #openscad
<InPhase>
JordanBrown: In the case of this model where the triangle arrangements mattered, the linear point specification of the bezier actually mattered a lot, because this determined the linear spacing of the horizontal lines after the bezier generation.
<InPhase>
JordanBrown: In fact I took advantage of that in my animated version to move the intermediate lines up and down by varying the z-value of all the points other than the end points.
<InPhase>
This was why I originally gave them z of 0, 10, 20, ... 90, 100.
<InPhase>
Then I generated 23 points, but the z will be linearly spaced between 0 and 100 if the control points are all linearly spaced.
<InPhase>
It "feels" like the bezier calculation is a weird curvy thing, but in fact it's a straight fractional ratio sort of calculation, so all three axes are processed othogonally as ratios of the control points.
<InPhase>
However, that said, the logic of the bezier calculation could be rewritten for a PolarBezier or SphericalBezier, using the appropriate complex-plane-averaging approaches for the angular terms, and then you could get a version that puts that orthogonality into the other coordinate systems.
<InPhase>
If you ever want to dive in and understand what it's actually doing, check one of those nice videos or animated gifs for an intuitive bit, then ignore the one that specifies for 4 control points and go straight to the recursive definition which is more instructive about what it really does. :)
<InPhase>
The recursive is basically do weighted average of points, then identically weighted average of the weighted averages, etc until one point is left, and slide the weighting along from 0 to 1 until you have your points generated.
epony has joined #openscad
J1A841 has quit [Quit: Client closed]
J1A841 has joined #openscad
J1A841 has quit [Quit: Client closed]
J1A841 has joined #openscad
J1A841 has quit [Ping timeout: 252 seconds]
snaked has quit [Ping timeout: 268 seconds]
snaked has joined #openscad
J1A84 has joined #openscad
snaked has quit [Ping timeout: 252 seconds]
snaked has joined #openscad
J1A84 has quit [Quit: Client closed]
J1A84 has joined #openscad
<JordanBrown>
Whoosh... the sound of that flying straight over my head :-)
<JordanBrown>
I've never tried to understand the math underlying Bézier curves. I understand that the control points control what direction the lines leave the end points, and how "hard" they are pulled in that direction, and that's been enough for my practical needs.
<JordanBrown>
Looking at the Wikipedia article, it looks like what I'm used to are cubic curves.
aiyion1 has quit [Ping timeout: 258 seconds]
fling has quit [Read error: Connection reset by peer]
fling has joined #openscad
aiyion1 has joined #openscad
<JordanBrown>
Looking at the animations on the Wikipedia page explains a lot, though the fifth-order one just makes my brain hurt.
<InPhase>
That fifth order one is a little too overlapping to visually parse. :)
<InPhase>
I can't make sense of that animation either. (Although probably could work an effort not worth it.)
<InPhase>
s/could work/could with/
<InPhase>
I would say just use the second, third, and maybe fourth to connect it to the recursion formula, and then trust the magic of recursion. :)
<JordanBrown>
yes, exactly.
<JordanBrown>
I understand the concept, I think, but cannot follow the animation.
<JordanBrown>
For each line segment, consider a point that moves from one end to the other across the interval.
<JordanBrown>
Those points give you N-1 line segments. Do the same for them.
<JordanBrown>
Continue until you only have one point.
<InPhase>
Yep.
<JordanBrown>
Doesn't mean that I have an intuitive understanding of what the control points do in a 4th order or higher one, though :-)
<InPhase>
"Make things trend this way at that part of the path." ;)
<JordanBrown>
Have you been following any of the "geometry as data" discussions?
<JordanBrown>
InPhase
<InPhase>
I saw a stream of recent emails but only clicked on and skimmed a few.
Nohus has joined #openscad
<InPhase>
So I suppose "no" is a close summary. :)
<JordanBrown>
I'm trying to figure out if there is a disconnect in expectations for this feature.
<JordanBrown>
I have been thinking about two variations of what it "means" to have geometry as data.
<Nohus>
Hello, is there a way to use OpenSCAD as a library? I want to write a desktop application that can generate an STL based on user's input, that would use OpenSCAD in the background (without requiring the user to have OpenSCAD installed).
<InPhase>
JordanBrown: I'm convinced the only logical approach is extracting numerical geometry data with data = render() to be processed and potentially passed back into polyhedron.
<InPhase>
JordanBrown: Our notions of geometry are too flexible for anything else to really make sense.
<JordanBrown>
One is that you take some OpenSCAD, you execute it, and you render it, and what you have is basically a polyhedron. You could look at the points in the polyhedron, modify them, et cetera.
<InPhase>
If we start parsing out language syntax components with reflection, that's a whole messy can of worms that will probably have very little utility. But I definitely see value in grabbing out bounding boxes, or taking points and then modifying them numerically and turning them back into a geometry.
<JordanBrown>
Another is that you take some OpenSCAD, you execute it, and what you have is a CSG tree that you could then inspect. (You might then render that CSG tree, as above, to yield a polyhedron.)
<JordanBrown>
Both of those yield immutable data. There is no executing to be done on them.
<JordanBrown>
But based on some what kwikius is saying, and some things that teepee has said, I wonder whether some people are thinking in terms of storing a reference to a piece of the OpenSCAD program, to be executed later.
<JordanBrown>
I would think of that last as a module reference, akin to what you get when you say "f = function () ...;".
<JordanBrown>
That's a valuable thing, but it's not the *same* thing as either of the other two.
<JordanBrown>
Do those distinctions make sense?
<InPhase>
Well we have the object literals, the module literals, data = render(), and the CSG tree proposal. They're all different things to me.
<InPhase>
Although I still see potential to merge object and module literals if we're clever.
<JordanBrown>
What does "module literal" mean?
<InPhase>
mysphere = module(r) { ... }
<InPhase>
mysphere(5);
<JordanBrown>
OK, what I would have called a module reference.
<InPhase>
MakeTenOf(mysphere);
<JordanBrown>
Right. The analogue to "f = function (x) ...;".
<InPhase>
Well it is, but the language of "literal" was locked in with function literals I suppose.
<JordanBrown>
Storing a reference to an executable piece of program.
<InPhase>
The object literals proposal is obj = { ... }
<JordanBrown>
And what goes inside the { ... }, and what could you do with it?
<InPhase>
The only real difference is we want to call mysphere(5); and we want to access obj.foo. But there's no real reason we can't do both with both. :)
<JordanBrown>
My mental model says that if you say obj = { ... }, obj is an immutable data structure. It, per se, is not executable.
<InPhase>
mysphere is also immutable. It's a literal.
<JordanBrown>
It might have an immutable data element that is a reference to an executable chunk.
<InPhase>
Sure could. All left to debate is if it's a good idea. :)
<JordanBrown>
mysphere = module(r) { d = r*2; sphere(d=d); }
<JordanBrown>
What would mysphere.d mean?
<InPhase>
undef
<JordanBrown>
I don't think you can peek inside one of those.
<InPhase>
undef would also be mysphere.nevertyped
<JordanBrown>
Once you've executed it, the result might include the value of d, and you might be able to peek at that, but I don't think it's meaningful to peek at it until you've supplied parameters and executed it.
<InPhase>
I am undecided as to whether one or both of those should be a warning. Although warnings are usually good.
<InPhase>
Correct, many things are not meaningful.
<JordanBrown>
I wouldn't let you look inside a module reference.
<JordanBrown>
Today, if you have 'f = function(x) let(a=3) ...;', can you talk about f.a?
<InPhase>
Nope.
<JordanBrown>
Right. Same here.
<JordanBrown>
I think that the object-literal mechanism - the ability to create what the internals call Type::OBJECT - aligns more closely with either the "resulting polyhedron" or CSG ideas.
<JordanBrown>
Either CSG or resulting-polyhedron are dealing with the results after you execute the subprogram.
teepee_ has joined #openscad
<JordanBrown>
Introspecting the not-yet-executed subprogram... might be meaningful, but I wouldn't let you look at its assignments. Maybe you could look at the number of arguments that it expects, or the names of those arguments, or their default values. (Maybe not default values - I'm not exactly sure how
<InPhase>
JordanBrown: You do make a solid point about the derived values, and that could be the key thing that forces object and module literals to remain separate entities.
<JordanBrown>
dynamic those are.)
<JordanBrown>
Maybe, but probably not usefully, you could look at the AST.
<InPhase>
Derived values have a well-defined state in object literals because the evaluation time is clear.
<JordanBrown>
When you say "derived values", do you mean the assignments inside the { ... }?
teepee has quit [Ping timeout: 258 seconds]
teepee_ is now known as teepee
<InPhase>
An example of a failure case that really supports your point: m = module() { nval = $fn; }
<InPhase>
$fn is going to potentially have a different value when m is defined than when m is used, so nval is not meaningful predefined.
<JordanBrown>
m.nval would probably need to be undef. Or it could be dynamically evaluated, but yuck.
<InPhase>
I think that example alone is hard proof that they cannot be merged under the syntax and semantics currently on the table.
<JordanBrown>
And that doesn't bother me at all.
<InPhase>
Well, I'm trying to avoid us multiplying types out of control. :)
<JordanBrown>
Sure.
<InPhase>
But at least two are needed there to get these two features I suppose.
<JordanBrown>
obejct, and module references?
<InPhase>
Yeah.
<JordanBrown>
Ignoring for a moment the "resulting geometry" question, that works for me.
<InPhase>
I'm not sold on the idea of an accessible CSG tree though. I'm not sure what it's good for given how unintuitively ugly CSG trees tend to get.
<JordanBrown>
I'm not sure about that either.
<JordanBrown>
What bugs me about always going to polyhedra is that it means that you have to get CGAL involved, possibly in cases where it's not needed.
<InPhase>
J1A84 had stumbled into a simple for loop case where the CSG size grew exponentially. This would be silly to throw in there.
<JordanBrown>
How did that happen?
<teepee>
InPhase: that was the CSG products for preview purpose
<JordanBrown>
I am not clear what the difference is between CSG products and the CSG tree.
<InPhase>
So, definitely no accessible products I think. :)
<teepee>
CSG tree is basically what the code is after resolving all the modules and functions, basically what "export to CSG gives"
<InPhase>
JordanBrown: Well, open that and compare "Design, CSG Tree" and "Design, CSG Product"
<JordanBrown>
Yes, just did that.
<JordanBrown>
CSG product is something related to the OpenGL magic that the previewer does?
<teepee>
yes
<InPhase>
The CSG Product is totally useless there, and in general. The CSG Tree is... still sort of useless. It's technically better, but I'm not sure that has utility.
<teepee>
it requires the expansion
<JordanBrown>
Yeah, not interested CSG product.
<teepee>
I'd rate that as obscure debug thing
<JordanBrown>
yes
<JordanBrown>
CSG tree is somewhat obscure, but still clearly tied to the program.
<InPhase>
To make use of the CSG Tree in any practical code you have to be very comfortable with matrix math, which tends to make a small group of people who could use it. I'm one of them, but I wouldn't want to do it that way I think. ;)
<JordanBrown>
Why, because all of the transforms look like multmatrix?
<InPhase>
Yeah.
<InPhase>
And every time I try to get people to use matrix math to make their designs, people get wide-eyed and shrug. ;)
<JordanBrown>
I use matrix math when I'm trying to simulate transforms in data.
<InPhase>
So probably not ideal for a geometry introspection feature.
<JordanBrown>
For actual geometry, I only use them for skews.
<JordanBrown>
Though there are some interesting and brain-damaging things that might be possible with full 4x4 matrixes.
<InPhase>
Alas, multmatrix ignores the 4th row.
<JordanBrown>
yes, I know.
<JordanBrown>
It shouldn't do that.
<InPhase>
Probably someone was trying to avoid damaging the brains.
<JordanBrown>
Yes.
<JordanBrown>
Not that I'm *sure* that those transforms are useful, but I'm not sure that they aren't.
<InPhase>
We could trivially add in 4th row support though. It wouldn't break any sane code out there.
<JordanBrown>
Right.
<JordanBrown>
Anyhow, going back to geometry-as-data...
<JordanBrown>
I agree that introspecting the CSG tree is questionable.
<InPhase>
So yeah. This is why I think data = render() is the ticket, where you get vertices and faces.
<InPhase>
With fast-csg this is no longer time burdensome.
<JordanBrown>
But OTOH I'm not sure that it's not useful to be able to carry around executed-but-not-rendered geometry, even if it's as a black box.
<InPhase>
And what I want to add in is: data = render(); polyhedron(geom=data);
<InPhase>
We could do the same for polygon for 2D.
<JordanBrown>
yes, that should certainly be available one way or another.
<JordanBrown>
Most of the clearly interesting stuff, like bends, come out of that.
<JordanBrown>
Or even simpler stuff like querying bounding boxes.
<InPhase>
And you could otherwise do polyhedron(points=data.points, faces=data.faces); or swap one out with a modified version or something.
<JordanBrown>
Sure.
<InPhase>
An example usage of this is those vases we made the other day. You could do data = render() rotate_extrude() curvyside(); and then do the helical rotation of the points, and polyhedron it.
<JordanBrown>
I haven't followed the fast-csg stuff. Is that a replacement for CGAL, that fully renders into polyhedra?
<JordanBrown>
Or is it a replacement for just the previewer, only generating a single 2D view?
<InPhase>
fast-csg uses a new CGAL feature to do things 5-20 times faster. In many cases render is the same performance as preview, but in most cases they are pretty comparable within a reasonable multiple with fast-csg.
<JordanBrown>
So just to be clear: it yields final triangles?
<JordanBrown>
... completely replacing what we do now with CGAL?
<JordanBrown>
... potentially replacing F5 with a faster F6?
<InPhase>
It still uses CGAL, but yes, renders final stuff you can output with stl or such.
<JordanBrown>
OK, I understand its role now.
<InPhase>
You just click it on, and render is fast. :)
<JordanBrown>
So in the model I was playing with, { cube(10); } would yield a data structure that would describe the CSG tree. (Ignoring any ordinary-data members.)
<InPhase>
It might have some bugs lurking, but a fair perspective is that it's actually less buggy than our regular render approach. It handles slightly more edge cases of weird inputs.
<JordanBrown>
Cool.
<JordanBrown>
We could have { cube(10); } yield a data structure that describes triangles.
<JordanBrown>
(Or maybe other polygons. A fully-rendered polyhedra structure.)
<JordanBrown>
I guess I have three concerns with that latter approach.
<InPhase>
The data = render() PR would do that with 8 data.points and 6 data.faces, plus a data.bbox
<JordanBrown>
(a) if we have a way to get a CSG tree, and a way to render a CSG tree into a polyhedron, then we can look at it either way. If we only have a way to get a polyhedron, and we later decide that we want to look at the CSG tree, there's no way to get it.
<InPhase>
I'd have to check the exact syntax settled on, but that in principle.
<JordanBrown>
(b) Rendering into triangles would inevitably take more execution time than into a CSG tree, so if there are applications that would be happy handling a CSG tree then they'd be slower.
<InPhase>
Here's my operative question on the CSG Tree: Can you propose a use case where it would be elegant to USE it?
<JordanBrown>
(c) Similarly, rendering into triangles is almost certain to take more memory than generating a CSG tree.
<JordanBrown>
I'm not sure.
<InPhase>
Like, type up an imagined authentic-seeming code example where this is an ideal output.
<JordanBrown>
Yeah, I understand the question.
<InPhase>
And, no rush. That's a thinking question probably. :)
<JordanBrown>
I am having a really hard time finding a reason to *look* at the CSG tree.
<JordanBrown>
But a reason to have it as a data item... not sure.
<JordanBrown>
If we can get rid of previewing as a concept, in favor of always rendering all the way to triangles, then I'm having a hard time coming up with a reason to have it as a data item.
<JordanBrown>
But if we still have previewing as a concept, if previewing is faster than rendering all the way to triangles, having { cube(10); } yield triangles means that you always have to pay that extra cost, even if you are previewing.
<JordanBrown>
It's one of the reasons why we don't slap render() in front of everything today.
<JordanBrown>
Also: at least today, CSG trees can represent color, and polyhedra can't.
<teepee>
but that is possible to fix, it's just a lot of work
<JordanBrown>
Now, maybe we can move forward on multi-color/multi-material support, so that a polyhedra-based data structure can represent multiple polyhedra in different colors.
<JordanBrown>
(I think I know how to do that mathematically, but I don't know whether it will survive the realities associated with differencing objects with coincident faces.)
<InPhase>
Color in render is going to be super important pretty soon.
<InPhase>
We'll get left in the dust in a few years if we can't keep up with multi-color printers. :)
<JordanBrown>
Right.
<JordanBrown>
And they are pretty much consumer-ready now.
<InPhase>
So I think it's safe to assume we're going to do that soon, in some manner, and design with that assumption.
<JordanBrown>
I mean, Prusa's multi-color kit is only a $300 add-on.
<InPhase>
Future-me is motivated for this feature, but present-me did not buy a dual-extruder setup yet.
<JordanBrown>
I think Prusa does it with a single extruder.
<JordanBrown>
Just pulling and pushing filament dynamically.
<InPhase>
I'm especially interested in multi-material support with flexibility and rigidity, so "color" is just a placeholder to me.
<JordanBrown>
Agree.
<JordanBrown>
When I don't mind the typing, I say multi-color/multi-material.
<JordanBrown>
When I don't want to type but want to be formally correct, I say multi-material.
<InPhase>
I think it might be worth keeping color differences for the display just so that we can actually SEE where the different materials are, but that's a future debate.
<JordanBrown>
But it's not instantly obvious that multi-material encompasses multi-color.
<JordanBrown>
Yes, but that's a UI question.
<JordanBrown>
Not really a language / rendering question.
<InPhase>
For purposes of openscad I think it's sufficient that we somehow pass along labels for regions of a model.
<JordanBrown>
Sorry, clarifying (probably unnecessarily): multi-material *does* encompass multi-color. But it's not obvious that it does.
<JordanBrown>
Yes.
<JordanBrown>
Here's a thought.
<JordanBrown>
Well, maybe.
<JordanBrown>
Suppose that we are lazy about rendering. If you say "x = { cube(10); }" it would store a CSG tree (that you couldn't look at, but could add to the model), but if you ever asked a question about it ("what is the bounding box?" "what are the vertexes?") *then* it would do the render.
<JordanBrown>
And, of course, once it did the render it would store the result.
<JordanBrown>
An application that didn't actually need the render would never do it.
<JordanBrown>
If we ever found an application for looking at the CSG tree, we could add that.
<JordanBrown>
Or, turning that on its head, we could do the render at creation time, and then in the future if we ever find CSG-centric use cases, we could change the render over to being lazy.
<JordanBrown>
That latter might be the best answer: it keeps things simpler today, and maybe forever.
<JordanBrown>
So: x = { ... } would yield a data value that has zero or more member-values, and zero or more data structures that represent polyhedra.
<JordanBrown>
And, going back a bit in the discussion and moving into what would be a clearly separate feature, "m = module (args) { ... }" would yield a reference to an executable module that could then be called, directly analogous to the existing "f = function (args) ...".
pa has quit [Ping timeout: 252 seconds]
pah has joined #openscad
<JordanBrown>
Making some cases be lazy in the future, if necessary, would be a bit painful but pretty clearly do-able.
<JordanBrown>
Obviously I have either put you to sleep, or you are so awe-struck by the brilliance of my arguments that there is nothing more to say.
<JordanBrown>
In either case, I should do some actual paying work for a while.
J1A84 has quit [Quit: Client closed]
J1A84 has joined #openscad
Nohus has quit [Quit: Client closed]
<J1A84>
color is like a flavor to multi part exports
<J1A84>
and that is already very important so i can export a model and print the parts separately but still only have one file
<InPhase>
JordanBrown: I was off doing some of that paying work. :)
<InPhase>
JordanBrown: Although I think we are generally in a solid agreement now. I think object literals should be created initially with no support for CSG like data structures inside them, but if we get some good use cases for that in the future there would be space to add it there or with another syntax.
<InPhase>
I don't think it's a harmful feature except that it hasn't been justified. (And every feature has a price.)
<InPhase>
The CSG one I think is probably a hefty price because of how complicated it would be to extract and interact with the elements, which adds maintenance on every future change to the CSG layouts (like potentially to add better material support).
<InPhase>
Which means if we add it, it should be worth something of sufficient merit. :)
<JordanBrown>
So then there is the question of whether we can unify object literals with... geometry literals? ... so that we don't have two similar-but-different syntaxes.
<JordanBrown>
What I'm envisioning is that when you say x = { a = 1; cube(10); } you would then be able to say "x.a" and get 1, and for some as-yet-unspecified f(x), f(x) would get you a data structure that represents a polyhedron with eight vertexes and six faces.
<JordanBrown>
I'm not sure what f(x) would be. Maybe it would be geometry(x). Maybe it would be x.geometry. Maybe x._geometry. Or maybe something else.
<JordanBrown>
It seems like it would be nice to have that as a unified concept, instead of having one syntax that is only for data values and one syntax that is only for geometry (but has data values in the source but not visible).
<JordanBrown>
Actually, come to think of it, once you have that you don't directly need "module literals". A module literal can be replaced by a function literal that creates a geometry object.
<JordanBrown>
That is, m = module(args) { ... } becomes almost the same as f = function (args) { ... }.
<JordanBrown>
The only difference would be that maybe you could directly say "m(actualargs);", versus having to say, for some as-yet-unspecified mechanism g(geometry) that adds geometry data to the model, g(f(actualargs)).
<JordanBrown>
And I realized as I finished typing that that I've overloaded f(), using it both as an unspecified pattern that extracts geometry data from a {...} object, and as an example function.
<JordanBrown>
g(geometry) is an unspecified pattern that causes a geometry object to be added to the model. Perhaps it is "add(geometry)", or perhaps "render(geometry)", or perhaps something else.
<InPhase>
I think it will be very helpful to have module literals that obey identical syntax to regular modules once created, except that they can be passed around.
<InPhase>
That will be a good user experience.
<JordanBrown>
It does bring up namespace issues.
<InPhase>
No more than function literals.
<JordanBrown>
Exactly analogous, yes.
<JordanBrown>
But here's a wild-assed thought...
<JordanBrown>
Suppose that you could say:
<JordanBrown>
x = { cube(10); }
<JordanBrown>
x;
<InPhase>
Which apparently function literals resolves by ignoring the conventional function.
<InPhase>
f = function() 5; function f() = 7; echo(f());
<InPhase>
You get 5 and no warnings.
<JordanBrown>
cool.
<InPhase>
But a warning could be added.
<InPhase>
I think that is more a side-effect of look-up order, but it is doing it in the correct direction. If you have a local function literal passed in, for example, you want to preference that.
<JordanBrown>
But it only ignores the conventional function if f is a function. f = 5; function f() = 7; echo(f()); yields 7, not a "you tried to call a non-function" error.
<InPhase>
The warning should probably exist though if they are set in the same context, because that's probably a user mistake.
<InPhase>
Yeah, it doesn't try to look up variables. Everything is by its type.
<InPhase>
With the type to look up inferred from syntax placement.
<InPhase>
Thus for example we've fenced ourselves into the corner where modules cannot ever return a value without breaking some existing code out there. :)
<JordanBrown>
yes
<JordanBrown>
Going back to my wild-assed thought...
<JordanBrown>
x = { cube(10); }
<JordanBrown>
x;
<JordanBrown>
would also imply
<JordanBrown>
sort of
<JordanBrown>
f = function (size) { cube(size); };
<JordanBrown>
f(10);
<JordanBrown>
that is, if an expression all by itself evaluates to an object with geometry, that object gets added to the model.
<JordanBrown>
Problem 1: namespace collision between function and modules.
<JordanBrown>
Problem 2: if it's an expression that *doesn't* evaluate to a geometry object, what happens?
<InPhase>
Well module syntax needs to be x();
<InPhase>
Which means that would be f(10)();
<JordanBrown>
there weren't any modules in what I just typed.
<InPhase>
Yes, but that's the syntax that means "make a geometry".
<JordanBrown>
hmmmmmmmm
<JordanBrown>
but it's also the syntax that says "call this subprogram".
<InPhase>
You're effectively declaring x equivalent to a module literal there.
<JordanBrown>
and "call this subprogram" doesn't apply here.
<InPhase>
Although a parameterless one.
<JordanBrown>
no, it's not a module at all.
<JordanBrown>
it's just data, no program.
<InPhase>
Ah, so $fn and such are pre-fixed.
<JordanBrown>
I guess you could think of it that way, yes.
<JordanBrown>
Look at the x example first.
<InPhase>
Well then, polyhedron(geom=x) is the sort of thing we need. But I'm not convinced this should be mashed into the object literals.
<InPhase>
In some sense we're trying to make classes here. Which we could. But should we?
<JordanBrown>
yes, that was what I was just coming to, that if { geometry } yields a polyhedra, then something related to polyhedron(o) should add it to the model.
<JordanBrown>
Hypothesize a mechanism g(o) that adds the geometry from o to the model. Probably g() is some variation on polyhedron(), but maybe not.
<JordanBrown>
o = { cube($fn); }
<InPhase>
For it to be compatible with data = render() it would imply that x = { cube(10); } makes x.points and x.faces and such.
<JordanBrown>
It makes something such that you can extract points and faces, yes.
<InPhase>
Which gets confusing if we go adding things to data = render() because then we have to worry about name collisions.
<JordanBrown>
I'm trying to unify the two concepts, so that we don't have two slightly different { ... stuff ... } concepts.
<InPhase>
An alternative is render(x)
<JordanBrown>
yes, quite possibly, especially as you add the possibility that the object might have multiple polyhedra in different materials.
<JordanBrown>
o = { sphere(10); }
<InPhase>
That basically becomes a separate path. data = render() foo(); is for numerical examination. render(obj); makes the object as a geometry. data = render(obj); extracts the points and faces.
<JordanBrown>
In that model I don't understand what render() foo() does, and I don't understand what obj on its own looks like.
<JordanBrown>
What is "numerical examination" that is different from "points and faces"?
<InPhase>
data = render() foo(); is the existing syntax in the PR for this which gets points and faces from module foo.
<InPhase>
And the bbox.
<JordanBrown>
Sure... and I am suggesting a modification to that PR.
<teepee>
why would there be any connection between the two?
<JordanBrown>
Well, I suppose that the first question there is whether a module is *required* for use with render().
<JordanBrown>
Can you say x = render() { cube(10); };
<JordanBrown>
?
<teepee>
yes
<JordanBrown>
and you can say
<JordanBrown>
y = { a=1; b=2; };
<JordanBrown>
?
<InPhase>
With object literals.
<teepee>
yes, but it will be empty
<teepee>
no, that has nothing to do with object literals at this point
<JordanBrown>
it will be empty in what sense? Will you not be able to say y.a and get 1?
<teepee>
well, it's the same as union() { }
<JordanBrown>
What is the syntax by which you would get a y, where y.a is 1?
<InPhase>
It's currently a syntax error. :)
<JordanBrown>
Sure, this is all hypothetical future stuff.
<teepee>
object literals means there's a value of type object somewhere
<JordanBrown>
yes... already is, just no way to construct one.
<teepee>
render() just takes a module instantiation
<JordanBrown>
So to construct an object o with members a and b, I want to say something very much like
<JordanBrown>
o = { a=1; b=2; };
<JordanBrown>
So far so good?
<JordanBrown>
and then o.a is 1 and o.b is 2.
<teepee>
yep
<JordanBrown>
and the render() proposal says
<JordanBrown>
g = render() { cube(10); };
<JordanBrown>
and yields g as an object with some members for vertexes, faces, et cetera.
<JordanBrown>
Right?
<InPhase>
I suppose if data = render() foo(); became data = render({foo();}); then it would be JordanBrown's geometry-inclusive objects, just with extra semicolons and curly brackets.
<teepee>
lets call it data structure for now as there's no definition on objects with geometry yet
<JordanBrown>
Why do you need the render() in there?
<InPhase>
To get points and faces.
<teepee>
because render() does CGAL mesh generation
<teepee>
as it already does right now
<JordanBrown>
Why doesn't {foo();} do that on its own?
ur5us has joined #openscad
<JordanBrown>
Why doesn't (hypothetically)
<teepee>
the only difference is that is introduced is that it is allowed to be called in function context and returns the data
<JordanBrown>
x = { cube(10); };
<InPhase>
JordanBrown: Because that just creates a CSG tree to process at a later stage.
<JordanBrown>
Hey, wait a minute, didn't we just decide that we didn't need a way to represent a CSG tree?
<JordanBrown>
Are you sitting in my chair?
<JordanBrown>
:-)
<InPhase>
We don't want a way to access one. ;)
<InPhase>
But they're used internally.
<JordanBrown>
So you are suggesting that { cube(10); } would yield a CSG tree as a black box, and render({cube(10);}) would consume that CSG tree and yield points, faces, et cetera?
<InPhase>
The process goes in stages, normally. The data = render() innovation was to jump ahead to a later stage, get the points and faces, and bring them back to the compute stage again.
<teepee>
yep, if we happen to get the object stuff sorted, it might be just obsolete
<teepee>
the idea was just that it might be an achievable middle ground
<InPhase>
JordanBrown: Right.
<JordanBrown>
So that's a lot like my proposal from a day or two ago, except that the CSG tree is a black box instead of being something you can look inside.
<InPhase>
JordanBrown: Which is essentially the same PR, but with a syntax tweak, and a semantic tweak grabbing an object's geometry.
<JordanBrown>
So when you say
<JordanBrown>
x = { cube(10); };
<JordanBrown>
what is x?
<JordanBrown>
Or, more exciting, when you say
<teepee>
a Value of type ObjectType
<JordanBrown>
x = { sphere(10); };
<teepee>
question is how it behaves :)
<InPhase>
I like the syntax a little less of render({cube(10);}), but one could fix it with some spaces, and I stipulate it DOES have an advantage that you can preassign it.
<teepee>
how the data part behaves is mostly clear, I suppose
<InPhase>
And in this approach you get the encapsulation advantages of coupling data with a geometry.
<JordanBrown>
What does "preassign" mean here?
<InPhase>
This provides annotation.
<teepee>
what's wrong with kepping the render() { ... }
<InPhase>
part1 = { label="thing"; cube(10); };
<teepee>
that's just normal children syntax
<JordanBrown>
x = render() { ... }
<JordanBrown>
is not children syntax.
<InPhase>
teepee: Because if you flip it you can provide an object as a value.
<teepee>
flip?
<InPhase>
teepee: data = render(part1); echo(part1.label);
<teepee>
render() part1()
<teepee>
children is pretty much the same as a single parameter
<JordanBrown>
there are no children in expressions.
<teepee>
there are in that PR
<JordanBrown>
sure, that's a proposal.
<teepee>
that's pretty much the core of the PR
<JordanBrown>
I'm suggesting what I think is a simpler variation of that proposal.
<teepee>
as I said in that case it has nothing to do with objects, if it would just return an array of stuff, it works without anything object related
<InPhase>
teepee: JordanBrown pointed out that's problematic because part1() does not pick up $fn and such, as it's not undergoing a calculate step at that point. The calculation must be complete at part1 = { label="thing"; cube(10); };
<InPhase>
Or somehow we collectively pointed that out.
<JordanBrown>
:-)
<teepee>
that's what Doug also said I think
<JordanBrown>
A key thing that I think may have occasionally been mixed up is that geometry-as-data is difference from module-references-as-data.
<InPhase>
So data = render() foo(); works for anything that's evaluated at the point of that line, but is otherwise suspicious as a pre-evaluated literal.
<InPhase>
BUT, data =render(foo); says I'm passing a constant in to render.
<JordanBrown>
Well, you're passing a value in. It's only a constant in the sense that any expression is a constant, once it's been evaluated.
<InPhase>
A module literal is also a value, but module literals would be called as bar() and evaluated where called.
<JordanBrown>
yes
<InPhase>
We do not want object foo() as a pre-evaluated and module bar() to be evaluated. :)
<InPhase>
So keeping a value syntax for the objects will be important.
<JordanBrown>
Right, () causes subprograms to be executed.
<teepee>
I think I'm too tired to follow
<InPhase>
Under this, object literals become pre-evaluated encapsulated objects with associated values and geometries, and module literals become values that can be executed to produce a geometry.
<JordanBrown>
yes
<InPhase>
data = render(..) ...; could in theory have both syntaxes, but to support both use cases would need at least data = render(...); because you can always throw anything into a transient object. But I'd be okay with both syntaxes for that.
<InPhase>
And objects require bare "render(part1);" to render them. Like if you did: translate([x, 0, 0]) render(part1); to make a line of part1's.
<InPhase>
This operation is slightly better actually because render(part1) needs to do no calculation, and doesn't even need to check the cache. It's a pre-generated geometry, so it's max speed of just throw them on the line.
<JordanBrown>
Is part1 CSG, or is it triangles?
<InPhase>
It's a csg tree internally.
<JordanBrown>
So it sounds like this is a lot like what I wrote in that Google doc, except that the CSG trees are opaque.
<InPhase>
Okay, I guess there are some calculations, right.
<InPhase>
I forgot how we were working that.
<InPhase>
The CSG tree is important because for now, that's the way to preserve color.
<JordanBrown>
"some", yes, remembering that CGAL rendering is usually the biggest processing load in the picture :-)
<InPhase>
But keeping that as an inaccessible "internal" leaves an optimization opportunity later.
<JordanBrown>
But hmm. if it's render(csg), that's kind of weird, because the result would presumably preserve color in preview, unlike real render().
<InPhase>
I won't lose sleep over this.
<InPhase>
Let us presume render will preserve color later.
<JordanBrown>
so render(csg) just passes through the csg on F5, and CGALs it on F6?
<teepee>
no
<InPhase>
Well passes through the csg on all of them until you get your final product for the next stage.
<InPhase>
Which is preview or render.
<teepee>
well, no for the current behavior at least, that's the very point of the thing
<InPhase>
Right, currently it takes no parameters, but render() foo() always triggers cgal evaluation.
<teepee>
yes, and that's why it was selected to "well, then it also could just give those vertices and faces out"
<InPhase>
Yep.
<JordanBrown>
"also" in a sense of putting the same word into a completely different syntactic context.
<teepee>
yes, in the context that deals with data as opposed to geometry
<InPhase>
And I've selected it by analogy to that in a mild misnomer to mean make a geometry out of this, or do the same thing as data = render(), when receiving an object. Bare "render(obj);" could be considered a misnomer, or it could be considered a geometry generation that preserves the preview optimization and color support.
<InPhase>
But I'd be okay with that.
<InPhase>
I still think preview goes away within 5 years.
<teepee>
plus 10 years due to chip shortage
<InPhase>
lol
<InPhase>
I need to head out for a bit. I feel like I gained some insights into how this could actually make some cohesive sense.
<teepee>
hopefully not plus 20 extra years worrying about taiwan
<InPhase>
JordanBrown: You want to try writing this down? :)
<teepee>
cool, I'm not there yet, I'll tag along then :)
<teepee>
too many distractions recently
<JordanBrown>
I am not sure, but I think that the only difference between what we've been discussing and what I wrote in that Google doc was that (a) the CSG tree is opaque, and (b) render(csg) is how you get a CSG object added to the model.
<teepee>
and that azure downtime did not exactly help
<JordanBrown>
Was there something else?
<InPhase>
JordanBrown: Maybe tweak that doc and I'll look at it again later? I think we should probably present a cohesive picture between data = render(), render of objects, and module literals, and try to construct a picture with all of these that makes sense.
<InPhase>
I can help edit some of this if it was shared with edit priviledges with me.
<InPhase>
Anyway, heading out for the moment.
<JordanBrown>
OK. I think module literals (what I would call module references) are actually totally orthogonal, but maybe they should be presented together to emphasize that orthogonality.
<JordanBrown>
I don't have a problem with banging out the words. Let's keep it with me for a moment, just so that it can be clear that it's my concept and that you haven't necessarily bought into it yet. (Not being possessive, just trying to keep it clear what is and isn't agreed.)
lastrodamo has quit [Quit: Leaving]
snakedGT has joined #openscad
pbsds9 has joined #openscad
n1essa_ has joined #openscad
abff_ has joined #openscad
abff_ has quit [Changing host]
abff_ has joined #openscad
phryk_ has joined #openscad
mlaga97_ has joined #openscad
n1essa has quit [Ping timeout: 244 seconds]
cbmuser_ has quit [Ping timeout: 244 seconds]
snaked has quit [Ping timeout: 244 seconds]
pbsds has quit [Ping timeout: 244 seconds]
mlaga97 has quit [Ping timeout: 244 seconds]
abff has quit [Ping timeout: 244 seconds]
phryk has quit [Ping timeout: 244 seconds]
n1essa_ is now known as n1essa
pbsds9 is now known as pbsds
abff_ is now known as abff
teepee_ has joined #openscad
teepee has quit [Remote host closed the connection]