11#ifndef JAU_GAMP_GRAPH_OUTLINESHAPE_HPP_
12#define JAU_GAMP_GRAPH_OUTLINESHAPE_HPP_
29 using namespace jau::math;
30 using namespace jau::math::geom;
31 using namespace jau::enums;
32 using jau::math::geom::plane::AffineTransform;
130 mutable bool m_complexShape;
140 : m_outlineVertCapacity(capacity),
142 m_outlines(m_outlineVertCapacity),
145 m_addedVertexCount(0),
146 m_complexShape(false),
150 m_outlines.emplace_back(outlineVertCapacity);
155 constexpr const Vec3f&
normal() const noexcept {
return m_normal; }
167 constexpr float sharpness() const noexcept {
return m_sharpness; }
171 if( m_sharpness != s ) {
180 m_outlines.emplace_back(m_outlineVertCapacity);
185 m_addedVertexCount = 0;
186 m_complexShape =
false;
205 void validateBoundingBox() const noexcept {
208 for (
const auto & m_outline : m_outlines) {
209 m_bbox.
resize(m_outline.bounds());
216 validateBoundingBox();
221 bool empty() const noexcept {
return m_outlines.empty(); }
225 return m_outlines.size();
231 for(
const Outline& o : m_outlines) {
232 res += o.vertexCount();
249 return m_outlines[m_outlines.size()-1];
257 return m_outlines[m_outlines.size()-1];
290 m_complexShape =
false;
292 for(
size_type i=0; i<sz && !m_complexShape; ++i) {
297 return m_complexShape;
329 m_outlines.emplace_back(m_outlineVertCapacity);
360 if( m_outlines.size() == position ) {
366 m_outlines[position-1] =
outline;
368 m_bbox.resize(
outline.bounds());
375 m_outlines.insert(position,
outline);
377 m_bbox.resize(
outline.bounds());
407 m_outlines.insert(position,
outline);
420 m_outlines.erase(position);
436 m_bbox.resize(v.
coord());
453 m_bbox.resize(v.
coord());
468 void addVertex(
float x,
float y,
float z,
bool onCurve) {
567 void quadTo(
float x1,
float y1,
float z1,
float x2,
float y2,
float z2) {
588 void cubicTo(
float x1,
float y1,
float z1,
float x2,
float y2,
float z2,
float x3,
float y3,
float z3) {
645 return newOutlineShape;
654 for(
Vertex& v : o.vertices()) {
655 v.coord().z = ( v.coord().z * -1.0f ) + zoffset;
668 const float otherSize = other.bounds().size();
671 }
else if(thisSize < otherSize){
691 if(
bounds() != o.bounds() ) {
695 if(
outline(i) != o.outline(i) ) {
724 m_addedVertexCount += 2;
736 void checkOverlaps() {
739 bool firstpass =
true;
741 for (
size_type cc = 0; cc < count; ++cc) {
744 for(
size_type i=0; i < ol.vertexCount(); ++i) {
745 Vertex& currentVertex = ol.vertex(i);
746 if ( !currentVertex.onCurve()) {
747 const Vertex& nextV = ol.vertex((i+1)%
vertexCount);
756 overlap = checkTriOverlaps0(prevV, currentVertex, nextV);
763 subdivideTriangle(ol, prevV, currentVertex, nextV, i);
766 m_addedVertexCount+=2;
768 if(overlap && !overlap->onCurve()) {
770 overlaps.push_back(*overlap);
778 }
while( !overlaps.empty() );
781 Vertex* checkTriOverlaps0(
const Vertex& a,
const Vertex& b,
const Vertex& c) {
783 for (
size_type cc = 0; cc < count; ++cc) {
787 Vertex& currV = ol.vertex(i);
788 if( !currV.onCurve() && currV != a && currV != b && currV != c) {
793 if(prevV != c && nextV != a) {
795 currV.coord(), nextV.coord(), prevV.coord()) ) {
810 void cleanupOutlines() {
813 for (
size_type cc = 0; cc < count; ++cc) {
817 if( transformOutlines2Quadratic ) {
819 Vertex& currentVertex = ol.vertex(i);
821 Vertex& nextVertex = ol.vertex(j);
822 if ( !currentVertex.onCurve() && !nextVertex.onCurve() ) {
823 Vec3f mp =
midpoint(currentVertex.coord(), nextVertex.coord());
829 ++m_addedVertexCount;
839 ol.vertex(0).coord() == ol.lastVertex().coord() )
848 uint32_t generateVertexIds() {
849 uint32_t maxVertexId = 0;
850 for(
size_type i=0; i<m_outlines.size(); ++i) {
853 vertice.id() = maxVertexId++;
872 bool updated =
false;
875 for(
const Outline& ol : m_outlines) {
877 m_vertices.push_back(v.
begin(), v.
end());
883 jau::PLAIN_PRINT(
true,
"OutlineShape.getVertices().X: %u, updated %d", m_vertices.size(), updated);
886 for(
Vertex& v : m_vertices) {
895 struct SizeDescending {
905 void sortOutlines() {
906 std::sort(m_outlines.begin(), m_outlines.end(), sizeDescending);
909 void triangulateImpl() {
910 if( 0 < m_outlines.size() ) {
915 tess::CDTriangulator2D triangulator2d;
916 triangulator2d.setComplexShape(
isComplex() );
917 for(Outline& ol : m_outlines) {
918 triangulator2d.addCurve(m_triangles, ol, m_sharpness);
920 triangulator2d.generate(m_triangles);
921 m_addedVertexCount += triangulator2d.getAddedVerticeCount();
922 triangulator2d.reset();
937 bool updated =
false;
951 jau::PLAIN_PRINT(
true,
"OutlineShape.getTriangles().X: %u, updated %d", m_triangles.size(), updated);
965 std::string r(
"OutlineShape[");
966 r.append(
"dirty ").append(
to_string(m_dirtyBits))
967 .append(
", outlines ").append(std::to_string(
outlineCount()))
968 .append(
", vertices ").append(std::to_string(
vertexCount()))
constexpr size_type addedVertexCount() const noexcept
Return the number of newly added vertices during getTriangles(VerticesState) while transforming the o...
size_type outlineCount() const noexcept
Returns the number of Outlines.
JAU_MAKE_BITFIELD_ENUM_STRING_MEMBER(DirtyBits, bounds, vertices, triangles, convex, convexOverride)
void addVertex(size_type position, float x, float y, float z, bool onCurve)
Add a 3D Vertex to the last open outline to the shape at position.
void addVertex(float x, float y, float z, bool onCurve)
Add a 3D Vertex to the last open outline to the shape's tail.
const AABBox3f & bounds() const noexcept
void setSharpness(float s) noexcept
Sets sharpness, defaults to DEFAULT_SHARPNESS.
void clearCache() noexcept
Clears cached triangulated data, i.e.
static constexpr size_type max_elements
byte-size int32_t limit: 536'870'911 (FIXME: Adjust to actual type, i.e. Vertex = 2x Vec3f?...
VertexState outlineState() const noexcept
void setOverrideConvex(bool convex) noexcept
Overrides isComplex() using the given value instead of computing via Outline#isComplex().
bool isComplex() const noexcept
Returns cached or computed result if at least one polyline outline(size_type) is a complex shape,...
int compareTo(const OutlineShape &other) const noexcept
Compare two outline shape's Bounding Box size.
const VertexList & getVertices()
Return list of concatenated vertices associated with all Outlines of this object.
OutlineList & outlines() noexcept
Winding windingOfLastOutline() const noexcept
Compute the Winding of the getLastOutline() using the VectorUtil#area(ArrayList) function over all of...
@ triangles
<Modified shape, requires to update the vertices and triangles, here: vertices
@ convexOverride
<Modified shape, requires to update the convex determination
@ convex
<Modified shape, requires to update the vertices and triangles, here: triangulation.
JAU_MAKE_ENUM_STRING_MEMBER(VertexState, quadratic_nurbs)
void cubicTo(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
Add a cubic Bézier curve segment, intersecting the last point and the second given point x3/y3 (P3).
void removeOutline(size_type position)
Removes the Outline element at the given position.
void addVertex(float x, float y, bool onCurve)
Add a 2D Vertex to the last open outline to the shape's tail.
const Outline & lastOutline() const noexcept
Get the last added outline to the list of outlines that define the shape.
const OutlineList & outlines() const noexcept
const TriangleRefList & getTriangles(VertexState destinationType=VertexState::quadratic_nurbs)
Triangulate the OutlineShape generating a list of triangles, while transformOutlines(VerticesState) b...
void addVertex(const Vec2f &v, bool onCurve)
Add a 2D Vertex to the last open outline to the shape's tail.
size_type vertexCount() const noexcept
Returns the total vertex number of all Outlines.
const Outline & outline(size_type i) const noexcept
std::string toString() const noexcept
void addVertex(const Vec3f &v, bool onCurve)
Add a 3D Vertex to the last open outline to the shape's tail.
constexpr Vec3f & normal() noexcept
Writing the normal vector, optionally used by tesselator to add (interleaved) normals.
void closeLastOutline(bool closeTail)
Closes the last outline in the shape.
OutlineShape(size_type capacity, size_type outlineVertCapacity)
constexpr bool verticesDirty() const noexcept
void addOutline(size_type position, const Outline &outline)
Insert the Outline element at the given position.
void setWindingOfLastOutline(Winding enforced)
Sets the enforced Winding of the getLastOutline().
constexpr void reserve(size_type newCapacity)
void setIsQuadraticNurbs() noexcept
Claim this outline's vertices are all VertexState::quadratic_nurbs, hence no cubic transformations wi...
constexpr bool operator==(const OutlineShape &o) const noexcept
void clear()
Clears all data and reset all states as if this instance was newly created.
bool empty() const noexcept
void quadTo(float x1, float y1, float z1, float x2, float y2, float z2)
Add a quadratic curve segment, intersecting the last point and the second given point x2/y2 (P2).
void markClean(DirtyBits flags) noexcept
void addOutlineShape(const OutlineShape &outlineShape)
Insert the OutlineShape elements of type Outline, .
constexpr const Vec3f & normal() const noexcept
Normal vector, optionally used by tesselator to add (interleaved) normals.
void moveTo(float x, float y, float z)
Start a new position for the next line segment at given point x/y (P1).
void clearOverrideConvex() noexcept
Clears the isComplex() override done by setOverrideConvex(boolean).
void closePath()
Closes the current sub-path segment by drawing a straight line back to the coordinates of the last mo...
void addVertex(size_type position, const Vertex &v)
Adds a vertex to the last open outline to the shape at position @endiliteral.
static constexpr float DEFAULT_SHARPNESS
Initial sharpness() value, which can be modified via setSharpness(float).
constexpr float sharpness() const noexcept
Sharpness value, defaults to DEFAULT_SHARPNESS.
constexpr bool trianglesDirty() const noexcept
Outline & lastOutline() noexcept
Get the last added outline to the list of outlines that define the shape.
OutlineShape transform(const AffineTransform &t) const
Return a transformed instance with all Outlines are copied and transformed.
Outline & outline(size_type i) noexcept
OutlineShape flipFace(float zoffset=0) const
Returns a copy of this instance with normal() and all outlines() vertices()'s z-axis sign-flipped,...
void lineTo(float x, float y, float z)
Add a line segment, intersecting the last point and the given point x/y (P1).
void addEmptyOutline()
Add a new empty Outline to the end of this shape's outline list.
void setOutline(size_type position, const Outline &outline)
Replaces the Outline element at the given position.
void addOutline(const Outline &outline)
Appends the Outline element to the end, ensuring a clean tail.
void addVertex(const Vertex &v)
Adds a vertex to the last open outline to the shape's tail.
constexpr DirtyBits dirtyBits() const noexcept
Define a single continuous stroke by control vertices.
void addVertex(const Vertex &vertex)
Appends a vertex to the outline loop/strip.
constexpr const VertexList & vertices() const noexcept
bool isComplex() const noexcept
Returns cached or computed result if whether this Outlines polyline is a complex shape.
constexpr bool empty() const noexcept
void setWinding(Winding enforce)
Sets Winding to this outline.
int compareTo(const Outline &other) const noexcept
Compare two outline's Bounding Box size.
Winding getWinding() const noexcept
Returns the cached or computed winding of this Outlines polyline using VectorUtil#area(ArrayList).
constexpr const Vec3f & coord() const noexcept
constexpr bool onCurve() const noexcept
constexpr iterator end() noexcept
constexpr iterator begin() noexcept
Axis Aligned Bounding Box.
constexpr AABBox3f & reset() noexcept
Reset this box to the inverse low/high, allowing the next resize(float, float, float) command to hit.
constexpr float size() const noexcept
Get the size of this aabbox3f where the size is represented by the length of the vector between low a...
AABBox3f & resize(const AABBox3f &o) noexcept
Resize the aabbox3f to encapsulate another AABox.
constexpr bool contains(InputArray &array, const T &value) noexcept
Return true if value is contained in array.
constexpr bool eraseFirst(InputArray &array, const T &value)
constexpr bool is_set(const E mask, const E bits) noexcept
std::enable_if_t< std::is_floating_point_v< T >, bool > constexpr equals2(const T &a, const T &b, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if both values are equal, i.e.
jau::darray< Outline, jau::nsize_t > OutlineList
jau::darray< Vertex, uint32_t > VertexList
std::shared_ptr< Triangle > TriangleRef
jau::darray< TriangleRef, uint32_t > TriangleRefList
constexpr Vec3f midpoint(const Vec3f &a, const Vec3f &b) noexcept
std::string to_string(const math_error_t v) noexcept
Returns std::string representation of math_error_t.
constexpr bool testTri2SegIntersection2D(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &d, const Vec3f &e)
Check if a segment intersects with a triangle using FloatUtil#EPSILON w/o considering collinear-case.
constexpr bool isInTriangle3(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) noexcept
Check if one of three vertices are in triangle using barycentric coordinates computation.
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.