NDEVR
API Documentation
Extruder.h
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Design
28File: Extruder
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/Geometry.h>
34#include <NDEVR/Plane.h>
35namespace NDEVR
36{
52 {
53 public:
54
73 {
74 lib_assert(linework.getGeometryType() == GeometryType::e_linework, "Can only extrude thickness along geometry of type linework");
75 fltp08 thickness = linework.get<NDPG::thickness>();
76 lib_assert(IsValid(thickness) && thickness > 0.0, "Thickness must be > 0.0");
77 Polyline<3, fltp08> geo_line;
78 switch (linework.thicknessMode())
79 {
82 linework.setSolidVertexCountValue(0);
85 return;
88 geo_line.add({ -thickness / 2.0, 0, 0 });
89 geo_line.add({ thickness / 2.0, 0, 0 });
90 break;
93 {
94 uint04 width_segments = 128;
95 for (uint04 x = 0; x <= width_segments; x++)
96 {
97 fltp08 u = cast<fltp08>(x) / cast<fltp08>(width_segments);
98 const Angle angle = u * Angle<fltp08>(DEGREES, 360.0f);
99 Vertex<3, fltp08> position(-thickness * cos(angle), thickness * sin(angle), 0.0);
100 geo_line.add(position);
101
102 }
103 } break;
104 }
105
106
107 ExtrudePolylineAlongGeo(linework, geo_line, transform);
108 }
109
125 static void ExtrudePolylineAlongGeo(Geometry& linework, const Polyline<3, fltp08>& geo_line, const Matrix<fltp08>& transform = Matrix<fltp08>(1.0))
126 {
127 lib_assert(linework.getGeometryType() == GeometryType::e_linework, "Can only extrude thickness along geometry of type linework");
128
130
131
132
133 bool is_closed = linework.get<NDPG::has_closed_primitive>();
135
137 Buffer<Vertex<3, fltp08>> vertices;
138 Matrix<fltp08> poly_transform = (transform * linework.get<NDPO::transform>()).invert();
139 //Extrude Shape
140 for (uint04 i = 0; i < polylines.size(); i++)
141 {
142 polylines[i].simplify();
143 Vector<3, fltp08> poly_normal = plane_normal;
144 if (IsInvalid(poly_normal))
145 {
146 Vector<3, fltp08> bounds = polylines[i].bounds().span();
147 if (bounds[X] * bounds[X] + bounds[Y] * bounds[Y] > bounds[Z] * bounds[Z])
148 poly_normal = { 0.0, 0.0, 1.0 };
149 else if (bounds[X] * bounds[X] > bounds[Y] * bounds[Y])
150 poly_normal = { 0.0, 1.0, 0.0 };
151 else
152 poly_normal = { 1.0, 0.0, 0.0 };
153 }
154 Extrude(indices, vertices, geo_line, polylines[i], poly_normal, is_closed, poly_transform);
155 }
156
157 //Add shape to Geometry
158 uint04 solid_vertex_offset = linework.solidVertexOffset();
159 if (IsInvalid(solid_vertex_offset))
160 {
161 solid_vertex_offset = linework.vertexCount();
162 linework.setSolidVertexOffsetValue(solid_vertex_offset);
163 }
164 uint04 solid_vertex_size = linework.solidVertexReservedCount();
165 if (solid_vertex_size < vertices.size())
166 {
167 linework.addVertices(solid_vertex_offset, vertices.size() - solid_vertex_size);
168 linework.setSolidVertexReservedValue(vertices.size());
169 }
170 linework.setSolidVertexCountValue(vertices.size());
171 for (uint04 i = 0; i < vertices.size(); i++)
172 {
173 linework.setVertex(VertexProperty::Position, solid_vertex_offset + i, vertices[i]);
174 }
177 linework.setPrimitiveRange(PrimitiveProperty::Solid, index_offset, indices.size());
178 for (uint04 i = 0; i < indices.size(); i++)
179 {
180 linework.setPrimitive(PrimitiveProperty::Solid, i, solid_vertex_offset + indices[i]);
181 }
182 linework.updateVertexColumns();
183 linework.updateSolidVertexColumns();
184 linework.updatePrimitiveColumns();
185 linework.updateModifiedTime();
186 }
187
218 template<class t_type>
219 static void Extrude(Buffer<Vector<3, uint04>>& indices
220 , Buffer<Vertex<3, t_type>>& vertices
221 , const Polyline<3, t_type>& shape_to_extrude
222 , const Polyline<3, t_type>& extrude_path
224 , bool is_path_closed
226 {
227 if (extrude_path.vertexCount() <= 1)
228 return;
229 Buffer<Vector<3, t_type>> last(shape_to_extrude.vertexCount());
230 Buffer<Vector<3, t_type>> current(shape_to_extrude.vertexCount());
231 //Loop over each segment in the extrusion path, projecting the shape at each vertex and connecting the neighboring projections
232 Ray<3, fltp08> last_right = Constant<Vector<3, fltp08>>::Invalid;
233
234 for (uint04 i = 0; i < extrude_path.vertexCount(); i++)
235 {
236 current.clear();
237 Vertex<3, t_type> offset = extrude_path.vertex(i);
238 bool greater_than_90_turn = false;
239 if (IsValid(offset))
240 {
241 Ray<3, t_type> dir;
242 Ray<3, t_type> original_dir;
243 if (is_path_closed && (i == 0 || i == extrude_path.segmentCount()))
244 {
245 //Since our path is closed, we will use the last segment as our -1 index segment in order to have
246 // a properly curved solid
247 original_dir = extrude_path.segment(extrude_path.segmentCount() - 1).ray().template normalized<t_type>();
248 Vector<3, t_type> dir_2 = extrude_path.segment(0).ray().template normalized<t_type>();
249 dir = (dir_2 + original_dir).template normalized<t_type>();
250 greater_than_90_turn = dot(dir_2, original_dir) < 0;
251 }
252 else if (last.size() == 0)
253 {
254 //We have no last reference, meaning our path should be totally based on this line segment
255 original_dir = extrude_path.segment(i).ray().template normalized<t_type>();
256 dir = original_dir;
257
258 }
259 else if (i == extrude_path.segmentCount())
260 {
261 //We have no future reference, meaning our path should be totally based on the last line segment
262 original_dir = extrude_path.segment(i - 1).ray().template normalized<t_type>();
263 dir = original_dir;
264 }
265 else
266 {
267 //Normal case: We are at some center section, our path will be influenced by 3 vertices
268 original_dir = extrude_path.segment(i - 1).ray().template normalized<t_type>();
269 Vector<3, t_type> dir_2 = extrude_path.segment(i).ray().template normalized<t_type>();
270 dir = (dir_2 + original_dir).template normalized<t_type>();
271 greater_than_90_turn = dot(dir_2, original_dir) < 0;
272
273 }
274 //If the segment has 0 length, then we will either be undefined or have a 0 magnitude.
275
276 if (dir.template magnitude<fltp08>() == 0.0 || IsInvalid(dir))
277 {
278 //lib_assert(false, "Encountered a zero length polyline. Please call simplify on the extrusion path prior to pass it to this function");
279 continue;
280 }
281 //This vector points to the right of the extrusion path segment
282 Ray<3, t_type> right = cross(dir, plane_normal).template normalized<t_type>();
283
284 if (IsInvalid(right))//Handle Vertical segments
285 {
286 if (IsInvalid(last_right))
287 {
288 right = Ray<3, fltp08>(plane_normal[Y], plane_normal[Z], plane_normal[X]);
289 }
290 else
291 {
292 right = last_right;
293 }
294 //TODO: right may be undefined if dir is along the plane normal, in which case we need to do
295 //a look ahead, and look behind to determine a suitable interpolated right vector.
296 }
297 last_right = right;
298
299 //This vector points 'up' from the extrusion path segment
300 //const Vertex<3, t_type> up = cross(dir, right).normalized<t_type>();
301 const Ray<3, fltp08> up = cross(dir, right).template normalized<fltp08>();
302
303 //Depending on how much our line curves, we need to project outward further. For example, a 90 degree turn requires
304 // our projected point to go out sqrt(orginal_distance^2+orginal_distance^2) in distance in addition to the original distance
305 const t_type p_off_original = cast<t_type>(1.0) - dot(dir, original_dir) * dot(dir, original_dir);
306
307 t_type extra_distance = sqrt(4 * p_off_original * p_off_original + 1.0);
308 if (greater_than_90_turn)
309 extra_distance = 2.0 / extra_distance;
310
311 //loop over our shape to extrude, marking the points
312 for (const auto& vertex : shape_to_extrude)
313 {
314 Ray<3, t_type> projection;
315 projection += vertex[X] * right;
316 projection += vertex[Y] * up;
317 projection += vertex[Z] * dir;
318 projection = projection.template normalized<fltp08>();
319 projection = (transform * projection) * vertex.template magnitude<fltp08>();
320 current.add((extra_distance * projection) + offset);
321 }
322 //Ensure that we have added vertices to this path before
323 if (last.size() > 0)
324 {
325 for (uint04 n = 0; n < shape_to_extrude.vertexCount() - 1; n++)
326 {
327 //Create a quad in the shape that connects the corrosponding segments. Note that this
328 //function also handles degenerate quads which may occur given sharp corners in the extrusion path.
329 indices.add(vertices.size() + Vector<3, uint04>(0, 1, 2));
330 indices.add(vertices.size() + Vector<3, uint04>(0, 2, 3));
331 vertices.add(last[n]);
332 vertices.add(current[n]);
333 vertices.add(current[n + 1]);
334 vertices.add(last[n + 1]);
335 }
336 }
337 }
338 last = current;
339 }
340 }
341 };
342}
343
344
345
Stores an angle in an optimized internal format with support for efficient trigonometric operations.
Definition Angle.h:83
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
void add(t_type &&object)
Adds object to the end of the buffer.
Definition Buffer.hpp:190
constexpr decltype(auto) get(t_property_type property) const
Retrieves a property value from the database, cast to the requested type.
Provides static functions to extrude 2D/3D shapes along polyline paths, generating triangulated solid...
Definition Extruder.h:52
static void ExtrudeRealThickness(Geometry &linework, const Matrix< fltp08 > &transform=Matrix< fltp08 >(1.0))
Extrudes a flat or circular cross-section along a linework geometry based on its real thickness prope...
Definition Extruder.h:72
static void ExtrudePolylineAlongGeo(Geometry &linework, const Polyline< 3, fltp08 > &geo_line, const Matrix< fltp08 > &transform=Matrix< fltp08 >(1.0))
Extrudes a given polyline cross-section along a linework geometry, producing a triangulated solid sto...
Definition Extruder.h:125
static void Extrude(Buffer< Vector< 3, uint04 > > &indices, Buffer< Vertex< 3, t_type > > &vertices, const Polyline< 3, t_type > &shape_to_extrude, const Polyline< 3, t_type > &extrude_path, const Vector< 3, t_type > &plane_normal, bool is_path_closed, const Matrix< fltp08 > &transform=Matrix< fltp08 >(1.0))
Extrudes a cross-section polyline along an extrusion path, generating triangle indices and vertices f...
Definition Extruder.h:219
A core class within the model hierarchy containing vertex-based data (Usually 3D data) within a set c...
Definition Geometry.h:143
Buffer< Polyline< t_dims, t_type > > polylines(PrimitiveProperty primitive_property, VertexProperty vertex_property) const
Retrieves all polylines from the geometry.
Definition Geometry.h:2053
ThicknessMode thicknessMode() const
Retrieves the current thickness mode.
void updateVertexColumns(bool invalidate_bounds=true, bool erase_kd_tree=true)
Notifies the system that all vertex columns have been modified.
void setSolidVertexCountValue(uint04 count)
Sets the solid vertex count value in the database.
Definition Geometry.h:2257
void setSolidVertexReservedValue(uint04 count)
Sets the solid vertex reserved count value in the database.
Definition Geometry.h:2264
void updateSolidVertexColumns(bool invalidate_bounds=true, bool erase_kd_tree=true)
Notifies the system that all solid vertex columns have been modified.
uint04 solidVertexReservedCount() const
Returns the reserved capacity for solid vertices.
Definition Geometry.h:1294
void updateModifiedTime(Time time=Time::SystemTime())
Updates the modified timestamp for this geometry.
void updatePrimitiveColumns(bool remove_tree=true)
Notifies the system that all primitive columns have been modified.
uint04 solidVertexOffset() const
Returns the offset of solid (thickness-expanded) vertices in the vertex table.
Definition Geometry.h:1287
@ e_none
No thickness applied.
Definition Geometry.h:196
@ e_pixel
Thickness in screen pixels.
Definition Geometry.h:197
@ e_flat_single
Flat thickness, single value for all vertices.
Definition Geometry.h:198
@ e_circle_per_vertex
Circular cross-section thickness, per-vertex value.
Definition Geometry.h:201
@ e_flat_per_vertex
Flat thickness, per-vertex value.
Definition Geometry.h:199
@ e_circle
Circular cross-section thickness, single value.
Definition Geometry.h:200
void setPrimitiveMode(PrimitiveProperty property, PrimitiveMode mode)
Sets the primitive mode for a given property.
void setPrimitive(PrimitiveProperty property, uint04 index, t_type index_value)
Sets a single primitive index value.
Definition Geometry.h:712
uint04 primitiveCount(PrimitiveProperty property) const
Returns the number of primitives for a specific property.
Definition Geometry.h:1163
uint04 addVertices(uint04 size)
Adds multiple vertices to the geometry.
Definition Geometry.h:1195
void setSolidVertexOffsetValue(uint04 count)
Sets the solid vertex offset value in the database.
Definition Geometry.h:2271
PrimitiveMode mode(PrimitiveProperty property) const
Retrieves the primitive mode for a given primitive property.
Definition Geometry.h:643
uint04 indexOffset() const
Returns the base index offset for this geometry within the shared index column.
Definition Geometry.h:1087
uint04 vertexCount() const
Returns the number of vertices in this geometry.
Definition Geometry.h:1280
uint04 primitiveIndexCount() const
Returns the total number of primitive indices across all properties.
Definition Geometry.h:1155
void setVertex(VertexProperty property, uint04 index, const t_type &vector)
Sets a standard vertex property value at the given index.
Definition Geometry.h:1654
void setPrimitiveRange(PrimitiveProperty mode, uint04 start, uint04 primitive_count)
Sets the start offset and count for a primitive property range.
GeometryType getGeometryType() const
Retrieves the geometry type identifier.
Templated logic for doing matrix multiplication.
Definition Matrix.hpp:182
A sequence of connected line segments defined by ordered vertices along a path.
Definition PolyLine.hpp:55
uint04 vertexCount() const
Definition PolyLine.hpp:194
LineSegment< t_dims, t_type, t_vertex > segment(uint04 index) const
Definition PolyLine.hpp:164
const t_vertex & vertex(uint04 index) const
Definition PolyLine.hpp:146
uint04 segmentCount() const
Definition PolyLine.hpp:209
void add(const t_vertex &vertex)
Definition PolyLine.hpp:244
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
Definition Vector.hpp:62
A point in N-dimensional space, used primarily for spatial location information.
Definition Vertex.hpp:44
The primary namespace for the NDEVR SDK.
@ Position
XYZ position of the vertex.
@ e_triangle
Each triplet of indices defines a triangle.
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
@ e_linework
Lines or polylines.
double fltp08
Defines an alias representing an 8 byte floating-point number.
@ DEGREES
Angle measured in degrees (0 to 360 for a full circle).
Definition Angle.h:58
constexpr Vector< 1, t_type > cross(const Vector< 1, t_type > &, const Vector< 1, t_type > &)
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388
@ transform
A 4x4 transform matrix that maps local coordinates into global space.
t_type sqrt(const t_type &value)
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type sin(const Angle< t_type > &angle)
Performs optimized sine operation on the given angle using pre-computed lookup table for optimal spee...
@ Outline
Line-based outline rendering of primitives.
@ Solid
Solid filled rendering of primitives.
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type cos(const Angle< t_type > &angle)
Performs optimized cosine operation on the given angle using pre-computed lookup table for optimal sp...
@ has_closed_primitive
Whether primitives are closed, enabling volume calculations.
Definition Geometry.h:63
@ thickness
The thickness value applied to geometry rendering.
Definition Geometry.h:58
@ plane_normal
The normal ray of the surface plane.
Definition Geometry.h:64
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...