gsohler / openscad

OpenSCAD - The Programmers Solid 3D CAD Modeller
https://www.openscad.org
Other
26 stars 7 forks source link

more granularity in the centering of objects #27

Open petaflot opened 5 months ago

petaflot commented 5 months ago

in standard openscad

this can make placement of objects quite awkward ; in fact many years ago I wrote this library for openscad that makes this behaviour a little more uniform. see the prism() module here: https://github.com/petaflot/scadlib/blob/b5dedf222b124ac132a624b5d943df110fe6f9d6/scadlib.scad#L118

in particular, the center boolean true/false is replaced by an array with a boolean for each axis ; by default all prism objects are centered like a cylinder, and I have aliases (included from another file) such as ttf=[true,true,false], tft=[true,false,true etc. this has saved me a lot of time hassle and I would really like to see this type of behavior when using python in openscad.

gsohler commented 5 months ago

Hi Petaflot, yes i like the idea of specifying a vector of 3 bools for center in a primitive instead of a single primitive. But before implementing your proposal, I feel we should even do more. My idea is that for each coordinate we should have even have 3 anchor points. So e.g. for the x coordinate min, mid, max would mean left, centered, right. I am just not sure if it would make sense to use False, None and True (and number) as "Tribool" Ultimately for a sphere and a cylinder this would mean that the reference point could be outside of the object Not mandatory to specify a number, but if so, the number could represent a percentage between left and right.

This would safe a lot of translate functions in the code and when displacements of two primitives are not automatically combined, code becomes much clearer.

I am just not sure, how to best solve the tribool issue.

petaflot commented 5 months ago

yes.. but no? the problem I see is "it is relative" or "is it absolute". pretty much every part I design is a functional part (no companion cube or the like)

one idea is that if it is an int, is is absolute ; if it is a string (that ends with %) then it is relative

petaflot commented 5 months ago

IMHO having such control (relative/absolute on each axis) would really be cool and make for clean code

gsohler commented 5 months ago

No need to stick with strings only

from openscad import * # yields constans OMIN, OMID, OMAX

cube(1) # Cube with origin on xmin, ymin, zmin cube(1, center=True) # cube with origin on xmid, ymid, zmid cube(1,center=[False, True, False] ) # cube with origin on xmin, ymid, zmin cube(1,center=[OMAX, OMAX, OMID]) # cube with origin on xmax, ymax, zmid] cube(1,center=[0.5, OMID, OMID] ) # cube with origin on 75% of X, ymid, zmid

just a proposal

c

petaflot commented 5 months ago

so.. OMIN, OMID,OMAX would be "dynamic" constants?

cube(1,center=[0.5, OMID, OMID] ) # cube with origin on 75% of X, ymid, zmid

I really don't like the 0.5 value being 75%. TBH, I even set my printer's bed center to be at 0,0 because otherwise I thought it was so annoying. [0,0,0] should IMHO be the grav center of the volume

petaflot commented 5 months ago

.. or I somewhat misunderstood. grav center on spheres, cylinders and cubes is pretty straight forward. for more complicated shapes we might want a vertice as a reference : but then, what is relative positioning?

petaflot commented 5 months ago

@gsohler I'd really like to share with you some code I've been working on for a few years ; ideally though I need to get a patent on some stuff because TBH I can barely eat, and getting health care is a whole different story

gsohler commented 5 months ago

Yes OMIN, OMAX ,OMID would be dynamic constants and would change with the cube size e..g my previously suggested mapping was would be -1: total left -0.5: half left 0 center 0.5 half right (75% away from left side) 1 total right

but of course everything to be discussed(names, nomiclatures,etc) once everything makes sense, we implement

BTW feel free to send me secret data to my email, promise to keep it secret unless otherwise told

petaflot commented 5 months ago

k I'll do that tomorrow

petaflot commented 5 months ago

@gsohler it's taking me more time than expected, meanwhile I've had ideas that expand the whole thing and I'm pretty sure you'd have good input about this.

maybe you could start reading this https://github.com/openscad/openscad/issues/5120#issuecomment-2095285764 and preferably we'll meet on IRC so we can have a proper discussion about this and that and I could send you specific files as the discussion goes, answering any questions you might have.

petaflot commented 5 months ago

I have this rather obsolete documentation on my project but unfortunately I cannot update it because of issues with gohugo ; meanwhile I've been able to generate and print some pretty interesting parts (examples attached).

this work was heavily inspired by openscad (I really like the concept of writing code to design parts), but it takes a totally different approach that does not compete with openscad, rather it's complimentary to it. FIY, I started it way before python for openscad, its origins date back to 2015-2016. it was started to offer a lot more control on the generation of gcode, and as it turns out it can be used efficiently for other purposes (one example is an automatic soldering machine I'm working on with a friend).

_8_spiral _4_polytope_concat _3_polytope_interpolation PS_VM_RD_mainboard-solder sample source files

gsohler commented 5 months ago

are you writing your own slicer in python ? if yes , what's its latest state ?

I am regularly checking #openscad and #pyopenscad

petaflot commented 4 months ago

are you writing your own slicer in python ?

it's more than a slicer... because I program toolpaths, I can include gcode commands at specific points... but basically yes

latest state is working, I can export AND import gcode, made a number of successful prints with it, there still are a lot of features missing but I'm pretty happy with the way it works. and it's really fast too

petaflot commented 4 months ago

oh and I still have to adjust the projection in quaternion space in order to make good use of the slerp() function

gsohler commented 4 months ago

I was always excited about quaternions, but I never really understood, how they are working, but i presume, these influence the "tool path" of the 3d printer nozzle ? Can you give some examples, why your slicer is different and where are its advantages over others ?

petaflot commented 4 months ago

objects (Polytopes) are basically a "string", made of a number of successive (in time ans space) vertices. This "string" could then be bent and folded along a chord, and printed with ie. a 6-axis robot, bent into knots (see knot theory for possible extensions and applications). Since a segment between two vertices is a (very simple) Polytope, one can define a sub-Polytope to replace that segment, and recursively, allowing for very intricate patterns and geometries.

My program (I don't like to call it a a slicer, because really it's very different from that) allows to have different layer thicknesses within objects (see second example image above), allows setting any number of properties to a Polytope (such as color, temperature, extrusion ratio, toolhead orientation...) for each vertices that can be either inherited from the Polytope or set individually for a point.

Since the order of the vertices and each of their individual properties can be defined at "drawing" time, this makes it most useful to control various machines that need to go around objects to do operation such as placing and soldering of electronic components. As a side-note, I also wrote a urwid-based program to send gcode to machine and that is specifically designed to get a number of machines work collaboratively : it is not finished and still has a few issues that need to be addressed (such as performance) but it looks very promising and can do stuff like gcode injection (and soon gcode interlacing.)

In my paradigm and to make it simple, a Polytope is basically a 4+D object that gets projected into 3D space based on a set of parameters that are all treated as rotating vectors (I actually started using pairs of complex numbers, like you do when using complex numbers to compute solutions in electricity

Below, a few more images of the things I've had to define in order to have consistency and not mix myself up in this quite complicated paradigm, and problems that still need to be solved.

quaternion segment skirt travelling_toolhead_problem

Yet another example of _5_hilbert_curve a quite complicated object (based on a portion of the hilbert curve)

petaflot commented 4 months ago

second image above, I just realized the title should not be Segment() but Polytope() ; also, it is missing a dimension normal to the pseudo-plane.

petaflot commented 4 months ago

Couldn't help adding this one too ;-) (some vertices are randomized for a better view)

_2_polyhedrae

Above (Skirt and convergent fill computation), it must be noted that the the normals to the plane through each point are not necessarily aligned (if we add a point D that is not on the plane, it is obvious that the normal though C will not be parallel to that through B ; the "plane" along the entire path is actually a mathematical strip (similar to a Moebius strip of infinite width.

petaflot commented 4 months ago

I just realized in the "Skirt and convergent fill computation" image above that with proper use of quaternions and SLERP this problem may pretty much go away on its own..

petaflot commented 4 months ago

[...] actually a mathematical strip [...]

In essence, a Polytope is the sequence of points that form the edge of a strip ; in a Moebius strip, that edge runs parallel to itself ; if a strip has a length l, the edge has a length 2*l : this makes a lot of sense when one thinks in terms of 2*Pi for a full turn or single rotation.

The shortest path "between" those two halves of the edge form the strip ; the "unused" component (it really is meshed with all XYZ coordinates in the quaternion space) defines the local curvature of that path (normal to the edge)

gsohler commented 4 months ago
  • quaternions allow to avoid the singularities when doing rotations

objects (Polytopes) are basically a "string", made of a number of successive (in time ans space) vertices. This "string" could then be bent and folded along a chord, and printed with ie. a 6-axis robot, bent into knots (see knot theory for possible extensions and applications). Since a segment between two vertices is a (very simple) Polytope, one can define a sub-Polytope to replace that segment, and recursively, allowing for very intricate patterns and geometries.

  • quaternions have 4 components, that can be mapped arbitrarily to XYZ space (with pretty much any arithmetic, as long as we can do the forward and reverse operation). This leaves us with an extra "trash" (or redundant) component that can be used efficiently to specify ie. the "twist" of that segment.
  • quaternions can be interpolated with the SLERP function, computationally very effective and that has the side effect of making transitions very smooth and "organic" : drawing pipes that go through space becomes almost too easy.

My program (I don't like to call it a a slicer, because really it's very different from that) allows to have different layer thicknesses within objects (see second example image above), allows setting any number of properties to a Polytope (such as color, temperature, extrusion ratio, toolhead orientation...) for each vertices that can be either inherited from the Polytope or set individually for a point.

Since the order of the vertices and each of their individual properties can be defined at "drawing" time, this makes it most useful to control various machines that need to go around objects to do operation such as placing and soldering of electronic components. As a side-note, I also wrote a urwid-based program to send gcode to machine and that is specifically designed to get a number of machines work collaboratively : it is not finished and still has a few issues that need to be addressed (such as performance) but it looks very promising and can do stuff like gcode injection (and soon gcode interlacing.)

In my paradigm and to make it simple, a Polytope is basically a 4+D object that gets projected into 3D space based on a set of parameters that are all treated as rotating vectors (I actually started using pairs of complex numbers, like you do when using complex numbers to compute solutions in electricity

Below, a few more images of the things I've had to define in order to have consistency and not mix myself up in this quite complicated paradigm, and problems that still need to be solved.

quaternion segment skirt travelling_toolhead_problem

Yet another example of _5_hilbert_curve a quite complicated object (based on a portion of the hilbert curve)

now I understand quaternions. its basically same concept like with quadcopters. there is pitch, yaw and roll. I am just not completely sure, if your software is a slicer or rather an aid to describe detailled movements in a clever way. Using your "tool path calculation as a slicer will have additional restrictions:

gsohler commented 4 months ago

as for defining slicing properties in the openscad source, i don' t see that happen because

rather there are quite straght forward solutions viable with python like so:

solid1 = cube(10) | cylidner(r=5,h=10)

props_3mf = {"shell_thickness": 3, "bottom_layers: 3 ]

solid1.props_3mf = props_3mf export(solid1,"solid.3mf")

====== during exporting 3mf I could watch for keyword "props_3mf" and literally copy all available properties onto 3mf file Part using the 3MF set-property-on-part function.

petaflot commented 4 months ago

now I understand quaternions. its basically same concept like with quadcopters. there is pitch, yaw and roll.

not really, but close. if you're interested, see geometrical transforms in the plane with complex numbers. quaternions are basically a pair of complex numbers

solid1 = cube(10) | cylidner(r=5,h=10) props_3mf = {"shell_thickness": 3, "bottom_layers: 3 ] solid1.props_3mf = props_3mf export(solid1,"solid.3mf")

====== during exporting 3mf I could watch for keyword "props_3mf" and literally copy all available properties onto 3mf file Part using the 3MF set-property-on-part function.

this looks very clean to me. I don't like comment parsing either...

gsohler commented 4 months ago

I came up with this code now:

Any example code on how to use SetObjectLevelProperty ?

void Export3mfInfo::writePropsFloat(void pobj, const char name, float f) const { Lib3MF::PMeshObject obj = (Lib3MF::PMeshObject ) pobj; printf("Writing %s: %f\n",name, f); //void SetObjectLevelProperty(const Lib3MF_uint32 nUniqueResourceID, const Lib3MF_uint32 nPropertyID); }