-
-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduction of assemblies? #220
Comments
What you describe here are definitely desired features. I don't have a concrete plan for them though, and not having thought about it from an implementation perspective much, I don't know if that's something that could be added in the short-term, or if it requires the underlying infrastructure to mature. Some notes:
Given that there's no concrete plan for implementing this, I'm tempted to close this issue and move it to the Feature Wishlist. And to be clear, such a plan isn't something that I would have to come up with. Anyone is free to work out the requirements for such a feature, and how it can be implemented (which could then be tracked in one or multiple issues). I just like to keep issues actionable, and leave idea-stage features to the wishlist. What do you think? Do you have specific ideas for improvements that could be made in the short-term, or do you think moving this to the wishlist would be appropriate? |
Thank you for explaining your use case, @therealprof, that's really helpful! This is definitely all stuff that I'd like to support. I'll mull over this a bit. I assume that there are parts of this that can be done near-term (i.e. don't require expansive infrastructure to be built). I'll probably open more specific issues for those. Some other aspects might need to go into the wishlist, to be picked up later. Also, cc @hendrikmaus, who expressed interest in furniture building (in case you want to weigh in).
Yes. To be clear, I only mention this as a workaround that's currently possible. I don't mean to imply that it is even close to a desirable solution. |
I've had some time to think about this. Here's what I've come up with so far: Multiple types of artifacts (artifact system)Models need the ability to produce multiple types of artifacts, like sketches, components, assemblies, etc. Each of those could expose a different API in the CAD kernel, be displayed differently in the viewer, etc. My favored approach for specifying this, is to add attributes to free functions. Something along those lines: /// An assembly
///
/// The attribute would type-check the function (to make sure it returns
/// `fj::Assembly`, or whatever the types end up being), parse the arguments (so
/// they can be exposed in the UI or via the CLI for parametrization), and
/// register the function somehow (so the Fornjot application can load it).
///
/// Otherwise, this should not transform the function, so it can be called by
/// other functions in the same model, or even other models.
#[fj::assembly]
pub fn assembly(number_of_thingies: u64) -> fj::Assembly {
// Create the assembly; call other functions defined below
}
/// A component
///
/// Pretty much the same as the assembly above, except it returns
/// `fj::Component` (or whatever the type ends up being), which can provide a
/// different API to the kernel and can be displayed differently in the app.
#[fj::component]
pub fn component(width: fj::Scalar, height: fj::Scalar) -> fj::Component {
// Create the component
}
/// A sketch
///
/// Same, only this time it's a sketch.
#[fj::sketch]
pub fn sketch() -> fj::Sketch {
// Create the sketch
} I like this approach, because it can provide the structure that the kernel and viewer will likely require, while still allowing regular model code to call these functions. From the perspective of the kernel/viewer, those functions could just as well return some This work is related to #13 and #72, and could potentially be done as part of either of those, which is why I'm not going to open a separate issue for this. While this work is not strictly blocked by anything, it probably makes sense to wait for #71 before working on this, as that might change the implementation quite a bit. Plans for each partI think this basically comes down to being able to export technical drawings, possibly with some additional metadata, like assembly instructions. Technical drawings are on the feature wishlist. As for assembly instructions, I'm not sure about which approach to take. I want to make it really easy to embed Fornjot models into websites (#73), and maybe a system could be built around that. Maybe it also makes sense to add assembly instructions (and the like) as a feature to Fornjot itself, but I don't know. I expect to revisit this once other steps have been taken in that direction. Cut listsThis would require teaching Fornjot about materials, and how to get parts out of them. This would also play into the artifact system I've described above. I'm inclined to consider this out-of-scope for now, as it's somewhat orthogonal to the current development priorities (which are centered around getting a stable base working) and can probably be prototyped in "user space" (i.e. model code). Exploded viewOnce the artifact system above exists, this "just" becomes a matter of improving the renderer and making it use the available data. I don't think it makes much sense to think about this right now, until things like the artifact system and #13 are in place. Those are my thoughts, so far. I'm going to link this comment in #13 and #72, which are more actionable in the near-term. I'm pretty sure I'm going to close this issue soon in favor of adding an entry to the feature wishlist (to be re-evaluated once these other issues have been addressed), but I haven't decided yet. I'm leaving it open for now. |
As I alluded to in my previous comment, I've decided to close this issue as not actionable. I've added Assemblies (including exploded view), Assembly instructions, and Cut lists to the feature wishlist. We can open more specific issues based on them later. As I've mentioned before, #13 and #72 are existing issues that are relevant. Closing this issue doesn't mean that further discussion here is not welcome! It just means that this feature request is now tracked on the feature wishlist, to keep the number of open issues to a manageable level. Feel free to post here, if assemblies are something you'd like to see, or if you have anything to add to the discussion. Thank you, @therealprof for opening this issue! |
I don't know how much time you already spent on planning a structure for the features of a model and thus its representation, but I have suggestion which I would like to turn into a proof of concept if you agree on the general direction. @hannobraun (and everyone of course) So let's start with my idea: Currently By annotating free functions with the corresponding attribute the component would be inserted in its respective container automatically and can then be refered to by other components. Of course one has to think of the order in which the these components are created/defined to be able to use them, since you can't use stuff that doesn't exist yet. With this idea the assembly approach could initially be limited to only affect model creation, since the I'm not sure if this explanation of my idea is comprehensible, but either way I'm looking forward to a response to either clear up any confusion or just giving me the green light to play with a proof of concept implementation. If a visual representation of the idea would help to clarify it let me know. |
The current structure is a reflection of the current requirements, nothing more. I am 100% sure that things are going to change drastically going forward. I do have some reservations regarding your idea, but those are based on specific problems I see, based on the current use cases. Any help with figuring out where things needs to go is certainly welcome! I've read your comment, but only have a few minutes right now, which isn't enough to fully understand it and reply to it. I'll get back to you as soon as I have some time! |
Sorry that it's taking me a bit of time to get to this, @gabsi26! The timing was a bit unfortunate for me, with the weekend + the public holiday on Monday. I will most likely reply tomorrow. |
Okay, here we go, @gabsi26. Thank you for your patience!
What you call "features" here is called "objects" in current Fornjot kernel parlance. In the context of CAD, I understand the word "feature" to refer to a collection of such objects, that make up a region of the part. I'm not saying my own use of these words is the definite one, and I'm open to change nomenclature where it makes sense. I'm just mentioning it here, to avoid confusion.
I see a problem here: Objects within If there were global object stores, then we'd have to find some way to keep the current use cases working, preferably without making things harder to do than they already are. I think the sweep algorithm might be a good testbed for this, since what it does is really simple from a conceptual level (1. copy the original sketch and invert its orientation, creating the bottom face; 2. copy the original sketch and translate it along the sweep path, creating the top face; 3. connect the vertices and edges of the bottom and top face, creating the side faces), but implementing it, especially step 3, has turned out way too gnarly. Basically, if we can still implement the sweep algorithm using global object stores, without making it even more complicated, then that's a good sign that things can work out. And maybe there are even opportunities to simplify things using your proposal. A lot of the complexity in the sweep algorithm stems from I have to think more about this. Maybe we're onto something here.
I think you've lost me there. Are you saying that we have freestanding functions that are annotated as defining 2D or 3D components, for example, which are then inserted into the 2D or 3D containers? If they're inserted automatically, where would another component get the handle from to refer to them? Maybe some example syntax would help here.
I think the underlying concept of having global object stores is quite clear to me (although I might have totally misunderstood that part 😄), but I don't understand how the concept relates to defining models. What's also not clear to me (and I think that follows from my previously expressed lack of understanding), is what this concept is trying to achieve. You mention that it would hopefully no longer necessary to clone things, and while that sounds good, all that cloning might1 not be a problem right now. And I'm suspicious of trying to solve to solve performance issues before they are an actual problem. That just means you're making changes without being able to properly assess them, which is especially relevant if they have negative impacts too (for example, by making things more complicated). Footnotes
|
No problem
Of course you are right sorry for the mixed terminology
I think we should be able to make them immutable once inserted, which would of course make those object stores different from the one use in
Great to hear that if nothing else I have at least inspired you in some way.
I imagine it something like this (where the expanded version of the two example functions is written below the attribute macro one) : #[fj::model]
pub fn model() -> Shape {
cross_section();
sweep_cross_section();
}
#[fj::sketch]
pub fn cross_section() {
//.... something to create the sketch
fj::Sketch::from_points(points)
}
pub fn cross_section(global_container_2d: &mut ContainerType2d) {
//.... something to create the sketch
global_container_2d.insert(fj::Sketch::from_points(points));
}
#[fj::sweep]
pub fn sweep_cross_section() {
fj::Sweep::from_path(cross_section, [0., 0., h])
}
pub fn sweep_cross_section(global_container_2d: &ContainerType2d, global_container_3d: &mut ContainerType3d) {
global_container_3d.insert(fj::Sweep::from_path(cross_section, [0., 0., h]));
} The
You understood the global stores part correctly ;). It helps in the creation of a model structure and thus the ability to display it once the GUI part of has been settled on.
I was hoping the suggestion would lead to more structured models and a clearer way of how to make assemblies happen. Avoiding cloning was meant more as way to tidy things up and not have as many semi-duplicates around. I did not think of this as performance imporvement to be honest, I simply believe it to be more intuitive to retrieve an I have but some thought into it of course but I'm nowhere near a good solution to achieve any of it. I'll try to implement parts and maybe that process reveals the way to go or makes more issues apparent to me. Anyways I hope I've made my ideas a bit more obvious and gave you the chance to better judge if it even makes sense or has a chance to work. |
You say that it is no issue, but I'm not so sure. I don't doubt that it can be made to work somehow, but the somehow is where all the details live, and those are what causes all the trouble. When sweeping a sketch, how to we create the top face? Do we just copy the original sketch, and translate it? Then we need to remember which edges and vertices of the original sketch correspond to which edges and vertices of the top face, otherwise we can't create the side edge/faces later. And how do we know which objects to translate in the first place? We can't just translate the whole So I guess we're either writing a lot of tedious and manual code, or we write some generic infrastructure that can translate an object, and all objects it references, returning the new object, as well as some kind of mapping between the handles of the original objects and those of the translated objects. (Remember, we need those, or we won't know which vertices/edges to connect with side edges/faces later.) But maybe creating the top face by creating translated copies isn't the right way to do it. Isn't that just the kind of copying and redundancy we were going to avoid in the first place? So maybe we can just have a new "transform" object that references the original objects that it transforms. Maybe the original sketch is a Sounds good, but of course those new Okay, so I guess we need dynamically typed handles now, and use those in I'll stop here. What I'm trying to say is, it's easy to imagine how things should work, but using those things in real code will cause real problems, and those will need to be solved. The current I'm excited about the promise that those global stores have, but I absolutely know there are a million problems to be solved, before any of that promise can be realized.
You may already know this, since you have looked at the code, but in the interest of clarity, I should note that So what you are proposing here, is essentially a new thing, as far as the So yeah, I don't know how that would look when implemented. Plus, your example is still a bit hand-wavy. Wouldn't I'm also not sure this is the best approach to do it, as sorting stuff into different containers based on annotated functions might be a bit too magical. Maybe it would be better to achieve the same thing using a more straight-forward API that is passed into the model function. Then you could do stuff like
I think we're talking about at least 3 different problems here:
I'll be thinking more about point 1, as I see a lot of promise there (but as I said, with a million problems still to be solved). Points 2 and 3 seem more nebulous to me. No idea, how good of a chance any work in those areas has to work out. Maybe prototyping is the best way to answer that, or maybe not. I don't know. |
I've spent some more hours thinking about the "global store for all objects" idea, only in relation to how it could affect data structures in the kernel, not how to possibly expose that through the My premise for this was, that all objects are part of a single graph, and that shapes are basically just references into that graph. This graph is not redundant (i.e. common objects are shared between shapes), the graph is append-only, and objects within the graph are immutable. While this is a promising concept that I remain interested in, I wasn't able to figure out a good way to implement it. The core problem is that without mutability, you need nodes in the graph that modify objects they reference (like a I couldn't find a way to make this kind of polymorphism work without lots of traits and I will keep thinking about this in the background. Maybe I can come up with a simpler idea. |
Follow-up to my previous comment here: While I still don't have a solution for the polymorphism problem, some other aspects I've been thinking about in relation to the "global object store" idea have solidified into a concrete plan: #691 Thank you for triggering that line of thought, @gabsi26! I'm not sure if the overall idea will lead anywhere, but it looks like there are some concrete benefits coming out of it. |
Sometimes you don't want to consider a model made from a single piece but rather multiple pieces which are then produced individually and then assembled together (think furniture, boxes or other containers, 3D printed gears, etc.). Those would show up in the same model, allowing to verify correct dimensioning and completeness but internally will be treated as individual objects, allowing to e.g. produce exploded views, individual parts exports and parts lists.
The text was updated successfully, but these errors were encountered: