SUAPI-CppWrapper
C++WrapperforSketchUpCAPI
GeometryInput.cpp
1 //
2 // GeometryInput.cpp
3 //
4 // Sketchup C++ Wrapper for C API
5 // MIT License
6 //
7 // Copyright (c) 2017 Tom Kaneko
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 
16 // The above copyright notice and this permission notice shall be included in all
17 // copies or substantial portions of the Software.
18 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 // SOFTWARE.
26 //
27 
28 // Macro for getting rid of unused variables commonly for assert checking
29 #define _unused(x) ((void)(x))
30 
31 #include <cassert>
32 #include <iostream>
33 
34 #include "SUAPI-CppWrapper/model/GeometryInput.hpp"
35 
36 #include <SketchupAPI/sketchup_info.h>
37 
38 #include "SUAPI-CppWrapper/Initialize.hpp"
39 #include "SUAPI-CppWrapper/model/Model.hpp"
40 #include "SUAPI-CppWrapper/model/Entities.hpp"
41 #include "SUAPI-CppWrapper/model/Vertex.hpp"
42 #include "SUAPI-CppWrapper/model/Loop.hpp"
43 #include "SUAPI-CppWrapper/model/LoopInput.hpp"
44 #include "SUAPI-CppWrapper/model/Layer.hpp"
45 #include "SUAPI-CppWrapper/model/Material.hpp"
46 #include "SUAPI-CppWrapper/model/Face.hpp"
47 #include "SUAPI-CppWrapper/model/Edge.hpp"
48 #include "SUAPI-CppWrapper/model/MaterialInput.hpp"
49 
50 namespace CW {
51 
52 std::unordered_map<SUGeometryInputRef, size_t> GeometryInput::num_objects_ = {};
53 
54 /***************************
55 ** Private Static Methods **
56 ****************************/
57 SUGeometryInputRef GeometryInput::create_geometry_input() {
58  SUGeometryInputRef geom_input = SU_INVALID;
59  SUResult res = SUGeometryInputCreate(&geom_input);
60  assert(res == SU_ERROR_NONE); _unused(res);
61  return geom_input;
62 }
63 
64 /*
65 SUResult GeometryInput::add_loop(LoopInput &loop) {
66  std::vector<Point3D> vertices = loop.get_vertices();
67 
68  std::vector<size_t> indices = add_vertices(vertices);
69  std::vector<Edge> edges = loop.get_edges();
70 
71  for (size_t i=0; i < indices.size(); i++) {
72  SULoopInputEdgeSetHidden(loop.ref(), indices[i], edges[i].hidden());
73  SULoopInputEdgeSetSoft(loop.ref(), indices[i], edges[i].soft());
74  SULoopInputEdgeSetSmooth(loop.ref(), indices[i], edges[i].smooth());
75  }
76  return SU_ERROR_NONE;
77 }
78 */
79 
80 /******************************
81 ** Constructors / Destructor **
82 *******************************/
83 GeometryInput::GeometryInput(SUModelRef target_model):
84  m_geometry_input(create_geometry_input()),
85  m_attached(false),
86  m_target_model(target_model)
87 {
88  num_objects_[m_geometry_input] = 1;
89 }
90 
91 
93  if (SUIsValid(m_geometry_input) && !m_attached && num_objects_[m_geometry_input] == 1) {
94  num_objects_.erase(m_geometry_input);
95  SUResult res = SUGeometryInputRelease(&m_geometry_input);
96  assert(res == SU_ERROR_NONE); _unused(res);
97  }
98  else {
99  --num_objects_[m_geometry_input];
100  }
101 }
102 
103 
105  m_target_model(other.m_target_model)
106 {
107  if (SUIsValid(m_geometry_input) && !m_attached && num_objects_[m_geometry_input] == 1) {
108  num_objects_.erase(m_geometry_input);
109  SUResult res = SUGeometryInputRelease(&m_geometry_input);
110  assert(res == SU_ERROR_NONE); _unused(res);
111  }
112  else {
113  --num_objects_[m_geometry_input];
114  }
115  m_geometry_input = other.m_geometry_input;
116  m_attached = other.m_attached;
117  ++num_objects_[m_geometry_input];
118 }
119 
120 
122  if (SUIsValid(m_geometry_input) && !m_attached && num_objects_[m_geometry_input] == 1) {
123  num_objects_.erase(m_geometry_input);
124  SUResult res = SUGeometryInputRelease(&m_geometry_input);
125  assert(res == SU_ERROR_NONE); _unused(res);
126  }
127  else {
128  --num_objects_[m_geometry_input];
129  }
130  m_geometry_input = other.m_geometry_input;
131  m_attached = other.m_attached;
132  m_target_model = other.m_target_model;
133  ++num_objects_[m_geometry_input];
134  return (*this);
135 }
136 
137 
138 
139 SUGeometryInputRef GeometryInput::ref() const {
140  return m_geometry_input;
141 }
142 
143 
145  return SUIsInvalid(m_geometry_input);
146 }
147 
148 
149 size_t GeometryInput::num_faces() const {
150  if(!(*this)) {
151  throw std::logic_error("CW::GeometryInput::num_faces(): GeometryInput is null");
152  }
153  return this->counts()[1];
154 }
155 
156 
157 size_t GeometryInput::add_face(const Face &face, bool copy_material_layer) {
158  if(!(*this)) {
159  throw std::logic_error("CW::GeometryInput::add_face(): GeometryInput is null");
160  }
161  if(!face) {
162  throw std::invalid_argument("CW::GeometryInput::add_face(): Face argument is null");
163  }
164  LoopInput outer_loop_input;
165  // Add outer loop
166  std::vector<Point3D> outer_points = face.outer_loop().points();
167  std::vector<Edge> outer_edges = face.outer_loop().edges();
168  for (size_t i=0; i < outer_points.size(); ++i) {
169  size_t v_index = this->add_vertex(outer_points[i]);
170  outer_loop_input.add_vertex_index(v_index);
171  if (outer_edges[i].hidden()) {
172  outer_loop_input.set_edge_hidden(v_index, true);
173  }
174  if (outer_edges[i].smooth()) {
175  outer_loop_input.set_edge_smooth(v_index, true);
176  }
177  if (outer_edges[i].soft()) {
178  outer_loop_input.set_edge_soft(v_index, true);
179  }
180  // TODO: set layer and material
181  }
182  size_t added_face_index = this->add_face(outer_loop_input);
183  // Add inner loops
184  std::vector<Loop> inner_loops = face.inner_loops();
185  for (size_t i=0; i < inner_loops.size(); ++i) {
186  LoopInput inner_loop_input;
187  std::vector<Point3D> inner_points = inner_loops[i].points();
188  std::vector<Edge> inner_edges = inner_loops[i].edges();
189  for (size_t j=0; j < inner_points.size(); ++j) {
190  size_t v_index = this->add_vertex(inner_points[i]);
191  inner_loop_input.add_vertex_index(v_index);
192  if (inner_edges[i].hidden()) {
193  inner_loop_input.set_edge_hidden(v_index, true);
194  }
195  if (inner_edges[i].smooth()) {
196  inner_loop_input.set_edge_smooth(v_index, true);
197  }
198  if (inner_edges[i].soft()) {
199  inner_loop_input.set_edge_soft(v_index, true);
200  }
201  // TODO: set layer and material
202  }
203  this->face_add_inner_loop(added_face_index, inner_loop_input);
204  }
205  if (copy_material_layer) {
206  // Add layer
207  Layer face_layer = face.layer();
208  if (!!face_layer) {
209  assert(Model(m_target_model, false).layer_exists(face_layer));
210  this->face_layer(added_face_index, face_layer);
211  face_layer.attached(true);
212  }
213  // Set Materials TODO: not done quite right here, I don't think... uv coords are not set.
214  Material front_mat = face.material();
215  if (!!front_mat) {
216  MaterialInput front_material_input(front_mat);
217  assert(Model(m_target_model, false).material_exists(front_material_input.material()));
218  this->face_front_material(added_face_index, front_material_input);
219  }
220  Material back_mat = face.back_material();
221  if (!!back_mat) {
222  MaterialInput back_material_input(face.back_material());
223  assert(Model(m_target_model, false).material_exists(back_material_input.material()));
224  this->face_back_material(added_face_index, back_material_input);
225  }
226  // TODO: create a way to add attributes to the faces.
227  }
228  return added_face_index;
229 }
230 
231 
232 size_t GeometryInput::add_faces(const std::vector<Face>& faces, bool copy_material_layer) {
233  if(!(*this)) {
234  throw std::logic_error("CW::GeometryInput::add_faces(): GeometryInput is null");
235  }
236  size_t index = 0;
237  for (size_t i=0; i < faces.size(); ++i) {
238  index = add_face(faces[i]);
239  }
240  return index;
241 }
242 
243 
244 size_t GeometryInput::add_edge(const Edge &edge) {
245  if(!edge) {
246  throw std::invalid_argument("CW::GeometryInput::add_edge(): Edge argument is null");
247  }
248  if (SU_API_VERSION_MAJOR < 5) {
249  // Edges can only be added since SU2017
250  return 0;
251  }
252  Point3D start_point = edge.start().position();
253  size_t start_index = this->add_vertex(start_point);
254  Point3D end_point = edge.end().position();
255  size_t end_index = this->add_vertex(end_point);
256  size_t added_edge_index = this->add_edge(start_index, end_index);
257 
258  // Add other information about the edge
259  if (edge.hidden()) {
260  this->edge_hidden(added_edge_index, true);
261  }
262  if (edge.smooth()) {
263  this->edge_smooth(added_edge_index, true);
264  }
265  if (edge.soft()) {
266  this->edge_soft(added_edge_index, true);
267  }
268  // TODO: add edge Layer and Material
269  return added_edge_index;
270 }
271 
272 
273 size_t GeometryInput::add_edges(const std::vector<Edge>& edges) {
274  if(!(*this)) {
275  throw std::logic_error("CW::GeometryInput::add_edges(): GeometryInput is null");
276  }
277  size_t index = 0;
278  for (size_t i=0; i < edges.size(); ++i) {
279  index = add_edge(edges[i]);
280  }
281  return index;
282 }
283 
284 
285 bool GeometryInput::empty() const {
286  if(!(*this)) {
287  throw std::logic_error("CW::GeometryInput::empty(): GeometryInput is null");
288  }
289  std::array<size_t, 5> counts = this->counts();
290  if (counts[1] == 0 && counts[2] == 0) {
291  return true;
292  }
293  return false;
294 }
295 
296 
297 size_t GeometryInput::add_vertex(const Point3D& point) {
298  SUResult res = SUGeometryInputAddVertex(m_geometry_input, point);
299  assert(res == SU_ERROR_NONE); _unused(res);
300  m_vertex_index++;
301  return m_vertex_index-1;
302 }
303 
304 
305 void GeometryInput::set_vertices(const std::vector<SUPoint3D>& points) {
306  assert(this->counts()[1] == 0); // Undefined behaviour when overwriting vertices
307  assert(this->counts()[2] == 0); // Undefined behaviour when overwriting vertices
308  SUResult res = SUGeometryInputSetVertices(m_geometry_input, points.size(), points.data());
309  assert(res == SU_ERROR_NONE); _unused(res);
310  // Overwrite the existing vertex count
311  m_vertex_index = points.size();
312 }
313 
314 
315 void GeometryInput::set_vertices(const std::vector<Point3D>& points) {
316  std::vector<SUPoint3D> point_refs(points.size());
317  std::transform(points.begin(), points.end(), point_refs.begin(),
318  [](const Point3D& value) {
319  return value;
320  });
321  return this->set_vertices(point_refs);
322 }
323 
324 
325 size_t GeometryInput::add_edge(size_t vertex0_index, size_t vertex1_index) {
326  size_t added_edge_index;
327  SUResult res = SUGeometryInputAddEdge(m_geometry_input, vertex0_index, vertex1_index, &added_edge_index);
328  assert(res == SU_ERROR_NONE); _unused(res);
329  return added_edge_index;
330 }
331 
332 
333 void GeometryInput::edge_hidden(size_t edge_index, bool hidden) {
334  SUResult res = SUGeometryInputEdgeSetHidden(m_geometry_input, edge_index, hidden);
335  assert(res == SU_ERROR_NONE); _unused(res);
336 }
337 
338 
339 void GeometryInput::edge_soft(size_t edge_index, bool soft) {
340  SUResult res = SUGeometryInputEdgeSetSoft(m_geometry_input, edge_index, soft);
341  assert(res == SU_ERROR_NONE); _unused(res);
342 }
343 
344 
345 void GeometryInput::edge_smooth(size_t edge_index, bool smooth) {
346  SUResult res = SUGeometryInputEdgeSetSmooth(m_geometry_input, edge_index, smooth);
347  assert(res == SU_ERROR_NONE); _unused(res);
348 }
349 
350 
351 void GeometryInput::edge_material(size_t edge_index, const Material& material) {
352  SUResult res = SUGeometryInputEdgeSetMaterial(m_geometry_input, edge_index, material.ref());
353  assert(res == SU_ERROR_NONE); _unused(res);
354  // TODO: check that material exists in target model.
355 }
356 
357 
358 void GeometryInput::edge_layer(size_t edge_index, const Layer& layer) {
359  SUResult res = SUGeometryInputEdgeSetLayer(m_geometry_input, edge_index, layer.ref());
360  assert(res == SU_ERROR_NONE); _unused(res);
361  // TODO: check that layer exists in target model.
362 }
363 
364 
365 size_t GeometryInput::add_curve(const std::vector<size_t>& edge_indices) {
366  size_t added_curve_index;
367  SUResult res = SUGeometryInputAddCurve(m_geometry_input, edge_indices.size(), edge_indices.data(), &added_curve_index);
368  assert(res == SU_ERROR_NONE); _unused(res);
369  return added_curve_index;
370 }
371 
372 
373 std::pair<size_t, size_t> GeometryInput::add_arc_curve(size_t start_point, size_t end_point, const Point3D& center, const Vector3D& normal, size_t num_segments) {
374  size_t added_curve_index;
375  size_t control_edge_index;
376  SUResult res = SUGeometryInputAddArcCurve(m_geometry_input, start_point, end_point, center, normal, num_segments, &added_curve_index, &control_edge_index);
377  assert(res == SU_ERROR_NONE); _unused(res);
378  return std::pair<size_t, size_t> {added_curve_index, control_edge_index};
379 }
380 
381 
382 size_t GeometryInput::add_face(LoopInput& loop_input) {
383  size_t added_face_index;
384  SULoopInputRef loop_ref = loop_input.ref();
385  SUResult res = SUGeometryInputAddFace(m_geometry_input, &loop_ref, &added_face_index);
386  assert(res == SU_ERROR_NONE); _unused(res);
387  loop_input.m_attached = true;
388  return added_face_index;
389 }
390 
391 
392 void GeometryInput::face_reverse(size_t face_index, bool reverse) {
393  SUResult res = SUGeometryInputFaceSetReverse(m_geometry_input, face_index, reverse);
394  assert(res == SU_ERROR_NONE); _unused(res);
395 }
396 
397 
398 void GeometryInput::face_layer(size_t face_index, const Layer& layer) {
399  SUResult res = SUGeometryInputFaceSetLayer(m_geometry_input, face_index, layer.ref());
400  assert(res == SU_ERROR_NONE); _unused(res);
401 }
402 
403 
404 void GeometryInput::face_add_inner_loop(size_t face_index, LoopInput& inner_loop) {
405  SULoopInputRef loop_ref = inner_loop.ref();
406  SUResult res = SUGeometryInputFaceAddInnerLoop(m_geometry_input, face_index, &loop_ref);
407  assert(res == SU_ERROR_NONE); _unused(res);
408  inner_loop.m_attached = true;
409 }
410 
411 
412 void GeometryInput::face_front_material(size_t face_index, MaterialInput& material_input) {
413  SUMaterialInput material_ref = material_input.ref();
414  SUResult res = SUGeometryInputFaceSetFrontMaterial(m_geometry_input, face_index, &material_ref);
415  assert(res == SU_ERROR_NONE); _unused(res);
416  // TODO: assert MateriealRef in the MaterialInput is not attached to a different model from the one it will be added to.
417 }
418 
419 
420 void GeometryInput::face_back_material(size_t face_index, MaterialInput& material_input) {
421  SUMaterialInput material_ref = material_input.ref();
422  SUResult res = SUGeometryInputFaceSetBackMaterial (m_geometry_input, face_index, &material_ref);
423  assert(res == SU_ERROR_NONE); _unused(res);
424  // TODO: assert MateriealRef in the MaterialInput is not attached to a different model from the one it will be added to.
425 }
426 
427 
428 void GeometryInput::face_hidden(size_t face_index, bool hidden) {
429  SUResult res = SUGeometryInputFaceSetHidden(m_geometry_input, face_index, hidden);
430  assert(res == SU_ERROR_NONE); _unused(res);
431 }
432 
433 
434 std::array<size_t, 5> GeometryInput::counts() const {
435  std::array<size_t, 5> count_arr;
436  SUResult res = SUGeometryInputGetCounts(m_geometry_input, &count_arr[0], &count_arr[1], &count_arr[2], &count_arr[3], &count_arr[4]);
437  assert(res == SU_ERROR_NONE); _unused(res);
438  return count_arr;
439 }
440 
441 } /* namespace CW */
442 
443 bool operator==(const SUGeometryInputRef& lhs, const SUGeometryInputRef& rhs) {
444  return lhs.ptr == rhs.ptr;
445 }
446 
size_t add_vertex(const Point3D &point)
void set_vertices(const std::vector< SUPoint3D > &points)
std::array< size_t, 5 > counts() const
void edge_soft(size_t edge_index, bool soft)
Point3D position() const
Definition: Vertex.cpp:79
size_t add_curve(const std::vector< size_t > &edge_indices)
std::vector< Edge > edges() const
Definition: Loop.cpp:93
void face_front_material(size_t face_index, MaterialInput &material_input)
bool attached() const
Returns true if the entity is attached to another object.
Definition: Entity.cpp:100
void face_reverse(size_t face_index, bool reverse)
GeometryInput(SUModelRef target_model)
std::vector< Loop > inner_loops() const
Definition: Face.cpp:315
size_t add_face(const Face &face, bool copy_material_layer=true)
void face_hidden(size_t face_index, bool hidden)
void face_add_inner_loop(size_t face_index, LoopInput &inner_loop)
void edge_material(size_t edge_index, const Material &material)
std::vector< Point3D > points() const
Definition: Loop.cpp:131
bool operator!() const
SULayerRef ref() const
Definition: Layer.cpp:109
GeometryInput & operator=(const GeometryInput &other)
void face_back_material(size_t face_index, MaterialInput &material_input)
bool empty() const
size_t add_edge(const Edge &edge)
void edge_hidden(size_t edge_index, bool hidden)
SUGeometryInputRef ref() const
Definition: Color.hpp:34
std::pair< size_t, size_t > add_arc_curve(size_t start_point, size_t end_point, const Point3D &center, const Vector3D &normal, size_t num_segments)
size_t num_faces() const
void edge_layer(size_t edge_index, const Layer &layer)
void edge_smooth(size_t edge_index, bool smooth)
LoopInput & add_vertex_index(const size_t index)
Definition: LoopInput.cpp:166
void face_layer(size_t face_index, const Layer &layer)