Skip to content
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

Feature request: passing parameters by reference #4258

Closed
fxeconomist opened this issue May 10, 2022 · 12 comments
Closed

Feature request: passing parameters by reference #4258

fxeconomist opened this issue May 10, 2022 · 12 comments

Comments

@fxeconomist
Copy link

fxeconomist commented May 10, 2022

I know this gets shut down all the time, but coding around that is abnormal.
This feature is not an extra that structured languages have, it's part of what makes them functional.

Imagine you design something really big, and you need to expose anchor point coordinates for every sub-structure you draw,
so that you have a point on which to attach other ones and so on.

This can only be achieved with multiplicated code, by coding functions that return anchor data.

Suppose I have an "object" that creates a parametrized building, and then I want to add a chimney in a certain position.

The functions that get to the anchor points somewhere on the roof that can be used for adding the chimney, will contain all of them the same formulas for creating most of the building, just to get to an output relating to a point on the roof.

An elegant, yet abnormal solution, would be to have an array exposed in documentation, which the user creates in the code, and then an order of calling that is, functions have to be called in this order, assigned returns to these positions in the array so that everything has a one time call. This would simulate a full construction of an object along its public properties.

All of this would be easy peasy with a module that returns whatever it needs to return by reference. One time coding.

@t-paul
Copy link
Member

t-paul commented May 10, 2022

Sorry, I have no idea what you are asking for. If it's about making values mutable, that's unlikely to happen. The are steps into the direction of making data structures available to user code (#3087).

@jordanbrown0
Copy link
Contributor

I started to think about a return-by-reference scheme, where a module could return a value by assignment to a specially-marked argument, but the current order of execution would make that impossible. All assignments happen before all module invocations, and so an assignment cannot depend on a module invocation.


In many cases the best way to achieve this goal with OpenSCAD is to make use of its "child" mechanism. The "house" module would accept a "chimney" child, and would position it appropriately.

module house() {
    d = 10*sqrt(2);
    cube(d, center=true);
    translate([0, 0, d/2]) rotate([0,45,0]) cube([10,d,10], center=true);
    translate([0,0,d]) children(0);
}

house() {
    cube([2,2,5], center=true);
};

translate([20,0,0]) {
    house() {
        cylinder(d=2, h=5, $fn=20, center=true);
    }
}

@t-paul
Copy link
Member

t-paul commented May 15, 2022

Ok, closing this as there's no repsonse. I'm open to discussions about this, but we are not going to have this ticket open with the questions hanging in the air.

@t-paul t-paul closed this as completed May 15, 2022
@fxeconomist
Copy link
Author

fxeconomist commented May 16, 2022

I wrote some code to allow rotation of a point around a center, using 3 angles of rotation: xy, xz and yz.
This entire gibberish could collapse in a single procedure returning coordinates by reference, however I was forced to slash it into several functions. It's still not fully functional, I don't understand yet why the XY rotation doesn't work, however the other two axes rotations are well done.

function PlaneDistance(x1, y1, x2, y2) = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

function _GetXFromXYRotation(x, y, z, RotationAngleXY, xc, yc, zc) = xc + PlaneDistance(x,y, xc, yc)*cos(atan2(y-yc, x-xc)+RotationAngleXY);
function _GetYFromXYRotation(x, y, z, RotationAngleXY, xc, yc, zc) = yc + PlaneDistance(x,y, xc, yc)*sin(atan2(y-yc, x-xc)+RotationAngleXY);

function _GetXFromXZRotation(x, y, z, RotationAngleXZ, xc, yc, zc) = xc + PlaneDistance(x,z, xc, zc)*cos(atan2(z-zc, x-xc)+RotationAngleXZ);
function _GetZFromXZRotation(x, y, z, RotationAngleXZ, xc, yc, zc) = zc + PlaneDistance(x,z, xc, zc)*sin(atan2(z-zc, x-xc)+RotationAngleXZ);

function _GetYFromYZRotation(x, y, z, RotationAngleYZ, xc, yc, zc) = yc + PlaneDistance(y,z, yc, zc)*cos(atan2(z-zc, y-yc)+RotationAngleYZ);
function _GetZFromYZRotation(x, y, z, RotationAngleYZ, xc, yc, zc) = zc + PlaneDistance(y,z, yc, zc)*sin(atan2(z-zc, y-yc)+RotationAngleYZ);

/* Rotation schema

Original X |      | x1     |      | x2 |    | x2 |
Original Y |  XY  | y1     |  XZ  | y1 | YZ | y2 |
Original Z |      | Zorig  |      | z1 |    | z2 |
                                  PARTIAL    FULL

Partial rotation obtains x1, y1 and z1,
full functions get to x2, y2, z2

*/

function _PartiallyRotatedX(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _GetXFromXZRotation(
                                                                                _GetXFromXYRotation(x, y, z, xyangle, xc, yc, zc),
					  				        _GetYFromXYRotation(x, y, z, xyangle, xc, yc, zc),
										z, xzangle, xc, yc, zc);
																			   
function _PartiallyRotatedY(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _GetYFromXYRotation(
                                                                               x, y, z, xyangle, xc, yc, zc);
																			   
function _PartiallyRotatedZ(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _GetZFromXZRotation(
                                                                                _GetXFromXYRotation(x, y, z, xyangle, xc, yc, zc),
				  					        _GetYFromXYRotation(x, y, z, xyangle, xc, yc, zc),
										z, xzangle, xc, yc, zc);																			   
																			   
function RotateX(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _PartiallyRotatedX(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc);

function RotateY(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _GetYFromYZRotation(
                                                                      _PartiallyRotatedX(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
								      _PartiallyRotatedY(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
								      _PartiallyRotatedZ(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
																	  yzangle, xc, yc, zc);
																	  																	  
																	  
function RotateZ(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc) = _GetZFromYZRotation(
                                                                      _PartiallyRotatedX(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
								      _PartiallyRotatedY(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
								      _PartiallyRotatedZ(x, y, z, xyangle, xzangle, yzangle, xc, yc, zc),
								       yzangle, xc, yc, zc);
														

@jordanbrown0
Copy link
Contributor

Wouldn't this be a function that accepts three 3-vectors (point to transform, rotation center, rotation angles) and returns one 3-vector (transformed point)?

This sounds like it's precisely BOSL2's rot() function function, with a "cp" specified.

But if you'd like a how-to, this isn't the right place. Take it to the mailing list.

@fxeconomist
Copy link
Author

I'm a noob, Jordan. I have no idea how to write a function that returns a vector. After all, a function is a one-line formula here, unlike C. If I cannot fully write all 3 vector formulas in the same line, it can't be done. And I don't know about that mailing list.

@jordanbrown0
Copy link
Contributor

Functions can return any OpenSCAD type.

function myvec() = [ 1, 2, 3 ];

OpenSCAD has vector arithmetic as a native feature and so the natural way to solve problems like this is to construct appropriate transformation matrixes for each step and multiply them together, then multiply by the point to be transformed.

For more, join the mailing list (openscad.org -> community -> mailing list) or drop me a note at openscad (at) jordan.maileater.net.

@nophead
Copy link
Member

nophead commented May 16, 2022

Also functions don't have to be one line. You can use let() to calculate as many intermediate values as you need.

@fxeconomist
Copy link
Author

How ? Can you give an example ? I see it doesn't have a procedural body ending with a "return", but it's just an equal...

@nophead
Copy link
Member

nophead commented May 16, 2022

//
// Generate all the transforms for the profile of the swept volume.
//
function sweep_transforms(path, loop = false, twist = 0) =
    let(len = len(path),
        last = len - 1,

        tangents = [tangent(path, loop ? last : 0, 0, 1),
                    for(i = [1 : last - 1]) tangent(path, i - 1, i, i + 1),
                    tangent(path, last - 1, last, loop ? 0 : last)],

        lengths = [for(i = 0, t = 0; i < len; t = t + norm(path[min(i + 1, last)] - path[i]), i = i + 1) t],
        length = lengths[last],

        rotations = [for(i = 0, rot = fs_frame(tangents);
                         i < len;
                         i = i + 1,
                         rot = i < len ? rotate_from_to(tangents[i - 1], tangents[i]) * rot : undef) rot],

        missmatch = loop ? calculate_twist(rotations[0], rotations[last]) : 0,
        rotation = missmatch + twist
    )
    [for(i = [0 : last])
        let(za = rotation * lengths[i] / length)
            orientate(path[i], rotations[i] * rot3_z(za))
    ];

@fxeconomist
Copy link
Author

Oh, that's something. I didn't even know you can apply a for cycle inside the assignment of an array...

@jordanbrown0
Copy link
Contributor

That's list comprehensions.

But again, a github issue isn't really a good place to discuss this. I'm happy to (and many other people are happy to) give hints, advice, and instructions, but here isn't the right place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants