Wrap an image around a cylinder
Asked Answered
N

1

4

Someone asked me recently if I could print a bracelet with a custom image engraved on its side.

To me, the problem is simple: I have a 2d cartesian system (x,y) that expresses the points of the vectorized image the person sent me. I want to treat these as a 3d cylindrical system (theta, r, z') where r is constant. Finally, I want to convert this 3d cylindrical system to a 3d cartesian system (x',y',z') in the usual way.

So:

z' = y
y' = r cos(x)
x' = r sin(x)

The problem is I don't know how to express this to OpenSCAD. There is an option for matrix transformation using multmatrix(), but this only allows for linear transformation - i.e. I can't express things like cos(x), at least to my knowledge.

What I want is either:

  • an existing module/hack to express this transformation, or

  • a generic method for performing per-vertex transformations, much like a vertex shader in glsl

At very least, is it possible to confirm such things are not available in OpenSCAD?

Negrophobe answered 21/10, 2014 at 14:58 Comment(0)
F
2

you can use surface(), see http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Surface. Calculate the heightmap in an external script and write the values in a file, e.g. 'surface.dat'. you can translate and rotate the resulting surface and use it in difference().

I tried it with this code and the 'surface.dat' from documentation

difference() {
translate([0,0,5])cube([10,10,10], center =true);
rotate([0,0,90])surface(file = "surface.dat", center = true, convexity = 5);}

edit 28.10.2014: in another way you can use pixeldata in a matrix to place pixel by pixel on the circumference of the bracelet by a for loop and iteration over the matrix. The vectors in the matrix contain pixel(x), pixel(y) and the greyvalue/255 as dimension for depth of engraving. To reduce the number of shapes the pixels of one column can be pooled, creating a polygon representing the depth-profile of this column and linear-extrude it. In this case the vectors contain the pixel(x) and the pointmatrix of the polygon. I tried it successfully with the known graphic of Che. To generate the matrix i use python3.4, PyQt5 and Qt.QtGui.QImage. By default openscad turns off rendering at 2000 elements. You can set it to the needed number under Edit/Preferences/Advanced

the openscad-script:

include <./matrix_p.scad>;
difference() {
    translate([-b,0,0]) rotate([0,90,0]) difference() {
        cylinder(h = hb, r = rb, center = false);
        translate([0,0,-0.5]) cylinder(h = hb+1, r = rb-tb, center = false);
    } 
    for (val = m)
    rotate([-ap*val[0],0,0]) translate([0,-rb-0.1,-ps/2]) linear_extrude(height = ps) polygon(points = val[1]);
}

parameter set in matrix_p.scad:

// userinput
rb = 50;                    //radius bracelet
tb = 5;                     //thickness of b.
hb = 80;                    //height of b.
b = 10;                     //borderwidth beside engraving
// input from Qt.QtGui.QImage
iw = 590;                   //imagewidth in pixel
ih = 726;                    //height in pixel
ps = (hb-2*b)/ih;           //scaling of pixel to fill the free place
ap = (ps*180)/(PI*rb);      //angle per pixel

Download all scripts

Ferryboat answered 23/10, 2014 at 10:47 Comment(2)
I can't see how this works as a solution. I know surface() can be used on the image otherwise I would have asked that question. The problem is not how to convert the image to a 3d shape, but how to bend the resulting 3d shape to conform to the sides of a bracelet.Negrophobe
This is the way, i had in mind: Turn your bracelet with its axis parallel to the y-axis and calculate for every point on the x-y-plane the z-value on the circumference of your bracelet. Using these values in surface.dat you get with surface() the counterpart of the underpart of your bracelet. You can adjust x and z by the depth of engraving. As with surface() only 1 unique z to every point ist possible, perhaps you need to divide in several sectors.Ferryboat

© 2022 - 2024 — McMap. All rights reserved.