Plane triangle intersection raveh gonen's blog
-
Upload
eddy-castro -
Category
Documents
-
view
226 -
download
5
description
Transcript of Plane triangle intersection raveh gonen's blog
![Page 1: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/1.jpg)
Raveh Gonen's BlogJust another WordPress.com weblog
Stereolithography (3D Printing) Algorithmsand ThoughtsFebruary 19, 2013
Play ing with 3D Printing Algorithmic Concepts. Let’s start with what
we (the world) already hav e: lot’s of software, open source and
commercial, lot’s of file formats, but STL is still dominant and … lots
of 3D Printers. This week, I was looking into the algorithms (Math,
Computer Science) behind the world of 3D Printing. As an excersize,
I started to explore the mechanics of taking a digital model of an
object from an STL file (ThingVerse, F16 Model) and generating slices
from this model so a printer could print. Here is a slide of the basic
process:
Home About Me
Follow
Follow “Raveh
![Page 2: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/2.jpg)
The input: F16.stl (ascii or binary format)
. The output: an ascii or binary file with a set of slices where each
slice has a set of line segments. a line segment has 2 coordinates {p0,
p1} with {x ,y ,z} v alues. Before we div e into the math (simple) and
algorithmic issues, let’s see the images: the 3D model, the slices on a
2D image, side-by -side from left-to-right top-to-bottom, the 3D
Model constructed by multiple adjacent slices:
Follow “RavehGonen's Blog”
Get every new post delivered
to your Inbox.
Enter your email address
Sign me up
Pow ered by WordPress.com
![Page 3: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/3.jpg)
The Main Algorithm (Pseudo Code)
v 3 -> a v ector with 3 floats {x ,y ,z}
LineSegment -> {v 3 point0, point1}
Plane -> {v 3 normal, float distance}
Triangle -> {v 3 v ertices[3], normal}
TriangleMesh -> {v ector of Triangle}
read-stl-file -> generate a TriangleMesh ‘TM’
nSlices -> compute-number-of-slices using slice-size and 3D Model
aabb
for each slice
- fix -a-cutting-plane using the slice-index
- for each Triangle in TriangleMesh
- – intersect(Triangle, Plane) -> find zero or two intersection points
- – take only the second case and generate a Line Segment from two
points
- – Gather all Line Segment for this slice in a v ector
output all line segments to an Ascii or Binary file for v iewing or
manipulating
That’s all. Here are a set of slides that explain the Triangle-Plane-
Intersection mecahnics:
![Page 4: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/4.jpg)
![Page 5: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/5.jpg)
![Page 6: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/6.jpg)
Here is the full source code that compiles under Microsoft VisualC++ 2010. Just create a solution and add this code as main.cpp,
download the open source Opengl Mathematics c++ library (Header
files only ) from http://glm.g-truc.net/. After y ou build it, download
any STL file y ou want.
Adjusting Parameters: use the command line parameters:
-slicesize <size>
-model <stl file name>
-ascii (the default is a binary STL file)
-eulerangles rx ry rz (to rotate the 3D Model before slicing starts)
Please note that this is a demonstration code (and documented) and
not a bullet-proof one. It is targeted as an educational and
exploratory tool. I hope y ou hav e fun with it.
Some more output from the program {Stanford Bunny , Spaceship}
![Page 7: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/7.jpg)
![Page 8: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/8.jpg)
Spaceship:
![Page 9: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/9.jpg)
The Full Source Code (C++):
#include <fstream>
#include <string>
#include <v ector>#include <math.h>
![Page 10: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/10.jpg)
#include “glm/glm/glm.hpp”
#include “glm/glm/gtc/matrix_transform.hpp”
#include “glm/glm/gtc/ty pe_ptr.hpp”
#define DEG_TO_RAD(x) (x*0.017 4532925199f)
using namespace std;
struct v 3 {
float x , y , z; v 3(float _x=0, float _y =0, float _z=0) : x (_x), y (_y ), z(_z) {}
float dotproduct(const v 3 &v ) const { return x*v .x + y *v .y + z*v .z;
}
v oid transform(const glm::mat4 &mat) { glm::v ec4 v =
glm::v ec4(x , y , z, 1 .0f), v t; v t = mat*v ; x=v t.x ; y =v t.y ; z=v t.z;}
v 3& operator-=(const v 3 &pt) { x -=pt.x ; y -=pt.y ; z-=pt.z; return
*this; }
v 3 operator-(const v 3 &pt) { return v 3(x-pt.x , y -pt.y , z-pt.z); }
v 3 operator+(const v 3 &pt) { return v 3(x+pt.x , y +pt.y , z+pt.z); } v 3 operator/(float a) { return v 3(x/a, y /a, z/a); }
v 3 operator*(float a) { return v 3(x*a, y *a, z*a); }
float normalize() const { return sqrt(x*x+y *y +z*z); }
};
v 3 operator-(const v 3 &a, const v 3 &b) {return v 3(a.x-b.x , a.y -b.y ,
a.z-b.z); }
v 3 operator+(const v 3 &a, const v 3 &b) {return v 3(a.x+b.x , a.y +b.y ,
a.z+b.z); }
struct LineSegment {
LineSegment(v 3 p0=v 3(), v 3 p1=v 3()) { v [0]=p0; v [1]=p1; }
v 3 v [2];
};
class Plane {
public:
Plane() : mDistance(0) {}
float distance() const { return mDistance; }
float distanceToPoint(const v 3 &v ertex) const { returnv ertex .dotproduct(mNormal) – mDistance; }
v oid setNormal(v 3 normal) { mNormal = normal; }
v oid setDistance(float distance) { mDistance = distance; }
protected:
v 3 mNormal; // normalized Normal-Vector of the plane
float mDistance; // shortest distance from plane to Origin
};
struct Triangle {
Triangle(v 3 n, v 3 v 0, v 3 v 1 , v 3 v 2) : normal(n) { v [0]=v 0; v [1]=v 1 ;
v [2]=v 2; } Triangle& operator-=(const v 3 &pt) { v [0]-=pt; v [1]-=pt; v [2]-=pt;
return *this;}
v oid transform(const glm::mat4 &mat) { v [0].transform(mat);
v [1].transform(mat); v [2].transform(mat);}
// @return -1 = all triangle is on plane back side
// 0 = plane intersects the triangle
// 1 = all triangle is on plane front side
// -2 = error in function
int intersectPlane(const Plane &plane, LineSegment &ls) const { // a triangle has 3 v ertices that construct 3 line segments
size_t cntFront=0, cntBack=0;
for (size_t j=0; j<3; ++j) {
float distance = plane.distanceToPoint(v [j]);
if (distance<0) ++cntBack;
else ++cntFront;
![Page 11: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/11.jpg)
}
if (3 == cntBack) {
return -1 ;
}
else if (3 == cntFront) {
return 1 ;
}
size_t lines[] = {0,1 ,1 ,2,2,0}; // CCW Triangle
std::v ector<v 3> intersectPoints; for (size_t i=0; i<3; ++i) {
const v 3 &a = v [lines[i*2+0]];
const v 3 &b = v [lines[i*2+1]];
const float da = plane.distanceToPoint(a);
const float db = plane.distanceToPoint(b);
if (da*db<0) {
const float s = da/(da-db); // intersection factor (between 0and 1)
v 3 bMinusa = b-a; intersectPoints.push_back(a+bMinusa*s);
}
else if (0==da) { // plane falls exactly on one of the threeTriangle v ertices
if (intersectPoints.size()<2
intersectPoints.push_back(a);
}
else if (0==db) { // plane falls exactly on one of the threeTriangle v ertices
if (intersectPoints.size()<2
intersectPoints.push_back(b);
}
}
if (2==intersectPoints.size()) {
// Output the intersecting line segment object
ls.v [0]=intersectPoints[0];
ls.v [1]=intersectPoints[1];
return 0;
}
return -2;
}
v 3 v [3], normal;
};class TriangleMesh {
public:
TriangleMesh() : bottomLeftVertex(999999,999999,999999),upperRightVertex(-999999,-999999,-999999) {}
size_t size() const { return mesh.size(); }
// mov e 3D Model coordinates to be center around COG(0,0,0)
v oid normalize() {
v 3 halfBbox = (upperRightVertex – bottomLeftVertex)/2.0f;
v 3 start = bottomLeftVertex + halfBbox;
for (size_t i=0; i<mesh.size(); ++i) {
Triangle &triangle = mesh[i];
triangle -= start;
}
bottomLeftVertex = halfBbox*-1 .0f;
upperRightVertex = halfBbox;
}
v oid push_back(const Triangle &t) {
mesh.push_back(t); for (size_t i=0; i<3; ++i) {
if (t.v [i].x < bottomLeftVertex .x) bottomLeftVertex .x =
![Page 12: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/12.jpg)
t.v [i].x ;
if (t.v [i].y < bottomLeftVertex .y ) bottomLeftVertex .y =t.v [i].y ;
if (t.v [i].z < bottomLeftVertex .z) bottomLeftVertex .z = t.v [i].z;
if (t.v [i].x > upperRightVertex .x) upperRightVertex .x =t.v [i].x ;
if (t.v [i].y > upperRightVertex .y ) upperRightVertex .y =t.v [i].y ;
if (t.v [i].z > upperRightVertex .z) upperRightVertex .z = t.v [i].z;
}
}
v 3 meshAABBSize() const {
return v 3(upperRightVertex .x-bottomLeftVertex .x ,
upperRightVertex .y -bottomLeftVertex .y , upperRightVertex .z-bottomLeftVertex .z);
}
std::v ector<Triangle>& getMesh() { return mesh; }
const std::v ector<Triangle>& getMesh() const { return mesh; }
v 3 getBottomLeftVertex() const { return bottomLeftVertex ; }
v 3 getUpperRightVertex() const { return upperRightVertex ; }
// Mesh COG point should be at (0,0,0)
int transform(const glm::mat4 &mat) {
for (size_t i=0; i<mesh.size(); ++i) {
Triangle &triangle = mesh[i];
triangle.transform(mat);
} return 0;
}
protected:
std::v ector<Triangle> mesh;
v 3 bottomLeftVertex , upperRightVertex ;
};
// read the giv en STL file name (ascii or binary is set using
‘isBinary Format’)
// and generate a Triangle Mesh object in output parameter ‘mesh’
int stlToMeshInMemory (const char *stlFile, TriangleMesh *mesh,
bool isBinary Format) {
if (!isBinary Format) {
ifstream in(stlFile);
if (!in.good()) return 1 ;
char title[80];
std::string s0, s1 ;
float n0, n1 , n2, f0, f1 , f2, f3, f4, f5, f6, f7 , f8; in.read(title, 80);
while (!in.eof()) {
in >> s0; // facet || endsolid
if (s0==”facet”) {
in >> s1 >> n0 >> n1 >> n2; // normal x y z
in >> s0 >> s1 ; // outer loop
in >> s0 >> f0 >> f1 >> f2; // v ertex x y z
in >> s0 >> f3 >> f4 >> f5; // v ertex x y z
in >> s0 >> f6 >> f7 >> f8; // v ertex x y z
in >> s0; // endloop
in >> s0; // endfacet
// Generate a new Triangle with Normal as 3 Vertices
Triangle t(v 3(n0, n1 , n2), v 3(f0, f1 , f2), v 3(f3, f4, f5), v 3(f6,
f7 , f8));
mesh->push_back(t);
}
else if (s0==”endsolid”) {
![Page 13: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/13.jpg)
break;
}
}
in.close();
}
else {
FILE *f = fopen(stlFile, “rb”);
if (!f) return 1 ;
char title[80]; int nFaces;
fread(title, 80, 1 , f);
fread((v oid*)&nFaces, 4, 1 , f);
float v [12]; // normal=3, v ertices=3*3 = 12
unsigned short uint16; // Ev ery Face is 50 By tes: Normal(3*float), Vertices(9*float), 2
By tes Spacer
for (size_t i=0; i<nFaces; ++i) {
for (size_t j=0; j<12; ++j) {
fread((v oid*)&v [j], sizeof(float), 1 , f);
} fread((v oid*)&uint16, sizeof(unsigned short), 1 , f); // spacer
between successiv e faces Triangle t(v 3(v [0], v [1], v [2]), v 3(v [3], v [4], v [5]), v 3(v [6],
v [7 ], v [8]), v 3(v [9], v [10], v [11]));
mesh->push_back(t);
}
fclose(f); }
mesh->normalize();
return 0;}
// Take an input Triangle Mesh ‘mesh’ and fill the output
// parameter ‘slicesWithLineSegments’ with line segments for
// each slice
int triMeshSlicer(
const TriangleMesh *mesh, // the const input mesh
std::v ector<std::v ector<LineSegment>>
&slicesWithLineSegments,
// the result slices
const float sliceSize) {// slice size in 3D Model
digital units
Plane plane; // The intersection plane
plane.setNormal(v 3(0, 0, 1 )); // normal does not
change during slicing
const v 3 aabb = mesh->meshAABBSize(); // as the model
for it’s 3D ax is-aligned bounding-box const size_t nSlices = 1+(int)(aabb.z/sliceSize); // compute
number of output slices
const std::v ector<Triangle> &m = mesh->getMesh(); // get a
const handle to the input mesh
const float z0 = mesh->getBottomLeftVertex().z; // find the
minimal z coordinate of the model (z0)
for (size_t i=0; i<nSlices; ++i) { // start generating slices
std::v ector<LineSegment> linesegs; // the linesegs
v ector for each slice
plane.setDistance(z0+(float)i*sliceSize); // position the plane
according to slice index
for (size_t t=0; t<m.size(); ++t) { // iterate all mesh
triangles
const Triangle &triangle = m[t]; // get a const handle to a
![Page 14: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/14.jpg)
triangle
LineSegment ls; if (0==triangle.intersectPlane(plane, ls)) {// the plane does
intersect the triangle linesegs.push_back(ls); // push a new Line Segment
object to this slice
}
} slicesWithLineSegments.push_back(linesegs); // push this
v ector to the slices v ector
}
return 0;}
// GIV is a free v iewer: http://giv .sourceforge.net/giv /
// output a single GIV ascii file with the slices, lay ed out in a matrix
form
int exportSingleGIVFormat(
const std::v ector<std::v ector<LineSegment>>
&slicesWithLineSegments,
const v 3 &aabbSize) {
char filename[256];
FILE *f=NULL;
float dx=0, dy =0;
f=fopen(“out.marks”, “w”);
if (!f) return 1 ;
const size_t nSlices = slicesWithLineSegments.size();
const size_t slicePerRow = (size_t)sqrt((float)nSlices);
for (size_t i=0; i<nSlices; ++i) {
const std::v ector<LineSegment> &lss =
slicesWithLineSegments[i]; dx = (float)(i%slicePerRow)*(aabbSize.x*1 .05f);
dy = (float)(i/slicePerRow)*(aabbSize.y *1 .05f);
for (size_t j=0; j<lss.size(); ++j) {
fprintf(f, “\n\n$line”);
fprintf(f, “\n$color blue”);
fprintf(f, “\n%f %f”, dx+lss[j].v [0].x , dy +lss[j].v [0].y );
fprintf(f, “\n%f %f”, dx+lss[j].v [1].x , dy +lss[j].v [1].y );
}
}
fclose(f);
return 0;
}
// GIV is a free v iewer: http://giv .sourceforge.net/giv /
// output a single GIV ascii file with the slices, lay ed out in 3D form
int exportSingleGIVFormat3D(
const std::v ector<std::v ector<LineSegment>>
&slicesWithLineSegments,
const v 3 &aabbSize) {
// Generate a 3D View using OpenGL Math Library
glm::detail::tv ec3<float> eulerAngles(0, 0.0f, 45.0f);
glm::detail::tquat<float> quaternion = glm::detail::tquat<float>
(DEG_TO_RAD(eulerAngles)); // This glm func wants v alues as
radians
float angle = glm::angle(quaternion);
glm::detail::tv ec3<float> ax is = glm::ax is(quaternion);
glm::mat4 View = glm::rotate(glm::mat4(1 .0), angle, ax is);
glm::mat4 Projection = glm::perspectiv e(45.0f, 4.0f / 3.0f, 0.1 f,
100.f);
![Page 15: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/15.jpg)
glm::mat4 Model = glm::lookAt(
glm::v ec3(1 , 1 , 1 ), // Ey e point (where am I?)
glm::v ec3(0, 0, 0), // Look at Center point (What am I lookingat?)
glm::v ec3(0, 1 , 0));// UP v ector of the camera (Where is my UPv ector?)
glm::mat4 MVP = Projection * View * Model;
// Start Output
char filename[256];
FILE *f=NULL;
v 3 p0, p1 ;
f=fopen(“out3D.marks”, “w”);
if (!f) return 1 ;
const size_t nSlices = slicesWithLineSegments.size();
const size_t slicePerRow = (size_t)sqrt((float)nSlices); for (size_t i=0; i<nSlices; ++i) {
const std::v ector<LineSegment> &lss =
slicesWithLineSegments[i];
for (size_t j=0; j<lss.size(); ++j) {
p0=lss[j].v [0];
p1=lss[j].v [1];
p0.transform(MVP);
p1 .transform(MVP);
fprintf(f, “\n\n$line”);
fprintf(f, “\n$color blue”);
fprintf(f, “\n%f %f”, p0.x , p0.y );
fprintf(f, “\n%f %f”, p1 .x , p1 .y );
}
}
fclose(f);
return 0;
}
int main(int argc, char **argv ) {
float sliceSize = 1 .0f;
char modelFileName[1024];
bool isBinary Format = true;
glm::detail::tv ec3<float> eulerAngles(0,0,0);
for (int i=1 ; i<argc;) {
if (0==strcmp(argv [i], “-slicesize”)) {
sliceSize = atof(argv [i+1]);
i+=2;
}
else if (0==strcmp(argv [i], “-model”)) {
strcpy (modelFileName, argv [i+1]);
i+=2;
}
else if (0==strcmp(argv [i], “-ascii”)) {
isBinary Format = false;
i+=1;
}
else if (0==strcmp(argv [i], “-eulerangles”)) {
eulerAngles.x = atof(argv [i+1]); eulerAngles.y = atof(argv [i+2]);
eulerAngles.z = atof(argv [i+3]);
i+=4;
}
else {
++i;
![Page 16: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/16.jpg)
Uncategorized(20)
CategoriesJanuary 2014December 2013February 2013May 2012January 2012December 2011November 2011October 2011August 2011November 2010October 2010April 2010February 2010January 2010
ArchivesRegisterLog inValid XHTMLXFNWordPress
Meta
}
}
// Parse the file and generate a TriangleMesh
TriangleMesh mesh;
if (stlToMeshInMemory (modelFileName, &mesh,isBinary Format)!=0)
return 1 ;
fprintf(stderr, “Mesh has %d triangles\n”, mesh.size());
// Optional Model Rotation Around COG Point using GLM Library
glm::mat4 mat = glm::mat4(1 .0f);
glm::detail::tquat<float> quaternion = glm::detail::tquat<float>
(DEG_TO_RAD(eulerAngles)); // This glm func wants v alues as
radians
float angle = glm::angle(quaternion);
glm::detail::tv ec3<float> ax is = glm::ax is(quaternion);
mat = glm::rotate(mat, angle, ax is);
mesh.transform(mat);
// Generate Slices
std::v ector<std::v ector<LineSegment>> slicesWithLineSegments;
triMeshSlicer(&mesh, slicesWithLineSegments, sliceSize);
// Output in 2D Matrix form
exportSingleGIVFormat(slicesWithLineSegments,
mesh.meshAABBSize());
// Output in 3D Lay ered Form
exportSingleGIVFormat3D(slicesWithLineSegments,
mesh.meshAABBSize());
return 0;
}
Posted in Uncategorized | Tagged: 3D Printing, Algorithms, GLMLibrary, Mesh Slicing, Plane-Triangle-Intersection,Stereolithography, STL File Format | 9 Comments »
![Page 17: Plane triangle intersection raveh gonen's blog](https://reader030.fdocuments.us/reader030/viewer/2022020107/568c57931a28ab4916cb0c93/html5/thumbnails/17.jpg)
Type and Press Enter to Search...
Th e Da y Dr ea m Th em e. Blog a t Wor dPr ess.com .