mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-05 14:39:41 +08:00
1392 lines
37 KiB
C++
1392 lines
37 KiB
C++
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
#include "opennurbs_subd_data.h"
|
|
|
|
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2014 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
|
|
static void* ON_SubD__Allocate(size_t sz)
|
|
{
|
|
if (0 == sz)
|
|
return nullptr;
|
|
|
|
// double array allocation is used to insure the memory
|
|
// returned by new is properly aligned for any type.
|
|
double* a;
|
|
size_t sz1 = sz % sizeof(a[0]);
|
|
if (sz1 > 0)
|
|
sz += (sizeof(a[0]) - sz1);
|
|
a = new(std::nothrow) double[sz];
|
|
|
|
if (nullptr == a)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
return a;
|
|
}
|
|
|
|
static void ON_SubD__Free(void* p)
|
|
{
|
|
if (nullptr != p)
|
|
{
|
|
double* a = (double*)p;
|
|
delete[] a;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubD_FixedSizeHeap
|
|
//
|
|
|
|
unsigned int ON_SubD_FixedSizeHeap::m__sn_factory = 0;
|
|
|
|
ON_SubD_FixedSizeHeap::~ON_SubD_FixedSizeHeap()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
void ON_SubD_FixedSizeHeap::Destroy()
|
|
{
|
|
Reset();
|
|
m_v_capacity = 0;
|
|
m_e_capacity = 0;
|
|
m_f_capacity = 0;
|
|
m_p_capacity = 0;
|
|
void* p[4] = { m_v, m_e, m_f, m_p };
|
|
m_v = nullptr;
|
|
m_e = nullptr;
|
|
m_f = nullptr;
|
|
m_p = nullptr;
|
|
ON_SubD__Free(p[0]);
|
|
ON_SubD__Free(p[1]);
|
|
ON_SubD__Free(p[2]);
|
|
ON_SubD__Free(p[3]);
|
|
}
|
|
|
|
void ON_SubD_FixedSizeHeap::Reset()
|
|
{
|
|
m_v_index = 0;
|
|
m_e_index = 0;
|
|
m_f_index = 0;
|
|
m_p_index = 0;
|
|
}
|
|
|
|
bool ON_SubD_FixedSizeHeap::InUse() const
|
|
{
|
|
return (m_v_index > 0 || m_e_index > 0 || m_f_index>0 || m_p_index>0);
|
|
}
|
|
|
|
|
|
bool ON_SubD_FixedSizeHeap::ReserveSubDWorkspace(
|
|
size_t vertex_capacity,
|
|
size_t edge_capacity,
|
|
size_t face_capacity,
|
|
size_t array_capacity
|
|
)
|
|
{
|
|
if (0 == vertex_capacity || (0 == edge_capacity && 0 == face_capacity && 0 == array_capacity))
|
|
{
|
|
Destroy();
|
|
return true;
|
|
}
|
|
|
|
if (m_v_capacity >= vertex_capacity && m_e_capacity >= edge_capacity && m_f_capacity >= face_capacity && m_p_capacity >= array_capacity)
|
|
{
|
|
Reset();
|
|
return true;
|
|
}
|
|
|
|
Destroy();
|
|
|
|
size_t max_capacity = 0xFFFFFFF0U;
|
|
if (vertex_capacity > max_capacity || edge_capacity > max_capacity || face_capacity > max_capacity || array_capacity > max_capacity)
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
|
|
for (;;)
|
|
{
|
|
m_v = (ON_SubDVertex*)ON_SubD__Allocate(vertex_capacity*sizeof(m_v[0]));
|
|
if (nullptr == m_v && vertex_capacity > 0)
|
|
break;
|
|
m_e = (ON_SubDEdge*)ON_SubD__Allocate(edge_capacity*sizeof(m_e[0]));
|
|
if (nullptr == m_e && edge_capacity > 0)
|
|
break;
|
|
m_f = (ON_SubDFace*)ON_SubD__Allocate(face_capacity*sizeof(m_f[0]));
|
|
if (nullptr == m_f && face_capacity > 0)
|
|
break;
|
|
m_p = (ON__UINT_PTR*)ON_SubD__Allocate(array_capacity*sizeof(m_p[0]));
|
|
if (nullptr == m_p && array_capacity > 0)
|
|
break;
|
|
|
|
m_v_capacity = (unsigned int)vertex_capacity;
|
|
m_e_capacity = (unsigned int)edge_capacity;
|
|
m_f_capacity = (unsigned int)face_capacity;
|
|
m_p_capacity = (unsigned int)array_capacity;
|
|
return true;
|
|
}
|
|
|
|
Destroy();
|
|
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
|
|
|
|
bool ON_SubD_FixedSizeHeap::ReserveSubDWorkspace(
|
|
ON_SubD::SubDType subdivision_type,
|
|
unsigned int extraordinary_valence
|
|
)
|
|
{
|
|
if (0 == extraordinary_valence)
|
|
{
|
|
Destroy();
|
|
return true;
|
|
}
|
|
|
|
// capacity depends on extraordinary_valence and subdivision_type
|
|
|
|
bool bTri = (ON_SubD::SubDType::TriLoopWarren == subdivision_type);
|
|
|
|
unsigned int ordinary_valence = bTri ? 6 : 4;
|
|
|
|
if (extraordinary_valence < ordinary_valence)
|
|
extraordinary_valence = ordinary_valence;
|
|
|
|
// When ON_SubD::FacetType::Unset == facet_type,
|
|
// the maximum of quad or tri capcacity is used.
|
|
// For all but the face array, tri capacity < quad capacity.
|
|
|
|
const unsigned int v_capacity
|
|
= bTri
|
|
? (extraordinary_valence + 6)
|
|
: (2 * extraordinary_valence + 8); // quads
|
|
|
|
const unsigned int e_capacity
|
|
= bTri
|
|
? (extraordinary_valence + 14)
|
|
: (3 * extraordinary_valence + 12); // quads or unset
|
|
|
|
// const unsigned int f_capacity = extraordinary_valence + 7 for tris
|
|
// const unsigned int f_capacity = extraordinary_valence + 5 for quads
|
|
// 7 is alwasy used to accomodate unset as well
|
|
const unsigned int f_capacity = extraordinary_valence + 7;
|
|
|
|
const unsigned int p_capacity = 2*(ordinary_valence*v_capacity + (extraordinary_valence - ordinary_valence));
|
|
|
|
return ReserveSubDWorkspace(v_capacity, e_capacity, f_capacity, p_capacity);
|
|
}
|
|
|
|
|
|
ON_SubDVertex* ON_SubD_FixedSizeHeap::AllocateVertex(
|
|
const double vertexP[3],
|
|
unsigned int edge_capacity,
|
|
unsigned int face_capacity
|
|
)
|
|
{
|
|
if (nullptr == m_v || m_v_index >= m_v_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
if (edge_capacity + face_capacity + m_p_index >= m_p_capacity )
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON__UINT_PTR* a = nullptr;
|
|
if (0 != edge_capacity || 0 != face_capacity)
|
|
{
|
|
if ( edge_capacity > 0xFFFFu)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if ( face_capacity > 0xFFFFu)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
a = AllocatePtrArray(edge_capacity + face_capacity, true);
|
|
if (nullptr == a)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
}
|
|
|
|
ON_SubDVertex* v = m_v + m_v_index;
|
|
memset(v, 0, sizeof(*v));
|
|
if (m_v_index > 0)
|
|
{
|
|
// code in ON_SubDFaceNeighborhood.Subdivide() relies on
|
|
// m_next_vertex being set this way.
|
|
m_v[m_v_index - 1].m_next_vertex = v;
|
|
v->m_prev_vertex = &m_v[m_v_index - 1];
|
|
}
|
|
v->m_id = ++m_v_index;
|
|
|
|
if (nullptr != vertexP)
|
|
{
|
|
v->m_P[0] = vertexP[0];
|
|
v->m_P[1] = vertexP[1];
|
|
v->m_P[2] = vertexP[2];
|
|
}
|
|
|
|
if (edge_capacity > 0)
|
|
{
|
|
v->m_edge_capacity = (unsigned short)edge_capacity;
|
|
v->m_edges = (ON_SubDEdgePtr*)a;
|
|
a += edge_capacity;
|
|
}
|
|
if (face_capacity > 0)
|
|
{
|
|
v->m_face_capacity = (unsigned short)face_capacity;
|
|
v->m_faces = (const ON_SubDFace**)a;
|
|
}
|
|
a = 0;
|
|
|
|
return v;
|
|
}
|
|
|
|
ON_SubDVertex* ON_SubD_FixedSizeHeap::AllocateVertex(
|
|
const ON_SubDVertex* vertex0,
|
|
ON_SubD::SubDType subdivision_type,
|
|
bool bUseSavedSubdivisionPoint,
|
|
unsigned int edge_capacity,
|
|
unsigned int face_capacity
|
|
)
|
|
{
|
|
if ( nullptr == vertex0)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
double subdP[3];
|
|
if (false == vertex0->GetSubdivisionPoint(subdivision_type,bUseSavedSubdivisionPoint,subdP))
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
ON_SubDVertex* v1 = AllocateVertex(subdP,edge_capacity,face_capacity);
|
|
|
|
if ( nullptr == v1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
v1->m_level = vertex0->m_level+1;
|
|
|
|
v1->m_vertex_tag = vertex0->m_vertex_tag;
|
|
|
|
//if ( ON_SubD::SubDType::QuadCatmullClark == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Quad;
|
|
//else if ( ON_SubD::SubDType::TriLoopWarren == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Tri;
|
|
|
|
if (bUseSavedSubdivisionPoint && subdivision_type == vertex0->SavedLimitPointType())
|
|
{
|
|
ON_SubDSectorLimitPoint limit_point;
|
|
if (vertex0->GetLimitPoint(subdivision_type, vertex0->m_faces[0], bUseSavedSubdivisionPoint, limit_point))
|
|
{
|
|
if (nullptr == limit_point.m_sector_face)
|
|
{
|
|
limit_point.m_next_sector_limit_point = (const ON_SubDSectorLimitPoint*)1;
|
|
v1->SetSavedLimitPoint(subdivision_type, limit_point);
|
|
}
|
|
}
|
|
}
|
|
|
|
return v1;
|
|
}
|
|
|
|
ON_SubDVertex* ON_SubD_FixedSizeHeap::AllocateVertex(
|
|
const ON_SubDEdge* edge0,
|
|
ON_SubD::SubDType subdivision_type,
|
|
bool bUseSavedSubdivisionPoint,
|
|
unsigned int edge_capacity,
|
|
unsigned int face_capacity
|
|
)
|
|
{
|
|
if ( nullptr == edge0)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
double subdP[3];
|
|
if (false == edge0->GetSubdivisionPoint(subdivision_type,bUseSavedSubdivisionPoint,subdP))
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDVertex* v1 = AllocateVertex(subdP,edge_capacity,face_capacity);
|
|
if ( nullptr == v1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
v1->m_level = edge0->m_level+1;
|
|
|
|
if (ON_SubD::EdgeTag::Smooth == edge0->m_edge_tag || ON_SubD::EdgeTag::X == edge0->m_edge_tag)
|
|
v1->m_vertex_tag = ON_SubD::VertexTag::Smooth;
|
|
else if (ON_SubD::EdgeTag::Crease == edge0->m_edge_tag)
|
|
v1->m_vertex_tag = ON_SubD::VertexTag::Crease;
|
|
|
|
//if ( ON_SubD::SubDType::QuadCatmullClark == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Quad;
|
|
//else if ( ON_SubD::SubDType::TriLoopWarren == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Tri;
|
|
|
|
return v1;
|
|
}
|
|
|
|
ON_SubDVertex* ON_SubD_FixedSizeHeap::AllocateVertex(
|
|
const ON_SubDFace* face0,
|
|
ON_SubD::SubDType subdivision_type,
|
|
bool bUseSavedSubdivisionPoint,
|
|
unsigned int edge_capacity,
|
|
unsigned int face_capacity
|
|
)
|
|
{
|
|
if ( nullptr == face0)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
double subdP[3];
|
|
if (false == face0->GetSubdivisionPoint(subdivision_type,bUseSavedSubdivisionPoint,subdP))
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDVertex* v1 = AllocateVertex(subdP,edge_capacity,face_capacity);
|
|
if ( nullptr == v1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
v1->m_level = face0->m_level+1;
|
|
|
|
v1->m_vertex_tag = ON_SubD::VertexTag::Smooth;
|
|
|
|
//if ( ON_SubD::SubDType::QuadCatmullClark == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Quad;
|
|
//else if ( ON_SubD::SubDType::TriLoopWarren == subdivision_type)
|
|
// v1->m_vertex_facet_type = ON_SubD::VertexFacetType::Tri;
|
|
|
|
return v1;
|
|
}
|
|
|
|
ON_SubDEdge* ON_SubD_FixedSizeHeap::AllocateEdge(
|
|
ON_SubDVertex* v0,
|
|
double v0_sector_weight,
|
|
ON_SubDVertex* v1,
|
|
double v1_sector_weight
|
|
)
|
|
{
|
|
if ( nullptr != v0 && nullptr == v0->m_edges)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if ( nullptr != v1 && nullptr == v1->m_edges)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == m_e || m_e_index >= m_e_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
bool bTaggedVertex[2];
|
|
if (nullptr != v0)
|
|
{
|
|
if (nullptr == v0->m_edges || v0->m_edge_count >= v0->m_edge_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (ON_SubD::VertexTag::Smooth == v0->m_vertex_tag)
|
|
{
|
|
bTaggedVertex[0] = false;
|
|
v0_sector_weight = ON_SubDSectorType::IgnoredSectorWeight;
|
|
}
|
|
else
|
|
{
|
|
bTaggedVertex[0] = (ON_SubD::VertexTag::Unset != v0->m_vertex_tag);
|
|
}
|
|
}
|
|
else
|
|
bTaggedVertex[0] = false;
|
|
|
|
if (nullptr != v1)
|
|
{
|
|
if (nullptr == v1->m_edges || v1->m_edge_count >= v1->m_edge_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (ON_SubD::VertexTag::Smooth == v1->m_vertex_tag)
|
|
{
|
|
bTaggedVertex[1] = false;
|
|
v1_sector_weight = ON_SubDSectorType::IgnoredSectorWeight;
|
|
}
|
|
else
|
|
{
|
|
bTaggedVertex[1] = (ON_SubD::VertexTag::Unset != v0->m_vertex_tag);
|
|
if (bTaggedVertex[0] && bTaggedVertex[1])
|
|
{
|
|
// crease edge - no weights
|
|
v0_sector_weight = ON_SubDSectorType::IgnoredSectorWeight;
|
|
v1_sector_weight = ON_SubDSectorType::IgnoredSectorWeight;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bTaggedVertex[1] = false;
|
|
|
|
if ( false == ON_SubDSectorType::IsValidSectorWeightValue(v0_sector_weight, true))
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
if ( false == ON_SubDSectorType::IsValidSectorWeightValue(v1_sector_weight, true))
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDEdge* e = m_e + m_e_index;
|
|
memset(e, 0, sizeof(*e));
|
|
if (m_e_index > 0)
|
|
{
|
|
// code in ON_SubDFaceNeighborhood.Subdivide() relies on m_next_edge being set this way.
|
|
m_e[m_e_index - 1].m_next_edge = e;
|
|
e->m_prev_edge = &m_e[m_e_index - 1];
|
|
}
|
|
|
|
e->m_id = ++m_e_index;
|
|
|
|
if (nullptr != v0)
|
|
{
|
|
e->m_vertex[0] = v0;
|
|
v0->m_edges[v0->m_edge_count++] = ON_SubDEdgePtr::Create(e,0);
|
|
//v0->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
e->m_level = v0->m_level;
|
|
}
|
|
|
|
if (nullptr != v1)
|
|
{
|
|
e->m_vertex[1] = v1;
|
|
v1->m_edges[v1->m_edge_count++] = ON_SubDEdgePtr::Create(e,1);
|
|
//v1->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
if ( e->m_level < v1->m_level)
|
|
e->m_level = v1->m_level;
|
|
}
|
|
|
|
e->m_sector_coefficient[0] = v0_sector_weight;
|
|
e->m_sector_coefficient[1] = v1_sector_weight;
|
|
e->m_edge_tag = (bTaggedVertex[0] && bTaggedVertex[1]) ? ON_SubD::EdgeTag::Crease : ON_SubD::EdgeTag::Smooth;
|
|
|
|
return e;
|
|
}
|
|
|
|
ON_SubDFace* ON_SubD_FixedSizeHeap::AllocateFace(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id
|
|
)
|
|
{
|
|
if (nullptr == m_f || m_f_index >= m_f_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
ON_SubDFace* f = m_f + m_f_index;
|
|
memset(f, 0, sizeof(*f));
|
|
if (m_f_index > 0)
|
|
{
|
|
// code in ON_SubDFaceNeighborhood.Subdivide() relies on
|
|
// m_next_face being set this way.
|
|
m_f[m_f_index-1].m_next_face = f;
|
|
f->m_prev_face = &m_f[m_f_index-1];
|
|
}
|
|
|
|
f->m_id = ++m_f_index;
|
|
f->m_zero_face_id = (0 == zero_face_id) ? parent_face_id : zero_face_id;
|
|
f->m_parent_face_id = parent_face_id;
|
|
|
|
return f;
|
|
}
|
|
|
|
ON_SubDFace* ON_SubD_FixedSizeHeap::AllocateQuad(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id,
|
|
const ON_SubDEdgePtr eptrs[4]
|
|
)
|
|
{
|
|
if (nullptr == eptrs)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDEdge* edges[4] = {
|
|
ON_SUBD_EDGE_POINTER(eptrs[0].m_ptr),
|
|
ON_SUBD_EDGE_POINTER(eptrs[1].m_ptr),
|
|
ON_SUBD_EDGE_POINTER(eptrs[2].m_ptr),
|
|
ON_SUBD_EDGE_POINTER(eptrs[3].m_ptr)};
|
|
|
|
if (nullptr == edges[0] || edges[0]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == edges[1] || edges[1]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == edges[2] || edges[2]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == edges[3] || edges[3]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON__UINT_PTR edgedirs[4] = {
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[0].m_ptr),
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[1].m_ptr),
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[2].m_ptr),
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[3].m_ptr)};
|
|
|
|
ON_SubDVertex* vertices[4] = {
|
|
const_cast<ON_SubDVertex*>(edges[0]->m_vertex[edgedirs[0]]),
|
|
const_cast<ON_SubDVertex*>(edges[1]->m_vertex[edgedirs[1]]),
|
|
const_cast<ON_SubDVertex*>(edges[2]->m_vertex[edgedirs[2]]),
|
|
const_cast<ON_SubDVertex*>(edges[3]->m_vertex[edgedirs[3]]) };
|
|
|
|
if (nullptr == vertices[0] || nullptr == vertices[0]->m_faces || vertices[0]->m_face_count >= vertices[0]->m_face_capacity || vertices[0] != edges[3]->m_vertex[1-edgedirs[3]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == vertices[1] || nullptr == vertices[1]->m_faces || vertices[1]->m_face_count >= vertices[1]->m_face_capacity || vertices[1] != edges[0]->m_vertex[1-edgedirs[0]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == vertices[2] || nullptr == vertices[2]->m_faces || vertices[2]->m_face_count >= vertices[2]->m_face_capacity || vertices[2] != edges[1]->m_vertex[1-edgedirs[1]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == vertices[3] || nullptr == vertices[3]->m_faces || vertices[3]->m_face_count >= vertices[3]->m_face_capacity || vertices[3] != edges[2]->m_vertex[1-edgedirs[2]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDFace* f = AllocateFace(zero_face_id,parent_face_id);
|
|
if (nullptr == f)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
f->m_edge_count = 4;
|
|
f->m_edge4[0] = eptrs[0];
|
|
f->m_edge4[1] = eptrs[1];
|
|
f->m_edge4[2] = eptrs[2];
|
|
f->m_edge4[3] = eptrs[3];
|
|
|
|
edges[0]->m_face2[edges[0]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[0]);
|
|
edges[1]->m_face2[edges[1]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[1]);
|
|
edges[2]->m_face2[edges[2]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[2]);
|
|
edges[3]->m_face2[edges[3]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[3]);
|
|
|
|
vertices[0]->m_faces[vertices[0]->m_face_count++] = f;
|
|
//vertices[0]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
vertices[1]->m_faces[vertices[1]->m_face_count++] = f;
|
|
//vertices[1]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
vertices[2]->m_faces[vertices[2]->m_face_count++] = f;
|
|
//vertices[2]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
vertices[3]->m_faces[vertices[3]->m_face_count++] = f;
|
|
//vertices[3]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
|
|
f->m_level = edges[0]->m_level;
|
|
|
|
return f;
|
|
}
|
|
|
|
|
|
ON_SubDFace* ON_SubD_FixedSizeHeap::AllocateTri(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id,
|
|
const ON_SubDEdgePtr eptrs[3]
|
|
)
|
|
{
|
|
if (nullptr == eptrs)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDEdge* edges[3] = {
|
|
ON_SUBD_EDGE_POINTER(eptrs[0].m_ptr),
|
|
ON_SUBD_EDGE_POINTER(eptrs[1].m_ptr),
|
|
ON_SUBD_EDGE_POINTER(eptrs[2].m_ptr)};
|
|
|
|
if (nullptr == edges[0] || edges[0]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == edges[1] || edges[1]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == edges[2] || edges[2]->m_face_count > 1)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON__UINT_PTR edgedirs[3] = {
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[0].m_ptr),
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[1].m_ptr),
|
|
ON_SUBD_EDGE_DIRECTION(eptrs[2].m_ptr)};
|
|
|
|
ON_SubDVertex* vertices[3] = {
|
|
const_cast<ON_SubDVertex*>(edges[0]->m_vertex[edgedirs[0]]),
|
|
const_cast<ON_SubDVertex*>(edges[1]->m_vertex[edgedirs[1]]),
|
|
const_cast<ON_SubDVertex*>(edges[2]->m_vertex[edgedirs[2]])};
|
|
|
|
if (nullptr == vertices[0] || nullptr == vertices[0]->m_faces || vertices[0]->m_face_count >= vertices[0]->m_face_capacity || vertices[0] != edges[2]->m_vertex[1-edgedirs[2]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == vertices[1] || nullptr == vertices[1]->m_faces || vertices[1]->m_face_count >= vertices[1]->m_face_capacity || vertices[1] != edges[0]->m_vertex[1-edgedirs[0]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if (nullptr == vertices[2] || nullptr == vertices[2]->m_faces || vertices[2]->m_face_count >= vertices[2]->m_face_capacity || vertices[2] != edges[1]->m_vertex[1-edgedirs[1]])
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON_SubDFace* f = AllocateFace(zero_face_id,parent_face_id);
|
|
if (nullptr == f)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
f->m_edge_count = 3;
|
|
f->m_edge4[0] = eptrs[0];
|
|
f->m_edge4[1] = eptrs[1];
|
|
f->m_edge4[2] = eptrs[2];
|
|
|
|
edges[0]->m_face2[edges[0]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[0]);
|
|
edges[1]->m_face2[edges[1]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[1]);
|
|
edges[2]->m_face2[edges[2]->m_face_count++] = ON_SubDFacePtr::Create(f,edgedirs[2]);
|
|
|
|
vertices[0]->m_faces[vertices[0]->m_face_count++] = f;
|
|
//vertices[0]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
vertices[1]->m_faces[vertices[1]->m_face_count++] = f;
|
|
//vertices[1]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
vertices[2]->m_faces[vertices[2]->m_face_count++] = f;
|
|
//vertices[2]->m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
|
|
f->m_level = edges[0]->m_level;
|
|
|
|
return f;
|
|
}
|
|
ON__UINT_PTR* ON_SubD_FixedSizeHeap::AllocatePtrArray(
|
|
unsigned int capacity,
|
|
bool bZeroMemory
|
|
)
|
|
{
|
|
if (0 == capacity)
|
|
return nullptr;
|
|
|
|
if (nullptr == m_p || capacity + m_p_index >= m_p_capacity)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
|
|
ON__UINT_PTR* p = m_p + m_p_index;
|
|
m_p_index += capacity;
|
|
|
|
if (bZeroMemory)
|
|
{
|
|
ON__UINT_PTR* p1 = p + capacity;
|
|
while (p1 > p)
|
|
{
|
|
*(--p1) = 0;
|
|
}
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
bool ON_SubD_FixedSizeHeap::ReturnPtrArray(
|
|
unsigned int capacity,
|
|
void* p
|
|
)
|
|
{
|
|
if (nullptr != m_p && capacity <= m_p_index && p == m_p + (m_p_index - capacity))
|
|
{
|
|
m_p_index -= capacity;
|
|
return true;
|
|
}
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDHeap
|
|
//
|
|
|
|
size_t ON_SubDHeap::m_offset_vertex_id = 0;
|
|
size_t ON_SubDHeap::m_offset_edge_id = 0;
|
|
size_t ON_SubDHeap::m_offset_face_id = 0;
|
|
|
|
ON_SubDHeap::ON_SubDHeap()
|
|
{
|
|
m_fspv.Create(sizeof(class ON_SubDVertex), 0, 0);
|
|
m_fspe.Create(sizeof(class ON_SubDEdge), 0, 0);
|
|
m_fspf.Create(sizeof(class ON_SubDFace), 0, 0);
|
|
m_fsp5.Create(5 * sizeof(ON__UINT_PTR), 0, 0);
|
|
m_fsp9.Create(9 * sizeof(ON__UINT_PTR), 0, 0);
|
|
m_fsp17.Create(17 * sizeof(ON__UINT_PTR), 0, 0);
|
|
|
|
if (0 == ON_SubDHeap::m_offset_vertex_id)
|
|
{
|
|
ON_SubDVertex v;
|
|
ON_SubDHeap::m_offset_vertex_id = ((const char*)(&v.m_id)) - ((const char*)&v);
|
|
ON_SubDEdge e;
|
|
ON_SubDHeap::m_offset_edge_id = ((const char*)(&e.m_id)) - ((const char*)&e);
|
|
ON_SubDFace f;
|
|
ON_SubDHeap::m_offset_face_id = ((const char*)(&f.m_id)) - ((const char*)&f);
|
|
}
|
|
}
|
|
|
|
ON_SubDHeap::~ON_SubDHeap()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
class ON_SubDVertex* ON_SubDHeap::AllocateVertexAndSetId(unsigned int& max_vertex_id)
|
|
{
|
|
// In order for m_fspv.ElementFromId() to work, it is critical that
|
|
// once a vertex is allocated from m_fspv, the value of m_id never
|
|
// changes. This is imporant because the value of m_id must persist
|
|
// in binary archives in order for ON_COMPONENT_INDEX values to
|
|
// persist in binary archives.
|
|
ON_SubDVertex* v;
|
|
if (m_unused_vertex)
|
|
{
|
|
v = m_unused_vertex;
|
|
m_unused_vertex = (ON_SubDVertex*)(m_unused_vertex->m_next_vertex);
|
|
const unsigned int id = v->m_id;
|
|
if (ON_UNSET_UINT_INDEX == (&v->m_id)[1])
|
|
{
|
|
memset(v, 0, sizeof(*v));
|
|
v->m_id = id;
|
|
}
|
|
else
|
|
{
|
|
// something is modifying ids of returned elements
|
|
ON_SubDIncrementErrorCount();
|
|
v->m_id = ++max_vertex_id;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v = (class ON_SubDVertex*)m_fspv.AllocateElement();
|
|
v->m_id = ++max_vertex_id;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
void ON_SubDHeap::ReturnVertex(class ON_SubDVertex* v)
|
|
{
|
|
if (nullptr != v)
|
|
{
|
|
ReturnVertexEdgeAndFaceArrays(v);
|
|
(&v->m_id)[1] = ON_UNSET_UINT_INDEX; // m_archive_id == ON_UNSET_UINT_INDEX marks the fixed size pool element as unused
|
|
v->m_next_vertex = m_unused_vertex;
|
|
m_unused_vertex = v;
|
|
// NO! // m_fspv.ReturnElement(v);
|
|
// See comments in AllocateVertexAndSetId();
|
|
}
|
|
}
|
|
|
|
class ON_SubDEdge* ON_SubDHeap::AllocateEdgeAndSetId(unsigned int& max_edge_id)
|
|
{
|
|
// In order for m_fspe.ElementFromId() to work, it is critical that
|
|
// once a edge is allocated from m_fspe, the value of m_id never
|
|
// changes. This is imporant because the value of m_id must persist
|
|
// in binary archives in order for ON_COMPONENT_INDEX values to
|
|
// persist in binary archives.
|
|
ON_SubDEdge* e;
|
|
if (m_unused_edge)
|
|
{
|
|
e = m_unused_edge;
|
|
m_unused_edge = (ON_SubDEdge*)(m_unused_edge->m_next_edge);
|
|
const unsigned int id = e->m_id;
|
|
if (ON_UNSET_UINT_INDEX == (&e->m_id)[1])
|
|
{
|
|
memset(e, 0, sizeof(*e));
|
|
e->m_id = id;
|
|
}
|
|
else
|
|
{
|
|
// something is modifying ids of returned elements
|
|
ON_SubDIncrementErrorCount();
|
|
e->m_id = ++max_edge_id;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e = (class ON_SubDEdge*)m_fspe.AllocateElement();
|
|
e->m_id = ++max_edge_id;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
void ON_SubDHeap::ReturnEdge(class ON_SubDEdge* e)
|
|
{
|
|
if (nullptr != e)
|
|
{
|
|
if (nullptr != e->m_facex)
|
|
ReturnArray(e->m_facex_capacity,(ON__UINT_PTR*)e->m_facex);
|
|
(&e->m_id)[1] = ON_UNSET_UINT_INDEX; // m_archive_id == ON_UNSET_UINT_INDEX marks the fixed size pool element as unused
|
|
e->m_next_edge = m_unused_edge;
|
|
m_unused_edge = e;
|
|
// NO! // m_fspe.ReturnElement(e);
|
|
// See comments in AllocateVertexAndSetId();
|
|
}
|
|
}
|
|
|
|
class ON_SubDFace* ON_SubDHeap::AllocateFaceAndSetId(unsigned int& max_face_id)
|
|
{
|
|
// In order for m_fspf.ElementFromId() to work, it is critical that
|
|
// once a face is allocated from m_fspf, the value of m_id never
|
|
// changes. This is imporant because the value of m_id must persist
|
|
// in binary archives in order for ON_COMPONENT_INDEX values to
|
|
// persist in binary archives.
|
|
ON_SubDFace* f;
|
|
if (m_unused_face)
|
|
{
|
|
f = m_unused_face;
|
|
m_unused_face = (ON_SubDFace*)(m_unused_face->m_next_face);
|
|
const unsigned int id = f->m_id;
|
|
if (ON_UNSET_UINT_INDEX == (&f->m_id)[1])
|
|
{
|
|
memset(f, 0, sizeof(*f));
|
|
f->m_id = id;
|
|
}
|
|
else
|
|
{
|
|
// something is modifying ids of returned elements
|
|
ON_SubDIncrementErrorCount();
|
|
f->m_id = ++max_face_id;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f = (class ON_SubDFace*)m_fspf.AllocateElement();
|
|
f->m_id = ++max_face_id;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
void ON_SubDHeap::ReturnFace(class ON_SubDFace* f)
|
|
{
|
|
if (nullptr != f)
|
|
{
|
|
ReturnArray(f->m_edgex_capacity,(ON__UINT_PTR*)f->m_edgex);
|
|
(&f->m_id)[1] = ON_UNSET_UINT_INDEX; // m_archive_id == ON_UNSET_UINT_INDEX marks the fixed size pool element as unused
|
|
f->m_next_face = m_unused_face;
|
|
m_unused_face = f;
|
|
// NO! // m_fspf.ReturnElement(f);
|
|
// See comments in AllocateVertexAndSetId();
|
|
}
|
|
}
|
|
|
|
void ON_SubDHeap::Clear()
|
|
{
|
|
class tagWSItem* p = m_ws;
|
|
m_ws = 0;
|
|
while (p)
|
|
{
|
|
class tagWSItem* next = p->m_next;
|
|
onfree(p);
|
|
p = next;
|
|
}
|
|
m_fspv.ReturnAll();
|
|
m_fspe.ReturnAll();
|
|
m_fspf.ReturnAll();
|
|
m_fsp5.ReturnAll();
|
|
m_fsp9.ReturnAll();
|
|
m_fsp17.ReturnAll();
|
|
|
|
m_unused_vertex = nullptr;
|
|
m_unused_edge = nullptr;
|
|
m_unused_face = nullptr;
|
|
}
|
|
|
|
void ON_SubDHeap::Destroy()
|
|
{
|
|
Clear();
|
|
m_fspv.Destroy();
|
|
m_fspe.Destroy();
|
|
m_fspf.Destroy();
|
|
m_fsp5.Destroy();
|
|
m_fsp9.Destroy();
|
|
m_fsp17.Destroy();
|
|
}
|
|
|
|
void ON_SubDHeap::ClearArchiveId()
|
|
{
|
|
ON_FixedSizePoolIterator fit;
|
|
fit.Create(&m_fspv);
|
|
for (ON_SubDVertex* v = (ON_SubDVertex*)fit.FirstElement(); nullptr != v; v = (ON_SubDVertex*)fit.NextElement())
|
|
{
|
|
if ( ON_UNSET_UINT_INDEX != v->ArchiveId())
|
|
v->SetArchiveId(0);
|
|
}
|
|
fit.Create(&m_fspe);
|
|
for (ON_SubDEdge* e = (ON_SubDEdge*)fit.FirstElement(); nullptr != e; e = (ON_SubDEdge*)fit.NextElement())
|
|
{
|
|
if ( ON_UNSET_UINT_INDEX != e->ArchiveId())
|
|
e->SetArchiveId(0);
|
|
}
|
|
fit.Create(&m_fspf);
|
|
for (ON_SubDFace* f = (ON_SubDFace*)fit.FirstElement(); nullptr != f; f = (ON_SubDFace*)fit.NextElement())
|
|
{
|
|
if ( ON_UNSET_UINT_INDEX != f->ArchiveId())
|
|
f->SetArchiveId(0);
|
|
}
|
|
}
|
|
|
|
const class ON_SubDVertex* ON_SubDHeap::VertexFromId(
|
|
unsigned int vertex_id
|
|
) const
|
|
{
|
|
if ( 0 == vertex_id || ON_UNSET_UINT_INDEX == vertex_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
const class ON_SubDVertex* vertex = (const class ON_SubDVertex*)m_fspv.ElementFromId(ON_SubDHeap::m_offset_vertex_id,vertex_id);
|
|
if ( nullptr == vertex || vertex_id != vertex->m_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if ( ON_UNSET_UINT_INDEX == vertex->ArchiveId() )
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
return vertex;
|
|
}
|
|
|
|
const class ON_SubDEdge* ON_SubDHeap::EdgeFromId(
|
|
unsigned int edge_id
|
|
) const
|
|
{
|
|
if ( 0 == edge_id || ON_UNSET_UINT_INDEX == edge_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
const class ON_SubDEdge* edge = (const class ON_SubDEdge*)m_fspe.ElementFromId(ON_SubDHeap::m_offset_edge_id,edge_id);
|
|
if ( nullptr == edge || edge_id != edge->m_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if ( ON_UNSET_UINT_INDEX == edge->ArchiveId() )
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
return edge;
|
|
}
|
|
|
|
const class ON_SubDFace* ON_SubDHeap::FaceFromId(
|
|
unsigned int face_id
|
|
) const
|
|
{
|
|
if ( 0 == face_id || ON_UNSET_UINT_INDEX == face_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
const class ON_SubDFace* face = (const class ON_SubDFace*)m_fspf.ElementFromId(ON_SubDHeap::m_offset_face_id,face_id);
|
|
if ( nullptr == face || face_id != face->m_id)
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
if ( ON_UNSET_UINT_INDEX == face->ArchiveId() )
|
|
return ON_SUBD_RETURN_ERROR(nullptr);
|
|
return face;
|
|
}
|
|
|
|
unsigned int ON_SubDHeap::MaximumVertexId() const
|
|
{
|
|
return m_fspv.MaximumElementId(ON_SubDHeap::m_offset_vertex_id);
|
|
}
|
|
|
|
unsigned int ON_SubDHeap::MaximumEdgeId() const
|
|
{
|
|
return m_fspe.MaximumElementId(ON_SubDHeap::m_offset_edge_id);
|
|
}
|
|
|
|
unsigned int ON_SubDHeap::MaximumFaceId() const
|
|
{
|
|
return m_fspf.MaximumElementId(ON_SubDHeap::m_offset_face_id);
|
|
}
|
|
|
|
|
|
bool ON_SubDHeap::IsValid() const
|
|
{
|
|
return m_fspv.ElementIdIsIncreasing(ON_SubDHeap::m_offset_vertex_id)
|
|
&& m_fspe.ElementIdIsIncreasing(ON_SubDHeap::m_offset_edge_id)
|
|
&& m_fspf.ElementIdIsIncreasing(ON_SubDHeap::m_offset_face_id);
|
|
}
|
|
|
|
void ON_SubDHeap::ResetId()
|
|
{
|
|
const unsigned int first_id = 1;
|
|
m_fspv.ResetElementId(ON_SubDHeap::m_offset_vertex_id,first_id);
|
|
m_fspe.ResetElementId(ON_SubDHeap::m_offset_edge_id,first_id);
|
|
m_fspf.ResetElementId(ON_SubDHeap::m_offset_face_id,first_id);
|
|
}
|
|
|
|
size_t ON_SubDHeap::OversizedElementCapacity(size_t count)
|
|
{
|
|
size_t capacity = 32 * (count / 32);
|
|
if (count % 32 > 0 || 0 == count)
|
|
capacity += 32;
|
|
return capacity;
|
|
}
|
|
|
|
ON__UINT_PTR* ON_SubDHeap::AllocateOversizedElement(size_t* capacity)
|
|
{
|
|
class tagWSItem* p;
|
|
size_t actual_capacity = ON_SubDHeap::OversizedElementCapacity(*capacity);
|
|
size_t sz = (actual_capacity + 1)*sizeof(ON__UINT_PTR);
|
|
sz += sizeof(*p);
|
|
p = (class tagWSItem*)onmalloc(sz);
|
|
p->m_next = m_ws;
|
|
if (p->m_next)
|
|
p->m_next->m_prev = p;
|
|
p->m_prev = 0;
|
|
m_ws = p;
|
|
ON__UINT_PTR* a = (ON__UINT_PTR*)(p + 1);
|
|
*a++ = actual_capacity;
|
|
*capacity = actual_capacity;
|
|
return a;
|
|
}
|
|
|
|
void ON_SubDHeap::ReturnOversizedElement(
|
|
size_t capacity,
|
|
ON__UINT_PTR* a
|
|
)
|
|
{
|
|
if (0 != a && capacity > 0)
|
|
{
|
|
class tagWSItem* p = ((class tagWSItem*)(a - 1)) - 1;
|
|
if (p == m_ws)
|
|
{
|
|
m_ws = p->m_next;
|
|
p->m_next->m_prev = 0;
|
|
}
|
|
else
|
|
{
|
|
if (p->m_next)
|
|
p->m_next->m_prev = p->m_prev;
|
|
p->m_prev->m_next = p->m_next;
|
|
}
|
|
onfree(p);
|
|
}
|
|
}
|
|
|
|
ON__UINT_PTR* ON_SubDHeap::ResizeArray(
|
|
size_t current_count,
|
|
size_t current_capacity,
|
|
ON__UINT_PTR* current_a,
|
|
size_t* new_capacity
|
|
)
|
|
{
|
|
ON__UINT_PTR capacity = ON_SubDHeap::ArrayCapacity(current_capacity,current_a);
|
|
if (capacity <= 0)
|
|
{
|
|
return (ON__UINT_PTR*)AllocateArray(new_capacity);
|
|
}
|
|
|
|
if (*new_capacity <= 0)
|
|
{
|
|
ReturnArray(current_capacity,current_a);
|
|
*new_capacity = 0;
|
|
return nullptr;
|
|
}
|
|
|
|
if (*new_capacity <= capacity)
|
|
{
|
|
return current_a;
|
|
}
|
|
|
|
ON__UINT_PTR* new_a = AllocateArray(new_capacity);
|
|
ON__UINT_PTR* a1 = new_a + current_count;
|
|
while (new_a < a1)
|
|
{
|
|
*new_a++ = *current_a++;
|
|
}
|
|
ReturnArray(current_capacity,current_a - current_count);
|
|
return (a1 - current_count);
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowVertexEdgeArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
if ( nullptr == v)
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if ( 0 == capacity )
|
|
capacity = v->m_edge_count+1;
|
|
if ( capacity <= v->m_edge_capacity)
|
|
return true;
|
|
ON__UINT_PTR* a = ResizeArray(v->m_edge_count,v->m_edge_capacity,(ON__UINT_PTR*)v->m_edges,&capacity);
|
|
if ( nullptr == a )
|
|
{
|
|
v->m_edge_count = 0;
|
|
v->m_edge_capacity = 0;
|
|
v->m_edges = 0;
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
v->m_edges = (ON_SubDEdgePtr*)a;
|
|
v->m_edge_capacity = (unsigned short)capacity;
|
|
return true;
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowVertexFaceArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
if ( nullptr == v)
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if ( 0 == capacity )
|
|
capacity = v->m_face_count+1;
|
|
if ( capacity <= v->m_face_capacity)
|
|
return true;
|
|
ON__UINT_PTR* a = ResizeArray(v->m_face_count,v->m_face_capacity,(ON__UINT_PTR*)v->m_faces,&capacity);
|
|
if (nullptr == a)
|
|
{
|
|
v->m_face_count = 0;
|
|
v->m_face_capacity = 0;
|
|
v->m_faces = nullptr;
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
v->m_faces = (const ON_SubDFace**)a;
|
|
v->m_face_capacity = (unsigned short)capacity;
|
|
return true;
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowEdgeFaceArray(
|
|
ON_SubDEdge* e,
|
|
size_t capacity
|
|
)
|
|
{
|
|
if ( nullptr == e)
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if ( 0 == capacity )
|
|
capacity = e->m_face_count+1;
|
|
if ( capacity <= (size_t)(2 + e->m_facex_capacity))
|
|
return true;
|
|
size_t xcapacity = capacity-2;
|
|
ON__UINT_PTR* a = ResizeArray((e->m_face_count>2) ? (e->m_face_count-2) : 0,e->m_facex_capacity,(ON__UINT_PTR*)e->m_facex,&xcapacity);
|
|
if ( nullptr == a )
|
|
{
|
|
e->m_face_count = 0;
|
|
e->m_facex_capacity = 0;
|
|
e->m_facex = nullptr;
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
e->m_facex = (ON_SubDFacePtr*)a;
|
|
e->m_facex_capacity = (unsigned short)xcapacity;
|
|
return true;
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowFaceEdgeArray(
|
|
ON_SubDFace* f,
|
|
size_t capacity
|
|
)
|
|
{
|
|
if ( nullptr == f)
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if ( 0 == capacity )
|
|
capacity = f->m_edge_count+1;
|
|
if ( capacity <= (size_t)(4 + f->m_edgex_capacity))
|
|
return true;
|
|
size_t xcapacity = capacity-4;
|
|
ON__UINT_PTR* a = ResizeArray((f->m_edge_count>4) ? (f->m_edge_count-4) : 0,f->m_edgex_capacity,(ON__UINT_PTR*)f->m_edgex,&xcapacity);
|
|
if ( nullptr == a )
|
|
{
|
|
f->m_edge_count = 0;
|
|
f->m_edgex_capacity = 0;
|
|
f->m_edgex = nullptr;
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
}
|
|
f->m_edgex = (ON_SubDEdgePtr*)a;
|
|
f->m_edgex_capacity = (unsigned short)xcapacity;
|
|
return true;
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowVertexEdgeArrayByOne(
|
|
ON_SubDVertex* v
|
|
)
|
|
{
|
|
return GrowVertexEdgeArray(v,0);
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowVertexFaceArrayByOne(
|
|
ON_SubDVertex* v
|
|
)
|
|
{
|
|
return GrowVertexFaceArray(v,0);
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowEdgeFaceArrayByOne(
|
|
ON_SubDEdge* e
|
|
)
|
|
{
|
|
return GrowEdgeFaceArray(e,0);
|
|
}
|
|
|
|
bool ON_SubDHeap::GrowFaceEdgeArrayByOne(
|
|
ON_SubDFace* f
|
|
)
|
|
{
|
|
return GrowFaceEdgeArray(f,0);
|
|
}
|
|
|
|
bool ON_SubDimple::GrowVertexEdgeArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
return m_heap.GrowVertexEdgeArray(v,capacity);
|
|
}
|
|
|
|
bool ON_SubDimple::GrowVertexFaceArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
return m_heap.GrowVertexFaceArray(v,capacity);
|
|
}
|
|
|
|
bool ON_SubDimple::GrowEdgeFaceArray(
|
|
ON_SubDEdge* e,
|
|
size_t capacity
|
|
)
|
|
{
|
|
return m_heap.GrowEdgeFaceArray(e,capacity);
|
|
}
|
|
|
|
bool ON_SubDimple::GrowFaceEdgeArray(
|
|
ON_SubDFace* f,
|
|
size_t capacity
|
|
)
|
|
{
|
|
return m_heap.GrowFaceEdgeArray(f,capacity);
|
|
}
|
|
|
|
bool ON_SubD::GrowVertexEdgeArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
ON_SubDimple* subdimple = SubDimple(false);
|
|
if ( nullptr == subdimple )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
return subdimple->GrowVertexEdgeArray(v,capacity);
|
|
}
|
|
|
|
bool ON_SubD::GrowVertexFaceArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
)
|
|
{
|
|
ON_SubDimple* subdimple = SubDimple(false);
|
|
if ( nullptr == subdimple )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
return subdimple->GrowVertexFaceArray(v,capacity);
|
|
}
|
|
|
|
bool ON_SubD::GrowEdgeFaceArray(
|
|
ON_SubDEdge* e,
|
|
size_t capacity
|
|
)
|
|
{
|
|
ON_SubDimple* subdimple = SubDimple(false);
|
|
if ( nullptr == subdimple )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
return subdimple->GrowEdgeFaceArray(e,capacity);
|
|
}
|
|
|
|
bool ON_SubD::GrowFaceEdgeArray(
|
|
ON_SubDFace* f,
|
|
size_t capacity
|
|
)
|
|
{
|
|
ON_SubDimple* subdimple = SubDimple(false);
|
|
if ( nullptr == subdimple )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
return subdimple->GrowFaceEdgeArray(f,capacity);
|
|
}
|
|
|
|
ON__UINT_PTR ON_SubDHeap::ArrayCapacity(
|
|
size_t capacity,
|
|
ON__UINT_PTR* a
|
|
)
|
|
{
|
|
#if defined(ON_DEBUG)
|
|
size_t acapacity = (nullptr == a) ? 0 : a[-1];
|
|
if (capacity != acapacity)
|
|
{
|
|
ON_SubDIncrementErrorCount();
|
|
}
|
|
#endif
|
|
return (nullptr == a) ? 0 : a[-1];
|
|
}
|
|
|
|
bool ON_SubDHeap::ReturnVertexEdgeAndFaceArrays(
|
|
ON_SubDVertex* v
|
|
)
|
|
{
|
|
if ( nullptr == v )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if (nullptr != v->m_edges || v->m_edge_capacity > 0 || v->m_edge_count > 0)
|
|
{
|
|
ReturnArray(v->m_edge_capacity,(ON__UINT_PTR*)v->m_edges);
|
|
v->m_edges = nullptr;
|
|
v->m_edge_capacity = 0;
|
|
v->m_edge_count = 0;
|
|
}
|
|
if (nullptr != v->m_faces || v->m_face_capacity > 0 || v->m_face_count > 0)
|
|
{
|
|
ReturnArray(v->m_face_capacity,(ON__UINT_PTR*)v->m_faces);
|
|
v->m_faces = nullptr;
|
|
v->m_face_capacity = 0;
|
|
v->m_face_count = 0;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
bool ON_SubDHeap::ReturnEdgeExtraArray(
|
|
ON_SubDEdge* e
|
|
)
|
|
{
|
|
if ( nullptr == e )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if (nullptr != e->m_facex || e->m_facex_capacity > 0)
|
|
{
|
|
ReturnArray(e->m_facex_capacity,(ON__UINT_PTR*)e->m_facex);
|
|
e->m_facex = nullptr;
|
|
e->m_facex_capacity = 0;
|
|
}
|
|
if (e->m_face_count > 2)
|
|
e->m_face_count = 2;
|
|
return true;
|
|
}
|
|
|
|
bool ON_SubDHeap::ReturnFaceExtraArray(
|
|
ON_SubDFace* f
|
|
)
|
|
{
|
|
if ( nullptr == f )
|
|
return ON_SUBD_RETURN_ERROR(false);
|
|
if (nullptr != f->m_edgex || f->m_edgex_capacity > 0)
|
|
{
|
|
ReturnArray(f->m_edgex_capacity,(ON__UINT_PTR*)f->m_edgex);
|
|
f->m_edgex = nullptr;
|
|
f->m_edgex_capacity = 0;
|
|
}
|
|
if (f->m_edge_count > 4)
|
|
f->m_edge_count = 4;
|
|
return true;
|
|
}
|
|
|
|
ON__UINT_PTR* ON_SubDHeap::AllocateArray(size_t* capacity)
|
|
{
|
|
ON__UINT_PTR* a;
|
|
size_t requested_capacity = *capacity;
|
|
if (requested_capacity <= 0)
|
|
return nullptr;
|
|
|
|
if (requested_capacity <= 4)
|
|
{
|
|
a = (ON__UINT_PTR*)m_fsp5.AllocateElement();
|
|
*a++ = 4;
|
|
*capacity = 4;
|
|
return a;
|
|
}
|
|
|
|
if (requested_capacity <= 8)
|
|
{
|
|
a = (ON__UINT_PTR*)m_fsp9.AllocateElement();
|
|
*a++ = 8;
|
|
*capacity = 8;
|
|
return a;
|
|
}
|
|
|
|
if (requested_capacity <= 16)
|
|
{
|
|
a = (ON__UINT_PTR*)m_fsp17.AllocateElement();
|
|
*a++ = 16;
|
|
*capacity = 16;
|
|
return a;
|
|
}
|
|
|
|
return AllocateOversizedElement(capacity);
|
|
}
|
|
|
|
void ON_SubDHeap::ReturnArray(
|
|
size_t capacity,
|
|
ON__UINT_PTR* a
|
|
)
|
|
{
|
|
if (nullptr != a && 0 == capacity)
|
|
{
|
|
ON_SubDIncrementErrorCount();
|
|
}
|
|
|
|
switch (ON_SubDHeap::ArrayCapacity(capacity,a))
|
|
{
|
|
case 0:
|
|
break;
|
|
case 4:
|
|
m_fsp5.ReturnElement(a - 1);
|
|
break;
|
|
case 8:
|
|
m_fsp9.ReturnElement(a - 1);
|
|
break;
|
|
case 16:
|
|
m_fsp17.ReturnElement(a - 1);
|
|
break;
|
|
default:
|
|
ReturnOversizedElement(capacity,a);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|