area515 / Photonic3D

Control software for resin 3D printers
http://photonic3d.com
GNU General Public License v3.0
133 stars 112 forks source link

Ability to perform AffineTransforms against image (mainly for x/y shifting) #133

Closed WesGilster closed 7 years ago

WesGilster commented 8 years ago

Generally this feature is only going to be used to perform translations against the image in order to move the object to a different location on the build platform. However, you could use it to perform some pretty strange 2D transformation matrices in here: https://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html

jmkao commented 8 years ago

Hmm, I also need this to flip images on the Y or X axis after slicing for bottom-up projection, otherwise the printed object will be flipped.

WesGilster commented 8 years ago

Yeah, it will do that too. You already know this, but flipping is just a negative width or height translation.

jmkao commented 8 years ago

I'm working with some interns from Kudo3D on this in two phases. First on the flip around the X axis, and then on shifting.

Shifting will require some kind of placement preview and impact the UI, which would need to be coordinated with whatever work on the Printables page occurs related to #35

WesGilster commented 8 years ago

Awesome, that's really exciting. I don't want to step on any toes, but you're right though, there is about to be quite a few hands in a very small amount of code(less than 250 lines of JS). Generally that means we'll need to have some coordination on a design path.

I've just added the restful file download for raw STLs for Robin, so he can move forward on that. I'm glad you mentioned this, because I was going to work on this next as well. I was planning on building a Javascript calculator that would return an java.awt.geom.AffineTransform that you could modify with the GUI through the Printables page. Not sure if I want to go down this road if there are other plans though.

Let me know what you guys are thinking and we can come up with something that meets both of our requirements. Then I'll leave the coding up to the younger interns. :)

jmkao commented 8 years ago

I think we'll be approaching this from the perspective the requirements necessary to print in conjunction with the built-in slicer or an integrated browser slicer to flip the image if necessary and to choose where in the build area to place the print.

The desire is for this to function both for STLs and ZipImages in a single location. That will require me to refactor StandaloneImageRenderer to extend the CurrentImageRenderer so that we have a common place to store and apply the transform.

WesGilster commented 8 years ago

I like where this is going. I was hoping for some exotic dynamic matrix transforms with AffineTransform. For example it would be cool to see an Eiffel Tower twist in 3d by increasing the rotation on the 2d AffineTransform on every slice. Not practical, but kindof a show off feature.

One little thing to keep in mind is similar to what I told Robin. You guys are looking at org.area515.resinprinter.job.render.CurrentImageRenderer which is actually a really great idea. However, these features need to be designed in terms of Printables not PrintJobs. ImageRendering is currently only performed after a PrintFileProcessor has started a print on a Printer. I'm assuming you are going to want to start some sort of "Simulated" print for these GUI operations? If so, you will need to "Select" a Printer to associate these transformations with. Maybe default the "Selected" printer to be the first started printer or something like that.

I've been thinking about building the concept of a Customizer. This would be a Printer/Printable association with further settings so that you can setup different ways that you can print a Printable on a Printer. That way, we could store these Customizer settings independently from Printers and Printables. This would be the perfect place to store your transformation settings. In essence, the Customizer is conceptual to a persistent PrintJob.

I would make the Customizers completely transparent to the GUI other than a dropdown of all the customizers available to a given Printable. That would work great for text files and other 2d file settings where I can't store all of the settings with the file itself, and it also doesn't make sense to store the information in the Printer profile settings since they are unique to the Printable. What do you think?

kloknibor commented 8 years ago

I would love to see this feature and I'm fine with it either way but I wanted to sum up some of my thoughts on this. (Although it may not be possible to finish this in the limited time the interns got, so it might be something for the future)

First I know James uses zipfiles currently so he can check his print, all slices and is sure the parameters are right. But personally I feel like primarily stl files are important as soon as the complete software works. 99% of all 3d printable files have been stl files before becoming something else. So why not try to eliminate the additional convert step. This way you can check the transforms easily in the 3D viewer. But since we can't currently check the slices easily and the interns have limited time I think James won't agree with me yet and that is totally fine! But maybe it would be cool for the future.

About the Costumizer this could be an addition to the 3D transforms I described above. Personally I would think to keep this in the printables page. There is plenty of space left and instead of keeping the costumize function seperated from printables and printjob why not just create a "save" and "save as" button? I think this will be easiest to implement and you can decide if you want to change the original file (so "save") because that is the only one you're gonna print or if you want to "save as" so you can reprint the costumized part and the original part.

Also about the mirroring for making the images correct for some printers (like text with an dlp machine) I personally think this would just be a checkbox somewhere which you can turn on. If it works you don't need to check it everytime!

This checkbox can be implemented in the printer settings.

also not trying to step on any toes. just my personal thoughts! Also should I wait with the implementation of the 3dviewer on the printables page so we aren't messing in the same code? Because I think I will need like 2 weeks before I can finish it (still kind of busy coming days and I don't think i will succeed directly).

jmkao commented 8 years ago

I think I did say that I want the AffineTransform to work the same way between STLs and pre-sliced images.

jmkao commented 8 years ago

I think most likely we'll want to store the AffineTransform itself, along with any configure parameters, in the Printable and then have the Job pass it to the renderer when it runs. That makes the same transform accessible to whether mechanism is used to provide previews.

The previewer will probably need access to the renderer appropriate to the print job.

Designing this as a pluggable list of Customizers at the Printable level makes sense, I do wonder about how to make a modular API at the Service level though.

Each Customizer would have its own unique input parameters and its own unique UI, which may entail separate REST end points for each one, or maybe multiple end points depending on how the previewing works.

WesGilster commented 8 years ago

Good conversation. I like having everyone's expectations up-front so we can build the best solution possible. It seems like we are all working towards the concept of a persistent Customizer. For now, we only agree on the AffineTransform customization, so let's start there. Simply put, all PrintFileProcessors must use an image at some point, so I think it's pretty safe to build this concept generic to all PrintFileProcessors/Renderers. So this is a great place to start from all standpoints.

James you mentioned storing the Customizer "in" the Printable itself. I assume by store, you are talking about object containment and not persistence. If you are talking about persistence, we'll need to invent the concept of a zip file that zips the Customizer + Printable together. I'm guessing that's not what you meant.

What if instead of containing the Customizer in the Printable, we store references to the Printable and Printer in the Customizer. Similar to this: Customizer | |-----Printable |-----Printer |-----AffineTransform settings

This way we can persist this concept as another form of an object that is directly printable. You should also be able to plug-unplug Printers and Printables from the Customizer for sharing purposes. If you like this direction, I could build the restful CustomizerService, and the interns could build out the GUI. I'm assuming they are more interested in JS anyway...

CustomizerService | |-----saveCustomizer(Customizer) |-----deleteCustomizer(Customizer) |-----getCustomizersByPrintableName(String printableName) |-----getCustomizersByPrinterName(String printerName) |-----renderImage(Customizer, int currentSlice)

PrinterService | |-----printCustomizer(Customizer)

jmkao commented 8 years ago

Yeah, when I said "store" I didn't mean persistence.

If a Customizer instance has references to a printer and a printable, how would if you needed more than one Customizer?

WesGilster commented 8 years ago

Ah, I see. You are looking at a Customizer from the standpoint of a mixin pattern, and that's why you asked about different service endpoints for each Customizer. I was looking at a Customizer from the standpoint of a Composite object containing Printer/Printable/AllOverriddenSettings: CustomizerComposite | |-----Printable |-----Printer |-----AffineTransform settings (day 1) |-----Other settings (Some day in the future)

Actually, though a mixin could work great too... This involves creating two new objects instead of one, but honestly that's not too big of a deal. PrintableComposite | |-----Printable |-----Printer |-----AffineTransformCustomizerMixin settings (day 1) |-----SomeOtherCustomizerMixin (Some day in the future)

What do you think?

jmkao commented 8 years ago

Hmm... if we had 100 developers I'd probably go with the mixin, but now that you pose it this way, I think having a kind of uber-Customizer that represents all customizations (and things we might want to do to preview customizations) would probably be easier to implement and easier for people to understand, especially since the impact of mixins on the JSON payload and the UI is probably not that composable anyway. The amount of UI code necessary to negotiate a set of relevant customizations and then encapsulating them as separately loadable items is beyond what we want to do now.

The CustomizerComposite would more closely represent what we could build within a reasonable time frame in the UI.

WesGilster commented 8 years ago

Awesome, you understood the difference between the two without having to show the service layer changes for this. After looking at the two class layouts I showed above, I was afraid I wasn't very clear(they kindof look identical except for name changes). The difference really comes in the form of the service changes and GUI changes required to support a mixin.

It's true, the mixin is going to require quite a bit more work to maintain both in the GUI and Service side(new service methods for each new type of Customizer), but in the beginning it's really not much more work. A mixin would also allow us to perform a querySupportedCustomizersByPrintable(). Although, I'm afraid I'm starting to scope creep on those interns... :)

jmkao commented 8 years ago

Yeah, let's go with the CustomizerComposite. The interns are ramping up on Angular.js this week, so we'll need to tap into this pretty soon.

WesGilster commented 8 years ago

Cool. Sounds like the CustomizerService is the next priority then. I can have something pretty simple available tonight.

WesGilster commented 8 years ago

Added CustomizerService and some methods you'll probably need. No implementations, but you should have swagger annotations for the interface.