Openscad示例

Openscad sample

Openscad是3D建模的软件,与其它常见的3D建模软件不同,Openscad以程序的形式生成3D模型。这种方式特别适合制作相对规整的模型,不太适合制作艺术品。

Openscad的语法相对简单,一页纸就涵盖了所有的函数,可在使用时查阅cheatsheet

一些注意事项

  • Openscad的变量值在编译时确定,有点像其它编程语言的常量,但是如果在多个地方定义了变量,这个变量的实际值为最后一次定义的值
  • 使用*移除后面的模型。与使用//注释只影响当前行不同,使用*会移除后面的完整模型。
    *translate([50, 0, 0])
      cube([50, 50, 50], false);
    
  • if语句在function里不可用,但三目运算= ? ... : ...可以
  • 可使用includeuse导入其它scad文件。include导入当于复制粘贴,use导入只导入module与function定义,其它命令都会被忽略。
  • 可使用import指令导入stl文件,用于展示。

Openscad示例

// cheatsheet: https://www.openscad.org/cheatsheet/index.html?version=2019.05

// Number of fragments, larger number makes the curved surface looks smoother
// Has no effect on the printed model
$fn = 80;

// Set default display color for following objects
// RGB color also works, color([0.5, 0.3, 0.8])
color("green")
// Use intersection to remove all parts with no overlapping
intersection(){
  // Use * to remove the following object
  *translate([50, 0, 0])
    cube([50, 50, 50], true);

  // Use # to hightlight the object
  #cylinder(  25, d1=29,  d2=29  );

  // Use % to make the object transparent
  %sphere(20);
  // Use ! to hide all objects except the current one
  // !sphere(20);


  rotate(a=[0,180,0]) {
    cylinder(h=105, r1=2.5, r2=9.5, center=true);
  };
}


// Use difference to remove the following parts from the first object
translate([0, 0, 120])
difference(){
  sphere(40);
  cylinder(r=20, h=200, center=true);
}

color([0.2, 0.5, 0.8])
// Note for loop does a union for you
translate([50, 0, 0])
for(i = [10:5:30]){
  x = i*2;
  translate([x, i, 0])
    cylinder(h=80, r1=5, r2=i, center=true);
};

// Intersection for loop
color([1, 0.5, 0.8])
// Note for loop does a union for you
translate([110, 30, 80])
rotate([180, 0, 120])
intersection_for(i = [10:10:30]){
  translate([i/2, i/2, 0])
    cylinder(h=80, r1=5, r2=i, center=true);
 };


// Use module to create reusable objects
module pyramid(loc=[0, 0, 0], height=22){
  // Create a pyramid from a 2D square using linear_extrude
  translate(loc)
    linear_extrude(height=height, scale=0)
    square(height, true);
}

pyramid([0, -50, 0], 30);
pyramid([0, -100, 0], 40);


// Use `children()` in module to apply command to all child components
// Use `children(0)` to refer to the first child component
module move_to(loc){
  translate(loc) children();
}

color("lightgreen")
move_to([0, 40, 0])
pyramid(height=28);

// Create donuts using rotate_extrude
// rotate_extrude first rotate a 2D shape 90deg around x-axis, then rotate around z-axis
color("pink")
translate([0, 0, 80])
rotate_extrude(angle=360, $fn=100)
translate([30, 0, 0])
circle(10, $fn=100);


// You can import 2D shape and generate a 3D shape from it
color("blue")
translate([0, 100, 0])
linear_extrude(height=22)
scale(0.1)
// In Inkscape, you can use Path-Trace Bitmap to create path from bitmap automatially
import(file="Io.svg");

// Include a file, everything in that file will be included
// include <myfile.scad>

// Use a lib, only module and function definition will be imported
// use <myfile.scad>

// When applying + or - on two vectors, the two vectors are added or subtracted element-wise.
// When applying * on two vectors, the result is a single number, the dot product of the two vectors

从命令行导出STL

从命令行导出STL的优点是可以批量导出STL。可以用下面的脚本辅助导出STL:

# Filename scad_to_stl.py
# Usage
# Convert input scad file to stl
# python3 scad_to_stl.py -i myfile.scad -o myfile-top.stl --append ' SHOW_TOP=1; '
#
#

from subprocess import check_output
import logging
from logging import info

logging.basicConfig(format='%(name)s - %(levelname)s - %(message)s', level=logging.INFO)


_top_opts = ' TShell=1; BShell=0; FPanL=0; BPanL=0;PanelFeatures=0; '
_bot_opts = ' TShell=0; BShell=1; FPanL=0; BPanL=0;PanelFeatures=0; '
_front_opts = ' TShell=0; BShell=0; FPanL=1; BPanL=0;PanelFeatures=1; '
_back_opts = ' TShell=0; BShell=0; FPanL=0; BPanL=1;PanelFeatures=1; '

_sides = dict(top=_top_opts,
              bottom=_bot_opts,
              front=_front_opts,
              back=_back_opts)

def scad_to_stl(p_scad, p_stl, append=''):
    with open(p_scad, 'r') as f:
        content = f.read() + ' ' + append
        # https://github.com/openscad/openscad/issues/615
        # openscad /dev/null -D "cube([2,3,4]);" -o dump.png
        resp = check_output(['openscad', '/dev/null', '-D', content, '-o', p_stl])
        info(f'resp: {resp}')


if __name__ == "__main__":
    import argparse
    ap = argparse.ArgumentParser()

    ap.add_argument("-i", "--input", type=str, help="Input scad file")
    ap.add_argument("-s", "--side", type=str,
                    default='',
                    help="Side to export to stl file, only for https://github.com/jbebel/Ultimate-Box-Maker.\nOptions: top, bottom, front, back")
    ap.add_argument("--append", required=False, type=str,
                    default='',
                    help="Additional content to append to the input file, you can use this option to override variables in scad source")
    ap.add_argument("-o", "--output", type=str, help="Output stl file")

    args = vars(ap.parse_args())
    side = args['side']
    opts = _sides.get(side, '')
    append = opts + args['append']
    info(f'Convert scad to stl using additional opts: {append}')
    scad_to_stl(args['input'], args['output'], append)

如果你的模型会有多个面需要打印,可以利用opencad变量值以最后一次定义为准的特点,在openscad源码里定义变量用于控制某个面是否显示,在导出时配置需要覆盖的参数,例如

python3 scad_to_stl.py -i myfile.scad -o myfile-top.stl --append ' SHOW_TOP=1; '

Openscad库

MCAD包含了多面体,文本,数据计算等工具。

Comment