request-for-comments: object properties and/or alignment?

classic Classic list List threaded Threaded
4 messages Options
rk
Reply | Threaded
Open this post in threaded view
|

request-for-comments: object properties and/or alignment?

rk
Hi,

is there a standard way to automatically or semi-automatically center
and/or align objects?

The center-parameter of e.g. cube() can only center it in all axes or
none, but I would like to be able to selectively center it and to
align it to the positive or negative side of an axis. I know I can
do this by adding translate(), but I don't like that I have to manually
enter the size of the object into the translate-parameters.

So, I have two ideas:

1. Adding a parameter to all my modules, e.g.:

   module mytest(..., align=[1,1,1]) {
        ...
   }

   "align" has three elements, one for each axis. Each element can have
   three values: 0 = center on this axis, 1 = object is on positive side
   of the axis, -1 = object is on the negative side of the axis.

   Have you already done something like this? Is there a standard-name
   for the parameter I named "align"? Or is there abetter/easier way?


2. Using/adding object-properties (or local-scoped contants):
   (similar to the ideas of https://github.com/openscad/openscad/issues/301)

   If I could access some object-properies (either set manually or
   determined automatically like on the linked post), I could write
   generic alignment-functions/modules.

   Example:

   module mytest() {
        SIZE_X = 10; // manually given, since it could be hard to
        SIZE_Y = 20; // determine automatically on more complex
        SIZE_Z = 30; // objects
        CENTER = [5,10,15];
        color("red") // could automatically define "COLOR"
            cube([10, 20, 30]);
   }
   module center(object, center=[false, false, false]) {
        translate([center[0] ? -children().CENTER[0] : 0,
                   center[1] ? -children().CENTER[1] : 0,
                   center[2] ? -children().CENTER[2] : 0])
        children();
   }
   module align(object, align=[0, 0, 0]) {
        translate([align[0] ? -children().CENTER[0]+children().SIZE_X : 0,
                   align[1] ? -children().CENTER[1]+children().SIZE_Y : 0,
                   align[2] ? -children().CENTER[2]+children().SIZE_Z : 0])
        children();
   }

   The code doesn't work, but the idea should be clear.

   I think this approach would be quite powerful, make it possible to
   automatically align or stack things, mix the colors of objects on
   union()) and may things I currently don't think of. But it would
   probably be quite complex, too.

   What do you think?


best regards
Roland

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: request-for-comments: object properties and/or alignment?

doug.moen
Solving this problem is one of my goals for the OpenSCAD2 project that I'm working on. The code you've written for idea #2 is pretty close to valid OpenSCAD2 code. In other words, the language does support object properties, using pretty much the syntax you describe.

Unfortunately, this is all just in the design phase right now. There's no working code that I can share. But I agree with your proposal.

Doug Moen.

On 2 July 2015 at 14:03, Roland Koebler <[hidden email]> wrote:
Hi,

is there a standard way to automatically or semi-automatically center
and/or align objects?

The center-parameter of e.g. cube() can only center it in all axes or
none, but I would like to be able to selectively center it and to
align it to the positive or negative side of an axis. I know I can
do this by adding translate(), but I don't like that I have to manually
enter the size of the object into the translate-parameters.

So, I have two ideas:

1. Adding a parameter to all my modules, e.g.:

   module mytest(..., align=[1,1,1]) {
        ...
   }

   "align" has three elements, one for each axis. Each element can have
   three values: 0 = center on this axis, 1 = object is on positive side
   of the axis, -1 = object is on the negative side of the axis.

   Have you already done something like this? Is there a standard-name
   for the parameter I named "align"? Or is there abetter/easier way?


2. Using/adding object-properties (or local-scoped contants):
   (similar to the ideas of https://github.com/openscad/openscad/issues/301)

   If I could access some object-properies (either set manually or
   determined automatically like on the linked post), I could write
   generic alignment-functions/modules.

   Example:

   module mytest() {
        SIZE_X = 10;    // manually given, since it could be hard to
        SIZE_Y = 20;    // determine automatically on more complex
        SIZE_Z = 30;    // objects
        CENTER = [5,10,15];
        color("red")    // could automatically define "COLOR"
            cube([10, 20, 30]);
   }
   module center(object, center=[false, false, false]) {
        translate([center[0] ? -children().CENTER[0] : 0,
                   center[1] ? -children().CENTER[1] : 0,
                   center[2] ? -children().CENTER[2] : 0])
        children();
   }
   module align(object, align=[0, 0, 0]) {
        translate([align[0] ? -children().CENTER[0]+children().SIZE_X : 0,
                   align[1] ? -children().CENTER[1]+children().SIZE_Y : 0,
                   align[2] ? -children().CENTER[2]+children().SIZE_Z : 0])
        children();
   }

   The code doesn't work, but the idea should be clear.

   I think this approach would be quite powerful, make it possible to
   automatically align or stack things, mix the colors of objects on
   union()) and may things I currently don't think of. But it would
   probably be quite complex, too.

   What do you think?


best regards
Roland

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: request-for-comments: object properties and/or alignment?

Neon22
as we need overlap sometimes to get good unions in CGAL.
how about using floats and interpreting them specially.

E.g. align=[1,1,1] does what is suggested
but align[1.1, 1.1, 1.1] would use the floating point section of teh number to overlap at the align boundary.

The question is would [1,0,0] effectively be doing a
   - translate([1,0,0]) scale([1.1, 1,1])  
and therefore making the object slightly wider. So the far width was at the exact position and the scale allowed overlap at the align boundary ?
Reply | Threaded
Open this post in threaded view
|

Re: request-for-comments: object properties and/or alignment?

blobule
This post has NOT been accepted by the mailing list yet.
This post was updated on .
In reply to this post by rk
Hi,

Given that computing bounds of objects can be intensive (i.e. it requires a rendering to be accurate), I don' t think that automatically computing bounds for everything would be efficient.

Bounds are only useful one in while, but when you need it you badly need it...

I just updated my proposal (inside issue #301) of a probe() function that will compute the bounds of its first children, and then evaluate its other children with access to bound information (bbox min, max, size, center and empty testing). It is implemented and submitted here : https://github.com/openscad/openscad/pull/1388.

Note that the bounds are computed on demand only, and are made available only within the scope of the probe(). From there, you can easily define modules to display the bounding box, align to a position, align to another object, resize to known size or to the size of another object, etc.

I implemented seebbox(), align(), alignto(), resizer(), resizeto(), ... from probe(). Here is an example of how you can use this to align text, one of the nightmare of openscad... :-)

Say we have an object and a message to align together:

module message(t="Bonjour!") { rotate([90,0,0]) linear_extrude(height=3) text(t); }
module object(c="red") { color(c) cube([100,70,30],center=true); }




-----------------------

To see the bounding box of the message:

seebbox() message();


-------------------------

To align corner [0,1,0] of the message to corner [0,0,0] of the object:

alignto(anchor=[0,1,0],anchorto=[0,0,0]) { object(); message(); }
object();



I decided to specify the position as a fraction of the bounding box. So 0 is minimum bounding box value, 1 is maximum bounding box value, and obviously 0.5 is the center of the bounding box. "false" can be using to imply "do not align on this axis".

This means that [0,1,0] is the minimum of the bounding box in X and Z, but maximum value in Y.

-----------------------------

To center on the X-Z face of the object, we align corner [0.5,1,0.5] of the message to corner [0.5,0,0.5] of the object.

alignto(anchor=[0.5,1,0.5],anchorto=[0.5,0,0.5]) { object(); message(); }
object();



------------------------------

To embed text inside the other object, simply align the minimum Y instead of the maximum Y of the message... (i used  0.01 instead of 0 to get a clean preview)
difference() {
    object();
    alignto(anchor=[0.5,0.01,0.5],anchorto=[0.5,0,0.5]) { object(); message(); }
}


-------------------------------

It is also possible to resize before aligning. Here is a module that will make the message the same size as the object in X,Z only, with 4 example use:

module example(color,aspect,sizeX,position,t="Bonjour, ca va?") {
  translate(position) {
    object(color);
    alignto(anchor=[0.5,1,0.5],anchorto=[0.5,0,0.5]) {
      object();
      resizeto(newsize=[sizeX,false,1],aspect=aspect) { object(); message(t); }
    }
  }
}

// resize to fit in X-Z without caring about the aspect ratio.
example("red",false,1,[0,0,0]);
// same as previous, but preserving aspect ratio of the message
example("green",true,1,[110,0,0]);
// same as previous, but make it only 80% of the X size, to get a margin
example("blue",true,0.8,[0,0,40]);
// same previous, but with other text.
example("purple",true,0.8,[110,0,40],"Bonjour!");


----------------------
As for the code of the various functions, here it is to illustrate how probe() works (sorry for the lack of comments):

// display bounding box of the children
module seebbox() {
    probe()  {
        children();
        if( !bbempty ) {
            %translate(bbcenter) cube(bbsize,center=true);
        }
        children();
    }
}

// align each children bounding box to a position.
// anchor is 0/1 to get minimum/maximum bounding value, or false for no aligning.
// default to centering the object to the origin
module align(anchor=[0.5,0.5,0.5],position=[0,0,0]) {
    for(i=[0:$children-1]) {
      probe() {
        children(i); // the geometry to test
        if( !bbempty ) {
            translate([
            anchor[0]==false?0:position[0]-bbmin[0]-anchor[0]*bbsize[0],
            anchor[1]==false?0:position[1]-bbmin[1]-anchor[1]*bbsize[1],
            anchor[2]==false?0:position[2]-bbmin[2]-anchor[2]*bbsize[2]])
            children(i);
        }
      }
    }
}


// align second and subsequent children to the first children.
// the position on the first children is given with anchorto,
// the position on each children to align (second and later) is given by anchor (use false for no aligning)
// default to aligning centers to center.
module alignto(anchor=[0.5,0.5,0.5],anchorto=[0.5,0.5,0.5]) {
    probe() {
        children(0);
        for(i=[1:$children-1]) {
            align(anchor,[anchorto[0]*bbsize[0],
                          anchorto[1]*bbsize[1],
                          anchorto[2]*bbsize[2]]+bbmin) children(i);
        }
    }
}

// resize each children to a new size. use false not to resize an axis.
module resizer(newsize=[1,1,1],aspect=false) { ... }

// resize 2 and later children to the size of the first children.
// the newsize is relative to the first children size, so [1,1,1] mean same size, [0.5,05,0.5] = half size
// also use false not to resize an axis.
module resizeto(newsize=[1,1,1],aspect=false) {
        probe() {
                children(0);
                for(i=[1:$children-1]) {
                        resizer([
                                 newsize[0]==false?false:bbsize[0]*newsize[0],
                                 newsize[1]==false?false:bbsize[1]*newsize[1],
                                 newsize[2]==false?false:bbsize[2]*newsize[2]
                                ],aspect) children(i);
                }
        }
}
----------------------

Sorry for the lengthy post.

I hope this implementation and examples will convince that this "compute bounds" feature can be extremely useful in some circonstances.

sincerely,
Sebastien