...
 
Commits (12)
from flask import Flask, render_template, request, send_from_directory, abort, jsonify
from flask_cors import CORS
from wtforms import Form, IntegerField, SubmitField
from os.path import join
......@@ -6,6 +7,7 @@ from svggen.library import getComponent
from svggen.api.composables.graph.Joint import FingerJoint
'''
known_models = [
"Stool",
"SimpleTable",
......@@ -13,12 +15,27 @@ known_models = [
"RockerChair",
"Paperbot",
]
'''
known_models = [
"BoatBase",
"Tug",
"Canoe",
"Catamaran",
"CatFoil",
"Trimaran",
]
app = Flask(__name__, static_url_path="/static")
CORS(app)
@app.after_request
def add_header(response):
response.cache_control.no_cache = True
return response
def make(f, path, args, mkstl=True, mkdxf=True):
t = 0
def make(f, path, args, mkstl=True, mkdxf=True, mksvg=True):
t = 0.1
for p, v in args.iteritems():
try:
......@@ -33,18 +50,20 @@ def make(f, path, args, mkstl=True, mkdxf=True):
pass
j = None
if t:
if t > 1:
j = FingerJoint(thickness=t)
try:
print join(app.static_folder, path)
f.makeOutput(join(app.static_folder, path),
tree=False, unfolding=False, animate=False,
ss = f.makeOutput(join(app.static_folder, path),
tree=False, unfolding=mksvg, animate=False,
autofolding=False, display=False,
silhouette=mkdxf, stl=mkstl,
silhouette=mkdxf, stl=mkstl, stlstr=True,
thickness = t, joint = j)
stlstr = ss["graph"]["stl"]
except Exception as e:
return repr(e)
return stlstr
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST'])
@app.route('/<path:path>', methods=['GET', 'POST'])
......@@ -66,26 +85,30 @@ def catchall(path):
if ext == "json":
return jsonify(f.getParameterInfo())
if ext == "stl":
make(f, component, request.args, mkstl=True, mkdxf=False)
elif ext == "ajax":
ss = make(f, component, request.form)
return "Good"
elif ext == "svg":
#make(f, component, request.args, mkstl=False, mkdxf=False, mksvg=True)
return send_from_directory(join(app.static_folder, component), "graph-print.svg", as_attachment=True, cache_timeout=-1)
elif ext == "stl":
#make(f, component, request.args, mkstl=True, mkdxf=False, mksvg=False)
return send_from_directory(join(app.static_folder, component), "graph-model.stl", as_attachment=True, cache_timeout=-1)
elif ext == "dxf":
make(f, component, request.args, mkstl=False, mkdxf=True)
#make(f, component, request.args, mkstl=False, mkdxf=True, mksvg=False)
return send_from_directory(join(app.static_folder, component), "graph-silhouette.dxf", as_attachment=True, cache_timeout=-1)
elif ext:
abort(400)
elif request.args:
else:
make(f, component, request.args)
return render_template("3d.html", component=component, query=request.query_string)
else:
class ParamForm(Form):
pass
for k, v in f.parameters.iteritems():
setattr(ParamForm, k, IntegerField("%s: " % k, default=v))
return render_template("combined.html", component=component, query=request.query_string, form=ParamForm())
return render_template('params.html', form=ParamForm())
print component
else:
string = "<html><body>"
......
......@@ -2,68 +2,53 @@ if (!Detector.webgl) {
Detector.addGetWebGLMessage();
}
var container = document.getElementById('stl');
// All of these variables will be needed later, just ignore them for now.
var container;
var camera, controls, scene, renderer;
var lighting, ambient, keyLight, fillLight, backLight;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
// var width = window.innerWidth;
// var height = window.innerHeight;
var width = container.offsetWidth;
var height = container.offsetHeight;
var windowHalfX = width / 2;
var windowHalfY = height / 2;
stlinit();
render();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
function stlinit() {
// RENDERER
renderer = new THREE.WebGLRenderer( { alpha: true } );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMap.enabled = true;
// CAMERA
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.z = 200;
camera = new THREE.PerspectiveCamera(45, width / height, 1, 100000);
camera.position.z = 500;
// SCENE
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x72645b );
// OBJECT
var loader = new THREE.STLLoader();
if (typeof model == "undefined")
model = 'static/graph-model.stl';
loader.load( model, function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xff5533, specular: 0x111111, shininess: 200 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.scale.set(1000, 1000, 1000);
geometry.computeFaceNormals();
geometry.computeVertexNormals();
scene.add( mesh );
} );
// scene.background = new THREE.Color( 0x72645b );
// LIGHTING
scene.add( new THREE.HemisphereLight( 0x443333, 0x111122 ) );
addShadowedLight( 1000, 1000, 1000, 0xffffff, 1.35 );
addShadowedLight( 500, 1000, -1000, 0xffaa00, 1 );
// RENDERER
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMap.enabled = true;
// CONTROLS
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
controls.enableKeys = false;
container.appendChild(renderer.domElement);
stlload();
}
function addShadowedLight( x, y, z, color, intensity ) {
......@@ -83,8 +68,92 @@ function addShadowedLight( x, y, z, color, intensity ) {
directionalLight.shadow.bias = -0.002;
}
var mesh;
function stlload() {
// OBJECT
var loader = new THREE.STLLoader();
if (typeof stlmodel == "undefined")
stlmodel = 'static/graph-model.stl';
loader.load( stlmodel, function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xff5533, specular: 0x111111, shininess: 200 } );
mesh = new THREE.Mesh( geometry, material );
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.scale.set(1000, 1000, 1000);
geometry.computeFaceNormals();
geometry.computeVertexNormals();
scene.add( mesh );
} );
}
function stlunload() {
scene.remove(mesh);
}
function stlreload() {
stlunload();
stlload();
render();
}
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
var paramform = document.getElementById('paramform');
paramform.addEventListener("submit", function (event) {
event.preventDefault();
remake();
});
function remake() {
var xhr = new XMLHttpRequest();
var formdata = new FormData(paramform);
// Define what happens on successful data submission
xhr.addEventListener("load", function(event) {
console.log('success: ');
console.log(event.target.responseText);
stlreload();
svgreload();
});
// Define what happens in case of error
xhr.addEventListener("error", function(event) {
console.log('Oops! Something went wrong.');
});
xhr.open('POST', window.location.pathname + ".ajax");
xhr.send(formdata);
}
window.onload = function(e){
remake();
}
var cadview = document.getElementById('dxf');
function dxfinit() {
if (typeof dxfmodel == "undefined")
dxfmodel = 'static/graph-silhouette.dxf';
var dxfscene = new THREE.Scene();
dxfrenderer = new THREE.WebGLRenderer( );
dxfrenderer.setSize(cadview.offsetWidth, cadview.offsetHeight);
cadview.appendChild(dxfrenderer.domElement);
var loader = new THREE.DXFLoader()
loader.load( dxfmodel, function ( data ) {
dxfscene.add(data);
})
}
// dxfinit();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="static/three.js"></script>
<script src="static/Detector.js"></script>
<script src="static/OrbitControls.js"></script>
<script src="static/STLLoader.js"></script>
<style>
body {
overflow: hidden;
margin: 0;
padding: 0;
background: #72645b;
}
</style>
</head>
<body>
<center><a href="{{ component }}.stl?{{ query }}"><h2>Download STL</h2></a></center>
<center><a href="{{ component }}.dxf?{{ query }}"><h2>Download DXF</h2></a></center>
<script>model = 'static/{{ component }}/graph-model.stl'</script>
<script src="static/my.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="static/three.js"></script>
<script src="static/Detector.js"></script>
<script src="static/OrbitControls.js"></script>
<script src="static/STLLoader.js"></script>
<style>
body {
overflow: hidden;
margin: 0;
padding: 0;
background: lightsteelblue;
}
#downloads {
position: fixed;
bottom: 0;
left: 0;
padding: 1vw;
font-size: 1.5em;
}
#params {
position: fixed;
top: 0;
left: 0;
width: 20vw;
padding: 1vw;
}
#stl {
position: fixed;
top: 0;
right: 0;
width: 80vw;
height: 70vh;
}
#dxf {
position: fixed;
bottom: 0;
right: 0;
width: 80vw;
height: 30vh;
}
</style>
</head>
<body>
<div id="downloads">
<a href="{{ component }}.stl?{{ query }}">Download STL</a>
<br>
<a href="{{ component }}.dxf?{{ query }}">Download DXF</a>
</div>
<div id="params">
<h2>{{ component }}</h2>
<form id="paramform">
{% for field in form %}
<label>{{field.label}}</label> {{field}} <br>
{% endfor %}
<br><br>
Material:
<select name="$thickness">
<option value="0.1">Paper</option>
<option value="3">3mm plywood</option>
<option value="5">5mm plywood</option>
</select> <br><br>
<button type=submit>Make!</button>
</form>
</div>
<div id="stl"></div>
<div id="dxf">
<img id="svg" src="{{ component }}.svg">
</div>
<script>stlmodel = 'static/{{ component }}/graph-model.stl'</script>
<script>
function svgreload() {
document.getElementById('svg').src = "{{ component }}.svg?random="+new Date().getTime();
}
</script>
<script src="static/my.js"></script>
</body>
</html>
<html>
<head>
<title>Set parameters</title>
</head>
<body>
<form method="GET">
{% for field in form %}
<label>{{field.label}}</label> {{field}} <br>
{% endfor %}
<br><br>
Material:
<select name="$thickness">
<option value="0">Paper</option>
<option value="3">3mm plywood</option>
<option value="5">5mm plywood</option>
</select> <br><br>
<button type=submit>Make!</button>
</form>
</body>
</html>
......@@ -8,4 +8,5 @@ svgwrite
sympy
triangle
flask-wtf
flask-cors
-e .
......@@ -481,15 +481,18 @@ class Component(Parameterized):
# Process composables in some ordering based on type
orderedTypes = ['electrical', 'ui', 'code'] # 'code' needs to know about pins chosen by 'electrical', and 'code' needs to know about IDs assigned by 'ui'
# First call makeOutput on the ones of a type whose order is specified
rets = {}
for composableType in orderedTypes:
if composableType in self.composables:
kwargs["name"] = composableType
self.composables[composableType].makeOutput(filedir, **kwargs)
ss = self.composables[composableType].makeOutput(filedir, **kwargs)
rets[composableType] = ss
# Now call makeOutput on the ones whose type did not care about order
for (composableType, composable) in self.composables.iteritems():
if composableType not in orderedTypes:
kwargs["name"] = composableType
self.composables[composableType].makeOutput(filedir, **kwargs)
ss = self.composables[composableType].makeOutput(filedir, **kwargs)
rets[composableType] = ss
if kw("tree"):
print "Generating hierarchy tree... ",
......@@ -499,6 +502,7 @@ class Component(Parameterized):
print
print "Happy roboting!"
return rets
###
# OTHER STUFF
......
......@@ -108,6 +108,8 @@ class Graph(Composable, BaseGraph):
basename = filedir + "/" + kw("name", "") + "-"
rets = {}
if kw("unfolding"):
print "Generating cut-and-fold pattern... ",
sys.stdout.flush()
......@@ -146,3 +148,12 @@ class Graph(Composable, BaseGraph):
sys.stdout.flush()
self.toSTL(basename + "model.stl", **kwargs)
print "done."
if kw("stlstr"):
print "Generating 3D model (string)... ",
sys.stdout.flush()
s = self.toSTL(None, **kwargs)
rets["stl"] = s
print "done."
return rets
......@@ -19,13 +19,13 @@ class Drawing:
buffer = 10
for flist in g.facelists:
edges = []
hyperedges = []
for face in flist:
for edge in face.edges:
if edge not in edges:
edges.append(edge)
for hyperedge in face.edges:
if hyperedge not in hyperedges:
hyperedges.append(hyperedge)
pts = [p for e in edges for p in e.pts2D]
pts = [p for e in hyperedges for p in e.pts2D]
minx = min([x[0] for x in pts])
miny = min([x[1] for x in pts])
dx = maxx - minx
......@@ -34,7 +34,7 @@ class Drawing:
maxx = max([x[0] for x in pts]) + dx + buffer
maxy = max([x[1] for x in pts]) + dy + buffer
for e in edges:
for e in hyperedges:
if e.pts2D is None:
pass
#print "No coordinates for edge: " + e.name
......@@ -95,8 +95,14 @@ class Drawing:
@param mode:
"""
import svgwrite
svg = svgwrite.Drawing(filename)
minx, miny, maxx, maxy = self.boundingBox()
dx = maxx-minx
dy = maxy-miny
svg = svgwrite.Drawing(filename,
size=('%fmm' % dx, '%fmm' % dy),
viewBox=('%f %f %f %f' % (minx, miny, dx, dy)))
for e in self.edges.items():
e[1].toDrawing(svg, e[0] if labels else "", mode)
svg.save()
......@@ -119,10 +125,22 @@ class Drawing:
@return: a list of all Edge instance endpoints in Drawing (can include redundant points and edges)
"""
edges = []
for e in self.edges.items():
edges.append(e[1].coords())
for e in self.edges.itervalues():
edges.append(e.coords())
return edges
def boundingBox(self):
pts = [x[0] for x in self.edgeCoords()] + [x[1] for x in self.edgeCoords()]
minx = min([x[0] for x in pts])
miny = min([x[1] for x in pts])
maxx = max([x[0] for x in pts])
maxy = max([x[1] for x in pts])
dx = maxx - minx
dy = maxy + miny
return minx, miny, maxx, maxy
def renameedge(self, fromname, toname):
"""
Renames an Edge instance's Key
......@@ -148,13 +166,7 @@ class Drawing:
@return: Drawing with the new Edge instances.
"""
if relative is not None:
pts = [x[0] for x in self.edgeCoords()] + [x[1] for x in self.edgeCoords()]
xs = [x[0] for x in pts]
ys = [x[1] for x in pts]
minx = min(xs)
maxx = max(xs)
miny = min(ys)
maxy = max(ys)
minx, miny, maxx, maxy = self.boundingBox()
midx = minx + relative[0]*(maxx + minx)
midy = miny + relative[1]*(maxy + miny)
origin=(origin[0] - midx, origin[1] - midy)
......
......@@ -323,7 +323,7 @@ class Edge:
dpi = None
if mode in ( 'Corel', 'print'):
if mode in ( 'Corel'):
dpi = 96 # scale from mm to 96dpi for CorelDraw
elif mode == 'Inkscape':
dpi = 90 # scale from mm to 90dpi for Inkscape
......
......@@ -48,16 +48,26 @@ def STLWrite(faces, filename, **kwargs):
facets.append(np.dot(r, t) * scale)
triangles.extend(facets)
with open(filename.replace(".stl", "_%02d.stl" % i), 'wb') as fp:
writer = Binary_STL_Writer(fp)
writer.add_faces(facets)
writer.close()
if filename:
with open(filename.replace(".stl", "_%02d.stl" % i), 'wb') as fp:
writer = Binary_STL_Writer(fp)
writer.add_faces(facets)
writer.close()
faces = triangles
with open(filename, 'wb') as fp:
writer = Binary_STL_Writer(fp)
if filename:
with open(filename, 'wb') as fp:
writer = Binary_STL_Writer(fp)
writer.add_faces(faces)
writer.close()
else:
import StringIO
buf = StringIO.StringIO()
writer = Binary_STL_Writer(buf)
writer.add_faces(faces)
writer.close()
return buf.getvalue()
def DXFWrite(edges, filename):
from dxfwrite import DXFEngine as dxf
......@@ -301,7 +311,7 @@ class Graph():
else:
print "skipping face:", face.name
'''
STLWrite(stlFaces, filename, **kwargs)
return STLWrite(stlFaces, filename, **kwargs)
def toSVG(self, filename):
# XXX TODO
......