Images on curved (cylindrical) surface

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

Images on curved (cylindrical) surface

Lukas
This post has NOT been accepted by the mailing list yet.
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

MichaelAtOz
Administrator
Lukas wrote
Hi,

I am just getting started with OpenSCAD and just found the feature to import images via an Inkscape extension. But the tutorials I found only show the import/editing of flat images.

Is there any chance to put this flat image onto a curved surface such as a cylinder?

Hope the question makes sense...

Thanks,
Lukas
AFAIK no, not if you mean like wrapping a label around an object.
If the image is like a line drawing, you could linear_extrude it & intersect it with a hollow cylinder, but the result would be contorted.
Or you could slice it up and move the bits around, but the maths would be beyond me.
Admin - email* me if you need anything,
or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work.
Obviously inclusion of works of previous authors is not included in the above.


The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out!
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

Parkinbot
This post was updated on .
And it would be so easy, once one could get (programmatically) hands on the DXF representation in OpenSCAD ...  

But there is also a programmatic solution with current OpenSCAD using some windowing technique for discretization. Not the fastest but viable:

 

R = 45;  // radius
H = 2;   // height
L = 130; // centering offset
step = 5;

$fn=360/step;

for (i=[0:step:360])
{
  radian = R*PI/180;
  rotate([0, i, 0])   translate([0,0,R-H/2]) // cylinder stuff
  intersection()
  {
    translate([L-i*radian, 0, 0])  // shift dxf over the window
    linear_extrude(height = H, center = true, convexity = 4)
    import("geschafft.dxf");
    cube([radian*step, 100, H+1], center = true);  // window
  }
}

color("black", .7)
rotate([90, 0, 0])
cylinder(r=R-H, h = 100, center = true);
geschafft.dxf
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

David Eccles (gringer)
<quote author="Parkinbot">
But there is also a programmatic solution with current OpenSCAD using some windowing technique for discretization. Not the fastest but viable<quote>

I've got code for making pasta / pastry cutting rollers which imprint a tessellating image on the surface of a cylinder. The simplest version is one where the image needs no rotation and can tessellate by simple translation:

http://www.thingiverse.com/thing:1640712



It uses hull operations to combine two cylinders at interpolated points derived from the source polygon. Unfortunately I need to have an explicitly-defined source polygon at the moment, as I couldn't find a way in OpenSCAD to extract polygon paths from arbitrary objects. This can be extracted from SVG paths and pasted into the OpenSCAD code, but it's not particularly easy for a first-timer to do that.

    pr=20; // pattern radius
    pi=3.1415927;
    cr=3*pr/sin(60)/(2*pi); // cylinder radius
    pf=0.2; // relative size of edge points
   
    // Flattens an array down one level (removing the enclosing array)
    function flatten(pointArray, done=0, res=[]) =
        (done == len(pointArray)) ?
            res :
            flatten(pointArray=pointArray, done=done+1,
                res=concat(res,pointArray[done]));
               
    // linear interpolation between two points, excludes last point
    function intp(p1, p2, thr=0.5, res = []) =
        (norm(p2-p1) <= thr) ? concat(res,[p1]) :
            intp(p1=p1 + (thr/norm(p2-p1)) * (p2-p1), p2=p2,
                thr=thr, res = concat(res,[p1]));
   
    kath_poly = flatten([ for(i=[-30:60:329]) [
            [pr*cos(i)-pr*pf*cos(i),pr*sin(i)-pr*pf*sin(i)],
            [pr*cos(i),pr*sin(i)],
            [pr*cos(i)+pr*pf*cos(i+60),pr*sin(i)+pr*pf*sin(i+60)] ]]);
   
    int_kath = flatten([for(i = [0:(len(kath_poly)-1)])
            intp(p1=kath_poly[i], p2=kath_poly[(i+1) % len(kath_poly)], thr=2)]);
   
    cyl_kath = [ for(i = [0:(len(int_kath)-1)])
      [(cr)*cos(int_kath[i][0]/cr * 180/pi),(cr)*sin(int_kath[i][0]/cr * 180/pi),-int_kath[i][1]] ];
   
    module 3d_kath(){
        for(i = [0:(len(cyl_kath)-1)]){
            hull(){
                translate(cyl_kath[i])
                    rotate(int_kath[i][0]/cr * 180/pi) rotate([90,0,90])
                        translate([0,0,1])
                            cylinder(r1=2, r2=0, h=4, $fn=4, center=true);
                translate(cyl_kath[(i+1) % len(cyl_kath)])
                    rotate(int_kath[(i+1) % len(cyl_kath)][0]/cr * 180/pi) rotate([90,0,90])
                        translate([0,0,1])
                            cylinder(r1=2, r2=0, h=4, $fn=4, center=true);
            }
        }
    }
   
    module kath_roller(){
        cylinder(r=cr, h=110, center=true);
        3d_kath();
        rotate(180) 3d_kath();
        translate([0,0,1.5*pr]) rotate(90) 3d_kath();
        translate([0,0,1.5*pr]) rotate(270) 3d_kath();
        translate([0,0,-1.5*pr]) rotate(90) 3d_kath();
        translate([0,0,-1.5*pr]) rotate(270) 3d_kath();
    }

    kath_roller();
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

Neon22
This post was updated on .
However it is easy for a first timer to use Inkscape to create the svg and the openscad export tool to create polygon lists.
- http://www.thingiverse.com/thing:1065500

@david can you adjust your code to take those lists ?
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

Lukas
This post has NOT been accepted by the mailing list yet.
In reply to this post by Parkinbot
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

frankv
In reply to this post by Lukas
I was just looking at this problem myself. My starting point was http://www.thingiverse.com/thing:1481 which wraps 3 copies of an image around a cylinder, then extrudes. There's about 15KB of Python source that generates an OpenSCAD file. License on this is "Creative Commons - Attribution - Non-Commercial". The author is Philipp Tiefenbacher (wizard23). I've refactored his code a little, and extended it to include conic surfaces, without really understanding how the underlying stuff works. I haven't finished my tidy-up yet, but I'm happy to share (now or when finished) as per Philipp's license. I'm new to openSCAD & Python (but a long-time programmer) so my "tidy" may be less than your "tidy". I'm equally happy for someone else to finish this off. If all you're interested in is mapping text characters to a cylinder, then http://www.thingiverse.com/thing:1661993 is useful. Frank
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

frankv
Turned out to be easier than I thought... because openSCAD now can handle faces with more that 3 vertices, I could throw out all Philipp's stuff that I didn't understand. Here's working version:

#!/usr/bin/python
 
import sys
import png
import urllib
from math import *
from pyopenscad import *
 
# Wrap a 2D image around a conic surface
# Based on source code by Philipp Tiefenbacher (wizard23) 
# Licensed as per http://creativecommons.org/licenses/by-nc/3.0/ (Creative Commons - Attribution - Non-Commercial)
#
# Frank van der Hulst
# 11 July 2016
# Usage: python conewrap.py imgFile bottomRadius topRadius > output.scad
 
# Global variables
numRows = 0
numCols = 0
minRadius = 0
 
# Read a grey-scale PNG and return a table (array of arrays) of pixel values
def getPNG(filename):
  r=png.Reader(file=urllib.urlopen(filename))
  data = r.read()
  pixel = data[2]
  raw = []
  for row in pixel:
    r = []
    raw.append(r)
    for px in row:
      r.append(px)
  return raw
 
 
# Project a pixel from the bitmap onto a conic surface
# Each pixel represents a unit square
# The height describes the horizontal distance of that pixel from the surface of the cone. Where the cone is reasonably steep, this approximates to how high
# the image is embossed on the cone's surface (positive z values), or how deeply it is recessed into the surface (negative z values)
# bottomRadius and topRadius are the radii of the circles at the bottom and top of the conic fragment. They may be equal for a cylinder, or topRadius may be larger or smaller than bottomRadius.
# topRadius may be zero to produce an actual cone. If bottomRadius < the minimum radius to map the image (e.g. the image is 256 pixels wide && bottomRadius < 40.74 (256/2*pi)), bottomRadius is increased
# cylRange is the fraction (0-1) of the cylinder the image should be wrapped around (e.g. 0.25 means wrapi it around 90 degrees)
def projectCone(x, y, height, bottomRadius, topRadius, cylRange):
  # Calculate radial for wrapping
  a = x*2*pi/numCols*cylRange
  # Calculate distance from axis... linear interpolation between top and bottom radius of the cone
  r = topRadius + (bottomRadius-topRadius) * (numRows-y)*1.0/numRows + height
  # Calculate 3D coordinate of this point
  return [r*cos(a), r*sin(a), y]
 
# Map the pixMap onto a conic surface with the given radii
def mapImage(pixMap, bottomRadius, topRadius):
  minRadius=numCols/(2*pi)
  if (bottomRadius < minRadius):
    bottomRadius = minRadius
  cylRange = minRadius*1.0/bottomRadius
 
  # Generate all the points for the surface
  pts = []
  for y in xrange(0, numRows):
    # Generate a "circle" of points for this layer
    for x in xrange(0, numCols):
      # Pixels range in value from 0-255, where 0 = black and 255 = white
      p = projectCone(x, y, -pixMap[y][x]/255.0, bottomRadius, topRadius, cylRange)
      pts.append(p)
 
  # Generate bottom face: A face is 4 indices of points
  faces = []
  bottom=[]
  for x in xrange(0, numCols):
    bottom.append(x)
  bottom.append(0)
  faces.append(bottom)
   
  # Generate all the faces: A face is 4 indices of points
  for y in range(0, numRows-1):
    for x in range(0, numCols):
      p1 = y*numCols+(x+1)%numCols
      p2 = y*numCols+x
      p3 = (y+1)*numCols+x
      p4 = (y+1)*numCols + (x+1)%numCols
      f = [p1, p2, p3, p4]
      faces.append(f)
 
  # Generate top face if this not a complete cone... NB reverse direction
  if (topRadius != 0):
    top=[]
    for x in xrange(0, numCols):
      top.append(numRows*numCols - x)
    top.append(numRows*numCols)
    faces.append(top)
 
  return polyhedron(pts, faces, 6)
 
if (len(sys.argv) !=4):
  print "Usage: python ", sys.argv[0], "imgFile bottomRadius topRadius > output.scad"
  print "e.g.   python ", sys.argv[0], "santa-claus-grey.png 45 0 > santa.scad"
  exit()

# File to project must be 8-bit greyscale
imgFile = sys.argv[1]
 
# Radius of the bottom of the cone... if it is less than minRadius, the cone will be expanded to minRadius. If greater than minRadius, a D-shaped partial cone will be produced
# Zero means the output cone's radius will be adjusted to wrap the image exactly once around the cone
coneRadius = float(sys.argv[2])
 
# Radius of the top of the cone... may be zero
topRadius = float(sys.argv[3])
 
# Read pixel map from PNG file
pixMap = getPNG(imgFile)
# Flip image upside-down
pixMap.reverse()
numCols = len(pixMap[0])
numRows = len(pixMap)
 
result = mapImage(pixMap, coneRadius, topRadius)
 
import time
print time.strftime("// Generated: %Y-%m-%d %H:%M")
print "// Source file: ", imgFile
print "// Image Height = ", numRows
print "// Image Width = ", numCols
print "// Minimum cylinder radius = ", minRadius
print "// Cylinder radius = ", coneRadius
print "$fa=2; $fs=0.5;\n"
print result.render()


On Mon, Jul 11, 2016 at 12:54 PM, frankv <[hidden email]> wrote:
I was just looking at this problem myself. My starting point was http://www.thingiverse.com/thing:1481 which wraps 3 copies of an image around a cylinder, then extrudes. There's about 15KB of Python source that generates an OpenSCAD file. License on this is "Creative Commons - Attribution - Non-Commercial". The author is Philipp Tiefenbacher (wizard23). I've refactored his code a little, and extended it to include conic surfaces, without really understanding how the underlying stuff works. I haven't finished my tidy-up yet, but I'm happy to share (now or when finished) as per Philipp's license. I'm new to openSCAD & Python (but a long-time programmer) so my "tidy" may be less than your "tidy". I'm equally happy for someone else to finish this off. If all you're interested in is mapping text characters to a cylinder, then http://www.thingiverse.com/thing:1661993 is useful. Frank

View this message in context: Re: Images on curved (cylindrical) surface
Sent from the OpenSCAD mailing list archive at Nabble.com.

_______________________________________________
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: Images on curved (cylindrical) surface

blobule
When I need to wrap a shape around a cylinder, I cut it in small pieces that I reassemble on the cylinder.
The shape (here in orange) can be anything close to flat.



Here is the code:

w=30; // radius of cylinder
h=100; // height of cylinder

//
// the pattern should be at [w,0,0] and move in y according to a
// pattern should be 2Pi * w size in Y
// Some rings...
//
module pattern0(a=0) {
    for(i=[0:3]) {
        translate([w,a*PI/180*w+i*PI/2*w+w,-20])
        rotate([-90,0,-90])
        difference() {
            cylinder(d1=PI/2*w+3,d2=0,h=80);
            translate([0,0,-0.1]) cylinder(d1=PI/2*w-3,d2=45+50,h=80);
        }
    }
}
// some text...
module pattern1(a=0) {
    translate([w,a*PI/180*w,10])
    rotate([90,0,90])
    linear_extrude(height=5,convexity=2) text("bonjour!",32);
}

// rings and text...
module pattern2(a=0) {
    pattern0(a);
    pattern1(a);
}


module cutter(a=5,w=50,h=100) {
    render()
    intersection() {
        rotate([0,0,-a/2]) translate([0,0,-h/2]) cube([w,50,h]);
        rotate([0,0,a/2]) translate([0,-50,-h/2]) cube([w,50,h]);
    }
}

%cylinder(r=w,h=h,center=true);

color("orange") translate([0,0,0]) pattern2(0);

step=5;
for( i=[0:step:360+2*step] ) {
    rotate([0,0,i])
    intersection() {
        pattern2(-i);
        cutter(step,w+20,h+20);
    }
}


Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

kerog
In reply to this post by frankv
Would there be a way to package this in such a way that one could use it with the Thingiverse customizer?
Reply | Threaded
Open this post in threaded view
|

Re: Images on curved (cylindrical) surface

Neon22
you can't wrap the python for custoizer but if you embed the scad code into your single file. no problem. Customiser can't include or use any external file except for the ones the website includes itself. over which you have no control.