Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit da5721912e94fa33fb633ade96703a8acc121a1a @MaskedRetriever committed Jul 30, 2010
Showing with 628 additions and 0 deletions.
  1. +46 −0 Line.pde
  2. +79 −0 Mesh.pde
  3. +80 −0 Slice.pde
  4. +165 −0 SuperSkein.pde
  5. +207 −0 Triangle.pde
  6. +51 −0 readme.txt
  7. BIN sculpt_dragon.stl
46 Line.pde
@@ -0,0 +1,46 @@
+// Line Class
+// Once we have the slices as 2D lines,
+// we never look back.
+class Line2D {
+
+ float x1,y1,x2,y2;
+
+ Line2D(float nx1, float ny1, float nx2, float ny2) {
+ x1=nx1;
+ x2=nx2;
+ y1=ny1;
+ y2=ny2;
+ }
+
+ void Scale(float Factor)
+ {
+ x1=x1*Factor;
+ x2=x2*Factor;
+ y1=y1*Factor;
+ y2=y2*Factor;
+ }
+
+ void Flip()
+ {
+ float xn, yn;
+ xn = x1;
+ yn = y1;
+ x1 = x2;
+ y1 = y2;
+ x2 = xn;
+ y2 = yn;
+ }
+
+ void Rotate(float Angle)
+ {
+ float xn,yn;
+ xn = x1*cos(Angle) - y1*sin(Angle);
+ yn = x1*sin(Angle) + y1*cos(Angle);
+ x1 = xn;
+ y1 = yn;
+ xn = x2*cos(Angle) - y2*sin(Angle);
+ yn = x2*sin(Angle) + y2*cos(Angle);
+ x2 = xn;
+ y2 = yn;
+ }
+}
79 Mesh.pde
@@ -0,0 +1,79 @@
+// Mesh Class
+
+class Mesh {
+ ArrayList Triangles;
+ float bx1,by1,bz1,bx2,by2,bz2; //bounding box
+
+
+
+ //Mesh Loading routine
+ Mesh(String FileName)
+ {
+ byte b[] = loadBytes(FileName);
+ Triangles = new ArrayList();
+ float[] Tri = new float[9];
+ //Skip the header
+ int offs = 84;
+ //Read each triangle out
+ while(offs<b.length){
+ offs = offs + 12; //skip the normals entirely!
+ for(int i = 0; i<9; i++)
+ {
+ Tri[i]=bin_to_float(b[offs],b[offs+1],b[offs+2],b[offs+3]);
+ offs=offs+4;
+ }
+ offs=offs+2;//Skip the attribute bytes
+ Triangles.add(new Triangle(Tri[0],Tri[1],Tri[2],Tri[3],Tri[4],Tri[5],Tri[6],Tri[7],Tri[8]));
+ }
+ CalculateBoundingBox();
+ }
+
+
+ void Scale(float Factor)
+ {
+ for(int i = Triangles.size()-1;i>=0;i--)
+ {
+ Triangle tri = (Triangle) Triangles.get(i);
+ tri.Scale(Factor);
+ }
+ CalculateBoundingBox();
+ }
+
+ void Translate(float tx, float ty, float tz)
+ {
+ for(int i = Triangles.size()-1;i>=0;i--)
+ {
+ Triangle tri = (Triangle) Triangles.get(i);
+ tri.Translate(tx,ty,tz);
+ }
+ CalculateBoundingBox();
+ }
+
+ void CalculateBoundingBox()
+ {
+ for(int i = Triangles.size()-1;i>=0;i--)
+ {
+ Triangle tri = (Triangle) Triangles.get(i);
+ if(tri.x1<bx1)bx1=tri.x1;
+ if(tri.x2<bx1)bx1=tri.x2;
+ if(tri.x3<bx1)bx1=tri.x3;
+ if(tri.x1>bx2)bx2=tri.x1;
+ if(tri.x2>bx2)bx2=tri.x2;
+ if(tri.x3>bx2)bx2=tri.x3;
+ if(tri.y1<by1)by1=tri.y1;
+ if(tri.y2<by1)by1=tri.y2;
+ if(tri.y3<by1)by1=tri.y3;
+ if(tri.y1>by2)by2=tri.y1;
+ if(tri.y2>by2)by2=tri.y2;
+ if(tri.y3>by2)by2=tri.y3;
+ if(tri.z1<bz1)bz1=tri.z1;
+ if(tri.z2<bz1)bz1=tri.z2;
+ if(tri.z3<bz1)bz1=tri.z3;
+ if(tri.z1>bz2)bz2=tri.z1;
+ if(tri.z2>bz2)bz2=tri.z2;
+ if(tri.z3>bz2)bz2=tri.z3;
+ }
+ }
+
+
+}
80 Slice.pde
@@ -0,0 +1,80 @@
+// Slice Class
+//
+class Slice {
+
+ ArrayList Lines;
+
+ //Right now this is all in the constructor.
+ //It might make more sense to split these
+ //out but that's a pretty minor difference
+ //at the moment.
+ Slice(Mesh InMesh, float ZLevel) {
+
+ ArrayList UnsortedLines;
+ Line2D Intersection;
+ UnsortedLines = new ArrayList();
+ for(int i = InMesh.Triangles.size()-1;i>=0;i--)
+ {
+ Triangle tri = (Triangle) InMesh.Triangles.get(i);
+ Intersection = tri.GetZIntersect(ZLevel);
+ if(Intersection!=null)UnsortedLines.add(Intersection);
+ }
+
+
+ if(UnsortedLines==null)return;
+
+ //Slice Sort: arrange the line segments so that
+ //each segment leads to the nearest available
+ //segment. This is accomplished by using two
+ //arraylists of lines, and at each step moving
+ //the nearest available line segment from the
+ //unsorted pile to the next slot in the sorted pile.
+ Lines = new ArrayList();
+ Lines.add(UnsortedLines.get(0));
+ int FinalSize = UnsortedLines.size();
+ UnsortedLines.remove(0);
+
+ //ratchets for distance
+ //dflipped exists to catch flipped lines
+ float d,min_d,dflipped,min_dflipped;
+ min_d = 10000;
+ min_dflipped = 10000;
+
+ int iNextLine;
+
+ while(Lines.size()<FinalSize)
+ {
+ Line2D CLine = (Line2D) Lines.get(Lines.size()-1);//Get last
+ iNextLine = (Lines.size()-1);
+ min_d = 10000;
+ min_dflipped = 10000;
+ for(int i = UnsortedLines.size()-1;i>=0;i--)
+ {
+ Line2D LineCandidate = (Line2D) UnsortedLines.get(i);
+ d = pow((LineCandidate.x1-CLine.x2),2) + pow((LineCandidate.y1-CLine.y2),2);
+ dflipped = pow((LineCandidate.x1-CLine.x1),2) + pow((LineCandidate.y1-CLine.y1),2);
+
+ if(d<min_d)
+ {
+ iNextLine=i;
+ min_d = d;
+ }
+ if(dflipped<min_dflipped)
+ {
+ iNextLine=i;
+ min_dflipped = dflipped;
+ }
+
+ }
+
+ Line2D LineToMove = (Line2D) UnsortedLines.get(iNextLine);
+ if(min_dflipped>min_d)LineToMove.Flip();
+ Lines.add(LineToMove);
+ UnsortedLines.remove(iNextLine);
+ }
+ }
+
+
+
+
+}
165 SuperSkein.pde
@@ -0,0 +1,165 @@
+//SuperSkein!
+//
+//SuperSkein is an open source mesh slicer.
+//Note! Only takes binary-coded STL. ASCII
+//STL just breaks it for now.
+
+//Slicing Parameters-- someone should make
+//a GUI menu at some point...
+//Obviously not as many of them now...
+float PrintHeadSpeed = 2000.0;
+float LayerThickness = 0.3;
+String FileName = "sculpt_dragon.stl";
+
+
+//End of "easy" modifications you can make...
+//Naturally I encourage everyone to learn and
+//alter the code that follows!
+int t=0;
+float tfloat=0;
+float[] Tri = new float[9];
+ArrayList Slice;
+Mesh STLFile;
+PrintWriter output;
+float MeshHeight;
+
+
+void setup(){
+ size(640,360);
+
+ Slice = new ArrayList();
+ print("Loading STL...\n");
+ //Load the .stl
+ //Later we should totally make this runtime...
+ STLFile = new Mesh(FileName);
+ //Scale and locate the mesh
+ //STLFile.Scale(10);
+
+ //Put the mesh on the platform:
+ STLFile.Translate(0,0,-STLFile.bz1);
+ STLFile.Translate(0,0,-LayerThickness);
+ print("File Loaded, Slicing:\n");
+
+//Spit GCODE!
+Line2D Intersection;
+output = createWriter("output.gcode");
+
+//Header:
+output.println("G21");
+output.println("G90");
+output.println("M103");
+output.println("M105");
+output.println("M104 s220.0");
+output.println("M109 s110.0");
+output.println("M101");
+
+Slice ThisSlice;
+float Layers = STLFile.bz2/LayerThickness;
+for(float ZLevel = 0;ZLevel<(STLFile.bz2-LayerThickness);ZLevel=ZLevel+LayerThickness)
+{
+ ThisSlice = new Slice(STLFile,ZLevel);
+ print("Slicing: ");
+ TextStatusBar(ZLevel/STLFile.bz2,40);
+ print("\n");
+ for(int j = ThisSlice.Lines.size()-1;j>=0;j--)
+ {
+ Line2D lin = (Line2D) ThisSlice.Lines.get(j);
+ output.println("G1 X" + lin.x1 + " Y" + lin.y1 + " Z" + ZLevel + " F" + PrintHeadSpeed);
+ }
+}
+output.flush();
+output.close();
+
+print("Finished Slicing! Bounding Box is:\n");
+print("X: " + CleanFloat(STLFile.bx1) + " - " + CleanFloat(STLFile.bx2) + " ");
+print("Y: " + CleanFloat(STLFile.by1) + " - " + CleanFloat(STLFile.by2) + " ");
+print("Z: " + CleanFloat(STLFile.bz1) + " - " + CleanFloat(STLFile.bz2) + " ");
+
+
+ //THEN scale to fit
+ if((STLFile.bx2-STLFile.bx1)>(STLFile.by2-STLFile.by1))
+ {
+ STLFile.Scale(width/(STLFile.bx2-STLFile.bx1));
+ }
+ else
+ {
+ STLFile.Scale(height/(STLFile.by2-STLFile.by1));
+ }
+ STLFile.Translate(-STLFile.bx1,-STLFile.by1,-STLFile.bz1);
+ MeshHeight=STLFile.bz2-STLFile.bz1;
+
+}
+
+void draw()
+{
+ background(0);
+ //noStroke();
+
+ //background(0);
+ stroke(0);
+ strokeWeight(2);
+
+ //Generate a Slice
+ Line2D Intersection;
+ Slice = new ArrayList();
+ for(int i = STLFile.Triangles.size()-1;i>=0;i--)
+ {
+
+ Triangle tri = (Triangle) STLFile.Triangles.get(i);
+ Intersection = tri.GetZIntersect(MeshHeight*mouseX/width);
+ if(Intersection!=null)Slice.add(Intersection);
+ //if(Intersection!=null)print(Intersection.x1 + " \n");
+ }
+
+ for(int i = Slice.size()-1;i>=0;i--)
+ {
+ stroke(255);
+ Line2D lin = (Line2D) Slice.get(i);
+ //lin.Scale(15);
+ line(lin.x1,lin.y1,lin.x2,lin.y2);
+ }
+
+}
+
+
+//Convert the binary format of STL to floats.
+float bin_to_float(byte b0, byte b1, byte b2, byte b3)
+{
+ int exponent, sign;
+ float significand;
+ float finalvalue=0;
+
+ //fraction = b0 + b1<<8 + (b2 & 0x7F)<<16 + 1<<24;
+ exponent = (b3 & 0x7F)*2 | (b2 & 0x80)>>7;
+ sign = (b3&0x80)>>7;
+ exponent = exponent-127;
+ significand = 1 + (b2&0x7F)*pow(2,-7) + b1*pow(2,-15) + b0*pow(2,-23); //throwing away precision for now...
+
+ if(sign!=0)significand=-significand;
+ finalvalue = significand*pow(2,exponent);
+
+ return finalvalue;
+}
+
+
+//Display floats cleanly!
+float CleanFloat(float Value)
+{
+ Value = Value * 1000;
+ Value = round(Value);
+ return Value / 1000;
+}
+
+
+
+//Print a status bar
+void TextStatusBar(float Percent, int Width)
+{
+ print("[");
+ int Stars = int(Percent*Width)+1;
+ int Dashes = Width-Stars;
+ for(int i = 0; i<Stars; i++)print("X");
+ for(int i = 0; i<Dashes; i++)print(".");
+ print("]");
+}
+
207 Triangle.pde
@@ -0,0 +1,207 @@
+// Triangle Class
+
+class Triangle {
+
+ float x1,x2,x3,y1,y2,y3,z1,z2,z3,xn,yn,zn;
+
+ Triangle(float tX1, float tY1, float tZ1,float tX2, float tY2, float tZ2,float tX3, float tY3, float tZ3) {
+ x1 = tX1;
+ y1 = tY1;
+ z1 = tZ1;
+ x2 = tX2;
+ y2 = tY2;
+ z2 = tZ2;
+ x3 = tX3;
+ y3 = tY3;
+ z3 = tZ3;
+
+
+ //Sorting the Triangle according to
+ //height makes slicing them easier.
+ Resort();
+
+
+ }
+
+ void Scale(float Factor)
+ {
+ x1 = Factor*x1;
+ y1 = Factor*y1;
+ z1 = Factor*z1;
+ x2 = Factor*x2;
+ y2 = Factor*y2;
+ z2 = Factor*z2;
+ x3 = Factor*x3;
+ y3 = Factor*y3;
+ z3 = Factor*z3;
+ }
+
+
+ void Translate(float tX, float tY, float tZ)
+ {
+ x1=x1+tX;
+ x2=x2+tX;
+ x3=x3+tX;
+ y1=y1+tY;
+ y2=y2+tY;
+ y3=y3+tY;
+ z1=z1+tZ;
+ z2=z2+tZ;
+ z3=z3+tZ;
+ }
+
+ //Rotations-- feed these in radians!
+ //A great application is rotating your
+ //mesh to a desired orientation.
+ // 90 degrees = PI/2.
+ void RotateZ(float Angle)
+ {
+ float xn,yn;
+ xn = x1*cos(Angle) - y1*sin(Angle);
+ yn = x1*sin(Angle) + y1*cos(Angle);
+ x1 = xn;
+ y1 = yn;
+ xn = x2*cos(Angle) - y2*sin(Angle);
+ yn = x2*sin(Angle) + y2*cos(Angle);
+ x2 = xn;
+ y2 = yn;
+ xn = x3*cos(Angle) - y3*sin(Angle);
+ yn = x3*sin(Angle) + y3*cos(Angle);
+ x3 = xn;
+ y3 = yn;
+ Resort();
+ }
+ void RotateY(float Angle)
+ {
+ float xn,zn;
+ xn = x1*cos(Angle) - z1*sin(Angle);
+ zn = x1*sin(Angle) + z1*cos(Angle);
+ x1 = xn;
+ z1 = zn;
+ xn = x2*cos(Angle) - z2*sin(Angle);
+ zn = x2*sin(Angle) + z2*cos(Angle);
+ x2 = xn;
+ z2 = zn;
+ xn = x3*cos(Angle) - z3*sin(Angle);
+ zn = x3*sin(Angle) + z3*cos(Angle);
+ x3 = xn;
+ z3 = zn;
+ Resort();
+ }
+ void RotateX(float Angle)
+ {
+ float yn,zn;
+ yn = y1*cos(Angle) - z1*sin(Angle);
+ zn = y1*sin(Angle) + z1*cos(Angle);
+ y1 = yn;
+ z1 = zn;
+ yn = y2*cos(Angle) - z2*sin(Angle);
+ zn = y2*sin(Angle) + z2*cos(Angle);
+ y2 = yn;
+ z2 = zn;
+ yn = y3*cos(Angle) - z3*sin(Angle);
+ zn = y3*sin(Angle) + z3*cos(Angle);
+ y3 = yn;
+ z3 = zn;
+ Resort();
+ }
+
+
+ //The conditionals here are for working
+ //out what kind of intersections the triangle
+ //makes with the plane, if any. Returns
+ //null if the triangle does not intersect.
+ Line2D GetZIntersect(float ZLevel)
+ {
+ Line2D Intersect;
+ float xa,xb,ya,yb;
+ if(z1<ZLevel)
+ {
+ if(z2>ZLevel)
+ {
+ xa = x1 + (x2-x1)*(ZLevel-z1)/(z2-z1);
+ ya = y1 + (y2-y1)*(ZLevel-z1)/(z2-z1);
+ if(z3>ZLevel)
+ {
+ xb = x1 + (x3-x1)*(ZLevel-z1)/(z3-z1);
+ yb = y1 + (y3-y1)*(ZLevel-z1)/(z3-z1);
+ }
+ else
+ {
+ xb = x2 + (x3-x2)*(ZLevel-z2)/(z3-z2);
+ yb = y2 + (y3-y2)*(ZLevel-z2)/(z3-z2);
+ }
+ Intersect = new Line2D(xa,ya,xb,yb);
+ return Intersect;
+ }
+ else
+ {
+ if(z3>ZLevel)
+ {
+ xa = x1 + (x3-x1)*(ZLevel-z1)/(z3-z1);
+ ya = y1 + (y3-y1)*(ZLevel-z1)/(z3-z1);
+ xb = x2 + (x3-x2)*(ZLevel-z2)/(z3-z2);
+ yb = y2 + (y3-y2)*(ZLevel-z2)/(z3-z2);
+
+ Intersect = new Line2D(xa,ya,xb,yb);
+ return Intersect;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ //In the old days, a triangle's normal was defined
+ //by right-hand-rule from the order vertices were
+ //defined. If this were the case with STL this would
+ //scramble the normals horribly.
+ //Of course, we never USE the normals...
+ void Resort()
+ {
+ if(z3<z1)
+ {
+ xn=x1;
+ yn=y1;
+ zn=z1;
+ x1=x3;
+ y1=y3;
+ z1=z3;
+ x3=xn;
+ y3=yn;
+ z3=zn;
+ }
+ if(z2<z1)
+ {
+ xn=x1;
+ yn=y1;
+ zn=z1;
+ x1=x2;
+ y1=y2;
+ z1=z2;
+ x2=xn;
+ y2=yn;
+ z2=zn;
+ }
+ if(z3<z2)
+ {
+ xn=x3;
+ yn=y3;
+ zn=z3;
+ x3=x2;
+ y3=y2;
+ z3=z2;
+ x2=xn;
+ y2=yn;
+ z2=zn;
+ }
+ }
+
+
+}
51 readme.txt
@@ -0,0 +1,51 @@
+SuperSkein Manual
+
+*Parameters
+Currently, we're doing all the parameters with the godawful UI of having you type them in the first screen or so of code in the Processing sketch. This is terrible but it's what we've got for now.
+
+--->float PrintHeadSpeed = 2000.0;
+The F parameter of the gcode. Higher values make the extruder move more quickly.
+(Skeinforge users take note, This is "FeedRate" in Skeinforge.)
+
+--->float FlowRate = 255;
+Plastic flow rate. 255 is the maximum speed. Low values will not work and may jam your extruder! On MakerBots I've used, values higher than 170 or so extrude. Your results may vary.
+NOTE NOT IMPLEMENTED YET
+
+--->float LayerThickness = 0.3;
+Space between the layers, obviously. This affects both where the slicer cuts and where the print head moves. If you want to distort your model I recommend adding a non-proportion-constrained scale function to the Mesh class.
+
+
+--->String FileName = "sculpt_dragon.stl";
+
+
+
+
+*Hacking NOTES
+
+
+Things like the Sink function (lower the mesh so the bottom layer is big rather than small points, esp for character meshes) I don't know if I want them post-processing or pre-processing.
+
+We've got to worry about time; if you run something in post, you're hacking gcode which is a real (SLOW!!) pain because of all that ASCII and file io. If you do it before you slice, you can save a TON of hack time. But then again, we keep introducing hazards to the overall modularity and flow.
+
+(Actually now that I think about it doing ops to gcode might be 2/3 of why Skeinforge is so %$#$@ing slow.)
+
+I don't like the idea of losing modularity. That's probably a deal breaker. But how much can we get away with? Let's take a 10,000 ft look.
+
+Functions like sink, they're natively mesh things. Things which are mesh native we should go ahead and do to the mesh. I think if we're at least clear about "mesh transforms" and "slice transforms" and "line transforms" we can steer clear of breaking things too bad.
+
+SO WHAT ARE WE GOING TO DO TO THE MESH, YOU MAY ASK!
+
+Okay, how about this:
+
+*slicing
+*skinning
+*filling
+*shelling
+*mesh doctoring
+*repositioning the mesh
+*support material.... RAYS? YIKES RAYS
+
+
+Huh. About support material.
+
+We could definitely do raytracing. It's really straight forward when you're z-axis aligned. (Gosh, all the 3D is easy) Buuuuuuuuut it's volume-filling and not edge-defined, so, make a grid. What you do there is you put dots on your slices (give them two array lists? Or more perhaps...)
BIN sculpt_dragon.stl
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit da57219

Please sign in to comment.