Initial commit
This commit is contained in:
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
4
app/__main__.py
Normal file
4
app/__main__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .app import app
|
||||
|
||||
|
||||
app.run(debug=True)
|
124
app/app.py
Normal file
124
app/app.py
Normal file
@ -0,0 +1,124 @@
|
||||
import asyncio
|
||||
import io
|
||||
import shutil
|
||||
import tempfile
|
||||
from distutils.dir_util import copy_tree
|
||||
from pathlib import Path
|
||||
|
||||
from quart import Quart, abort, send_file, render_template, request
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
app = Quart(__name__, static_folder="static", template_folder="templates")
|
||||
|
||||
|
||||
# allow at most these many scad processes in parallel
|
||||
semaphore = asyncio.Semaphore(2)
|
||||
|
||||
|
||||
def package_path() -> Path:
|
||||
return Path(__file__).parent
|
||||
|
||||
|
||||
class Generator:
|
||||
GENERATOR_SCAD_FILE_NAME = "generator.scad"
|
||||
GENERATED_STL_FILE_NAME = "generated.stl"
|
||||
|
||||
def __init__(self, name: str, tempdir: Path | str):
|
||||
self._name = name
|
||||
self._tempdir = Path(tempdir)
|
||||
|
||||
def _generate_scad_template(self) -> str:
|
||||
return f"""
|
||||
use <bottle-clip.scad>
|
||||
$fn=180;
|
||||
// one name tag for 0.5l Club Mate and similar bottles
|
||||
bottle_clip(name="{self._name}", logo="thing-logos/fablab-cube2.dxf");
|
||||
"""
|
||||
|
||||
def _generate_files_in_temp_dir(self):
|
||||
copy_tree(str(package_path() / "openscad"), str(self._tempdir))
|
||||
|
||||
with open(self._tempdir / self.GENERATOR_SCAD_FILE_NAME, "w") as f:
|
||||
f.write(self._generate_scad_template())
|
||||
|
||||
async def generate_stl(self) -> str:
|
||||
self._generate_files_in_temp_dir()
|
||||
|
||||
openscad_path = shutil.which("openscad")
|
||||
|
||||
if not openscad_path:
|
||||
abort(500)
|
||||
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
openscad_path,
|
||||
self.GENERATOR_SCAD_FILE_NAME,
|
||||
"-o",
|
||||
self.GENERATED_STL_FILE_NAME,
|
||||
# "--hardwarnings",
|
||||
cwd=self._tempdir,
|
||||
)
|
||||
|
||||
await proc.wait()
|
||||
|
||||
if proc.returncode != 0:
|
||||
abort(500)
|
||||
|
||||
return self.GENERATED_STL_FILE_NAME
|
||||
|
||||
|
||||
@app.route("/generate/<name>")
|
||||
async def generate_rest(name: str):
|
||||
async with semaphore:
|
||||
with tempfile.TemporaryDirectory(prefix="fablab-bottle-clip-generator-") as tempdir:
|
||||
generator = Generator(name, tempdir)
|
||||
|
||||
generated_stl_file_name = await generator.generate_stl()
|
||||
|
||||
# to be able to use send_file with a temporary directory, we need buffer the entire file in memory
|
||||
# before the context manager gets to delete the dir
|
||||
bytes_io = io.BytesIO()
|
||||
|
||||
with open(Path(tempdir) / generated_stl_file_name, "rb") as f:
|
||||
while True:
|
||||
data = f.read(4096)
|
||||
if not data:
|
||||
break
|
||||
bytes_io.write(data)
|
||||
|
||||
# using secure_filename allows us to send the file to the user with some safe yet reasonably
|
||||
# identifiable filename
|
||||
return await send_file(
|
||||
bytes_io,
|
||||
mimetype="model/stl",
|
||||
as_attachment=True,
|
||||
attachment_filename=secure_filename(f"{name}.stl")
|
||||
)
|
||||
|
||||
|
||||
# aside from the RESTful API above, we need a "traditional" HTML forms compatible end point
|
||||
@app.route("/generate")
|
||||
async def generate_form():
|
||||
try:
|
||||
name = request.args["name"]
|
||||
except KeyError:
|
||||
abort(400)
|
||||
return
|
||||
|
||||
return await generate_rest(name)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def index():
|
||||
return await render_template("index.html")
|
||||
|
||||
|
||||
async def test():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
generator = Generator("testabc", td)
|
||||
generated_stl_file_name = await generator.generate_stl()
|
||||
shutil.copy(Path(td) / generated_stl_file_name, ".")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
asyncio.run(test())
|
119
app/openscad/bottle-clip.scad
Normal file
119
app/openscad/bottle-clip.scad
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* A name tag that can easily be clipped to the neck of your bottle.
|
||||
* Copyright (C) 2013 Roland Hieber <rohieb+bottleclip@rohieb.name>
|
||||
*
|
||||
* See examples.scad for examples on how to use this module.
|
||||
*
|
||||
* The contents of this file are licenced under CC-BY-SA 3.0 Unported.
|
||||
* See https://creativecommons.org/licenses/by-sa/3.0/deed for the
|
||||
* licensing terms.
|
||||
*/
|
||||
|
||||
include <write/Write.scad>
|
||||
|
||||
/**
|
||||
* Creates one instance of a bottle clip name tag. The default values are
|
||||
* suitable for 0.5l Club Mate bottles (and similar bottles). By default, logo
|
||||
* and text are placed on the name tag so they both share half the height. If
|
||||
* there is no logo, the text uses the total height instead.
|
||||
* Parameters:
|
||||
* ru: the radius on the upper side of the clip
|
||||
* rl: the radius on the lower side of the clip
|
||||
* ht: the height of the clip
|
||||
* width: the thickness of the wall. Values near 2.5 usually result in a good
|
||||
* clippiness for PLA prints.
|
||||
* name: the name that is printed on your name tag. For the default ru/rt/ht
|
||||
* values, this string should not exceed 18 characters to fit on the name tag.
|
||||
* gap: width of the opening gap, in degrees. For rigid materials this value
|
||||
* usually needs to be near 180 (but if you set it to >= 180, you won't have
|
||||
* anything left for holding the clip on the bottle). For flexible materials
|
||||
* like Ninjaflex, choose something near 0. For springy materials like PLA or
|
||||
* ABS, 90 has proven to be a good value.
|
||||
* logo: the path to a DXF file representing a logo that should be put above
|
||||
* the name. Logo files should be no larger than 50 units in height and should
|
||||
* be centered on the point (25,25). Also all units in the DXF file should be
|
||||
* in mm. This parameter can be empty; in this case, the text uses the total
|
||||
* height of the name tag.
|
||||
* font: the path to a font for Write.scad.
|
||||
*/
|
||||
module bottle_clip(ru=13, rl=17.5, ht=26, width=2.5, name="", gap=90,
|
||||
logo="thing-logos/stratum0-lowres.dxf", font="write/orbitron.dxf") {
|
||||
|
||||
e=100; // should be big enough, used for the outer boundary of the text/logo
|
||||
|
||||
difference() {
|
||||
rotate([0,0,-45]) union() {
|
||||
// main cylinder
|
||||
cylinder(r1=rl+width, r2=ru+width, h=ht);
|
||||
// text and logo
|
||||
if(logo == "") {
|
||||
writecylinder(name, [0,0,3], rl+0.5, ht/13*7, h=ht/13*8, t=max(rl,ru),
|
||||
font=font);
|
||||
} else {
|
||||
writecylinder(name, [0,0,0], rl+0.5, ht/13*7, h=ht/13*4, t=max(rl,ru),
|
||||
font=font);
|
||||
translate([0,0,ht*3/4-0.1])
|
||||
rotate([90,0,0])
|
||||
scale([ht/100,ht/100,1])
|
||||
translate([-25,-25,0.5])
|
||||
linear_extrude(height=max(ru,rl)*2)
|
||||
import(logo);
|
||||
}
|
||||
}
|
||||
// inner cylinder which is substracted
|
||||
translate([0,0,-1])
|
||||
cylinder(r1=rl, r2=ru, h=ht+2);
|
||||
// outer cylinder which is substracted, so the text and the logo end
|
||||
// somewhere on the outside ;-)
|
||||
difference () {
|
||||
cylinder(r1=rl+e, r2=ru+e, h=ht);
|
||||
translate([0,0,-1])
|
||||
// Note: bottom edges of characters are hard to print when character
|
||||
// depth is > 0.7
|
||||
cylinder(r1=rl+width+0.7, r2=ru+width+0.7, h=ht+2);
|
||||
}
|
||||
|
||||
// finally, substract an equilateral triangle as a gap so we can clip it to
|
||||
// the bottle
|
||||
gap_x=50*sin(45-gap/2);
|
||||
gap_y=50*cos(45-gap/2);
|
||||
translate([0,0,-1])
|
||||
linear_extrude(height=50)
|
||||
polygon(points=[[0,0], [gap_x, gap_y], [50,50], [gap_y, gap_x]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one instance of a bottle clip name tag suitable for 0.33l longneck
|
||||
* bottles (like fritz cola, etc.). All parameters are passed to the module
|
||||
* bottle_clip(), see there for their documentation.
|
||||
*/
|
||||
module bottle_clip_longneck(name="", width=2.5, gap=90,
|
||||
logo="thing-logos/stratum0-lowres.dxf", font="write/orbitron.dxf") {
|
||||
bottle_clip(name=name, ru=13, rl=15, ht=26, width=width, logo=logo, gap=gap,
|
||||
font=font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one instance of a bottle clip name tag suitable for 0.33l DIN 6199
|
||||
* beer bottles (also known as "Steinie", "Stubbi", "Knolle", etc.). Because of
|
||||
* reasons, there is no logo, but all other parameters are passed to the module
|
||||
* bottle_clip(), see there for their documentation.
|
||||
*/
|
||||
module bottle_clip_steinie(name="", width=2.5, gap=90, font="write/orbitron.dxf") {
|
||||
bottle_clip(name=name, ru=13, rl=17.5, ht=13, width=width, logo="", gap=gap,
|
||||
font=font);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create one instance of a bottle clip name tag suitable for 0.5l DIN 6198
|
||||
* bottle (also known as "Euroflasche" or "Euroform 2"). All parameters are
|
||||
* passed to the module bottle_clip(), see there for their documentation.
|
||||
*/
|
||||
module bottle_clip_euro2(name="", width=2.5, gap=90,
|
||||
logo="thing-logos/stratum0-lowres.dxf", font="write/orbitron.dxf") {
|
||||
bottle_clip(name=name, ru=13, rl=22.5, ht=26, width=width, logo=logo, gap=gap,
|
||||
font=font);
|
||||
}
|
||||
|
||||
// vim: set noet ts=2 sw=2 tw=80:
|
1964
app/openscad/thing-logos/fablab-cube2.dxf
Normal file
1964
app/openscad/thing-logos/fablab-cube2.dxf
Normal file
File diff suppressed because it is too large
Load Diff
2676
app/openscad/thing-logos/fablab-cube2.svg
Normal file
2676
app/openscad/thing-logos/fablab-cube2.svg
Normal file
File diff suppressed because it is too large
Load Diff
378
app/openscad/write/Write.scad
Normal file
378
app/openscad/write/Write.scad
Normal file
@ -0,0 +1,378 @@
|
||||
/* Version 3
|
||||
Added support for font selection (default is Letters.dxf)
|
||||
Added WriteCube module
|
||||
Added Rotate for text (rotates on the plane of the text)
|
||||
Added writesphere
|
||||
Added space= (spacing between characters in char widths) def=1
|
||||
Added writecylinder()
|
||||
|
||||
By Harlan Martin
|
||||
harlan@sutlog.com
|
||||
January 2012
|
||||
|
||||
(The file TestWrite.scad gives More usage examples)
|
||||
(This module requires the file Letters.dxf to reside in the same folder)
|
||||
(The file Letters.dfx was created with inkscape..Each letter is in its own layer)
|
||||
(This module seperates each letter in the string and imports it from Letters.dfx)
|
||||
|
||||
*/
|
||||
|
||||
pi=3.1415926535897932384626433832795028841971693993751058209;
|
||||
pi2=pi*2;
|
||||
|
||||
|
||||
// These control the default values for write() writesphere() writecube()
|
||||
// if the parameters are not included in the call. Feel free to set your own
|
||||
// defaults.
|
||||
|
||||
//default settings
|
||||
center=false;
|
||||
h = 4; //mm letter height
|
||||
t = 1; //mm letter thickness
|
||||
space =1; //extra space between characters in (character widths)
|
||||
rotate=0; // text rotation (clockwise)
|
||||
font = "Letters.dxf"; //default for aditional fonts
|
||||
|
||||
|
||||
// write cube defaults
|
||||
face = "front"; // default face (top,bottom,left,right,back,front)
|
||||
up =0; //mm up from center on face of cube
|
||||
down=0;
|
||||
right =0; //mm left from center on face of cube
|
||||
left=0;
|
||||
|
||||
|
||||
// write sphere defaults
|
||||
rounded=false; //default for rounded letters on writesphere
|
||||
north=0; // intial text position (I suggest leave these 0 defaults)
|
||||
south=0;
|
||||
east=0;
|
||||
west=0;
|
||||
spin=0;
|
||||
// writecylinder defaults
|
||||
middle=0; //(mm toward middle of circle)
|
||||
ccw=false; //write on top or bottom in a ccw direction
|
||||
r1=0; //(not implimented yet)
|
||||
r2=0; //(not implimented yet)
|
||||
|
||||
|
||||
|
||||
// Contact me if your interested in how to make your own font files
|
||||
// Its tedious and time consuming, but not very hard
|
||||
|
||||
|
||||
module writecylinder(text,where,radius,height){
|
||||
wid=(.125* h *5.5 * space);
|
||||
widall=wid*(len(text)-1)/2;
|
||||
//angle that measures width of letters on sphere
|
||||
function NAngle(radius)=(wid/(pi2*radius))*360;
|
||||
//angle of half width of text
|
||||
function mmangle(radius)=(widall/(pi2*radius)*360);
|
||||
|
||||
if ((face=="top")||(face=="bottom") ){
|
||||
if (face=="top" ){
|
||||
if (center==true){
|
||||
writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
|
||||
space=space,east=east,west=west,middle=middle,ccw=ccw);
|
||||
}else{
|
||||
writecircle(text,where+[0,0,height],radius-h,rotate=rotate,font=font,h=h,t=t,
|
||||
space=space,east=east,west=west,middle=middle,ccw=ccw);
|
||||
}
|
||||
}else{
|
||||
rotate(180,[1,0,0])
|
||||
if (center==true){
|
||||
writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
|
||||
space=space,east=east,west=west,middle=middle,ccw=ccw);
|
||||
}else{
|
||||
writecircle(text,where+[0,0,0],radius-h,rotate=rotate,font=font,h=h,t=t,
|
||||
space=space,east=east,west=west,middle=middle,ccw=ccw);
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
// if (radius>0){
|
||||
if (center==true) {
|
||||
rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
|
||||
translate(where)
|
||||
writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
|
||||
rotate=rotate,t=t,font=font,face=face,up=up,down=down,
|
||||
east=east,west=west,center=center,space=space,rounded=rounded);
|
||||
} else{
|
||||
rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
|
||||
translate(where+[0,0,height/2])
|
||||
writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
|
||||
rotate=rotate,t=t,font=font,face=face,up=up,down=down,
|
||||
east=east,west=west,center=center,space=space,rounded=rounded);
|
||||
}
|
||||
// the remarked out code is for cone shaped cylinders (not complete)
|
||||
// }else{
|
||||
// if (center==true) {
|
||||
// rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
|
||||
// translate(where)
|
||||
// writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
|
||||
// rotate=rotate,t=t,font=font,face=face,up=up,down=down,
|
||||
// east=east,west=west,center=center,space=space,rounded=rounded);
|
||||
// } else{
|
||||
// rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
|
||||
// translate(where+[0,0,height/2])
|
||||
// writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
|
||||
// rotate=rotate,t=t,font=font,face=face,up=up,down=down,
|
||||
// east=east,west=west,center=center,space=space,rounded=rounded);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
module writecircle(text,where,radius){
|
||||
wid=(.125* h *5.5 * space);
|
||||
widall=wid*(len(text)-1)/2;
|
||||
//angle that measures width of letters on sphere
|
||||
function NAngle(radius)=(wid/(pi2*radius))*360;
|
||||
//angle of half width of text
|
||||
function mmangle(radius)=(widall/(pi2*radius)*360);
|
||||
|
||||
if (ccw==true){
|
||||
rotate(-rotate+east-west,[0,0,1]){
|
||||
rotate(-mmangle(radius-middle),[0,0,1]){
|
||||
translate(where)
|
||||
for (r=[0:len(text)-1]){
|
||||
rotate(-90+r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
|
||||
translate([radius-middle,0,0])
|
||||
//rotate(90,[1,0,0])
|
||||
//rotate(90,[0,1,0])
|
||||
rotate(-270,[0,0,1]) // flip text (botom out = -270)
|
||||
write(text[r],center=true,h=h,t=t,font=font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rotate(-rotate-east+west,[0,0,1]){
|
||||
rotate(mmangle(radius-middle),[0,0,1]){
|
||||
translate(where)
|
||||
for (r=[0:len(text)-1]){
|
||||
rotate(90-r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
|
||||
translate([radius-middle,0,0])
|
||||
//rotate(90,[1,0,0])
|
||||
//rotate(90,[0,1,0])
|
||||
rotate(270,[0,0,1]) // flip text (botom out = -270)
|
||||
write(text[r],center=true,h=h,t=t,font=font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
module writethecylinder(text,where,radius,height,r1,r2){
|
||||
wid=(.125* h *5.5 * space);
|
||||
widall=wid*(len(text)-1)/2;
|
||||
//angle that measures width of letters on sphere
|
||||
function NAngle(radius)=(wid/(pi2*radius))*360*(1-abs(rotate)/90);
|
||||
//angle of half width of text
|
||||
|
||||
function mmangle(radius)=(widall/(pi2*radius)*360);
|
||||
translate([0,0,up-down])
|
||||
rotate(east-west,[0,0,1])
|
||||
for (r=[0:len(text)-1]){
|
||||
rotate(-90+(r*NAngle(radius)),[0,0,1])
|
||||
translate([radius,0,-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid)])
|
||||
rotate(90,[1,0,0])
|
||||
rotate(90,[0,1,0])
|
||||
write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
//echo("zloc=",height/2-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module writesphere(text,where,radius){
|
||||
wid=(.125* h *5.5 * space);
|
||||
widall=wid*(len(text)-1)/2;
|
||||
|
||||
echo("-----------------",widall,wid,mmangle(radius));
|
||||
//angle that measures width of letters on sphere
|
||||
function NAngle(radius)=(wid/(pi2*radius))*360;
|
||||
//angle of half width of text
|
||||
function mmangle(radius)=(widall/(pi2*radius)*360);
|
||||
|
||||
rotate(east-west,[0,0,1]){
|
||||
rotate(south-north,[1,0,0]){
|
||||
rotate(spin,[0,1,0]){
|
||||
rotate(-mmangle(radius),[0,0,1]){
|
||||
if ( rounded== false ){
|
||||
translate(where)
|
||||
for (r=[0:len(text)-1]){
|
||||
rotate(-90+r*NAngle(radius),[0,0,1])
|
||||
translate([radius,0,0])
|
||||
rotate(90,[1,0,0])
|
||||
rotate(90,[0,1,0])
|
||||
write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
}else{
|
||||
difference(){
|
||||
translate(where)
|
||||
for (r=[0:len(text)-1]){
|
||||
rotate(-90+r*NAngle(radius),[0,0,1])
|
||||
translate([radius,0,0])
|
||||
rotate(90,[1,0,0])
|
||||
rotate(90,[0,1,0])
|
||||
write(text[r],center=true,h=h,rotate=rotate,t=t*2+h,font=font);
|
||||
}
|
||||
difference(){ //rounded outside
|
||||
sphere(radius+(t*2+h)*2);
|
||||
sphere(radius+t/2);
|
||||
}
|
||||
sphere(radius-t/2); // rounded inside for indented text
|
||||
}
|
||||
}
|
||||
}
|
||||
}}}
|
||||
}
|
||||
|
||||
|
||||
module writecube(text,where,size){
|
||||
if (str(size)[0] != "["){
|
||||
// its a square cube (size was not a matrix so make it one)
|
||||
writethecube(text,where,[size,size,size],h=h,rotate=rotate,space=space,
|
||||
t=t,font=font,face=face,up=up,down=down,right=right,left=left);
|
||||
|
||||
}else{
|
||||
// its not square
|
||||
writethecube(text,where,size,h=h,rotate=rotate,space=space,
|
||||
t=t,font=font,face=face,up=up,down=down,right=right,left=left);
|
||||
}
|
||||
}
|
||||
// I split the writecube module into 2 pieces.. easier to add features later
|
||||
module writethecube(text,where,size){
|
||||
if (face=="front") {
|
||||
translate([where[0]+right-left,where[1]-size[1]/2,where[2]+up-down])
|
||||
rotate(90,[1,0,0])
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
if (face=="back") {
|
||||
translate([where[0]+right-left,where[1]+size[1]/2,where[2]+up-down])
|
||||
rotate(90,[1,0,0]) // rotate around the x axis
|
||||
rotate(180,[0,1,0]) // rotate around the y axis (z before rotation)
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
if (face=="left") {
|
||||
translate([where[0]-size[0]/2,where[1]-right+left,where[2]+up-down ])
|
||||
rotate(90,[1,0,0]) // rotate around the x axis
|
||||
rotate(90,[0,-1,0]) // rotate around the y axis (z before rotation)
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
if (face=="right") {
|
||||
translate([where[0]+size[0]/2,where[1]+right-left,where[2] +up-down])
|
||||
rotate(90,[1,0,0]) // rotate around the x axis
|
||||
rotate(90,[0,1,0]) // rotate around the y axis (z before rotation)
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
if (face=="top") {
|
||||
translate([where[0]+right-left,where[1]+up-down,where[2]+size[2]/2 ])
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
if (face=="bottom") {
|
||||
translate([where[0]+right-left,where[1]-up+down,where[2]-size[2]/2 ])
|
||||
rotate(180,[1,0,0])
|
||||
write(text,center=true,h=h,rotate=rotate,t=t,font=font);
|
||||
}
|
||||
}
|
||||
|
||||
module write(word){
|
||||
|
||||
echo (h);
|
||||
echo (word);
|
||||
echo ("There are " ,len(word) ," letters in this string");
|
||||
// echo ("The second letter is ",word[1]);
|
||||
// echo (str(word[0],"_"));
|
||||
rotate(rotate,[0,0,-1]){
|
||||
for (r = [0:len(word)]){ // count off each character
|
||||
// if the letter is lower case, add an underscore to the end for file lookup
|
||||
if ((word[r] == "a" ) || (word[r]== "b") || (word[r]== "c")
|
||||
|| (word[r]== "d") || (word[r]== "e") || (word[r]== "f")
|
||||
|| (word[r]== "g") || (word[r]== "h") || (word[r]== "i")
|
||||
|| (word[r]== "j") || (word[r]== "k") || (word[r]== "l")
|
||||
|| (word[r]== "m") || (word[r]== "n") || (word[r]== "o")
|
||||
|| (word[r]== "p") || (word[r]== "q") || (word[r]== "r")
|
||||
|| (word[r]== "s") || (word[r]== "t") || (word[r]== "u")
|
||||
|| (word[r]== "v") || (word[r]== "w") || (word[r]== "x")
|
||||
|| (word[r]== "y" )|| (word[r]== "z")){
|
||||
if (center == true) {
|
||||
translate([0,-h/2,0]){
|
||||
scale([.125*h,.125*h,t]){
|
||||
translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
|
||||
linear_extrude(height=1,convexity=10,center=true){
|
||||
import(file = font,layer=str(word[r],"_"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
translate([0,0,t/2]){
|
||||
scale([.125*h,.125*h,t]){
|
||||
translate([r*5.5*space,0,0])
|
||||
linear_extrude(height=1,convexity=10,center=true){
|
||||
import(file = font,layer=str(word[r],"_"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
if (center == true) {
|
||||
translate([0,-h/2,0]){
|
||||
scale([.125*h,.125*h,t]){
|
||||
translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
|
||||
linear_extrude(height=1,convexity=10,center=true){
|
||||
import(file = font,layer=str(word[r]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
translate([0,0,t/2]){
|
||||
scale([.125*h,.125*h,t]){
|
||||
translate([r*5.5*space,0,0])
|
||||
linear_extrude(height=1,convexity=10,center=true){
|
||||
import(file = font,layer=str(word[r]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*writecylinder test
|
||||
translate([0,0,0])
|
||||
%cylinder(r=20,h=40,center=true);
|
||||
color([1,0,0])
|
||||
writecylinder("rotate=90",[0,0,0],20,40,center=true,down=0,rotate=90);
|
||||
writecylinder("rotate = 30,east = 90",[0,0,0],20,40,center=true,down=0,rotate=30,east=90);
|
||||
writecylinder("ccw = true",[0,0,0],20,40,center=true,down=0,face="top",ccw=true);
|
||||
writecylinder("middle = 8",[0,0,0],20,40,h=3,center=true,down=0,face="top",middle=8);
|
||||
writecylinder("face = top",[0,0,0],20,40,center=true,down=0,face="top");
|
||||
writecylinder("east=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",east=90);
|
||||
writecylinder("west=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",ccw=true,west=90);
|
||||
writecylinder("face = bottom",[0,0,0],20,40,center=true,down=0,face="bottom");
|
||||
*/
|
||||
/*writesphere test
|
||||
sphere(20);
|
||||
color([1,0,0])
|
||||
writesphere("Hello World",[0,0,0],20,t=1,h=6);
|
||||
*/
|
||||
/* writecube test
|
||||
translate([30,30,30])
|
||||
cube([10,15,30],center=true);
|
||||
write("hello",center=true,rotate =30);
|
||||
color([1,0,0])
|
||||
writecube( "front",[30,30,30],[10,15,30],h=5,rotate=-90);
|
||||
color([0,1,0])
|
||||
writecube( "back",[30,30,30],size=[10,15,30],h=5,face="back",rotate=90,t=4);
|
||||
color([0,0,1])
|
||||
writecube( "left",[30,30,30],[10,15,30],h=5,face="left",up=5);
|
||||
color([1,1,0])
|
||||
writecube( "right",where=[30,30,30],size=[10,15,30],h=5,face="right",rotate=55);
|
||||
color([1,0,1])
|
||||
writecube( "top",where=[30,30,30],size=[10,15,30],h=5,face="top");
|
||||
color([1,1,1])
|
||||
writecube( "bttm",where=[30,30,30],size=[10,15,30],h=5,face="bottom",rotate=90);
|
||||
*/
|
||||
|
16730
app/openscad/write/orbitron.dxf
Normal file
16730
app/openscad/write/orbitron.dxf
Normal file
File diff suppressed because it is too large
Load Diff
81
app/static/logo.svg
Normal file
81
app/static/logo.svg
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 639 186" style="enable-background:new 0 0 639 186;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
.st1{fill:#939393;}
|
||||
.st2{fill:#D13F34;}
|
||||
.st3{fill:#16A3C4;}
|
||||
.st4{fill:none;stroke:#010101;}
|
||||
</style>
|
||||
<rect class="st0" width="639" height="186"/>
|
||||
<g id="g3" transform="translate(-18.822 2.708864)">
|
||||
<path id="path5" class="st1" d="M91.2,157.7v-20.8c0.7-0.3,1.5-0.6,2.2-1c9.9-5.8,11-22.4,2.3-37.1C87.1,84.1,72,77,62.1,82.9
|
||||
c-9.9,5.8-10.9,22.4-2.3,37.1c1.4,2.4,3,4.5,4.6,6.5v15.4l-21.4-12.2V53.1l-7.5-4.9C28.8,60.5,24.9,74.8,24.9,90
|
||||
c0,47.1,37.4,85.5,84.2,87.1l0-9L91.2,157.7z"/>
|
||||
<path id="path7" class="st2" d="M66.4,36l13.1,7.7c-0.3,2.1-0.3,4.5-0.3,5.3c0.1,11.5,15.7,20.2,32.7,20.1s29.1-10.5,29-20.6
|
||||
c-0.1-11.5-11.2-20.5-28.1-21c-5.7-0.2-11.3,1-13.8,1.5l-9.5-6.1L112,10l66.7,38.8l7.7-4.2c-7.4-12.1-17.8-22.6-30.9-30.2
|
||||
C114.6-9.1,62.7,4.2,38,43.9l7.6,4.8L66.4,36L66.4,36z"/>
|
||||
<path id="path9" class="st3" d="M181,78.2l-14.2,7.4c-0.5-0.1-3.7-3-4.4-3.4c-10-5.6-24.8,1.8-33.1,16.6
|
||||
c-8.3,14.8-7.6,31.8,2.5,37.4c10,5.6,25-1.1,33.3-16c1.3-2.4,3.1-7.9,3.9-10.4l12.1-7l-0.1,26.5l-66.6,38.9l0,8.8
|
||||
c14.2-0.4,28.4-4.3,41.5-11.9c40.7-23.8,54.9-75.5,32.6-116.6l-7.7,4.2V78.2L181,78.2z"/>
|
||||
</g>
|
||||
<path id="path11" class="st4" d="M119.6,176.5"/>
|
||||
<g>
|
||||
<path class="st1" d="M252.5,28.3h-31.3v21.8H250v16.2h-28.8v34.5h-20V12h51.3V28.3z"/>
|
||||
<path class="st1" d="M340.4,100.8h-21.8l-6.3-19.8h-31.6l-6.3,19.8h-21.7L285.1,12h23.7L340.4,100.8z M307.7,65.7l-9.5-29.9
|
||||
c-0.7-2.2-1.2-4.9-1.5-8h-0.5c-0.2,2.6-0.7,5.2-1.5,7.7l-9.7,30.1H307.7z"/>
|
||||
<path class="st1" d="M349.5,100.8V12h32.3c9.9,0,17.5,1.8,22.9,5.5c5.3,3.6,8,8.8,8,15.4c0,4.8-1.6,9-4.9,12.6
|
||||
c-3.2,3.6-7.4,6.1-12.4,7.5v0.2c6.3,0.8,11.4,3.1,15.1,7c3.8,3.9,5.7,8.6,5.7,14.2c0,8.1-2.9,14.6-8.7,19.4s-13.8,7.2-23.8,7.2
|
||||
H349.5z M369.5,26.7v21.1h8.8c4.1,0,7.4-1,9.8-3c2.4-2,3.6-4.8,3.6-8.3c0-6.5-4.9-9.8-14.6-9.8H369.5z M369.5,62.7v23.4h10.8
|
||||
c4.6,0,8.2-1.1,10.9-3.2c2.6-2.1,3.9-5.1,3.9-8.8c0-3.6-1.3-6.3-3.9-8.4c-2.6-2-6.2-3-10.8-3H369.5z"/>
|
||||
<path class="st1" d="M478.4,100.8h-46.1V12h10.4v79.4h35.7V100.8z"/>
|
||||
<path class="st1" d="M566.4,100.8h-11.5l-9.4-24.9h-37.7l-8.9,24.9h-11.6L521.4,12h10.8L566.4,100.8z M542.1,66.6l-13.9-37.8
|
||||
c-0.5-1.2-0.9-3.2-1.4-5.9h-0.2c-0.4,2.5-0.9,4.5-1.4,5.9l-13.8,37.8H542.1z"/>
|
||||
<path class="st1" d="M577.5,100.8V12h25.3c7.7,0,13.8,1.9,18.3,5.6c4.5,3.8,6.8,8.7,6.8,14.7c0,5-1.4,9.4-4.1,13.1
|
||||
c-2.7,3.7-6.5,6.4-11.3,7.9v0.2c6,0.7,10.8,3,14.4,6.8c3.6,3.8,5.4,8.8,5.4,14.9c0,7.6-2.7,13.8-8.2,18.5
|
||||
c-5.5,4.7-12.3,7.1-20.6,7.1H577.5z M587.9,21.4v28.7h10.7c5.7,0,10.2-1.4,13.4-4.1c3.3-2.7,4.9-6.6,4.9-11.6
|
||||
c0-8.6-5.7-12.9-17-12.9H587.9z M587.9,59.4v32H602c6.1,0,10.8-1.4,14.2-4.3c3.4-2.9,5-6.9,5-11.9c0-10.5-7.1-15.7-21.4-15.7H587.9
|
||||
z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st2" d="M227.7,176.5h-5.3v-5.1h-0.1c-2.3,3.9-5.7,5.9-10.1,5.9c-3.3,0-5.8-0.9-7.7-2.6c-1.8-1.7-2.8-4-2.8-6.9
|
||||
c0-6.1,3.6-9.7,10.8-10.7l9.8-1.4c0-5.6-2.3-8.4-6.8-8.4c-4,0-7.5,1.3-10.7,4V146c3.2-2.1,6.9-3.1,11.2-3.1
|
||||
c7.7,0,11.6,4.1,11.6,12.2V176.5z M222.4,159.9l-7.9,1.1c-2.4,0.3-4.3,0.9-5.5,1.8c-1.2,0.9-1.9,2.4-1.9,4.6c0,1.6,0.6,2.9,1.7,3.9
|
||||
c1.1,1,2.7,1.5,4.6,1.5c2.6,0,4.8-0.9,6.5-2.7c1.7-1.8,2.5-4.1,2.5-6.9V159.9z"/>
|
||||
<path class="st2" d="M242.8,176.5h-5.3v-48.6h5.3V176.5z"/>
|
||||
<path class="st2" d="M268.7,176.2c-1.2,0.7-2.9,1-4.9,1c-5.8,0-8.6-3.2-8.6-9.6v-19.4h-5.6v-4.5h5.6v-8l5.3-1.7v9.7h8.3v4.5h-8.3
|
||||
v18.5c0,2.2,0.4,3.8,1.1,4.7c0.7,0.9,2,1.4,3.7,1.4c1.3,0,2.5-0.4,3.4-1.1V176.2z"/>
|
||||
<path class="st2" d="M322.3,176.5h-5.3v-18.9c0-3.6-0.6-6.3-1.7-7.9c-1.1-1.6-3-2.4-5.7-2.4c-2.2,0-4.2,1-5.7,3.1
|
||||
c-1.6,2.1-2.4,4.5-2.4,7.4v18.7h-5.3V157c0-6.5-2.5-9.7-7.5-9.7c-2.3,0-4.2,1-5.7,2.9c-1.5,1.9-2.2,4.5-2.2,7.6v18.7h-5.3v-32.8
|
||||
h5.3v5.2h0.1c2.3-4,5.7-6,10.2-6c2.2,0,4.2,0.6,5.9,1.9c1.7,1.3,2.8,2.9,3.4,4.9c2.4-4.5,6.1-6.8,10.9-6.8
|
||||
c7.2,0,10.8,4.5,10.8,13.4V176.5z"/>
|
||||
<path class="st2" d="M358.8,176.5h-5.3v-5.2h-0.1c-2.2,4-5.6,6-10.1,6c-7.8,0-11.7-4.7-11.7-14v-19.6h5.2v18.8
|
||||
c0,6.9,2.7,10.4,8,10.4c2.6,0,4.7-0.9,6.3-2.8c1.7-1.9,2.5-4.4,2.5-7.4v-18.9h5.3V176.5z M339.3,137.4c-0.9,0-1.7-0.3-2.3-0.9
|
||||
c-0.6-0.6-0.9-1.4-0.9-2.2c0-0.9,0.3-1.6,0.9-2.2c0.6-0.6,1.4-0.9,2.2-0.9c0.9,0,1.6,0.3,2.3,0.9c0.6,0.6,1,1.4,1,2.2
|
||||
c0,0.9-0.3,1.6-0.9,2.2C340.9,137.1,340.2,137.4,339.3,137.4z M351.6,137.4c-0.9,0-1.6-0.3-2.2-0.9c-0.6-0.6-0.9-1.4-0.9-2.3
|
||||
c0-0.9,0.3-1.6,0.9-2.2c0.6-0.6,1.3-0.9,2.2-0.9c0.9,0,1.7,0.3,2.3,0.9s0.9,1.4,0.9,2.2c0,0.9-0.3,1.6-0.9,2.2
|
||||
C353.3,137.1,352.5,137.4,351.6,137.4z"/>
|
||||
<path class="st2" d="M396.7,176.5h-5.3v-18.9c0-6.8-2.5-10.3-7.6-10.3c-2.6,0-4.7,1-6.5,3c-1.8,2-2.6,4.5-2.6,7.6v18.6h-5.3v-48.6
|
||||
h5.3v21.2h0.1c2.5-4.1,6.1-6.2,10.8-6.2c7.4,0,11.1,4.5,11.1,13.4V176.5z"/>
|
||||
<path class="st2" d="M411.9,176.5h-5.3v-48.6h5.3V176.5z"/>
|
||||
<path class="st2" d="M438.7,132.5c-1-0.6-2.2-0.9-3.5-0.9c-3.7,0-5.5,2.3-5.5,7v5.1h7.7v4.5h-7.7v28.3h-5.2v-28.3h-5.6v-4.5h5.6
|
||||
v-5.3c0-3.4,1-6.2,3-8.2c2-2,4.5-3,7.4-3c1.6,0,2.9,0.2,3.8,0.6V132.5z"/>
|
||||
<path class="st2" d="M460.2,149c-0.9-0.7-2.2-1.1-4-1.1c-2.2,0-4.1,1.1-5.6,3.2s-2.3,5-2.3,8.7v16.7h-5.3v-32.8h5.3v6.8h0.1
|
||||
c0.7-2.3,1.9-4.1,3.4-5.4s3.3-1.9,5.2-1.9c1.4,0,2.4,0.1,3.1,0.4V149z"/>
|
||||
<path class="st2" d="M489.4,176.5h-5.3v-5.1H484c-2.3,3.9-5.7,5.9-10.1,5.9c-3.3,0-5.8-0.9-7.7-2.6s-2.8-4-2.8-6.9
|
||||
c0-6.1,3.6-9.7,10.8-10.7l9.8-1.4c0-5.6-2.3-8.4-6.8-8.4c-4,0-7.5,1.3-10.7,4V146c3.2-2.1,6.9-3.1,11.2-3.1
|
||||
c7.7,0,11.6,4.1,11.6,12.2V176.5z M484.1,159.9l-7.9,1.1c-2.4,0.3-4.3,0.9-5.5,1.8c-1.2,0.9-1.9,2.4-1.9,4.6c0,1.6,0.6,2.9,1.7,3.9
|
||||
c1.1,1,2.7,1.5,4.6,1.5c2.6,0,4.8-0.9,6.5-2.7c1.7-1.8,2.5-4.1,2.5-6.9V159.9z"/>
|
||||
<path class="st2" d="M526.5,176.5h-5.3v-18.7c0-7-2.5-10.5-7.6-10.5c-2.6,0-4.8,1-6.5,3c-1.7,2-2.6,4.5-2.6,7.5v18.7h-5.3v-32.8
|
||||
h5.3v5.5h0.1c2.5-4.1,6.1-6.2,10.8-6.2c3.6,0,6.3,1.2,8.2,3.5s2.9,5.7,2.9,10.1V176.5z"/>
|
||||
<path class="st2" d="M563.7,176.5h-7.4l-14.5-15.8h-0.1v15.8h-5.3v-48.6h5.3v30.8h0.1l13.8-15h6.9l-15.2,15.8L563.7,176.5z"/>
|
||||
<path class="st2" d="M594.2,161.4H571c0.1,3.7,1.1,6.5,2.9,8.5c1.9,2,4.5,3,7.8,3c3.7,0,7.1-1.2,10.2-3.7v4.9
|
||||
c-2.9,2.1-6.7,3.1-11.4,3.1c-4.6,0-8.3-1.5-10.9-4.5c-2.7-3-4-7.2-4-12.6c0-5.1,1.4-9.3,4.3-12.5c2.9-3.2,6.5-4.8,10.8-4.8
|
||||
s7.6,1.4,10,4.2c2.4,2.8,3.5,6.6,3.5,11.6V161.4z M588.8,156.9c0-3-0.8-5.4-2.2-7.1c-1.4-1.7-3.4-2.5-6-2.5c-2.5,0-4.6,0.9-6.3,2.7
|
||||
c-1.7,1.8-2.8,4.1-3.2,7H588.8z"/>
|
||||
<path class="st2" d="M629.4,176.5h-5.3v-18.7c0-7-2.5-10.5-7.6-10.5c-2.6,0-4.8,1-6.5,3c-1.7,2-2.6,4.5-2.6,7.5v18.7h-5.3v-32.8
|
||||
h5.3v5.5h0.1c2.5-4.1,6.1-6.2,10.8-6.2c3.6,0,6.3,1.2,8.2,3.5c1.9,2.3,2.9,5.7,2.9,10.1V176.5z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
2675
app/static/pico.css
Normal file
2675
app/static/pico.css
Normal file
File diff suppressed because it is too large
Load Diff
22
app/templates/index.html
Normal file
22
app/templates/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" xmlns="http://www.w3.org/1999/html" data-theme="dark">
|
||||
<head>
|
||||
<title>FabLab Bottle Clip Generator</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='pico.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="container">
|
||||
<center>
|
||||
<img src="{{ url_for('static', filename='logo.svg') }}" style="max-width: 350px; margin-bottom: 30px;">
|
||||
<h1>FabLab Bottle Clip Generator</h1>
|
||||
<p>Bitte gib deinen Namen in das Formular ein und drücke auf <b><i>Generieren</i></b>, um eine STL-Datei zu erhalten.</p>
|
||||
<form action="{{ url_for('generate_form') }}">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" style="text-align: center;" placeholder="Name">
|
||||
<input type="submit" value="Generieren">
|
||||
</form>
|
||||
</center>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user