File: polyhole-tessellator-libtess2.cpp

package info (click to toggle)
openscad 2015.03-2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 30,804 kB
  • ctags: 5,692
  • sloc: cpp: 39,386; sh: 3,856; ansic: 3,674; python: 1,393; yacc: 496; lex: 272; lisp: 159; makefile: 67; xml: 60
file content (159 lines) | stat: -rw-r--r-- 5,664 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <fstream>
#include <iostream>
#include <locale.h>

#include "GeometryUtils.h"
#include "Reindexer.h"
#include "linalg.h"
#include "grid.h"
#include "printutils.h"

static void export_stl(const IndexedTriangleMesh &trimesh, std::ostream &output)
{
  setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
  output << "solid OpenSCAD_Model\n";
  const Vector3f *verts = &trimesh.vertices.front();
  BOOST_FOREACH(const IndexedTriangle &t, trimesh.triangles) {
    assert(t[0] < trimesh.vertices.size());
    assert(t[1] < trimesh.vertices.size());
    assert(t[2] < trimesh.vertices.size());

    Vector3f p[3];
    p[0] = verts[t[0]];
    p[1] = verts[t[1]];
    p[2] = verts[t[2]];
    std::stringstream stream;
    stream << p[0][0] << " " << p[0][1] << " " << p[0][2];
    std::string vs1 = stream.str();
    stream.str("");
    stream << p[1][0] << " " << p[1][1] << " " << p[1][2];
    std::string vs2 = stream.str();
    stream.str("");
    stream << p[2][0] << " " << p[2][1] << " " << p[2][2];
    std::string vs3 = stream.str();
    //    if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) {
      // The above condition ensures that there are 3 distinct vertices, but
      // they may be collinear. If they are, the unit normal is meaningless
      // so the default value of "1 0 0" can be used. If the vertices are not
      // collinear then the unit normal must be calculated from the
      // components.
      Vector3f normal = (p[1] - p[0]).cross(p[2] - p[0]);
      normal.normalize();
      output << "  facet normal " << normal[0] << " " << normal[1] << " " << normal[2] << "\n";
      output << "    outer loop\n";
		
      for (int i=0;i<3;i++) {
        output << "      vertex " << p[i][0] << " " << p[i][1] << " " << p[i][2] << "\n";
      }
      output << "    endloop\n";
      output << "  endfacet\n";
      //    }
  }
  output << "endsolid OpenSCAD_Model\n";
  setlocale(LC_NUMERIC, "");      // Set default locale
}


/*!
  file format: 
  1. polygon coordinates (x,y,z) are comma separated (+/- spaces) and 
  each coordinate is on a separate line
  2. each polygon is separated by one or more blank lines
*/
bool import_polygon(IndexedPolygons &polyhole, const std::string &filename)
{
  Reindexer<Vector3f> uniqueVertices;
  std::ifstream ifs(filename.c_str());
  if (!ifs) return false;

  std::string line;
  IndexedFace polygon;
  while (std::getline(ifs, line)) {
    std::stringstream ss(line);
    double X = 0.0, Y = 0.0, Z = 0.0;
    if (!(ss >> X)) {
      //ie blank lines => flag start of next polygon 
      if (polygon.size() > 0) polyhole.faces.push_back(polygon);
      polygon.clear();
      continue;
    }
    char c = ss.peek();  
    while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
    if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
    while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
    if (!(ss >> Y)) {
      std::cerr << "Y error\n";
      return false;
    }
    c = ss.peek();
    while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
    if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
    while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
    if (!(ss >> Z)) {
      std::cerr << "Z error\n";
      return false;
    }
    polygon.push_back(uniqueVertices.lookup(Vector3f(X, Y, Z)));
  }
  if (polygon.size() > 0) polyhole.faces.push_back(polygon);
  ifs.close();
  uniqueVertices.copy(std::back_inserter(polyhole.vertices));
  return true;
}

int main(int argc, char *argv[])
{
  OpenSCAD::debug = "GeometryUtils";

  IndexedPolygons polyhole;
  Vector3f *normal = NULL;
  if (argc >= 2) {
    if (!import_polygon(polyhole, argv[1])) {
      std::cerr << "Error importing polygon" << std::endl;
      exit(1);
    }
    std::cerr << "Imported " << polyhole.faces.size() << " polygons" << std::endl;

    if (argc == 3) {
      std::vector<std::string> strs;
      std::vector<double> normalvec;
      std::string arg(argv[2]);
      boost::split(strs, arg, boost::is_any_of(","));
      assert(strs.size() == 3);
      BOOST_FOREACH(const std::string &s, strs) normalvec.push_back(boost::lexical_cast<double>(s));
      normal = new Vector3f(normalvec[0], normalvec[1], normalvec[2]);
      
   }
  }
  else {
    //construct two non-intersecting nested polygons  
    Reindexer<Vector3f> uniqueVertices;
    IndexedFace polygon1;
    polygon1.push_back(uniqueVertices.lookup(Vector3f(0,0,0)));
    polygon1.push_back(uniqueVertices.lookup(Vector3f(2,0,0)));
    polygon1.push_back(uniqueVertices.lookup(Vector3f(2,2,0)));
    polygon1.push_back(uniqueVertices.lookup(Vector3f(0,2,0)));
    IndexedFace polygon2;
    polygon2.push_back(uniqueVertices.lookup(Vector3f(0.5,0.5,0)));
    polygon2.push_back(uniqueVertices.lookup(Vector3f(1.5,0.5,0)));
    polygon2.push_back(uniqueVertices.lookup(Vector3f(1.5,1.5,0)));
    polygon2.push_back(uniqueVertices.lookup(Vector3f(0.5,1.5,0)));
    polyhole.faces.push_back(polygon1);
    polyhole.faces.push_back(polygon2);
    uniqueVertices.copy(std::back_inserter(polyhole.vertices));
  }

  std::vector<IndexedTriangle> triangles;
  bool ok = GeometryUtils::tessellatePolygonWithHoles(&polyhole.vertices.front(), polyhole.faces, triangles, normal);
  std::cerr << "Tessellated into " << triangles.size() << " triangles" << std::endl;

  IndexedTriangleMesh trimesh;
  trimesh.vertices = polyhole.vertices;
  trimesh.triangles = triangles;

  export_stl(trimesh, std::cout);
}