mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 03:26:09 +08:00
4050 lines
106 KiB
C++
4050 lines
106 KiB
C++
//
|
|
// Copyright (c) 1993-2022 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>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
static
|
|
const ON_BrepEdge* FindLinearEdge( const ON_Brep& brep, int vi0, int vi1 )
|
|
{
|
|
// searchs for a linear edge connecting the vertices
|
|
// brep.m_V[vi0] and brep.m_V[vi1].
|
|
if ( vi0 < 0 || vi0 >= brep.m_V.Count() )
|
|
return nullptr;
|
|
if ( vi1 < 0 || vi1 >= brep.m_V.Count() )
|
|
return nullptr;
|
|
if ( vi0 == vi1 )
|
|
return nullptr;
|
|
const ON_BrepVertex& v0 = brep.m_V[vi0];
|
|
//const ON_BrepVertex& v1 = brep.m_V[vi1];
|
|
int vei;
|
|
for ( vei = 0; vei < v0.m_ei.Count(); vei++ )
|
|
{
|
|
const ON_BrepEdge* edge = brep.Edge( v0.m_ei[vei] );
|
|
if ( !edge )
|
|
continue;
|
|
if ( edge->m_vi[0] != vi0 && edge->m_vi[1] != vi0 )
|
|
continue;
|
|
if ( edge->m_vi[0] != vi1 && edge->m_vi[1] != vi1 )
|
|
continue;
|
|
if ( !edge->IsLinear() )
|
|
continue;
|
|
return edge;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static
|
|
void SynchFaceOrientation( ON_Brep& brep, int fi )
|
|
{
|
|
const ON_BrepFace* face = brep.Face(fi);
|
|
if ( face )
|
|
{
|
|
int flip = -1, fli, lti;
|
|
for ( fli = 0; fli < face->m_li.Count(); fli++ )
|
|
{
|
|
const ON_BrepLoop* loop = brep.Loop( face->m_li[fli] );
|
|
if ( !loop )
|
|
continue;
|
|
for ( lti = 0; lti < loop->m_ti.Count(); lti++ )
|
|
{
|
|
const ON_BrepTrim* trim = brep.Trim( loop->m_ti[lti] );
|
|
if ( !trim )
|
|
continue;
|
|
const ON_BrepEdge* edge = brep.Edge( trim->m_ei );
|
|
if ( !edge )
|
|
continue;
|
|
if ( edge->m_ti.Count() != 2 )
|
|
continue;
|
|
const ON_BrepTrim* trim0 = brep.Trim( edge->m_ti[0] );
|
|
const ON_BrepTrim* trim1 = brep.Trim( edge->m_ti[1] );
|
|
if ( !trim0 || !trim1 )
|
|
continue;
|
|
bool bRev0 = trim0->m_bRev3d ? true : false;
|
|
bool bRev1 = trim1->m_bRev3d ? true : false;
|
|
if ( bRev0 == bRev1 )
|
|
{
|
|
if ( flip == -1 )
|
|
flip = 1;
|
|
else if (flip != 1 )
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if ( flip == -1 )
|
|
flip = 0;
|
|
else if (flip != 0 )
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if ( flip == 1 )
|
|
brep.FlipFace(brep.m_F[fi]);
|
|
}
|
|
}
|
|
|
|
ON_BrepFace* ON_Brep::NewRuledFace(
|
|
const ON_BrepEdge& edgeA,
|
|
bool bRevEdgeA,
|
|
const ON_BrepEdge& edgeB,
|
|
bool bRevEdgeB
|
|
)
|
|
{
|
|
if ( edgeA.m_edge_index == edgeB.m_edge_index )
|
|
return nullptr;
|
|
if ( Edge( edgeA.m_edge_index) != &edgeA )
|
|
return nullptr;
|
|
if ( Edge( edgeB.m_edge_index) != &edgeB )
|
|
return nullptr;
|
|
|
|
ON_NurbsCurve cA, cB;
|
|
if ( !edgeA.GetNurbForm( cA ) )
|
|
return nullptr;
|
|
if ( bRevEdgeA )
|
|
cA.Reverse();
|
|
if ( !edgeB.GetNurbForm( cB ) )
|
|
return nullptr;
|
|
if ( bRevEdgeB )
|
|
cB.Reverse();
|
|
ON_NurbsSurface* srf = ON_NurbsSurface::New();
|
|
if ( !srf->CreateRuledSurface( cA, cB ) )
|
|
{
|
|
delete srf;
|
|
return nullptr;
|
|
}
|
|
|
|
// corner vertices (sw,se,ne,nw)
|
|
int vid[4] = {-1,-1,-1,-1};
|
|
vid[0] = edgeA.m_vi[bRevEdgeA?1:0];
|
|
vid[1] = edgeA.m_vi[bRevEdgeA?0:1];
|
|
vid[2] = edgeB.m_vi[bRevEdgeB?0:1];
|
|
vid[3] = edgeB.m_vi[bRevEdgeB?1:0];
|
|
|
|
if ( vid[1] == vid[2] )
|
|
{
|
|
// make sure surface has a singular east side
|
|
srf->CollapseSide( 1 );
|
|
}
|
|
|
|
if ( vid[1] == vid[2] )
|
|
{
|
|
// make sure surface has a singular west side
|
|
srf->CollapseSide( 3 );
|
|
}
|
|
|
|
// side edges (s,e,n,w)
|
|
int eid[4] = {-1,-1,-1,-1};
|
|
bool bRev3d[4] = {false,false,false,false};
|
|
|
|
// south side
|
|
eid[0] = edgeA.m_edge_index;
|
|
bRev3d[0] = bRevEdgeA;
|
|
|
|
// east side
|
|
const ON_BrepEdge* east_edge = FindLinearEdge( *this, vid[1], vid[2] );
|
|
if ( east_edge )
|
|
{
|
|
eid[1] = east_edge->m_edge_index;
|
|
bRev3d[1] = (east_edge->m_vi[0] == vid[2]);
|
|
}
|
|
|
|
// north side
|
|
eid[2] = edgeB.m_edge_index;
|
|
bRev3d[2] = !bRevEdgeB;
|
|
|
|
// west side
|
|
const ON_BrepEdge* west_edge = FindLinearEdge( *this, vid[3], vid[0] );
|
|
if ( west_edge )
|
|
{
|
|
eid[3] = west_edge->m_edge_index;
|
|
bRev3d[3] = (west_edge->m_vi[0] == vid[0]);
|
|
}
|
|
|
|
ON_BrepFace* face = NewFace( srf, vid, eid, bRev3d );
|
|
if ( face )
|
|
SynchFaceOrientation( *this, face->m_face_index );
|
|
return face;
|
|
}
|
|
|
|
|
|
ON_BrepFace* ON_Brep::NewConeFace(
|
|
const ON_BrepVertex& vertex,
|
|
const ON_BrepEdge& edge,
|
|
bool bRevEdge
|
|
)
|
|
{
|
|
if ( Edge( edge.m_edge_index) != &edge )
|
|
return nullptr;
|
|
if ( Vertex( vertex.m_vertex_index) != &vertex )
|
|
return nullptr;
|
|
if ( edge.m_vi[0] == vertex.m_vertex_index )
|
|
return nullptr;
|
|
if ( edge.m_vi[1] == vertex.m_vertex_index )
|
|
return nullptr;
|
|
ON_NurbsCurve c;
|
|
if ( !edge.GetNurbForm( c ) )
|
|
return nullptr;
|
|
if ( bRevEdge )
|
|
c.Reverse();
|
|
ON_NurbsSurface* srf = ON_NurbsSurface::New();
|
|
if ( !srf->CreateConeSurface( vertex.point, c ) )
|
|
{
|
|
delete srf;
|
|
return nullptr;
|
|
}
|
|
|
|
// corner vertices (sw,se,ne,nw)
|
|
int vid[4] = {-1,-1,-1,-1};
|
|
vid[0] = edge.m_vi[bRevEdge?1:0];
|
|
vid[1] = edge.m_vi[bRevEdge?0:1];
|
|
vid[2] = vertex.m_vertex_index;
|
|
vid[3] = vertex.m_vertex_index;
|
|
|
|
// side edges (s,e,n,w)
|
|
int eid[4] = {-1,-1,-1,-1};
|
|
bool bRev3d[4] = {false,false,false,false};
|
|
|
|
// south side
|
|
eid[0] = edge.m_edge_index;
|
|
bRev3d[0] = bRevEdge;
|
|
|
|
// east side
|
|
const ON_BrepEdge* east_edge = FindLinearEdge( *this, vid[1], vid[2] );
|
|
if ( east_edge )
|
|
{
|
|
eid[1] = east_edge->m_edge_index;
|
|
bRev3d[1] = (east_edge->m_vi[0] == vid[2]);
|
|
}
|
|
|
|
// west side
|
|
const ON_BrepEdge* west_edge = FindLinearEdge( *this, vid[3], vid[0] );
|
|
if ( west_edge )
|
|
{
|
|
eid[3] = west_edge->m_edge_index;
|
|
bRev3d[3] = (west_edge->m_vi[0] == vid[0]);
|
|
}
|
|
|
|
ON_BrepFace* face = NewFace( srf, vid, eid, bRev3d );
|
|
if ( face )
|
|
SynchFaceOrientation( *this, face->m_face_index );
|
|
return face;
|
|
}
|
|
|
|
bool ON_Brep::SetTrimBoundingBoxes( bool bLazy )
|
|
{
|
|
bool rc = true;
|
|
int fi, face_count = m_F.Count();
|
|
for ( fi = 0; fi < face_count; fi++ )
|
|
{
|
|
if ( !SetTrimBoundingBoxes( m_F[fi], bLazy ) )
|
|
rc = false;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Brep::SetTrimBoundingBoxes( ON_BrepFace& face, bool bLazy )
|
|
{
|
|
bool rc = true;
|
|
int li, fli, loop_count = m_L.Count(), fl_count = face.m_li.Count();
|
|
for ( fli = 0; fli < fl_count; fli++ )
|
|
{
|
|
li = face.m_li[fli];
|
|
if ( li >= 0 && li < loop_count )
|
|
{
|
|
if ( !SetTrimBoundingBoxes( m_L[li], bLazy ) )
|
|
rc = false;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Brep::SetTrimBoundingBoxes( ON_BrepLoop& loop, bool bLazy )
|
|
{
|
|
// TL_Brep overrides this function and computes much tighter
|
|
// bounding boxes that take trim.m_t[] into account.
|
|
bool rc = true;
|
|
int ti, lti, trim_count = m_T.Count(), lt_count = loop.m_ti.Count();
|
|
bool bSetLoopBox = true;
|
|
if ( bLazy && loop.m_pbox.IsValid() )
|
|
bSetLoopBox = false;
|
|
else
|
|
loop.m_pbox.Destroy();
|
|
for ( lti = 0; lti < lt_count; lti++ )
|
|
{
|
|
ti = loop.m_ti[lti];
|
|
if ( ti >= 0 && ti < trim_count )
|
|
{
|
|
if ( !SetTrimBoundingBox( m_T[ti], bLazy ) )
|
|
rc = false;
|
|
else if ( bSetLoopBox )
|
|
loop.m_pbox.Union( m_T[ti].m_pbox );
|
|
}
|
|
}
|
|
return (rc && loop.m_pbox.IsValid()) ? true : false;
|
|
}
|
|
|
|
bool ON_Brep::SetTrimBoundingBox( ON_BrepTrim& trim, bool bLazy )
|
|
{
|
|
// TL_Brep overrides this function and computes much
|
|
// tighter bounding boxes that take trim.m_t[] into account.
|
|
bool rc = true;
|
|
if ( !trim.m_pbox.IsValid() || !bLazy )
|
|
{
|
|
trim.m_pbox.Destroy();
|
|
if ( trim.ProxyCurve() )
|
|
{
|
|
trim.m_pbox = trim.BoundingBox();
|
|
trim.m_pbox.m_min.z = 0.0;
|
|
trim.m_pbox.m_max.z = 0.0;
|
|
}
|
|
}
|
|
return (rc && trim.m_pbox.IsValid()) ? true : false;
|
|
}
|
|
|
|
void ON_Brep::SetTolerancesBoxesAndFlags(
|
|
bool bLazy,
|
|
bool bSetVertexTolerances,
|
|
bool bSetEdgeTolerances,
|
|
bool bSetTrimTolerances,
|
|
bool bSetTrimIsoFlags,
|
|
bool bSetTrimTypeFlags,
|
|
bool bSetLoopTypeFlags,
|
|
bool bSetTrimBoxes
|
|
)
|
|
{
|
|
int ei, ti, li;
|
|
const int trim_count = m_T.Count();
|
|
const int loop_count = m_L.Count();
|
|
const int edge_count = m_E.Count();
|
|
if ( bSetVertexTolerances )
|
|
SetVertexTolerances(bLazy);
|
|
if ( bSetEdgeTolerances )
|
|
{
|
|
for ( ei = 0; ei < edge_count; ei++ )
|
|
SetEdgeTolerance(m_E[ei],bLazy);
|
|
}
|
|
if ( bSetTrimTolerances )
|
|
{
|
|
for ( ti = 0; ti < trim_count; ti++ )
|
|
SetTrimTolerance(m_T[ti],bLazy);
|
|
}
|
|
if ( bSetTrimIsoFlags )
|
|
SetTrimIsoFlags();
|
|
if ( bSetTrimTypeFlags )
|
|
SetTrimTypeFlags(bLazy);
|
|
if ( bSetTrimTypeFlags )
|
|
SetTrimTypeFlags(bLazy);
|
|
if ( bSetLoopTypeFlags )
|
|
{
|
|
for ( li = 0; li < loop_count; li++ )
|
|
{
|
|
ON_BrepLoop& loop = m_L[li];
|
|
if ( loop.m_type == ON_BrepLoop::unknown || !bLazy )
|
|
{
|
|
loop.m_type = ComputeLoopType( loop );
|
|
}
|
|
}
|
|
}
|
|
if ( bSetTrimBoxes )
|
|
SetTrimBoundingBoxes(bLazy);
|
|
}
|
|
|
|
static
|
|
bool CheckForMatchingVertexIndices( int i, int j, int corner_vi[4] )
|
|
{
|
|
if (corner_vi[i] == corner_vi[j])
|
|
return true;
|
|
|
|
bool rc = false;
|
|
if ( corner_vi[i] >= 0 || corner_vi[j] >= 0 )
|
|
{
|
|
if ( corner_vi[i] == -1 )
|
|
{
|
|
corner_vi[i] = corner_vi[j];
|
|
rc = true;
|
|
}
|
|
else if ( corner_vi[j] == -1 )
|
|
{
|
|
corner_vi[j] = corner_vi[i];
|
|
rc = true;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
ON_BrepFace* ON_Brep::NewFace(
|
|
ON_Surface* pSurface,
|
|
int vid[4],
|
|
int eid[4],
|
|
bool bRev3d[4]
|
|
)
|
|
{
|
|
m_bbox.Destroy();
|
|
m_is_solid = 0;
|
|
bool bAddedSurface = false;
|
|
ON_BrepFace* pFace = nullptr;
|
|
if ( !pSurface )
|
|
return nullptr;
|
|
int si;
|
|
for ( si = 0; si < m_S.Count(); si++ )
|
|
{
|
|
if ( pSurface == m_S[si] )
|
|
break;
|
|
}
|
|
if ( si >= m_S.Count() )
|
|
{
|
|
si = AddSurface(pSurface);
|
|
bAddedSurface = (si >= 0);
|
|
}
|
|
int face_index = NewFace(si).m_face_index;
|
|
if ( NewOuterLoop( face_index, vid, eid, bRev3d ) )
|
|
{
|
|
pFace = &m_F[face_index];
|
|
}
|
|
else
|
|
{
|
|
// failed
|
|
if ( bAddedSurface )
|
|
{
|
|
m_S[si] = 0;
|
|
if ( m_S.Count() == si+1 )
|
|
m_S.SetCount(si);
|
|
}
|
|
DeleteFace( m_F[face_index], false );
|
|
if ( m_F.Count() == face_index+1 )
|
|
{
|
|
m_F.SetCount(face_index);
|
|
}
|
|
}
|
|
return pFace;
|
|
}
|
|
|
|
|
|
ON_BrepLoop* ON_Brep::NewOuterLoop(
|
|
int face_index,
|
|
int vid[4],
|
|
int eid[4],
|
|
bool boolRev3d[4]
|
|
)
|
|
{
|
|
// 2 Sept 2020 S. Baer (RH-59952)
|
|
// Destroy cached bounding box on breps when messing around with loops
|
|
m_bbox.Destroy();
|
|
m_is_solid = 0;
|
|
if ( face_index < 0 || face_index >= m_F.Count() )
|
|
return nullptr;
|
|
ON_BrepFace& face = m_F[face_index];
|
|
const ON_Surface* pSurface = face.SurfaceOf();
|
|
if (!pSurface)
|
|
return nullptr;
|
|
|
|
double u[2], v[2];
|
|
if (!pSurface->GetDomain(0, &u[0], &u[1]))
|
|
return 0;
|
|
if (!pSurface->GetDomain(1, &v[0], &v[1]))
|
|
return 0;
|
|
|
|
ON_3dPoint srf_P[2][2];
|
|
if ( !pSurface->EvPoint(u[0],v[0],srf_P[0][0] ) )
|
|
return 0;
|
|
if ( !pSurface->EvPoint(u[1],v[0],srf_P[1][0] ) )
|
|
return 0;
|
|
if ( !pSurface->EvPoint(u[0],v[1],srf_P[0][1] ) )
|
|
return 0;
|
|
if ( !pSurface->EvPoint(u[1],v[1],srf_P[1][1] ) )
|
|
return 0;
|
|
|
|
|
|
bool bIsSingular[4]; // south, east, north, west
|
|
bool bIsClosed[2]; // u direction, v direction
|
|
int i, eti;
|
|
ON_Curve* c3[4] = {nullptr,nullptr,nullptr,nullptr};
|
|
|
|
int bRev3d[4] = { 0 };
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( boolRev3d[i] )
|
|
bRev3d[i] = 1; // do this so we can use 1-bRev3d[i] as an array index
|
|
}
|
|
|
|
// check specified edge indices
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( eid[i] != -1 )
|
|
{
|
|
if ( eid[i] < 0 || eid[i] >= m_E.Count() )
|
|
{
|
|
ON_ERROR("Bad edge index passed to ON_BrepNewFace.");
|
|
return 0;
|
|
}
|
|
const int* edge_vi = m_E[eid[i]].m_vi;
|
|
int vi0 = edge_vi[bRev3d[i]];
|
|
int vi1 = edge_vi[1-bRev3d[i]];
|
|
if ( vi0 < 0 || vi1 < 0 )
|
|
{
|
|
ON_ERROR("ON_Brep::NewFace(ON_Surface*,...) error: Bad edge vertex informtion.");
|
|
return 0;
|
|
}
|
|
if ( vid[i] == -1 )
|
|
vid[i] = vi0;
|
|
else if ( vid[i] != vi0 )
|
|
{
|
|
ON_ERROR("ON_Brep::NewFace(ON_Surface*,...) error: Edge and vertex informtion do not match.");
|
|
return 0;
|
|
}
|
|
if ( vid[(i+1)%4] == -1 )
|
|
vid[(i+1)%4] = vi1;
|
|
else if ( vid[(i+1)%4] != vi1 )
|
|
{
|
|
ON_ERROR("ON_Brep::NewFace(ON_Surface*,...) error: Edge and vertex informtion do not match.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check specified vertex indices
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( vid[i] != -1 )
|
|
{
|
|
if ( vid[i] < 0 || vid[i] >= m_V.Count() )
|
|
{
|
|
ON_ERROR("Bad vertex index passed to ON_Brep::NewFace.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
bIsSingular[i] = pSurface->IsSingular(i);
|
|
for ( i = 0; i < 2; i++ )
|
|
bIsClosed[i] = pSurface->IsClosed(i);
|
|
|
|
for (i = 0; i < 2; i++ )
|
|
{
|
|
if ( bIsClosed[i] )
|
|
{
|
|
int j = i?0:1;
|
|
int k = j+2;
|
|
if ( eid[j] == -1 && eid[k] != -1)
|
|
{
|
|
eid[j] = eid[k];
|
|
bRev3d[j] = 1-bRev3d[k];
|
|
}
|
|
else if ( eid[k] == -1 && eid[j] != -1)
|
|
{
|
|
eid[k] = eid[j];
|
|
bRev3d[k] = 1-bRev3d[j];
|
|
}
|
|
else if ( eid[k] != -1 || eid[j] != -1)
|
|
{
|
|
if ( eid[j] != eid[k] || bRev3d[j] != 1-bRev3d[k] )
|
|
{
|
|
ON_ERROR("Bad edge information passed to ON_Brep::NewFace.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if surface has singularities or is closed, make sure vertex and edge information is correct
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( bIsSingular[i] )
|
|
{
|
|
if ( eid[i] != -1 || bRev3d[i] )
|
|
{
|
|
ON_ERROR("Bad edge information passed to ON_Brep::NewFace.");
|
|
return 0;
|
|
}
|
|
}
|
|
if ( bIsSingular[i] || bIsClosed[i%2] )
|
|
{
|
|
if ( !CheckForMatchingVertexIndices(i,(i+1)%4,vid) )
|
|
{
|
|
ON_ERROR("Bad vertex indices passed to ON_Brep::NewFace.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_C3.Reserve( m_C3.Count() + 4 );
|
|
// create missing 3d curves
|
|
bool bEdgeIsClosed[4]; // true if 3d edge is closed or edge is singular.
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
bEdgeIsClosed[i] = false;
|
|
if ( eid[i] != -1 )
|
|
{
|
|
const ON_BrepEdge& edge = m_E[eid[i]];
|
|
bEdgeIsClosed[i] = (edge.m_vi[0] == edge.m_vi[1]);
|
|
continue;
|
|
}
|
|
if ( bIsSingular[i] )
|
|
{
|
|
bEdgeIsClosed[i] = true;
|
|
continue;
|
|
}
|
|
if ( i >= 2 && bIsClosed[(i==2)?1:0] )
|
|
{
|
|
bEdgeIsClosed[i] = bEdgeIsClosed[i-2];
|
|
continue;
|
|
}
|
|
switch(i)
|
|
{
|
|
case 0: // south side
|
|
c3[i] = pSurface->IsoCurve(i%2, v[0]);
|
|
break;
|
|
case 1: // east side
|
|
c3[i] = pSurface->IsoCurve(i%2, u[1]);
|
|
break;
|
|
case 2: // north side
|
|
c3[i] = pSurface->IsoCurve(i%2, v[1]);
|
|
break;
|
|
case 3: // west side
|
|
c3[i] = pSurface->IsoCurve(i%2, u[0]);
|
|
break;
|
|
}
|
|
if ( !c3[i] )
|
|
{
|
|
ON_ERROR("ON_Brep::NewLoop unable to make 3d edge curve.");
|
|
return 0;
|
|
}
|
|
if ( pSurface->IsClosed(i%2) )
|
|
bEdgeIsClosed[i] = true;
|
|
else
|
|
bEdgeIsClosed[i] = c3[i]->IsClosed()?true:false;
|
|
if ( (i <= 1 && bRev3d[i]) || (i >= 2 && !bRev3d[i]) )
|
|
{
|
|
c3[i]->Reverse();
|
|
}
|
|
}
|
|
|
|
if ( m_V.Capacity() < 2 )
|
|
m_V.Reserve(4);
|
|
|
|
// create missing vertices
|
|
if ( vid[0] == -1 )
|
|
{
|
|
if ( vid[1] >= 0 && bEdgeIsClosed[0] )
|
|
vid[0] = vid[1];
|
|
else if ( vid[3] >= 0 && bEdgeIsClosed[3] )
|
|
vid[0] = vid[3];
|
|
else
|
|
vid[0] = NewVertex( srf_P[0][0],0.0).m_vertex_index;
|
|
}
|
|
|
|
if ( vid[1] == -1 )
|
|
{
|
|
if ( bEdgeIsClosed[0] )
|
|
vid[1] = vid[0];
|
|
else if ( vid[2] >= 0 && bEdgeIsClosed[1] )
|
|
vid[1] = vid[2];
|
|
else
|
|
vid[1] = NewVertex(srf_P[1][0],0.0).m_vertex_index;
|
|
}
|
|
|
|
if ( vid[2] == -1 )
|
|
{
|
|
if ( bEdgeIsClosed[1] )
|
|
vid[2] = vid[1];
|
|
else if (vid[3] >= 0 && bEdgeIsClosed[2] )
|
|
vid[2] = vid[3];
|
|
else
|
|
vid[2] = NewVertex( srf_P[1][1],0.0).m_vertex_index;
|
|
}
|
|
|
|
if ( vid[3] == -1 )
|
|
{
|
|
if ( bEdgeIsClosed[2] )
|
|
vid[3] = vid[2];
|
|
else if ( bEdgeIsClosed[3] )
|
|
vid[3] = vid[0];
|
|
else
|
|
vid[3] = NewVertex( srf_P[0][1],0.0).m_vertex_index;
|
|
}
|
|
|
|
if ( m_E.Capacity() < 4 )
|
|
m_E.Reserve(4);
|
|
|
|
// create missing edges
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( c3[i] )
|
|
{
|
|
int i0, i1;
|
|
if ( bRev3d[i] )
|
|
{
|
|
i0 = (i+1)%4;
|
|
i1 = i;
|
|
}
|
|
else
|
|
{
|
|
i0 = i;
|
|
i1 = (i+1)%4;
|
|
}
|
|
ON_BrepEdge& edge = NewEdge( m_V[vid[i0]], m_V[vid[i1]], AddEdgeCurve( c3[i] ) );
|
|
edge.m_tolerance = 0.0;
|
|
eid[i] = edge.m_edge_index;
|
|
if ( i == 0 && bIsClosed[1] )
|
|
{
|
|
eid[2] = eid[0];
|
|
bRev3d[2] = 1-bRev3d[0];
|
|
}
|
|
else if ( i == 1 && bIsClosed[0] )
|
|
{
|
|
eid[3] = eid[1];
|
|
bRev3d[3] = 1-bRev3d[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
m_T.Reserve( m_T.Count() + 4 );
|
|
m_C2.Reserve( m_C2.Count() + 4 );
|
|
|
|
ON_BrepLoop& loop = NewLoop( ON_BrepLoop::outer, face );
|
|
|
|
loop.m_pbox.m_min.x = u[0];
|
|
loop.m_pbox.m_min.y = v[0];
|
|
loop.m_pbox.m_min.z = 0.0;
|
|
|
|
loop.m_pbox.m_max.x = u[1];
|
|
loop.m_pbox.m_max.y = v[1];
|
|
loop.m_pbox.m_max.z = 0.0;
|
|
|
|
ON_3dPoint corners[4];
|
|
corners[0].Set(u[0],v[0],0.0);
|
|
corners[1].Set(u[1],v[0],0.0);
|
|
corners[2].Set(u[1],v[1],0.0);
|
|
corners[3].Set(u[0],v[1],0.0);
|
|
|
|
ON_Surface::ISO srf_iso[4] = {ON_Surface::S_iso,ON_Surface::E_iso,ON_Surface::N_iso,ON_Surface::W_iso};
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
ON_NurbsCurve* c2 = new ON_NurbsCurve( 2, 0, 2, 2 );
|
|
c2->SetCV(0,corners[i]);
|
|
c2->SetCV(1,corners[(i+1)%4]);
|
|
c2->m_knot[0] = 0.0;
|
|
c2->m_knot[1] = 1.0;
|
|
if ( i%2 )
|
|
c2->SetDomain(v[0],v[1]);
|
|
else
|
|
c2->SetDomain(u[0],u[1]);
|
|
int c2i = AddTrimCurve( c2 );
|
|
if ( bIsSingular[i] )
|
|
NewSingularTrim( m_V[vid[i]],loop,srf_iso[i],c2i);
|
|
else
|
|
{
|
|
ON_BrepTrim& trim = NewTrim( m_E[eid[i]], bRev3d[i], loop, c2i);
|
|
trim.m_iso = srf_iso[i];
|
|
if ( bIsClosed[(i+1)%2] )
|
|
trim.m_type = ON_BrepTrim::seam;
|
|
else {
|
|
trim.m_type = ON_BrepTrim::boundary;
|
|
const ON_BrepEdge& edge = m_E[eid[i]];
|
|
if ( edge.m_ti.Count() > 1 )
|
|
{
|
|
for ( eti = 0; eti < edge.m_ti.Count(); eti++ )
|
|
{
|
|
m_T[edge.m_ti[eti]].m_type = ON_BrepTrim::mated;
|
|
}
|
|
}
|
|
}
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
trim.m__legacy_2d_tol = 0.0;
|
|
trim.m__legacy_3d_tol = 0.0;
|
|
trim.m__legacy_flags_Set(-1,1);
|
|
}
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
boolRev3d[i] = bRev3d[i] ? true : false;
|
|
}
|
|
|
|
return &m_L[loop.m_loop_index];
|
|
}
|
|
|
|
|
|
|
|
|
|
ON_Brep* ON_BrepBox( const ON_3dPoint* box_corners, ON_Brep* pBrep )
|
|
{
|
|
ON_Brep* brep = 0;
|
|
int vi, ei, fi, si, c2i;
|
|
if (box_corners)
|
|
{
|
|
if ( pBrep ) {
|
|
pBrep->Destroy();
|
|
brep = pBrep;
|
|
}
|
|
else
|
|
brep = new ON_Brep();
|
|
brep->m_C2.Reserve(24);
|
|
brep->m_C3.Reserve(12);
|
|
brep->m_S.Reserve(6);
|
|
brep->m_V.Reserve(8);
|
|
brep->m_E.Reserve(12);
|
|
brep->m_L.Reserve(6);
|
|
brep->m_T.Reserve(24);
|
|
brep->m_F.Reserve(6);
|
|
for ( vi = 0; vi < 8; vi++ )
|
|
{
|
|
brep->NewVertex( box_corners[vi], 0.0 );
|
|
}
|
|
for ( ei = 0; ei < 4; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei];
|
|
ON_BrepVertex& v1 = brep->m_V[(ei+1)%4];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
for ( ei = 4; ei < 8; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei];
|
|
ON_BrepVertex& v1 = brep->m_V[ei==7?4:(ei+1)];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
for ( ei = 8; ei < 12; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei-8];
|
|
ON_BrepVertex& v1 = brep->m_V[ei-4];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
|
|
/*
|
|
// v7_______e6_____v6
|
|
// |\ |\
|
|
// | e7 | e5
|
|
// | \ ______e4_____\
|
|
// e11 v4 | v5
|
|
// | | e10 |
|
|
// | | | |
|
|
// 3---|---e2-----2 e9
|
|
// \ e8 \ |
|
|
// e3 | e1 |
|
|
// \ | \ |
|
|
// \v0_____e0_____\v1
|
|
*/
|
|
|
|
struct {
|
|
int e[4], bRev[4];
|
|
} f[6] = {
|
|
{{0, 9, 4, 8}, {false, false, true, true}},
|
|
{{1,10, 5, 9}, {false, false, true, true}},
|
|
{{2,11, 6,10}, {false, false, true, true}},
|
|
{{3, 8, 7,11}, {false, false, true, true}},
|
|
{{3, 2, 1, 0}, {true, true, true, true}},
|
|
{{4, 5, 6, 7}, {false, false, false, false}}
|
|
};
|
|
for ( fi = 0; fi < 6; fi++ )
|
|
{
|
|
ON_BrepEdge& e0 = brep->m_E[f[fi].e[0]];
|
|
ON_BrepEdge& e1 = brep->m_E[f[fi].e[1]];
|
|
ON_BrepEdge& e2 = brep->m_E[f[fi].e[2]];
|
|
ON_BrepEdge& e3 = brep->m_E[f[fi].e[3]];
|
|
ON_BrepVertex& v0 = brep->m_V[e0.m_vi[f[fi].bRev[0]?1:0]];
|
|
ON_BrepVertex& v1 = brep->m_V[e1.m_vi[f[fi].bRev[1]?1:0]];
|
|
ON_BrepVertex& v2 = brep->m_V[e2.m_vi[f[fi].bRev[2]?1:0]];
|
|
ON_BrepVertex& v3 = brep->m_V[e3.m_vi[f[fi].bRev[3]?1:0]];
|
|
|
|
si = brep->AddSurface( ON_NurbsSurfaceQuadrilateral( v0.point, v1.point, v2.point, v3.point ) );
|
|
ON_Interval s = brep->m_S[si]->Domain(0);
|
|
ON_Interval t = brep->m_S[si]->Domain(1);
|
|
ON_2dPoint p0(s[0],t[0]);
|
|
ON_2dPoint p1(s[1],t[0]);
|
|
ON_2dPoint p2(s[1],t[1]);
|
|
ON_2dPoint p3(s[0],t[1]);
|
|
|
|
ON_BrepFace& face = brep->NewFace( si );
|
|
ON_BrepLoop& loop = brep->NewLoop( ON_BrepLoop::outer, face );
|
|
|
|
loop.m_pbox.m_min.x = s[0];
|
|
loop.m_pbox.m_min.y = t[0];
|
|
loop.m_pbox.m_min.z = 0.0;
|
|
|
|
loop.m_pbox.m_max.x = s[1];
|
|
loop.m_pbox.m_max.y = t[1];
|
|
loop.m_pbox.m_max.z = 0.0;
|
|
|
|
// south side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p0, p1 ) );
|
|
ON_BrepTrim& trim0 = brep->NewTrim( e0, f[fi].bRev[0], loop, c2i );
|
|
trim0.m_tolerance[0] = 0.0;
|
|
trim0.m_tolerance[1] = 0.0;
|
|
trim0.m_type = (trim0.m_vi[0] != trim0.m_vi[1]) ? ON_BrepTrim::mated : ON_BrepTrim::singular;
|
|
trim0.m_iso = ON_Surface::S_iso;
|
|
|
|
// east side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p1, p2 ) );
|
|
ON_BrepTrim& trim1 = brep->NewTrim( e1, f[fi].bRev[1], loop, c2i );
|
|
trim1.m_tolerance[0] = 0.0;
|
|
trim1.m_tolerance[1] = 0.0;
|
|
trim1.m_type = (trim1.m_vi[0] != trim1.m_vi[1]) ? ON_BrepTrim::mated : ON_BrepTrim::singular;
|
|
trim1.m_iso = ON_Surface::E_iso;
|
|
|
|
// north side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p2, p3 ) );
|
|
ON_BrepTrim& trim2 = brep->NewTrim( e2, f[fi].bRev[2], loop, c2i );
|
|
trim2.m_tolerance[0] = 0.0;
|
|
trim2.m_tolerance[1] = 0.0;
|
|
trim2.m_type = (trim2.m_vi[0] != trim2.m_vi[1]) ? ON_BrepTrim::mated : ON_BrepTrim::singular;
|
|
trim2.m_iso = ON_Surface::N_iso;
|
|
|
|
// west side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p3, p0 ) );
|
|
ON_BrepTrim& trim3 = brep->NewTrim( e3, f[fi].bRev[3], loop, c2i );
|
|
trim3.m_tolerance[0] = 0.0;
|
|
trim3.m_tolerance[1] = 0.0;
|
|
trim3.m_type = (trim3.m_vi[0] != trim3.m_vi[1]) ? ON_BrepTrim::mated : ON_BrepTrim::singular;
|
|
trim3.m_iso = ON_Surface::W_iso;
|
|
}
|
|
if ( !brep->IsValid() ) {
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
else
|
|
delete brep;
|
|
brep = 0;
|
|
}
|
|
}
|
|
else
|
|
brep = 0;
|
|
return brep;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepWedge( const ON_3dPoint* corners, ON_Brep* pBrep )
|
|
{
|
|
ON_Brep* brep = 0;
|
|
|
|
int vi, ei, ti, fi, si, c2i;
|
|
|
|
if(corners)
|
|
{
|
|
// use the one passed in or make a new one
|
|
if( pBrep )
|
|
{
|
|
pBrep->Destroy();
|
|
brep = pBrep;
|
|
}
|
|
else
|
|
brep = new ON_Brep();
|
|
|
|
brep->m_C2.Reserve(18);
|
|
brep->m_C3.Reserve(9);
|
|
brep->m_S.Reserve(5);
|
|
brep->m_V.Reserve(6);
|
|
brep->m_E.Reserve(9);
|
|
brep->m_L.Reserve(5);
|
|
brep->m_T.Reserve(18);
|
|
brep->m_F.Reserve(5);
|
|
|
|
// vertices
|
|
for ( vi = 0; vi < 6; vi++ )
|
|
{
|
|
brep->NewVertex( corners[vi], 0.0 );
|
|
}
|
|
|
|
// 3d edges around bottom e0 - e2
|
|
for ( ei = 0; ei < 3; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei];
|
|
ON_BrepVertex& v1 = brep->m_V[(ei+1)%3];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
// 3d edges around top e3 - e5
|
|
for ( ei = 3; ei < 6; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei];
|
|
ON_BrepVertex& v1 = brep->m_V[ei==5?3:(ei+1)];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
// 3d vertical edges e6 - e8
|
|
for ( ei = 6; ei < 9; ei++ )
|
|
{
|
|
ON_BrepVertex& v0 = brep->m_V[ei-6];
|
|
ON_BrepVertex& v1 = brep->m_V[ei-3];
|
|
brep->m_C3.Append( new ON_LineCurve( v0.point, v1.point ) );
|
|
brep->NewEdge( v0, v1, ei, nullptr, 0.0 );
|
|
}
|
|
|
|
/*
|
|
//
|
|
// /v5
|
|
// /|\
|
|
// / | \
|
|
// e5 | e4
|
|
// / e8 \
|
|
// /__e3_____\
|
|
// v3| | |v4
|
|
// | | |
|
|
// | /v2 |
|
|
// e6 / \ e7
|
|
// | / \ |
|
|
// | e2 e1|
|
|
// |/ \|
|
|
// /____e0___\
|
|
// v0 v1
|
|
*/
|
|
|
|
struct {
|
|
int e[4], bRev[4];
|
|
} f[5] = {
|
|
{{0, 7, 3, 6}, {false, false, true, true}}, // vertical front
|
|
{{1, 8, 4, 7}, {false, false, true, true}}, // vertical right
|
|
{{2, 6, 5, 8}, {false, false, true, true}}, // vertical left
|
|
{{2, 1, 0,-1}, {true, true, true, true}}, // bottom
|
|
{{3, 4, 5,-1}, {false, false, false, false}} // top
|
|
};
|
|
for ( fi = 0; fi < 5; fi++ )
|
|
{
|
|
ON_BrepEdge* e0;
|
|
ON_BrepEdge* e1;
|
|
ON_BrepEdge* e2;
|
|
ON_BrepEdge* e3=0;
|
|
|
|
e0 = &brep->m_E[f[fi].e[0]];
|
|
e1 = &brep->m_E[f[fi].e[1]];
|
|
e2 = &brep->m_E[f[fi].e[2]];
|
|
if( f[fi].e[3] >= 0)
|
|
e3 = &brep->m_E[f[fi].e[3]];
|
|
|
|
ON_BrepVertex* v0;
|
|
ON_BrepVertex* v1;
|
|
ON_BrepVertex* v2;
|
|
ON_BrepVertex* v3=0;
|
|
|
|
v0 = &brep->m_V[e0->m_vi[f[fi].bRev[0]?1:0]];
|
|
v1 = &brep->m_V[e1->m_vi[f[fi].bRev[1]?1:0]];
|
|
v2 = &brep->m_V[e2->m_vi[f[fi].bRev[2]?1:0]];
|
|
if( f[fi].e[3] >= 0)
|
|
v3 = &brep->m_V[e3->m_vi[f[fi].bRev[3]?1:0]];
|
|
|
|
ON_NurbsSurface* srf;
|
|
|
|
if( f[fi].e[3] >= 0)
|
|
// 4 sided face
|
|
srf = ON_NurbsSurfaceQuadrilateral( v0->point, v1->point, v2->point, v3->point);
|
|
else
|
|
// 3 sided face
|
|
srf = ON_NurbsSurfaceQuadrilateral( v0->point, v1->point, v1->point + (v2->point - v0->point), v2->point);
|
|
|
|
si = brep->AddSurface( srf);
|
|
|
|
ON_Interval s = brep->m_S[si]->Domain(0);
|
|
ON_Interval t = brep->m_S[si]->Domain(1);
|
|
ON_2dPoint p0, p1, p2, p3;
|
|
p0.Set(s[0],t[0]);
|
|
p1.Set(s[1],t[0]);
|
|
p2.Set(s[1],t[1]);
|
|
p3.Set(s[0],t[1]);
|
|
|
|
ON_BrepFace& face = brep->NewFace( si );
|
|
ON_BrepLoop& loop = brep->NewLoop( ON_BrepLoop::outer, face );
|
|
|
|
if( f[fi].e[3] >= 0)
|
|
{
|
|
// south side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p0, p1 ) );
|
|
brep->NewTrim( *e0, f[fi].bRev[0], loop, c2i ).m_iso = ON_Surface::S_iso;
|
|
|
|
// east side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p1, p2 ) );
|
|
brep->NewTrim( *e1, f[fi].bRev[1], loop, c2i ).m_iso = ON_Surface::E_iso;
|
|
|
|
// north side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p2, p3 ) );
|
|
brep->NewTrim( *e2, f[fi].bRev[2], loop, c2i ).m_iso = ON_Surface::N_iso;
|
|
|
|
// west side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p3, p0 ) );
|
|
brep->NewTrim( *e3, f[fi].bRev[3], loop, c2i ).m_iso = ON_Surface::W_iso;
|
|
}
|
|
else
|
|
{
|
|
// south side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p0, p1 ) );
|
|
brep->NewTrim( *e0, f[fi].bRev[0], loop, c2i ).m_iso = ON_Surface::S_iso;
|
|
|
|
// diagonal from upper left to lower right
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p1, p3 ) );
|
|
brep->NewTrim( *e1, f[fi].bRev[1], loop, c2i ).m_iso = ON_Surface::not_iso;
|
|
|
|
// west side of surface
|
|
c2i = brep->AddTrimCurve( new ON_LineCurve( p3, p0 ) );
|
|
brep->NewTrim( *e2, f[fi].bRev[2], loop, c2i ).m_iso = ON_Surface::W_iso;
|
|
}
|
|
}
|
|
|
|
// set trim m_type and m_tolerance[]
|
|
for ( ti = 0; ti < brep->m_T.Count(); ti++ )
|
|
{
|
|
ON_BrepTrim& trim = brep->m_T[ti];
|
|
trim.m_type = ( trim.m_vi[0] != trim.m_vi[1] && trim.m_ei >= 0 )
|
|
? ON_BrepTrim::mated
|
|
: ON_BrepTrim::singular;
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
}
|
|
|
|
if ( !brep->IsValid() ) {
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
else
|
|
delete brep;
|
|
brep = 0;
|
|
}
|
|
}
|
|
else
|
|
brep = 0;
|
|
return brep;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepSphere( const ON_Sphere& sphere, ON_Brep* pBrep )
|
|
{
|
|
bool bArcLengthParameterization = true;
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
ON_RevSurface* pRevSurface = sphere.RevSurfaceForm(bArcLengthParameterization);
|
|
if ( pRevSurface )
|
|
{
|
|
brep = ON_BrepRevSurface( pRevSurface, false, false, pBrep );
|
|
if ( !brep )
|
|
delete pRevSurface;
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
ON_Brep* ON_BrepQuadSphere( const ON_3dPoint& Center, double radius, ON_Brep* pBrep)
|
|
|
|
{
|
|
if (radius < 0.0)
|
|
return 0;
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep ){
|
|
pBrep->Destroy();
|
|
brep = pBrep;
|
|
}
|
|
else
|
|
brep = ON_Brep::New();
|
|
|
|
ON_4dPoint CV[3][3];
|
|
CV[0][0].Set(-0.57735026918962584*radius, -0.57735026918962584*radius, 0.57735026918962584*radius, 1.0);
|
|
CV[0][1].Set(-0.70710678118654746*radius, 0.0, 0.70710678118654746*radius, 0.81649658092772603);
|
|
CV[0][2].Set(-0.57735026918962584*radius, 0.57735026918962584*radius, 0.57735026918962584*radius, 1.0);
|
|
|
|
CV[1][0].Set(0.0, -0.70710678118654746*radius, 0.70710678118654746*radius, 0.81649658092772603);
|
|
CV[1][1].Set(0.0, 0.0, 1.1093897997411788*radius, 0.46796046944844738);
|
|
CV[1][2].Set(0.0, 0.70710678118654746*radius, 0.70710678118654746*radius, 0.81649658092772603);
|
|
|
|
CV[2][0].Set(0.57735026918962584*radius, -0.57735026918962584*radius, 0.57735026918962584*radius, 1.0);
|
|
CV[2][1].Set(0.70710678118654746*radius, 0.0, 0.70710678118654746*radius, 0.81649658092772603);
|
|
CV[2][2].Set(0.57735026918962584*radius, 0.57735026918962584*radius, 0.57735026918962584*radius, 1.0);
|
|
|
|
|
|
ON_NurbsSurface* pZp = ON_NurbsSurface::New(3, true, 3, 3, 3, 3);
|
|
for (int i=0; i<2; i++){
|
|
pZp->m_knot[i][0] = pZp->m_knot[i][1] = 0.0;
|
|
pZp->m_knot[i][2] = pZp->m_knot[i][3] = radius;
|
|
}
|
|
|
|
for (int i=0; i<3; i++){
|
|
for (int j=0; j<3; j++)
|
|
pZp->SetCV(i, j, CV[i][j]);
|
|
}
|
|
|
|
ON_Xform roty;
|
|
roty[0][0] = roty[0][1] = roty[0][2] = 0.0;
|
|
roty[0][2] = 1.0;
|
|
roty[1][0] = roty[1][2] = roty[1][3] = 0.0;
|
|
roty[1][1] = 1.0;
|
|
roty[2][1] = roty[2][2] = roty[2][3] = 0.0;
|
|
roty[2][0] = -1.0;
|
|
roty[3][0] = roty[3][1] = roty[3][2] = 0.0;
|
|
roty[3][3] = 1.0;
|
|
|
|
ON_NurbsSurface* pXp = ON_NurbsSurface::New(*pZp);
|
|
pXp->Transform(roty);
|
|
|
|
ON_NurbsSurface* pZn = ON_NurbsSurface::New(*pXp);
|
|
pZn->Transform(roty);
|
|
|
|
ON_NurbsSurface* pXn = ON_NurbsSurface::New(*pZn);
|
|
pXn->Transform(roty);
|
|
|
|
ON_Xform rotx;
|
|
rotx[0][1] = rotx[0][2] = rotx[0][3] = 0.0;
|
|
rotx[0][0] = 1.0;
|
|
rotx[1][0] = rotx[1][1] = rotx[1][3] = 0.0;
|
|
rotx[1][2] = 1.0;
|
|
rotx[2][0] = rotx[2][2] = rotx[2][3] = 0.0;
|
|
rotx[2][1] = -1.0;
|
|
rotx[3][0] = rotx[3][1] = rotx[3][2] = 0.0;
|
|
rotx[3][3] = 1.0;
|
|
|
|
ON_NurbsSurface* pYp = ON_NurbsSurface::New(*pZp);
|
|
pYp->Transform(rotx);
|
|
|
|
ON_NurbsSurface* pYn = ON_NurbsSurface::New(*pZn);
|
|
pYn->Transform(rotx);
|
|
|
|
brep->Create(pZp);
|
|
|
|
ON_Brep brepxp;
|
|
brepxp.Create(pXp);
|
|
brep->Append(brepxp);
|
|
|
|
ON_Brep brepzn;
|
|
brepzn.Create(pZn);
|
|
brep->Append(brepzn);
|
|
|
|
ON_Brep brepxn;
|
|
brepxn.Create(pXn);
|
|
brep->Append(brepxn);
|
|
|
|
ON_Brep brepyp;
|
|
brepyp.Create(pYp);
|
|
brep->Append(brepyp);
|
|
|
|
ON_Brep brepyn;
|
|
brepyn.Create(pYn);
|
|
brep->Append(brepyn);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[0], brep->m_V[13]);
|
|
brep->CombineCoincidentVertices(brep->m_V[0], brep->m_V[21]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[1], brep->m_V[4]);
|
|
brep->CombineCoincidentVertices(brep->m_V[1], brep->m_V[20]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[2], brep->m_V[7]);
|
|
brep->CombineCoincidentVertices(brep->m_V[2], brep->m_V[17]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[3], brep->m_V[14]);
|
|
brep->CombineCoincidentVertices(brep->m_V[3], brep->m_V[16]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[5], brep->m_V[8]);
|
|
brep->CombineCoincidentVertices(brep->m_V[5], brep->m_V[23]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[6], brep->m_V[11]);
|
|
brep->CombineCoincidentVertices(brep->m_V[6], brep->m_V[18]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[9], brep->m_V[12]);
|
|
brep->CombineCoincidentVertices(brep->m_V[9], brep->m_V[22]);
|
|
|
|
brep->CombineCoincidentVertices(brep->m_V[10], brep->m_V[15]);
|
|
brep->CombineCoincidentVertices(brep->m_V[10], brep->m_V[19]);
|
|
|
|
brep->m_E[20].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[0], brep->m_E[20]);
|
|
|
|
brep->m_E[7].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[1], brep->m_E[7]);
|
|
|
|
brep->m_E[16].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[2], brep->m_E[16]);
|
|
|
|
brep->m_E[13].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[3], brep->m_E[13]);
|
|
|
|
brep->m_E[23].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[4], brep->m_E[23]);
|
|
|
|
brep->m_E[11].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[5], brep->m_E[11]);
|
|
|
|
brep->m_E[17].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[6], brep->m_E[17]);
|
|
|
|
brep->m_E[22].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[8], brep->m_E[22]);
|
|
|
|
brep->m_E[15].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[9], brep->m_E[15]);
|
|
|
|
brep->m_E[18].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[10], brep->m_E[18]);
|
|
|
|
brep->m_E[21].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[12], brep->m_E[21]);
|
|
|
|
brep->m_E[19].Reverse();
|
|
brep->CombineCoincidentEdges(brep->m_E[14], brep->m_E[19]);
|
|
|
|
|
|
brep->Compact();
|
|
|
|
ON_Xform trans;
|
|
trans = ON_Xform::TranslationTransformation(Center.x, Center.y, Center.z);
|
|
brep->Transform(trans);
|
|
|
|
brep->SetTolerancesBoxesAndFlags();
|
|
|
|
return brep;
|
|
}
|
|
|
|
ON_Brep* ON_BrepTorus( const ON_Torus& torus, ON_Brep* pBrep )
|
|
{
|
|
bool bArcLengthParameterization = true;
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
ON_RevSurface* pRevSurface = torus.RevSurfaceForm();
|
|
if ( pRevSurface )
|
|
{
|
|
if ( bArcLengthParameterization )
|
|
{
|
|
double r = fabs(torus.major_radius);
|
|
if ( r <= ON_SQRT_EPSILON )
|
|
r = 1.0;
|
|
r *= ON_PI;
|
|
pRevSurface->SetDomain(0,0.0,2.0*r);
|
|
r = fabs(torus.minor_radius);
|
|
if ( r <= ON_SQRT_EPSILON )
|
|
r = 1.0;
|
|
r *= ON_PI;
|
|
pRevSurface->SetDomain(1,0.0,2.0*r);
|
|
}
|
|
brep = ON_BrepRevSurface( pRevSurface, false, false, pBrep );
|
|
if ( !brep )
|
|
delete pRevSurface;
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepCylinder( const ON_Cylinder& cylinder,
|
|
bool bCapBottom,
|
|
bool bCapTop,
|
|
ON_Brep* pBrep )
|
|
{
|
|
bool bArcLengthParameterization = true;
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
ON_RevSurface* pRevSurface = cylinder.RevSurfaceForm();
|
|
if ( pRevSurface )
|
|
{
|
|
if ( bArcLengthParameterization )
|
|
{
|
|
double r = fabs(cylinder.circle.radius);
|
|
if ( r <= ON_SQRT_EPSILON )
|
|
r = 1.0;
|
|
pRevSurface->SetDomain(0,0.0,2.0*ON_PI*r);
|
|
}
|
|
brep = ON_BrepRevSurface( pRevSurface, bCapBottom, bCapTop, pBrep );
|
|
if ( !brep )
|
|
delete pRevSurface;
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepCone( const ON_Cone& cone, bool bCapBase, ON_Brep* pBrep )
|
|
{
|
|
bool bArcLengthParameterization = true;
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
ON_RevSurface* pRevSurface = cone.RevSurfaceForm();
|
|
if ( pRevSurface )
|
|
{
|
|
if ( bArcLengthParameterization )
|
|
{
|
|
double r = fabs(cone.radius);
|
|
if ( r <= ON_SQRT_EPSILON )
|
|
r = 1.0;
|
|
pRevSurface->SetDomain(0,0.0,2.0*ON_PI*r);
|
|
}
|
|
brep = ON_BrepRevSurface( pRevSurface, bCapBase, bCapBase, pBrep );
|
|
if ( !brep )
|
|
delete pRevSurface;
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepRevSurface(
|
|
ON_RevSurface*& pRevSurface,
|
|
bool bCapStart,
|
|
bool bCapEnd,
|
|
ON_Brep* pBrep
|
|
)
|
|
{
|
|
ON_Brep* brep = 0;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
if ( pRevSurface && pRevSurface->m_curve )
|
|
{
|
|
if ( pBrep )
|
|
brep = pBrep;
|
|
else
|
|
brep = new ON_Brep();
|
|
|
|
bool bTransposed = pRevSurface->m_bTransposed;
|
|
ON_Line axis = pRevSurface->m_axis;
|
|
ON_3dPoint R[2];
|
|
R[0] = pRevSurface->m_curve->PointAtStart();
|
|
R[1] = pRevSurface->m_curve->PointAtEnd();
|
|
if ( !pRevSurface->IsClosed(bTransposed?1:0) )
|
|
{
|
|
bCapStart = false;
|
|
bCapEnd = false;
|
|
}
|
|
|
|
if ( !brep->Create(pRevSurface) )
|
|
{
|
|
if (pBrep != brep)
|
|
delete brep;
|
|
brep = 0;
|
|
}
|
|
else if ( bCapStart || bCapEnd )
|
|
{
|
|
// cap ends
|
|
for ( int capcount = 0; capcount < 2; capcount++ )
|
|
{
|
|
int srf_trim_ti = -1;
|
|
// capcount = 0 for bottom cap and 1 for top cap
|
|
if ( capcount == 0 )
|
|
{
|
|
// cap circle at start of revolute
|
|
if ( !bCapStart )
|
|
continue;
|
|
srf_trim_ti = (bTransposed) ? 3 : 0;
|
|
}
|
|
else
|
|
{
|
|
// cap circle at start of revolute
|
|
if ( !bCapEnd )
|
|
continue;
|
|
srf_trim_ti = (bTransposed) ? 1 : 2;
|
|
}
|
|
if ( srf_trim_ti < 0 || srf_trim_ti >= brep->m_T.Count() )
|
|
continue;
|
|
|
|
if ( brep->m_T[srf_trim_ti].m_type != ON_BrepTrim::boundary )
|
|
continue;
|
|
if ( brep->m_T[srf_trim_ti].m_ei < 0 )
|
|
continue;
|
|
ON_BrepEdge& edge = brep->m_E[brep->m_T[srf_trim_ti].m_ei];
|
|
if ( !edge.IsClosed() )
|
|
continue;
|
|
|
|
ON_Circle circle;
|
|
{
|
|
ON_Arc arc;
|
|
const ON_Curve* edge_curve = edge.EdgeCurveOf();
|
|
if ( 0 == edge_curve )
|
|
continue;
|
|
if ( !edge_curve->IsArc( nullptr, &arc ) )
|
|
continue;
|
|
if ( !arc.IsCircle() )
|
|
continue;
|
|
circle = arc;
|
|
}
|
|
|
|
/*
|
|
if ( capcount == 0 )
|
|
circle.Reverse();
|
|
*/
|
|
circle.Reverse();
|
|
|
|
// create cap surface
|
|
double radius = circle.radius;
|
|
ON_NurbsSurface* pCapSurface = ON_NurbsSurfaceQuadrilateral(
|
|
circle.plane.PointAt(-radius,-radius),
|
|
circle.plane.PointAt(+radius,-radius),
|
|
circle.plane.PointAt(+radius,+radius),
|
|
circle.plane.PointAt(-radius,+radius)
|
|
);
|
|
pCapSurface->m_knot[0][0] = -fabs(radius);
|
|
pCapSurface->m_knot[0][1] = fabs(radius);
|
|
pCapSurface->m_knot[1][0] = pCapSurface->m_knot[0][0];
|
|
pCapSurface->m_knot[1][1] = pCapSurface->m_knot[0][1];
|
|
|
|
// trim curve circle
|
|
circle.Create( ON_xy_plane, ON_3dPoint::Origin, radius );
|
|
ON_NurbsCurve* c2 = new ON_NurbsCurve();
|
|
circle.GetNurbForm(*c2);
|
|
c2->ChangeDimension(2);
|
|
|
|
int si = brep->AddSurface(pCapSurface);
|
|
int c2i = brep->AddTrimCurve(c2);
|
|
ON_BrepFace& cap = brep->NewFace( si );
|
|
ON_BrepLoop& loop = brep->NewLoop( ON_BrepLoop::outer, cap );
|
|
ON_BrepTrim& trim = brep->NewTrim( edge, true, loop, c2i );
|
|
for ( int eti = 0; eti < edge.m_ti.Count(); eti++ )
|
|
brep->m_T[ edge.m_ti[eti] ].m_type = ON_BrepTrim::mated;
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
trim.m_pbox.m_min.x = -radius;
|
|
trim.m_pbox.m_min.y = -radius;
|
|
trim.m_pbox.m_min.z = 0.0;
|
|
trim.m_pbox.m_max.x = radius;
|
|
trim.m_pbox.m_max.y = radius;
|
|
trim.m_pbox.m_max.z = 0.0;
|
|
trim.m__legacy_2d_tol = 0.0;
|
|
trim.m__legacy_3d_tol = 0.0;
|
|
loop.m_pbox = trim.m_pbox;
|
|
brep->SetTrimTypeFlags(trim);
|
|
brep->SetTrimIsoFlags(trim);
|
|
}
|
|
}
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
|
|
|
|
static bool AddC3Curve( const ON_Curve* c3, ON_SimpleArray<ON_Curve*>& C3 )
|
|
{
|
|
int j;
|
|
if ( !c3 )
|
|
return false;
|
|
const int c3dim = c3->Dimension();
|
|
if ( c3dim != 3 && c3dim != 2 )
|
|
return false;
|
|
if ( ON_PolyCurve::Cast(c3) )
|
|
{
|
|
const ON_PolyCurve* polycrv = static_cast<const ON_PolyCurve*>(c3);
|
|
for ( j = 0; j < polycrv->Count(); j++ )
|
|
{
|
|
if ( !AddC3Curve( polycrv->SegmentCurve(j), C3 ) )
|
|
return false;
|
|
}
|
|
}
|
|
else if ( ON_PolylineCurve::Cast(c3) )
|
|
{
|
|
ON_Line line;
|
|
//ON_LineCurve* linecrv = 0;
|
|
const ON_PolylineCurve* pline = static_cast<const ON_PolylineCurve*>(c3);
|
|
line.to = pline->m_pline[0];
|
|
if ( 2 == c3dim )
|
|
line.to.z = 0.0;
|
|
for ( j = 1; j < pline->m_pline.Count(); j++ )
|
|
{
|
|
line.from = line.to;
|
|
line.to = pline->m_pline[j];
|
|
if ( 2 == c3dim )
|
|
line.to.z = 0.0;
|
|
if ( line.Length() > 0 )
|
|
C3.Append( new ON_LineCurve(line) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ON_Curve* c3dup = c3->DuplicateCurve();
|
|
if ( 0 == c3dup )
|
|
return false;
|
|
if ( 2 == c3dup->Dimension() )
|
|
{
|
|
c3dup->ChangeDimension(3);
|
|
if ( 3 != c3dup->Dimension() )
|
|
{
|
|
delete c3dup;
|
|
return false;
|
|
}
|
|
}
|
|
C3.Append( c3dup );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ON_Brep::NewPlanarFaceLoop(
|
|
int face_index,
|
|
ON_BrepLoop::TYPE loop_type,
|
|
ON_SimpleArray<ON_Curve*>& boundary,
|
|
bool bDuplicateCurves
|
|
)
|
|
{
|
|
m_is_solid = 0;
|
|
if ( face_index < 0 || face_index >= m_F.Count() || boundary.Count() < 1 )
|
|
return false;
|
|
ON_BrepFace& face = m_F[face_index];
|
|
const ON_PlaneSurface* pPlaneSurface = ON_PlaneSurface::Cast(face.SurfaceOf());
|
|
if ( !pPlaneSurface )
|
|
return false;
|
|
const ON_Plane plane(pPlaneSurface->m_plane);
|
|
|
|
// get 3d edge curves
|
|
ON_SimpleArray<ON_Curve*> C3( 2*boundary.Count() );
|
|
ON_Curve* c3;
|
|
int i, count = boundary.Count();
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
c3 = boundary[i];
|
|
if ( !c3 )
|
|
break;
|
|
if ( bDuplicateCurves )
|
|
{
|
|
if ( !AddC3Curve( c3, C3 ) )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
C3.Append(c3);
|
|
boundary[i] = 0;
|
|
}
|
|
}
|
|
|
|
if ( i < count )
|
|
{
|
|
ON_ERROR("ON_Brep::NewPlanarFaceLoop - null 3d curve in boundary[] array");
|
|
if ( bDuplicateCurves )
|
|
{
|
|
for ( i = 0; i < C3.Count(); i++ )
|
|
delete C3[i];
|
|
}
|
|
else
|
|
{
|
|
for ( i = 0; i < C3.Count(); i++ )
|
|
boundary[i] = C3[i];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// get 2d trim curves
|
|
ON_Xform proj_to_plane;
|
|
proj_to_plane[0][0] = plane.xaxis.x;
|
|
proj_to_plane[0][1] = plane.xaxis.y;
|
|
proj_to_plane[0][2] = plane.xaxis.z;
|
|
proj_to_plane[0][3] = -(plane.xaxis*plane.origin);
|
|
proj_to_plane[1][0] = plane.yaxis.x;
|
|
proj_to_plane[1][1] = plane.yaxis.y;
|
|
proj_to_plane[1][2] = plane.yaxis.z;
|
|
proj_to_plane[1][3] = -(plane.yaxis*plane.origin);
|
|
proj_to_plane[2][0] = plane.zaxis.x;
|
|
proj_to_plane[2][1] = plane.zaxis.y;
|
|
proj_to_plane[2][2] = plane.zaxis.z;
|
|
proj_to_plane[2][3] = -(plane.zaxis*plane.origin);
|
|
proj_to_plane[3][0] = 0.0;
|
|
proj_to_plane[3][1] = 0.0;
|
|
proj_to_plane[3][2] = 0.0;
|
|
proj_to_plane[3][3] = 1.0;
|
|
|
|
count = C3.Count();
|
|
ON_BoundingBox loop_pbox, cbox;
|
|
ON_SimpleArray<double> edge_tol(count);
|
|
ON_SimpleArray<ON_NurbsCurve*> C2( count );
|
|
ON_NurbsCurve* c2;
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
c3 = C3[i];
|
|
c2 = new ON_NurbsCurve();
|
|
if ( !c3->GetNurbForm(*c2) )
|
|
break;
|
|
if ( !c2->Transform(proj_to_plane) )
|
|
break;
|
|
if ( !c2->GetBoundingBox(cbox) )
|
|
break;
|
|
double d = fabs(cbox.m_max.z);
|
|
if ( d < fabs(cbox.m_min.z) )
|
|
d = fabs(cbox.m_min.z);
|
|
if ( d <= ON_ZERO_TOLERANCE )
|
|
d = 0.0;
|
|
edge_tol.Append( d );
|
|
if ( !c2->ChangeDimension(2) )
|
|
break;
|
|
if ( !c2->MakePiecewiseBezier() )
|
|
break;
|
|
cbox.m_min.z = 0.0;
|
|
cbox.m_max.z = 0.0;
|
|
loop_pbox.Union(cbox);
|
|
C2.Append(c2);
|
|
}
|
|
if ( i < count )
|
|
{
|
|
ON_ERROR("ON_Brep::NewPlanarFaceLoop - unable to create 2d trim curve");
|
|
for ( i = 0; i < C2.Count(); i++ )
|
|
delete C2[i];
|
|
for ( i = 0; i < C3.Count(); i++ )
|
|
delete C3[i];
|
|
return false;
|
|
}
|
|
|
|
// add new vertices
|
|
const int vi0 = m_V.Count();
|
|
m_V.Reserve( vi0 + count );
|
|
for ( i = 0; i < count; i++ )
|
|
NewVertex( C3[i]->PointAtStart() );
|
|
|
|
// add new edges
|
|
const int ei0 = m_E.Count();
|
|
m_E.Reserve( ei0 + count );
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
int c3i = AddEdgeCurve( C3[i] );
|
|
ON_BrepEdge& edge = NewEdge( m_V[vi0+i], m_V[vi0+((i+1)%count)], c3i );
|
|
edge.m_tolerance = edge_tol[i];
|
|
}
|
|
|
|
// add new trims
|
|
ON_3dPoint P, Q;
|
|
double trim_tol[2];
|
|
ON_BrepLoop& loop = NewLoop( loop_type, face );
|
|
loop.m_pbox = loop_pbox;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
int c2i = AddTrimCurve( C2[i] );
|
|
trim_tol[0] = 0.0;
|
|
trim_tol[1] = 0.0;
|
|
ON_NurbsCurve* c2_local = C2[i];
|
|
P = c2_local->PointAtEnd();
|
|
Q = C2[(i+1)%count]->PointAtStart();
|
|
double w = (c2_local->IsRational()) ? c2_local->Weight(c2_local->m_cv_count-1) : 1.0;
|
|
if (w < ON_ZERO_TOLERANCE)
|
|
w = 1.0;
|
|
if (c2_local->IsRational())
|
|
Q *= w;
|
|
c2_local->SetCV( c2_local->m_cv_count-1, Q );
|
|
if (c2_local->IsRational())
|
|
c2_local->SetWeight(c2_local->m_cv_count-1, w);
|
|
trim_tol[0] = fabs(P.x - Q.x);
|
|
trim_tol[1] = fabs(P.y - Q.y);
|
|
if ( trim_tol[0] <= ON_ZERO_TOLERANCE )
|
|
trim_tol[0] = 0.0;
|
|
if ( trim_tol[1] <= ON_ZERO_TOLERANCE )
|
|
trim_tol[1] = 0.0;
|
|
ON_BrepEdge& edge = m_E[ei0+i];
|
|
ON_BrepTrim& trim = NewTrim( edge, false, loop, c2i );
|
|
trim.m_type = ON_BrepTrim::boundary;
|
|
trim.m_tolerance[0] = 1.1*trim_tol[0];
|
|
trim.m_tolerance[1] = 1.1*trim_tol[1];
|
|
}
|
|
int loop_dir = LoopDirection( loop );
|
|
switch ( loop_type )
|
|
{
|
|
case ON_BrepLoop::outer:
|
|
if ( loop_dir < 0 )
|
|
FlipLoop( loop );
|
|
break;
|
|
case ON_BrepLoop::inner:
|
|
if ( loop_dir > 0 )
|
|
FlipLoop( loop );
|
|
break;
|
|
case ON_BrepLoop::unknown:
|
|
if ( loop_dir > 0 )
|
|
loop.m_type = ON_BrepLoop::outer;
|
|
else if ( loop_dir < 0 )
|
|
loop.m_type = ON_BrepLoop::inner;
|
|
break;
|
|
default:
|
|
// intentionally ignoring other ON_Brep::TYPE enum values
|
|
break;
|
|
}
|
|
|
|
SetTrimIsoFlags();
|
|
for ( i = vi0; i < m_V.Count(); i++ )
|
|
SetVertexTolerance( m_V[i] );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
ON_Brep* ON_BrepTrimmedPlane(
|
|
const ON_Plane& plane,
|
|
ON_SimpleArray<ON_Curve*>& boundary,
|
|
bool bDuplicateCurves,
|
|
ON_Brep* pBrep )
|
|
{
|
|
ON_Brep* brep;
|
|
if ( pBrep )
|
|
{
|
|
pBrep->Destroy();
|
|
brep = pBrep;
|
|
}
|
|
else
|
|
brep = new ON_Brep();
|
|
|
|
ON_PlaneSurface* s = new ON_PlaneSurface();
|
|
s->m_plane = plane;
|
|
s->SetDomain(0, -100.0, 100.0 ); // any domain and extents will do for now
|
|
s->SetDomain(1, -100.0, 100.0 );
|
|
s->SetExtents(0, s->Domain(0) );
|
|
s->SetExtents(1, s->Domain(1) );
|
|
const int si = brep->AddSurface(s);
|
|
ON_BrepFace& face = brep->NewFace( si );
|
|
face.DestroyRuntimeCache();
|
|
if ( brep->NewPlanarFaceLoop( face.m_face_index, ON_BrepLoop::outer, boundary, bDuplicateCurves ) )
|
|
{
|
|
// set face domain
|
|
const ON_BrepLoop* loop = brep->m_L.Last();
|
|
s->SetDomain(0, loop->m_pbox.m_min.x, loop->m_pbox.m_max.x );
|
|
s->SetDomain(1, loop->m_pbox.m_min.y, loop->m_pbox.m_max.y );
|
|
s->SetExtents(0,s->Domain(0));
|
|
s->SetExtents(1,s->Domain(1));
|
|
|
|
// need to update trim m_iso flags because we changed surface shape
|
|
brep->SetTrimIsoFlags(face);
|
|
}
|
|
else
|
|
{
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
else
|
|
delete brep;
|
|
brep = nullptr;
|
|
}
|
|
return brep;
|
|
}
|
|
|
|
|
|
|
|
ON_Brep* ON_BrepTrimmedPlane(
|
|
const ON_Plane& plane,
|
|
const ON_Curve& boundary,
|
|
ON_Brep* pBrep )
|
|
{
|
|
ON_SimpleArray<ON_Curve*> c;
|
|
c.Append(const_cast<ON_Curve*>(&boundary));
|
|
return ON_BrepTrimmedPlane( plane, c, true, pBrep );
|
|
}
|
|
|
|
|
|
ON_DECL
|
|
ON_Brep* ON_BrepFromMesh(
|
|
const ON_MeshTopology& mesh_topology,
|
|
bool bTrimmedTriangles,
|
|
ON_Brep* pBrep
|
|
)
|
|
{
|
|
double tol = .01;
|
|
return ON_BrepFromMeshWithNgons(mesh_topology, bTrimmedTriangles, false, tol, pBrep);
|
|
}
|
|
|
|
static ON_Mesh* NgonulateMesh(const ON_Mesh* mesh_input, double tol)
|
|
{
|
|
if (nullptr == mesh_input)
|
|
return nullptr;
|
|
|
|
ON_Mesh* mesh_output = new ON_Mesh(*mesh_input);
|
|
if (nullptr == mesh_output)
|
|
return nullptr;
|
|
|
|
if (0 < mesh_output->QuadCount())
|
|
mesh_output->ConvertNonPlanarQuadsToTriangles(tol, ON_UNSET_VALUE, 0);
|
|
|
|
mesh_output->SetNgonCount(0);
|
|
|
|
ON_MeshVertexFaceMap vfmap;
|
|
vfmap.SetFromMesh(mesh_output, true);
|
|
|
|
mesh_output->AddPlanarNgons(vfmap.VertexFaceMap(), tol, 3, 0, true );
|
|
//ON_DebugWriteObject(mesh_output);
|
|
|
|
if (mesh_output->NgonCount() <= 0)
|
|
{
|
|
delete mesh_output;
|
|
return nullptr;
|
|
}
|
|
|
|
mesh_output->SeparateNgons(const_cast<unsigned int**>(vfmap.VertexFaceMap()), 0, mesh_output->NgonUnsignedCount());
|
|
// adding vertices invalidates vfmap;
|
|
vfmap.Destroy();
|
|
vfmap.SetFromMesh(mesh_output, true);
|
|
|
|
mesh_output->SetNgonVertexNormals(0, mesh_output->NgonUnsignedCount());
|
|
|
|
mesh_output->RemoveNgonInteriorVertices(vfmap.VertexFaceMap(), 0, mesh_output->NgonUnsignedCount());
|
|
|
|
return mesh_output;
|
|
}
|
|
|
|
static bool FixNonPlanarNgons(ON_Mesh& mesh, double tol)
|
|
{
|
|
mesh.RemoveAllNgons();
|
|
ON_Mesh* pMesh = NgonulateMesh(&mesh, tol);
|
|
if (nullptr != pMesh)
|
|
{
|
|
mesh = *pMesh;
|
|
delete pMesh;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool AllNgonsArePlanar(const ON_Mesh* pMesh, double tol)
|
|
{
|
|
bool rc = true;
|
|
int i, ict = pMesh->NgonCount();
|
|
for (i = 0; ict > i && true == rc; i++)
|
|
{
|
|
const ON_MeshNgon* pNgon = pMesh->Ngon(i);
|
|
// establish a comparison plane with the first face.
|
|
int fi, fct = pNgon->m_Fcount;
|
|
if (0 == fct)
|
|
continue;
|
|
|
|
ON_MeshFace face = pMesh->m_F[pNgon->m_fi[0]];
|
|
ON_Plane plane;
|
|
plane.CreateFromPoints(pMesh->Vertex(face.vi[0]), pMesh->Vertex(face.vi[1]), pMesh->Vertex(face.vi[3]));
|
|
for (fi = 0; fct > fi && true == rc; fi++)
|
|
{
|
|
face = pMesh->m_F[pNgon->m_fi[fi]];
|
|
for (int vi = 0; 4 > vi && true == rc; vi++)
|
|
{
|
|
if (tol < plane.DistanceTo(pMesh->Vertex(face.vi[vi])))
|
|
rc = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
ON_DECL
|
|
ON_Brep* ON_BrepFromMeshWithNgons(
|
|
const ON_MeshTopology& input_topology,
|
|
bool bTrimmedTriangles,
|
|
bool bUseNgonsIfTheyExist,
|
|
double tol,
|
|
ON_Brep* pBrep
|
|
)
|
|
{
|
|
ON_BezierCurve edge_line(3,false,2);
|
|
ON_BezierCurve trim_line(2,false,2);
|
|
ON_Brep* brep = nullptr;
|
|
if ( pBrep )
|
|
pBrep->Destroy();
|
|
|
|
const ON_MeshTopology* mesh_topology = &input_topology;
|
|
const ON_Mesh* pMesh = mesh_topology->m_mesh;
|
|
if (nullptr == pMesh || false == mesh_topology->IsValid())
|
|
return nullptr;
|
|
|
|
bUseNgonsIfTheyExist = bUseNgonsIfTheyExist && pMesh->HasNgons();
|
|
bool bAllNgonsArePlanar = true;
|
|
if (true == bUseNgonsIfTheyExist)
|
|
bAllNgonsArePlanar = AllNgonsArePlanar(pMesh, tol);
|
|
|
|
ON_Mesh tmpmesh = *pMesh;
|
|
if (false == bAllNgonsArePlanar)
|
|
{
|
|
if (true == FixNonPlanarNgons(tmpmesh, tol))
|
|
{
|
|
pMesh = &tmpmesh;
|
|
mesh_topology = &pMesh->Topology();
|
|
}
|
|
}
|
|
|
|
if (nullptr == pMesh || false == mesh_topology->IsValid())
|
|
return nullptr;
|
|
|
|
const int ngon_count = pMesh->NgonCount();
|
|
|
|
bTrimmedTriangles = bTrimmedTriangles || bUseNgonsIfTheyExist;
|
|
bUseNgonsIfTheyExist = bUseNgonsIfTheyExist && pMesh->HasNgons();
|
|
|
|
brep = (pBrep != nullptr) ? pBrep : new ON_Brep();
|
|
const int vertex_count = mesh_topology->TopVertexCount();
|
|
const int edge_count = mesh_topology->TopEdgeCount();
|
|
const int face_count = mesh_topology->TopFaceCount();
|
|
brep->m_V.Reserve( vertex_count );
|
|
brep->m_E.Reserve( edge_count );
|
|
brep->m_C3.Reserve( edge_count );
|
|
brep->m_F.Reserve( face_count );
|
|
brep->m_L.Reserve( face_count );
|
|
brep->m_T.Reserve( 4*static_cast<size_t>(face_count) );
|
|
brep->m_C2.Reserve( 4*static_cast<size_t>(face_count) );
|
|
|
|
ON_Interval srf_dom[2];
|
|
ON_3dPoint srf_2d_corner[4];
|
|
ON_3dPoint srf_3d_corner[4];
|
|
ON_Surface::ISO quad_iso[4] = {ON_Surface::S_iso,ON_Surface::E_iso,ON_Surface::N_iso,ON_Surface::W_iso};
|
|
ON_Surface::ISO tri_iso[3] = {ON_Surface::S_iso,ON_Surface::E_iso,ON_Surface::not_iso};
|
|
|
|
// May 1, 2012 Tim Fix for RR 104209
|
|
// Use double precision vertexes from the mesh if they exist
|
|
const ON_3dPointArray* pDPV = 0;
|
|
if (pMesh->HasDoublePrecisionVertices())
|
|
pDPV = &pMesh->DoublePrecisionVertices();
|
|
|
|
for ( int vi = 0; vi < vertex_count; vi++ )
|
|
{
|
|
onmalloc(0);//for canceling.
|
|
ON_3dPoint pt;
|
|
|
|
// May 1, 2012 Tim Fix for RR 104209
|
|
// Use double precision vertexes from the mesh if they exist
|
|
const ON_MeshTopologyVertex& topvert = mesh_topology->m_topv[vi];
|
|
if (0 != pDPV)
|
|
pt = *pDPV->At(topvert.m_vi[0]);
|
|
else
|
|
pt = pMesh->m_V[topvert.m_vi[0]];
|
|
|
|
ON_BrepVertex& vertex = brep->NewVertex( pt, 0.0 );
|
|
memset(&vertex.m_vertex_user, 0, sizeof(vertex.m_vertex_user));
|
|
}
|
|
|
|
for ( int ei = 0; ei < edge_count; ei++ )
|
|
{
|
|
onmalloc(0);//for canceling.
|
|
const ON_MeshTopologyEdge& mesh_edge = mesh_topology->m_tope[ei];
|
|
ON_BrepVertex& v0 = brep->m_V[mesh_edge.m_topvi[0]];
|
|
ON_BrepVertex& v1 = brep->m_V[mesh_edge.m_topvi[1]];
|
|
edge_line.SetCV(0, v0.point);
|
|
edge_line.SetCV(1, v1.point);
|
|
ON_Curve* pEdgeCurve = new ON_NurbsCurve( edge_line );
|
|
int c3i = brep->AddEdgeCurve( pEdgeCurve );
|
|
ON_BrepEdge& edge = brep->NewEdge( v0, v1, c3i );
|
|
memset(&edge.m_edge_user, 0, sizeof(edge.m_edge_user));
|
|
edge.m_tolerance = 0.0;
|
|
}
|
|
|
|
ON_SimpleArray<bool> usedfaces(face_count);
|
|
usedfaces.SetCount(face_count);
|
|
usedfaces.MemSet(0);
|
|
|
|
if (true == bUseNgonsIfTheyExist)
|
|
{
|
|
const ON_3dPointListRef mesh_vertex_list(pMesh);
|
|
const ON_MeshFaceList& mesh_face_list(pMesh);
|
|
ON_MeshVertexFaceMap vf_map;
|
|
vf_map.SetFromMesh(pMesh, true);
|
|
|
|
for (int fi = 0; ngon_count > fi; fi++)
|
|
{
|
|
const ON_MeshNgon* pNgon = pMesh->Ngon(fi);
|
|
if (nullptr == pNgon || 1 == pNgon->m_Fcount)
|
|
continue; // handle single face ngons with original tri/quad code
|
|
|
|
int vcount = pNgon->m_Vcount;
|
|
ON_SimpleArray<ON_3dPoint> pts(vcount);
|
|
for (int lti = 0; vcount > lti; lti++)
|
|
pts.Append(pMesh->Vertex(pNgon->m_vi[lti]));
|
|
|
|
ON_Plane plane = ON_Plane::FromPointList(pts);
|
|
if (ON_Plane::UnsetPlane == plane)
|
|
continue;
|
|
|
|
ON_3dVector A(pMesh->Vertex(pMesh->m_F[pNgon->m_fi[0]].vi[1]) - pMesh->Vertex(pMesh->m_F[pNgon->m_fi[0]].vi[0]));
|
|
ON_3dVector B(pMesh->Vertex(pMesh->m_F[pNgon->m_fi[0]].vi[3]) - pMesh->Vertex(pMesh->m_F[pNgon->m_fi[0]].vi[0]));
|
|
A.Unitize(); B.Unitize();
|
|
ON_3dVector C = ON_CrossProduct(A, B);
|
|
double dot = ON_DotProduct(C, plane.Normal());
|
|
if (0 > dot)
|
|
plane.Flip();
|
|
|
|
ON_PlaneSurface* pSurface = new ON_PlaneSurface(plane);
|
|
if (nullptr == pSurface)
|
|
continue;
|
|
|
|
ON_BoundingBox bbox = ON_PointListBoundingBox(3, false, pts.Count(), 3, (double*)pts.Array());
|
|
|
|
double u0, u1, v0, v1;
|
|
plane.ClosestPointTo(bbox.Min(), &u0, &v0);
|
|
plane.ClosestPointTo(bbox.Max(), &u1, &v1);
|
|
pSurface->SetDomain(0, u0-10, u1+10);
|
|
pSurface->SetDomain(1, v0-10, v1+10);
|
|
pSurface->SetExtents(0, ON_Interval(u0 - 10, u1 + 10), true);
|
|
pSurface->SetExtents(1, ON_Interval(v0 - 10, v1 + 10), true);
|
|
|
|
ON_BrepFace& face = brep->NewFace(brep->AddSurface(pSurface));
|
|
|
|
ON_SimpleArray<unsigned int> ngon_vi;
|
|
ON_SimpleArray<unsigned int> ngon_vi_markers;
|
|
pNgon->FindNgonBoundaries(mesh_vertex_list, mesh_face_list, &vf_map, pNgon->m_Fcount, pNgon->m_fi, ngon_vi, ngon_vi_markers);
|
|
ON_SimpleArray<ON_3dPoint> boundary_pts(ngon_vi.Count());
|
|
for (int vi = 0; ngon_vi.Count() > vi; vi++)
|
|
boundary_pts.Append(pMesh->Vertex(ngon_vi[vi]));
|
|
|
|
int ct = 0;
|
|
for (int li = 0; ngon_vi_markers.Count() > li; li++)
|
|
{
|
|
ON_BrepLoop* pLoop = nullptr;
|
|
if (0 == li)
|
|
pLoop = &brep->NewLoop(ON_BrepLoop::outer, face);
|
|
else
|
|
pLoop = &brep->NewLoop(ON_BrepLoop::inner, face);
|
|
if (nullptr == pLoop)
|
|
continue;
|
|
|
|
bbox = ON_PointListBoundingBox(3, false, ngon_vi_markers[li], 3, (double*)boundary_pts.At(ct));
|
|
pLoop->m_pbox.m_min = bbox.Min();
|
|
pLoop->m_pbox.m_max = bbox.Max();
|
|
|
|
unsigned int* ngon_vi_loop = &ngon_vi[ct];
|
|
ct += ngon_vi_markers[li];
|
|
|
|
bool bFoundBadEdge = false;
|
|
for (unsigned int lti = 0; ngon_vi_markers[li] > lti && false == bFoundBadEdge; lti++)
|
|
{
|
|
onmalloc(0);//for canceling.
|
|
int topv0 = mesh_topology->m_topv_map[ngon_vi_loop[lti]];
|
|
int topv1 = mesh_topology->m_topv_map[ngon_vi_loop[0]];
|
|
if (ngon_vi_markers[li] - 1 > lti)
|
|
topv1 = mesh_topology->m_topv_map[ngon_vi_loop[lti + 1]];
|
|
|
|
|
|
int edge_index = mesh_topology->TopEdge(topv0, topv1);
|
|
if (-1 == edge_index)
|
|
{
|
|
bFoundBadEdge = true;
|
|
continue;
|
|
}
|
|
|
|
ON_BrepEdge& brep_edge = brep->m_E[edge_index];
|
|
// set the flag for vertex/edge we use and purge what isn't used when done.
|
|
brep_edge.m_edge_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[0]].m_vertex_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[1]].m_vertex_user.i = 1;
|
|
|
|
plane.ClosestPointTo(pMesh->m_V[mesh_topology->m_topv[topv0].m_vi[0]], &u0, &v0);
|
|
trim_line.SetCV(0, ON_3dPoint(u0, v0, 0));
|
|
plane.ClosestPointTo(pMesh->m_V[mesh_topology->m_topv[topv1].m_vi[0]], &u1, &v1);
|
|
trim_line.SetCV(1, ON_3dPoint(u1, v1, 0));
|
|
ON_Curve* pTrimCurve = new ON_NurbsCurve(trim_line);
|
|
int c2i = brep->AddTrimCurve(pTrimCurve);
|
|
|
|
const ON_MeshTopologyEdge& edge = mesh_topology->m_tope[edge_index];
|
|
bool b_reve = false, b_foundmatch = false;
|
|
for (int ff = 0; edge.m_topf_count > ff && false == b_foundmatch; ff++)
|
|
{
|
|
int face_idx = -1;
|
|
for (unsigned int hh = 0; pNgon->m_Fcount > hh; hh++)
|
|
{
|
|
if (pNgon->m_fi[hh] == (unsigned int)edge.m_topfi[ff])
|
|
face_idx = pNgon->m_fi[hh];
|
|
}
|
|
|
|
if (-1 == face_idx)
|
|
continue;
|
|
|
|
const ON_MeshTopologyFace& mesh_face = mesh_topology->m_topf[face_idx];
|
|
int gg_ct = mesh_face.IsQuad() ? 4 : 3;
|
|
for (int gg = 0; gg_ct > gg && false == b_foundmatch; gg++)
|
|
{
|
|
if (edge_index == mesh_face.m_topei[gg])
|
|
{
|
|
b_reve = mesh_face.m_reve[gg];
|
|
b_foundmatch = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
ON_BrepTrim& trim = brep->NewTrim(brep_edge, b_reve ? true : false, *pLoop, c2i);
|
|
trim.m__legacy_2d_tol = 0.0;
|
|
trim.m__legacy_3d_tol = 0.0;
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
trim.m_iso = ON_Surface::not_iso;
|
|
trim.m_type = (edge.m_topf_count > 1) ? ON_BrepTrim::mated : ON_BrepTrim::boundary;
|
|
}
|
|
}
|
|
|
|
//On success mark faces to omit.
|
|
for (unsigned int ff = 0; pNgon->m_Fcount > ff; ff++)
|
|
usedfaces[pNgon->m_fi[ff]] = true;
|
|
}
|
|
}
|
|
|
|
for ( int fi = 0; fi < face_count; fi++ )
|
|
{
|
|
if (true == usedfaces[fi])
|
|
continue;
|
|
|
|
onmalloc(0);//for canceling.
|
|
const ON_MeshTopologyFace& mesh_face = mesh_topology->m_topf[fi];
|
|
// NOTE: mesh_face.m_topei[0] ENDS at vertex fvi[0].
|
|
int fvi[4];
|
|
mesh_topology->GetTopFaceVertices( fi, fvi );
|
|
bool bTriangle = mesh_face.IsTriangle();
|
|
srf_3d_corner[0] = brep->m_V[fvi[0]].point;
|
|
srf_3d_corner[1] = brep->m_V[fvi[1]].point;
|
|
srf_3d_corner[2] = brep->m_V[fvi[2]].point;
|
|
if ( bTriangle )
|
|
{
|
|
if ( bTrimmedTriangles )
|
|
{
|
|
// trimmed triangle
|
|
srf_3d_corner[3] = srf_3d_corner[2] - srf_3d_corner[1] + srf_3d_corner[0];
|
|
}
|
|
else
|
|
{
|
|
// singular triangle
|
|
srf_3d_corner[3] = srf_3d_corner[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// quad
|
|
srf_3d_corner[3] = brep->m_V[fvi[3]].point;
|
|
}
|
|
|
|
ON_Surface* pSurface = ON_NurbsSurfaceQuadrilateral(
|
|
srf_3d_corner[0], srf_3d_corner[1],
|
|
srf_3d_corner[2], srf_3d_corner[3] );
|
|
|
|
if (nullptr == pSurface)
|
|
continue;
|
|
|
|
srf_dom[0] = pSurface->Domain(0);
|
|
srf_dom[1] = pSurface->Domain(1);
|
|
srf_2d_corner[0].Set( srf_dom[0][0], srf_dom[1][0], 0.0 ); // SW parameter space corner
|
|
srf_2d_corner[1].Set( srf_dom[0][1], srf_dom[1][0], 0.0 ); // SE parameter space corner
|
|
srf_2d_corner[2].Set( srf_dom[0][1], srf_dom[1][1], 0.0 ); // NE parameter space corner
|
|
srf_2d_corner[3].Set( srf_dom[0][0], srf_dom[1][1], 0.0 ); // NW parameter space corner
|
|
ON_BrepFace& face = brep->NewFace(brep->AddSurface(pSurface));
|
|
ON_BrepLoop& loop = brep->NewLoop( ON_BrepLoop::outer, face );
|
|
loop.m_pbox.m_min = srf_2d_corner[0];
|
|
loop.m_pbox.m_max = srf_2d_corner[2];
|
|
|
|
int edge_index;
|
|
int fei;
|
|
if ( bTriangle && bTrimmedTriangles )
|
|
{
|
|
// trimmed triangle
|
|
for ( int lti = 0; lti < 3; lti++ )
|
|
{
|
|
onmalloc(0);//for canceling.
|
|
fei = (lti+1)%3;
|
|
edge_index = mesh_face.m_topei[fei];
|
|
ON_BrepEdge& brep_edge = brep->m_E[edge_index];
|
|
// set the flag for vertex/edge we use and purge what isn't used when done.
|
|
brep_edge.m_edge_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[0]].m_vertex_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[1]].m_vertex_user.i = 1;
|
|
|
|
const ON_MeshTopologyEdge& mesh_edge = mesh_topology->m_tope[edge_index];
|
|
trim_line.SetCV(0,srf_2d_corner[lti]);
|
|
trim_line.SetCV(1,srf_2d_corner[(lti+1)%3]);
|
|
ON_Curve* pTrimCurve = new ON_NurbsCurve( trim_line );
|
|
int c2i = brep->AddTrimCurve( pTrimCurve );
|
|
ON_BrepTrim& trim = brep->NewTrim( brep_edge,
|
|
mesh_face.m_reve[fei]?true:false,
|
|
loop,
|
|
c2i );
|
|
trim.m__legacy_2d_tol = 0.0;
|
|
trim.m__legacy_3d_tol = 0.0;
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
trim.m_iso = tri_iso[lti];
|
|
trim.m_type = (mesh_edge.m_topf_count > 1) ? ON_BrepTrim::mated : ON_BrepTrim::boundary;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( int lti = 0; lti < 4; lti++ )
|
|
{
|
|
onmalloc(0);//for canceling.
|
|
trim_line.SetCV(0,srf_2d_corner[lti]);
|
|
trim_line.SetCV(1,srf_2d_corner[(lti+1)%4]);
|
|
ON_Curve* c2 = new ON_NurbsCurve( trim_line );
|
|
int c2i = brep->AddTrimCurve( c2 );
|
|
if ( bTriangle && lti == 3 )
|
|
{
|
|
// build a new singular edge
|
|
brep->NewSingularTrim( brep->m_V[fvi[0]],
|
|
loop,
|
|
quad_iso[lti],
|
|
c2i );
|
|
}
|
|
else
|
|
{
|
|
fei = bTriangle ? ((lti+1)%3) : ((lti+1)%4);
|
|
edge_index = mesh_face.m_topei[fei];
|
|
ON_BrepEdge& brep_edge = brep->m_E[edge_index];
|
|
// set the flag for vertex/edge we use and purge what isn't used when done.
|
|
brep_edge.m_edge_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[0]].m_vertex_user.i = 1;
|
|
brep->m_V[brep_edge.m_vi[1]].m_vertex_user.i = 1;
|
|
|
|
const ON_MeshTopologyEdge& mesh_edge = mesh_topology->m_tope[edge_index];
|
|
ON_BrepTrim& trim = brep->NewTrim( brep_edge,
|
|
mesh_face.m_reve[fei]?true:false,
|
|
loop,
|
|
c2i );
|
|
trim.m__legacy_2d_tol = 0.0;
|
|
trim.m__legacy_3d_tol = 0.0;
|
|
trim.m_tolerance[0] = 0.0;
|
|
trim.m_tolerance[1] = 0.0;
|
|
trim.m_iso = quad_iso[lti];
|
|
trim.m_type = (mesh_edge.m_topf_count > 1) ? ON_BrepTrim::mated : ON_BrepTrim::boundary;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// delete unused edges
|
|
int ee = 0, ect = brep->m_E.Count();
|
|
for (; ect > ee; ee++)
|
|
{
|
|
if (0 == brep->Edge(ee)->m_edge_user.i)
|
|
brep->DeleteEdge(*brep->Edge(ee), false);
|
|
}
|
|
|
|
// delete unused vertexes
|
|
int vv = 0, vct = brep->m_V.Count();
|
|
for (; vct > vv; vv++)
|
|
{
|
|
if (0 == brep->Vertex(vv)->m_vertex_user.i)
|
|
brep->DeleteVertex(*brep->Vertex(vv));
|
|
}
|
|
|
|
brep->Compact();
|
|
brep->SetTolerancesBoxesAndFlags(
|
|
false, //bool bLazy = false,
|
|
true, //bool bSetVertexTolerances = true,
|
|
true, //bool bSetEdgeTolerances = true,
|
|
true, //bool bSetTrimTolerances = true,
|
|
true, //bool bSetTrimIsoFlags = true,
|
|
true, //bool bSetTrimTypeFlags = true,
|
|
false, //bool bSetLoopTypeFlags = true,
|
|
true //bool bSetTrimBoxes = true
|
|
);
|
|
return brep;
|
|
}
|
|
|
|
|
|
//t0 and t1 will be indices into L.m_ti
|
|
static bool FoundSlitPair(const ON_BrepLoop& L, int* t0, int* t1)
|
|
|
|
{
|
|
ON_Brep* B = L.Brep();
|
|
if (!B) return false;
|
|
const ON_Surface* Srf = L.SurfaceOf();
|
|
double utol = 0.1*Srf->Domain(0).Length();
|
|
double vtol = 0.1*Srf->Domain(1).Length();
|
|
if (!Srf) return false;
|
|
int i, count = L.m_ti.Count();
|
|
for (i=0; i<count; i++){
|
|
int s0 = L.m_ti[i];
|
|
ON_BrepTrim& T0 = B->m_T[s0];
|
|
if (T0.m_type != ON_BrepTrim::seam) continue;
|
|
int s1 = (L.m_ti[(i+1)%count]);
|
|
ON_BrepTrim& T1 = B->m_T[s1];
|
|
if (T1.m_type != ON_BrepTrim::seam) continue;
|
|
if (T0.m_vi[0] != T1.m_vi[1]) continue;
|
|
if (T0.m_ei != T1.m_ei) continue;
|
|
const ON_BrepEdge& E = B->m_E[T0.m_ei];
|
|
if (E.m_ti.Count() != 2) continue;
|
|
ON_2dPoint P0, P1;
|
|
if (!B->GetTrim2dStart(s0, P0)) continue;
|
|
if (!B->GetTrim2dEnd(s1, P1)) continue;
|
|
if (fabs(P0[0] - P1[0]) > utol || fabs(P0[1] - P1[1]) > vtol) continue;
|
|
//*t0 = s0;
|
|
//*t1 = s1;
|
|
*t0 = i;
|
|
*t1 = (i+1)%count;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool ON_Brep::HasSlits(const ON_BrepLoop& L) const
|
|
|
|
{
|
|
if (L.m_loop_index < 0)
|
|
return false;
|
|
if (L.m_type == ON_BrepLoop::slit)
|
|
return true;
|
|
int t0, t1;
|
|
return FoundSlitPair(L, &t0, &t1);
|
|
}
|
|
|
|
bool ON_Brep::HasSlits(const ON_BrepFace& F) const
|
|
|
|
{
|
|
if (F.m_face_index < 0)
|
|
return false;
|
|
int i;
|
|
for (i=0; i<F.m_li.Count(); i++){
|
|
const ON_BrepLoop* pL = F.Loop(i);
|
|
if (!pL)
|
|
continue;
|
|
if (HasSlits(*pL))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ON_Brep::HasSlits() const
|
|
|
|
{
|
|
int i;
|
|
for (i=0; i<m_F.Count(); i++){
|
|
const ON_BrepFace& F = m_F[i];
|
|
if (HasSlits(F))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool MakeNurbClosed(ON_NurbsCurve& NC)
|
|
|
|
{
|
|
if (NC.IsLinear()) return false;
|
|
if (NC.CVCount() == 3){
|
|
double a[2];
|
|
if (NC.Order() == 3){
|
|
for (int i=0; i<2; i++) a[i] = NC.Domain().ParameterAt((double)i/3.0);
|
|
}
|
|
else { //order = 2;
|
|
for (int i=0; i<2; i++) a[i] = 0.5*(NC.Knot(i)+NC.Knot(i+1));
|
|
}
|
|
for (int i=0; i<2; i++) NC.InsertKnot(a[i], 1);
|
|
}
|
|
|
|
NC.ClampEnd(2);
|
|
ON_3dPoint P = 0.5*(NC.PointAtStart()+NC.PointAtEnd());
|
|
|
|
ON_4dPoint CV;
|
|
NC.GetCV(NC.CVCount()-1, CV);
|
|
CV[0] = P[0]*CV[3];
|
|
if (NC.Dimension() > 1)
|
|
CV[1] = P[1]*CV[3];
|
|
if (NC.Dimension() == 3)
|
|
CV[2] = P[2]*CV[3];
|
|
NC.SetCV(NC.CVCount()-1, CV);
|
|
|
|
NC.GetCV(0, CV);
|
|
CV[0] = P[0]*CV[3];
|
|
if (NC.Dimension() > 1)
|
|
CV[1] = P[1]*CV[3];
|
|
if (NC.Dimension() == 3)
|
|
CV[2] = P[2]*CV[3];
|
|
NC.SetCV(0, CV);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_Brep::MatchTrimEnds(ON_BrepTrim& T0,
|
|
ON_BrepTrim& T1
|
|
)
|
|
|
|
{
|
|
// Jan 28, 2009 - Lowell changed this to let any pair with any unset vertices through
|
|
// so it can work with loops that aren't completely done being built
|
|
if ( T0.m_vi[1] != T1.m_vi[0] && -1 != T0.m_vi[1] && -1 != T1.m_vi[0] )
|
|
return false;
|
|
|
|
// 6 June 2012 Dale Lear
|
|
// I changed from checking for the same face index to checking
|
|
// for the same loop index.
|
|
if ( T0.m_li != T1.m_li && -1 != T0.m_li && -1 != T1.m_li )
|
|
return false;
|
|
|
|
ON_2dPoint p0;
|
|
if (!GetTrim2dEnd(T0.m_trim_index, p0))
|
|
return false;
|
|
|
|
ON_2dPoint p1;
|
|
if (!GetTrim2dStart(T1.m_trim_index, p1))
|
|
return false;
|
|
|
|
if (p0 == p1)
|
|
return true;
|
|
|
|
// 6 June 2012 Dale Lear
|
|
// This makes no sense to me. I'm commenting it out.
|
|
//////const ON_Surface* pSrf = (T0.m_li >= 0) ? T0.SurfaceOf() : T1.SurfaceOf();
|
|
//////if (!pSrf)
|
|
////// return false;
|
|
//////if (fabs(p0[0] - p1[0]) > 0.1*pSrf->Domain(0).Length()
|
|
////// || fabs(p0[1] - p1[1]) > 0.1*pSrf->Domain(1).Length())
|
|
////// return true; //probably across a seam.
|
|
|
|
ON_NurbsCurve* nc0 = MakeTrimCurveNurb(T0);
|
|
if (0 == nc0)
|
|
return false;
|
|
ON_NurbsCurve* nc1 = (&T0 == &T1)
|
|
? nc0
|
|
: MakeTrimCurveNurb(T1);
|
|
if (0 == nc1)
|
|
return false;
|
|
|
|
if ( nc0 == nc1 )
|
|
{
|
|
bool rc = MakeNurbClosed(*nc0);
|
|
if (rc)
|
|
{
|
|
T0.m_pline.Destroy();
|
|
// the m_pbox will still be valid
|
|
T0.DestroyCurveTree();
|
|
}
|
|
}
|
|
|
|
ON_2dPoint p = 0.5*(p0+p1);
|
|
if ( p0.x == p1.x )
|
|
p.x = p0.x; // because x != 0.5*(x+x) for finite precision doubles
|
|
if ( p0.y == p1.y )
|
|
p.y = p0.y; // because y != 0.5*(y+y) for finite precision doubles
|
|
|
|
bool xiso0 = false, yiso0 = false, xiso1 = false, yiso1 = false;
|
|
|
|
if(T0.m_iso > ON_Surface::not_iso)
|
|
{
|
|
if(T0.m_iso % 2 == 1) xiso0 = true;
|
|
else yiso0 = true;
|
|
}
|
|
if(T1.m_iso > ON_Surface::not_iso)
|
|
{
|
|
if(T1.m_iso % 2 == 1) xiso1 = true;
|
|
else yiso1 = true;
|
|
}
|
|
|
|
if(xiso0 != xiso1 || yiso0 != yiso1) // not both xiso or both yiso
|
|
{
|
|
if(xiso0) p.x = p0.x;
|
|
if(yiso0) p.y = p0.y;
|
|
|
|
if(xiso1) p.x = p1.x;
|
|
if(yiso1) p.y = p1.y;
|
|
}
|
|
|
|
if (!nc0->SetEndPoint(ON_3dPoint(p)))
|
|
return false;
|
|
|
|
ON_BrepLoop* pLoop = T0.Loop();
|
|
if (pLoop && pLoop != T1.Loop())
|
|
pLoop = nullptr;
|
|
|
|
// clean up T1 flags and cached information
|
|
if(xiso0 && p0.x != p.x) T0.m_iso = ON_Surface::not_iso;
|
|
if(yiso0 && p0.y != p.y) T0.m_iso = ON_Surface::not_iso;
|
|
T0.m_pline.Destroy();
|
|
|
|
if ( T0.m_pbox.IsValid())
|
|
{
|
|
T0.m_pbox.Set( ON_3dPoint(p), true);
|
|
|
|
if (pLoop && pLoop->m_pbox.IsValid())
|
|
{
|
|
pLoop->m_pbox.Set(ON_3dPoint(p), true);
|
|
}
|
|
}
|
|
T0.DestroyCurveTree();
|
|
|
|
if (!nc1->SetStartPoint(ON_3dPoint(p)))
|
|
return false;
|
|
|
|
// clean up T1 flags and cached information
|
|
if(xiso1 && p1.x != p.x) T1.m_iso = ON_Surface::not_iso;
|
|
if(yiso1 && p1.y != p.y) T1.m_iso = ON_Surface::not_iso;
|
|
T1.m_pline.Destroy();
|
|
if ( T1.m_pbox.IsValid())
|
|
{
|
|
T1.m_pbox.Set( ON_3dPoint(p), true);
|
|
|
|
if (pLoop && pLoop->m_pbox.IsValid())
|
|
{
|
|
pLoop->m_pbox.Set(ON_3dPoint(p), true);
|
|
}
|
|
}
|
|
T1.DestroyCurveTree();
|
|
|
|
return true;
|
|
}
|
|
|
|
//match this trim to itsa next and prev in loop
|
|
bool ON_Brep::MatchTrimEnds(int trim_index)
|
|
|
|
{
|
|
if (trim_index < 0) return false;
|
|
ON_BrepTrim& T = m_T[trim_index];
|
|
if (T.m_li < 0) return false;
|
|
bool rc = true;
|
|
int pt = PrevTrim(trim_index);
|
|
if (pt >= 0) {
|
|
ON_BrepTrim& TP = m_T[pt];
|
|
if (!MatchTrimEnds(TP, T)) rc = false;
|
|
}
|
|
int nt = NextTrim(trim_index);
|
|
if (nt >= 0) {
|
|
ON_BrepTrim& TN = m_T[nt];
|
|
if (!MatchTrimEnds(T, TN)) rc = false;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Brep::MatchTrimEnds(ON_BrepLoop& Loop)
|
|
|
|
{
|
|
int i;
|
|
bool rc = true;
|
|
int count = Loop.m_ti.Count();
|
|
for (i=0; i<count; i++){
|
|
if (!MatchTrimEnds(m_T[Loop.m_ti[i]], m_T[Loop.m_ti[(i+1)%count]]))
|
|
{
|
|
rc = false;
|
|
}
|
|
}
|
|
|
|
// 11 Nov 2002 Dale Lear: I added this pbox setting stuff
|
|
Loop.m_pbox.Destroy();
|
|
for (i=0; i<count; i++)
|
|
{
|
|
ON_BrepTrim& trim = m_T[Loop.m_ti[i]];
|
|
trim.m_pbox.m_min.z = 0.0;
|
|
trim.m_pbox.m_max.z = 0.0;
|
|
Loop.m_pbox.Union( trim.m_pbox );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Brep::MatchTrimEnds()
|
|
|
|
{
|
|
bool rc = true;
|
|
for (int i=0; i<m_L.Count(); i++){
|
|
if (!MatchTrimEnds(m_L[i])) rc = false;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
//after calling this, m_C2[T.m_c2i] will be a nurbs curve only referenced by
|
|
//T, with domain = T.m_t.
|
|
ON_NurbsCurve* ON_Brep::MakeTrimCurveNurb(ON_BrepTrim& T)
|
|
|
|
{
|
|
// 11 Nov 2002 Dale Lear: I added the check to make sure we need to
|
|
// make a new NURBS curve
|
|
ON_NurbsCurve* nc = 0;
|
|
|
|
if ( T.m_c2i >= 0
|
|
&& T.m_c2i < m_C2.Count()
|
|
&& m_C2[T.m_c2i] == T.ProxyCurve()
|
|
&& T.ProxyCurveIsReversed() == false)
|
|
{
|
|
nc = ON_NurbsCurve::Cast(m_C2[T.m_c2i]);
|
|
if ( 0 != nc
|
|
&& T.ProxyCurveDomain() == nc->Domain()
|
|
&& 1 == TrimCurveUseCount( T.m_c2i, 2 ) )
|
|
{
|
|
// the trim's curve is OK.
|
|
return nc;
|
|
}
|
|
}
|
|
|
|
// get NURBS form
|
|
nc = new ON_NurbsCurve();
|
|
if ( !T.GetNurbForm(*nc) )
|
|
{
|
|
delete nc;
|
|
nc = 0;
|
|
}
|
|
else
|
|
{
|
|
nc->MakePiecewiseBezier();
|
|
T.m_c2i = AddTrimCurve(nc);
|
|
T.SetProxyCurve(nc);
|
|
//Dec 14 2010 - Chuck - this routine should not cause an iso to be not_iso.
|
|
//MakeTrimCuerveNurb is called in the middle of MatchTrimEnds() which uses m_iso.
|
|
//T.m_iso = ON_Surface::not_iso;
|
|
T.m_pline.Destroy();
|
|
T.m_pbox = nc->BoundingBox();
|
|
T.m_pbox.m_min.z = 0.0;
|
|
T.m_pbox.m_max.z = 0.0;
|
|
T.DestroyCurveTree();
|
|
}
|
|
|
|
return nc;
|
|
}
|
|
|
|
// Remove a slit pair found by FoundSlitPair. The Trims L.Trim(lti0) and L.Trim(lti1)
|
|
// will be removed, where L is If they are not consecutive in the loop
|
|
// a new loop will be created and will be returned in newloop, else newloop is returned as null.
|
|
// Returns false if an error was detected and the pair couldn't be deleted.
|
|
// Run compact afterward and delete the loop if it has been colapsed.
|
|
static
|
|
bool RemoveSlitPair(ON_Brep& B, int LI, int lti0, int lti1, ON_BrepLoop*& newloop)
|
|
{
|
|
bool rc = false;
|
|
ON_BrepLoop* L = B.Loop(LI);
|
|
newloop = nullptr;
|
|
int trim_count = L->TrimCount();
|
|
ON_ASSERT_OR_RETURN( lti0>=0 && lti0<trim_count, false );
|
|
ON_ASSERT_OR_RETURN( lti1>=0 && lti1<trim_count, false );
|
|
ON_ASSERT_OR_RETURN( lti0!=lti1, false );
|
|
ON_BrepFace* F = L->Face();
|
|
if( !F)
|
|
return rc;
|
|
if( LI<0 || LI>=B.m_L.Count())
|
|
return rc;
|
|
|
|
|
|
int delta = (lti0-lti1+trim_count)%trim_count;
|
|
|
|
if( delta == 1 || delta == trim_count-1){
|
|
// trims are consecutive. Just remove them
|
|
int s0 = L->Trim(lti0)->m_trim_index;
|
|
int s1 = L->Trim(lti1)->m_trim_index;
|
|
int pti = B.PrevTrim(s0);
|
|
int nti;
|
|
if (pti == s1){
|
|
pti = B.PrevTrim(s1);
|
|
nti = B.NextTrim(s0);
|
|
}
|
|
else
|
|
nti = B.NextTrim(s1);
|
|
|
|
// TRR#62112 crashed when the loop consist only of Trim(lti0) and Trim(lti1)
|
|
bool NextPrev =true; // true when pti and nti are distinct from s0 and s1
|
|
if( s0==pti || s1==pti)
|
|
NextPrev = false;
|
|
|
|
if( s0>=0 && s0<= B.m_T.Count() && s1>=0 && s1<= B.m_T.Count() ){
|
|
B.DeleteTrim(*B.Trim(s0), true);
|
|
B.DeleteTrim(*B.Trim(s1), true);
|
|
if (NextPrev && pti >= 0 && nti >= 0 && B.NextTrim(pti) == nti){
|
|
ON_BrepTrim& Tprev = B.m_T[pti];
|
|
ON_BrepTrim& Tnext = B.m_T[nti];
|
|
B.MatchTrimEnds( Tprev, Tnext );
|
|
|
|
// set m_type fields
|
|
// set m_pbox
|
|
B.SetTrimBoundingBoxes(*L);
|
|
}
|
|
|
|
rc = true;
|
|
}
|
|
}
|
|
else{
|
|
// Trims are not consecutive
|
|
// Split the existing loop into 2 loops
|
|
ON_BrepLoop::TYPE original_type = L->m_type;
|
|
if( original_type!=ON_BrepLoop::inner && original_type!=ON_BrepLoop::outer)
|
|
return false;
|
|
|
|
newloop = &B.NewLoop(original_type); // Check and possibly change the type later
|
|
L = B.Loop(LI); // Refresh L after possible reallocation of m_L array
|
|
if(lti0>lti1){
|
|
int temp = lti0;
|
|
lti0 = lti1;
|
|
lti1 = temp;
|
|
}
|
|
|
|
// remove slit trims from the loop
|
|
ON_BrepTrim& T0 = *L->Trim(lti0);
|
|
ON_BrepTrim& T1 = *L->Trim(lti1);
|
|
T0.m_li = -1;
|
|
T1.m_li = -1;
|
|
L->m_ti[lti0] = -1;
|
|
L->m_ti[lti1] = -1;
|
|
|
|
// build newloop->m_ti array by moving trims from L->m_ti
|
|
int lti, ltis;
|
|
for(lti=lti0+1; lti<lti1; lti++){
|
|
ON_BrepTrim* T = L->Trim(lti);
|
|
newloop->m_ti.Append( L->m_ti[lti] );
|
|
T->m_li = newloop->m_loop_index;
|
|
L->m_ti[lti] = -1;
|
|
}
|
|
|
|
for( lti = lti0, ltis = lti1+1 ; ltis<trim_count; lti++, ltis++)
|
|
L->m_ti[lti] = L->m_ti[ltis];
|
|
L->m_ti.SetCount(lti);
|
|
|
|
|
|
// Tune up newly adjacent trims to be sure they meet spot on.
|
|
newloop->m_fi = L->m_fi; // temporarily put the newloop on same face as old loop
|
|
ON_BrepTrim& Tstart = *newloop->Trim(0);
|
|
ON_BrepTrim& Tend = *newloop->Trim( newloop->TrimCount()-1);
|
|
B.MatchTrimEnds( Tend , Tstart );
|
|
|
|
int tc = L->TrimCount();
|
|
ON_BrepTrim& Tprev = *L->Trim( ( lti0 -1 + tc)%tc);
|
|
ON_BrepTrim& Tnext = *L->Trim( ( lti1+1)%tc) ;
|
|
B.MatchTrimEnds( Tprev, Tnext );
|
|
|
|
B.DeleteTrim(T0, true);
|
|
B.DeleteTrim(T1, true);
|
|
|
|
// set m_type fields
|
|
L->m_type = B.ComputeLoopType(*L);
|
|
newloop->m_type = B.ComputeLoopType(*newloop);
|
|
|
|
// set m_pbox
|
|
B.SetTrimBoundingBoxes(*L);
|
|
B.SetTrimBoundingBoxes(*newloop);
|
|
|
|
if( L->m_type==original_type && newloop->m_type==ON_BrepLoop::inner){
|
|
// Add new inner loop to original face
|
|
newloop->m_fi = L->m_fi;
|
|
F->m_li.Append(newloop->m_loop_index);
|
|
rc = true;
|
|
}
|
|
else if( L->m_type==original_type && newloop->m_type==ON_BrepLoop::outer){
|
|
// New loop is outer loop on a new face
|
|
ON_BrepFace& newface = B.NewFace( F->m_si );
|
|
F = nullptr; // F may no longer be a valid pointer because of array reallocation
|
|
newface.m_li.Append( newloop->m_loop_index);
|
|
newloop->m_fi = newface.m_face_index;
|
|
rc = true;
|
|
}
|
|
else if( original_type==ON_BrepLoop::inner &&
|
|
L->m_type== ON_BrepLoop::outer &&
|
|
newloop->m_type == ON_BrepLoop::inner)
|
|
{
|
|
// Add new inner loop to original face
|
|
newloop->m_fi = L->m_fi;
|
|
F->m_li.Append( newloop->m_loop_index );
|
|
|
|
// Remove L from *F. Move L to a new face
|
|
for(int fli=0; fli<F->LoopCount(); fli++)
|
|
if( F->m_li[fli]==L->m_loop_index ) {
|
|
F->m_li.Remove(fli);
|
|
break;
|
|
}
|
|
|
|
// Place L on a new face
|
|
ON_BrepFace& newface = B.NewFace( F->m_si );
|
|
F = nullptr; // F may no longer be a valid pointer because of array reallocation
|
|
newface.m_li.Append( L->m_loop_index);
|
|
L->m_fi = newface.m_face_index;
|
|
rc = true;
|
|
}
|
|
else if( original_type==ON_BrepLoop::outer &&
|
|
L->m_type== ON_BrepLoop::inner &&
|
|
newloop->m_type == ON_BrepLoop::outer)
|
|
{
|
|
// Add new outer loop to original face
|
|
newloop->m_fi = L->m_fi;
|
|
F->m_li.Insert(0,newloop->m_loop_index);
|
|
rc = true;
|
|
}
|
|
}
|
|
return rc;
|
|
|
|
}
|
|
|
|
bool ON_Brep::RemoveSlits(ON_BrepLoop& L)
|
|
|
|
{
|
|
bool rc = false;
|
|
bool rval = true;
|
|
const int li = L.m_loop_index;
|
|
|
|
int lti0, lti1;
|
|
while (rval && FoundSlitPair(*Loop(li), <i0, <i1)){
|
|
ON_BrepLoop* newloop = nullptr;
|
|
// Warning- This can add a loop and or face causing
|
|
// reallocation of arrays so refernces (like L) are
|
|
// no longer valid.
|
|
rval = RemoveSlitPair(*this, li, lti0, lti1, newloop);
|
|
rc = rc || rval;
|
|
if(rval && newloop)
|
|
RemoveSlits(*newloop);
|
|
}
|
|
|
|
// 22-Oct-2009 Crash Fix TRR#55897
|
|
if (Loop(li) && Loop(li)->m_ti.Count() == 0)
|
|
DeleteLoop(*Loop(li), true);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
bool ON_Brep::RemoveSlits(ON_BrepLoop& L)
|
|
|
|
{
|
|
if (L.m_loop_index < 0)
|
|
return false;
|
|
if (L.m_type == ON_BrepLoop::slit) {
|
|
DeleteLoop(L, true);
|
|
return true;
|
|
}
|
|
bool rc = false;
|
|
int t0, t1;
|
|
while (FoundSlitPair(L, &t0, &t1)){
|
|
rc = true;
|
|
DeleteTrim(m_T[t0], true);
|
|
DeleteTrim(m_T[t1], true);
|
|
}
|
|
if (L.m_ti.Count() == 0)
|
|
DeleteLoop(L, true);
|
|
return rc;
|
|
}
|
|
*/
|
|
|
|
bool ON_Brep::RemoveSlits(ON_BrepFace& F)
|
|
|
|
{
|
|
int i;
|
|
bool rc = false;
|
|
ON_SimpleArray<int> li = F.m_li;
|
|
for (i=0; i<li.Count(); i++){
|
|
ON_BrepLoop& L = m_L[li[i]];
|
|
if (L.m_loop_index != li[i])
|
|
continue;
|
|
if (RemoveSlits(L))
|
|
rc = true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
bool ON_Brep::RemoveSlits()
|
|
|
|
{
|
|
bool rc = false;
|
|
int i;
|
|
for (i=0; i<m_F.Count(); i++){
|
|
ON_BrepFace& F = m_F[i];
|
|
if (F.m_face_index != i) continue;
|
|
if (RemoveSlits(F))
|
|
rc = true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Brep::ChangeVertex( int old_vi, int new_vi, bool bClearTolerances )
|
|
{
|
|
if ( old_vi == new_vi )
|
|
return true;
|
|
|
|
ON_BrepVertex* old_v = Vertex(old_vi);
|
|
ON_BrepVertex* new_v = Vertex(new_vi);
|
|
|
|
if ( 0 == old_v )
|
|
return false;
|
|
if ( 0 == new_v )
|
|
return false;
|
|
if( old_v == new_v )
|
|
return true;
|
|
|
|
// clear type bits
|
|
old_vi = (int)(old_v - m_V.Array()); // the (int) is for 64 bit size_t conversion
|
|
new_vi = (int)(new_v - m_V.Array());
|
|
if ( old_vi == new_vi )
|
|
return true;
|
|
|
|
int vei, evi, eti, tvi, ei;
|
|
|
|
for ( vei = 0; vei < old_v->m_ei.Count(); vei++ )
|
|
{
|
|
ei = old_v->m_ei[vei];
|
|
ON_BrepEdge* edge = Edge( ei );
|
|
if ( 0 == edge )
|
|
continue;
|
|
// edges that start/end at the same vertex are listed twice in old_v->m_ei[].
|
|
if ( edge->m_vi[0] == old_v->m_vertex_index )
|
|
evi = 0;
|
|
else if ( edge->m_vi[1] == old_v->m_vertex_index )
|
|
evi = 1;
|
|
else
|
|
continue;
|
|
|
|
// connect edge to new vertex
|
|
new_v->m_ei.Append(ei);
|
|
edge->m_vi[evi] = new_vi;
|
|
if ( bClearTolerances )
|
|
{
|
|
edge->m_tolerance = ON_UNSET_VALUE;
|
|
new_v->m_tolerance = ON_UNSET_VALUE;
|
|
}
|
|
|
|
for ( eti = 0; eti < edge->m_ti.Count(); eti++ )
|
|
{
|
|
ON_BrepTrim* trim = Trim( edge->m_ti[eti]);
|
|
if ( 0 == trim )
|
|
continue;
|
|
tvi = trim->m_bRev3d ? 1-evi : evi;
|
|
trim->m_vi[tvi] = new_vi;
|
|
for(;;)
|
|
{
|
|
if ( 0 == tvi )
|
|
trim = Trim(PrevTrim(trim->m_trim_index));
|
|
else if ( 1 == tvi )
|
|
trim = Trim(NextTrim(trim->m_trim_index));
|
|
else
|
|
break;
|
|
|
|
if ( 0 == trim )
|
|
break;
|
|
|
|
if ( trim->m_ei >= 0 )
|
|
break; // not singular
|
|
|
|
if ( trim->m_vi[1-tvi] == old_vi )
|
|
trim->m_vi[1-tvi] = new_vi;
|
|
else
|
|
break;
|
|
|
|
if ( trim->m_vi[tvi] == old_vi )
|
|
trim->m_vi[tvi] = new_vi;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
old_v->m_ei.Destroy();
|
|
return true;
|
|
}
|
|
|
|
/* Obsolete. ON_Curve::SetStartPoint and SetEndPoint do the right thing.
|
|
bool ON_BrepEdge::SetStartPoint(ON_3dPoint start_point)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool ON_BrepEdge::SetEndPoint(ON_3dPoint end_point)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ON_BrepTrim::SetStartPoint(ON_3dPoint point)
|
|
{
|
|
if ( 0 == m_brep )
|
|
return false;
|
|
if ( point.x == ON_UNSET_VALUE || point.y == ON_UNSET_VALUE )
|
|
return false;
|
|
if ( m_c2i < 0 || m_c2i >= m_brep->m_C2.Count() )
|
|
return false;
|
|
const ON_Curve* c2 = m_brep->m_C2[m_c2i];
|
|
if ( 0 == c2 )
|
|
return false;
|
|
|
|
point.z = 0.0;
|
|
ON_Interval domain = Domain();
|
|
ON_3dPoint q = PointAtStart();
|
|
q.z = 0;
|
|
if ( point != q )
|
|
{
|
|
|
|
ON_NurbsCurve* nc2 = 0;
|
|
if ( ProxyCurveDomain() == c2->Domain() && !ProxyCurveIsReversed() )
|
|
nc2 = ON_NurbsCurve::Cast(c2);
|
|
int use_count = (0 != nc2 ) ? m_brep->TrimCurveUseCount(m_c2i,2) : 0;
|
|
if ( 0 == nc2 || use_count )
|
|
{
|
|
nc2 = NurbsCurve();
|
|
if ( 0 == nc2 )
|
|
return false;
|
|
}
|
|
nc2->ClampEnd();
|
|
nc2->SetDomain(domain[0],domain[1]);
|
|
if ( nc2->GetLocalClosestPoint( point, domain[0], &t ) )
|
|
{
|
|
nc2->Trim( ON_Interval(t,domain[1] );
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ON_BrepTrim::SetEndPoint(ON_3dPoint end_point)
|
|
{
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
|
|
bool ON_Brep::CloseTrimGap( ON_BrepTrim& trim0, ON_BrepTrim& trim1 )
|
|
{
|
|
|
|
// carefully close gap between end of prev_trim and start of next_trim
|
|
|
|
// make sure trim0 and trim1 are adjacent trims in a trimming loop
|
|
if ( trim0.m_vi[1] != trim1.m_vi[0] )
|
|
return false;
|
|
if ( trim0.m_li != trim1.m_li )
|
|
return false;
|
|
if ( trim0.m_li < 0 || trim0.m_li >= m_L.Count() )
|
|
return false;
|
|
ON_BrepLoop& loop = m_L[trim0.m_li];
|
|
int lti;
|
|
if ( loop.m_ti.Count() == 1 && trim0.m_trim_index == trim1.m_trim_index )
|
|
{
|
|
if ( trim0.IsClosed() )
|
|
return true;
|
|
lti = 0;
|
|
}
|
|
else
|
|
{
|
|
for ( lti = 0; lti < loop.m_ti.Count(); lti++ )
|
|
{
|
|
if ( loop.m_ti[lti] == trim0.m_trim_index && loop.m_ti[(lti+1)%loop.m_ti.Count()] == trim1.m_trim_index )
|
|
break;
|
|
}
|
|
}
|
|
if ( lti >= loop.m_ti.Count() )
|
|
return false;
|
|
|
|
// determine where trims end and where they should meet.
|
|
ON_Interval domain0 = trim0.Domain();
|
|
ON_Interval domain1 = trim1.Domain();
|
|
double t0 = domain0[1];
|
|
double t1 = domain1[0];
|
|
ON_3dPoint p0, p1;
|
|
trim0.EvPoint( t0, p0 );
|
|
trim1.EvPoint( t1, p1 );
|
|
p0.z = 0.0;
|
|
p1.z = 0.0;
|
|
ON_3dPoint p = ON_Line(p0,p1).PointAt(0.5);
|
|
if ( p0.x == p1.x )
|
|
p.x = p0.x;
|
|
if ( p0.y == p1.y )
|
|
p.y = p0.y;
|
|
|
|
int coord0_lock = -1;
|
|
int coord1_lock = -1;
|
|
switch(trim0.m_iso)
|
|
{
|
|
case ON_Surface::x_iso:
|
|
case ON_Surface::W_iso:
|
|
case ON_Surface::E_iso:
|
|
// vertical iso curve - lock x coordinate
|
|
coord0_lock = 0;
|
|
break;
|
|
case ON_Surface::y_iso:
|
|
case ON_Surface::S_iso:
|
|
case ON_Surface::N_iso:
|
|
// horizontal iso curve - lock y coordinate
|
|
coord0_lock = 1;
|
|
break;
|
|
default:
|
|
coord0_lock = -1;
|
|
}
|
|
|
|
switch(trim1.m_iso)
|
|
{
|
|
case ON_Surface::x_iso:
|
|
case ON_Surface::W_iso:
|
|
case ON_Surface::E_iso:
|
|
// vertical iso curve - lock x coordinate
|
|
coord1_lock = 0;
|
|
switch(coord0_lock)
|
|
{
|
|
case 0:
|
|
if ( ON_Surface::x_iso == trim0.m_iso && ON_Surface::x_iso != trim1.m_iso )
|
|
p.x = p1.x; // trim1 is on surface edge
|
|
else if ( ON_Surface::x_iso != trim0.m_iso && ON_Surface::x_iso == trim1.m_iso )
|
|
p.x = p0.x; // trim0 is on surface edge
|
|
else
|
|
{
|
|
// longest one wins
|
|
if ( p0.DistanceTo(trim0.PointAtStart()) >= p1.DistanceTo(trim1.PointAtEnd()) )
|
|
p.x = p0.x;
|
|
else
|
|
p.x = p1.x;
|
|
}
|
|
break;
|
|
case 1:
|
|
p.x = p1.x;
|
|
p.y = p0.y;
|
|
break;
|
|
default:
|
|
p.x = p1.x;
|
|
break;
|
|
}
|
|
break;
|
|
case ON_Surface::y_iso:
|
|
case ON_Surface::S_iso:
|
|
case ON_Surface::N_iso:
|
|
// horizontal iso curve - lock y coordinate
|
|
coord1_lock = 1;
|
|
switch(coord0_lock)
|
|
{
|
|
case 0:
|
|
p.x = p0.x;
|
|
p.y = p1.y;
|
|
break;
|
|
case 1:
|
|
if ( ON_Surface::x_iso == trim0.m_iso && ON_Surface::x_iso != trim1.m_iso )
|
|
p.y = p1.y; // trim1 is on surface edge
|
|
else if ( ON_Surface::x_iso != trim0.m_iso && ON_Surface::x_iso == trim1.m_iso )
|
|
p.y = p0.y; // trim0 is on surface edge
|
|
else
|
|
{
|
|
// longest one wins
|
|
if ( p0.DistanceTo(trim0.PointAtStart()) >= p1.DistanceTo(trim1.PointAtEnd()) )
|
|
p.y = p0.y;
|
|
else
|
|
p.y = p1.y;
|
|
}
|
|
break;
|
|
default:
|
|
p.x = p1.x;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch(coord0_lock)
|
|
{
|
|
case 0:
|
|
p.x = p0.x;
|
|
break;
|
|
case 1:
|
|
p.y = p0.y;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ON_ComparePoint(3,0,&p.x,&p0.x))
|
|
{
|
|
trim0.SetEndPoint(p);
|
|
}
|
|
if (ON_ComparePoint(3,0,&p.x,&p1.x))
|
|
{
|
|
trim1.SetStartPoint(p);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_Brep::CollapseEdge( int edge_index, bool bCloseTrimGap, int vertex_index )
|
|
{
|
|
ON_BrepEdge* edge = Edge(edge_index);
|
|
if ( 0 == edge )
|
|
return false;
|
|
edge_index = edge->m_edge_index; // clear high bit
|
|
|
|
int orig_vid0 = edge->m_vi[0];
|
|
int orig_vid1 = edge->m_vi[1];
|
|
|
|
if ( -1 == vertex_index )
|
|
vertex_index = edge->m_vi[0];
|
|
ON_BrepVertex* vertex = Vertex(vertex_index);
|
|
if ( 0 == vertex )
|
|
return false;
|
|
vertex_index = vertex->m_vertex_index; // clear high bit
|
|
|
|
int trim_count = edge->m_ti.Count();
|
|
if ( trim_count > 0 )
|
|
{
|
|
ON_SimpleArray<int> ti(trim_count);
|
|
ON_SimpleArray<int> li(trim_count);
|
|
ON_SimpleArray<int> prev_ti(trim_count);
|
|
ON_SimpleArray<int> next_ti(trim_count);
|
|
int i, eti;
|
|
for ( eti = 0; eti < trim_count; eti++ )
|
|
{
|
|
i = edge->m_ti[eti];
|
|
if ( i < 0 || i >= m_T.Count() )
|
|
continue;
|
|
const ON_BrepTrim& trim = m_T[i];
|
|
if ( trim.m_trim_index != i )
|
|
return false;
|
|
if ( trim.m_li < 0 || trim.m_li >= m_L.Count() )
|
|
return false;
|
|
i = PrevTrim(trim.m_trim_index);
|
|
if ( i < 0 || i == trim.m_trim_index )
|
|
return false;
|
|
prev_ti.Append(i);
|
|
i = NextTrim(trim.m_trim_index);
|
|
if ( i < 0 || i == trim.m_trim_index )
|
|
return false;
|
|
next_ti.Append(i);
|
|
ti.Append(trim.m_trim_index);
|
|
li.Append(trim.m_li);
|
|
}
|
|
|
|
ChangeVertex(edge->m_vi[0], vertex_index, true);
|
|
ChangeVertex(edge->m_vi[1], vertex_index, true);
|
|
|
|
trim_count = ti.Count();
|
|
for ( eti = 0; eti < trim_count; eti++ )
|
|
{
|
|
i = ti[eti];
|
|
ON_BrepTrim& trim = m_T[i];
|
|
//ON_BrepLoop& loop = m_L[li[eti]];
|
|
ON_BrepTrim& prev_trim = m_T[prev_ti[eti]];
|
|
ON_BrepTrim& next_trim = m_T[next_ti[eti]];
|
|
DeleteTrim(trim,false);
|
|
if ( bCloseTrimGap )
|
|
CloseTrimGap(prev_trim,next_trim);
|
|
}
|
|
}
|
|
|
|
DeleteEdge(*edge,false);
|
|
ON_BrepVertex* V0 = Vertex(orig_vid0);
|
|
if (V0 && V0->EdgeCount() == 0)
|
|
DeleteVertex(*V0);
|
|
ON_BrepVertex* V1 = Vertex(orig_vid1);
|
|
if (V1 && V1->EdgeCount() == 0)
|
|
DeleteVertex(*V1);
|
|
return true;
|
|
}
|
|
|
|
int ON_Brep::RemoveWireEdges( bool bDeleteVertices )
|
|
{
|
|
int rc = 0;
|
|
int ei, count = m_E.Count();
|
|
for ( ei = 0; ei < count; ei++ )
|
|
{
|
|
if ( ei == m_E[ei].m_edge_index && 0 == m_E[ei].m_ti.Count() )
|
|
{
|
|
rc++;
|
|
DeleteEdge( m_E[ei], bDeleteVertices );
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int ON_Brep::RemoveWireVertices()
|
|
{
|
|
int rc = 0;
|
|
int vi, count = m_V.Count();
|
|
for ( vi = 0; vi < count; vi++ )
|
|
{
|
|
if ( vi == m_V[vi].m_vertex_index && 0 == m_V[vi].m_ei.Count() )
|
|
{
|
|
rc++;
|
|
DeleteVertex( m_V[vi] );
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
bool ON_Brep::RemoveNesting(
|
|
bool bExtractSingleSegments,
|
|
bool bEdges,
|
|
bool bTrimCurves
|
|
)
|
|
{
|
|
bool rc = false;
|
|
// TODO
|
|
int i, count;
|
|
ON_PolyCurve* polycurve;
|
|
|
|
if ( bEdges )
|
|
{
|
|
count = m_C3.Count();
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
polycurve = ON_PolyCurve::Cast(m_C3[i]);
|
|
if ( 0 != polycurve )
|
|
{
|
|
if ( polycurve->RemoveNesting() )
|
|
rc = true;
|
|
if ( bExtractSingleSegments && 1 == polycurve->Count() )
|
|
{
|
|
// TODO - extract segment and update edge's proxy information
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bTrimCurves )
|
|
{
|
|
count = m_C2.Count();
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
polycurve = ON_PolyCurve::Cast(m_C2[i]);
|
|
if ( 0 != polycurve )
|
|
{
|
|
if ( polycurve->RemoveNesting() )
|
|
rc = true;
|
|
if ( bExtractSingleSegments && 1 == polycurve->Count() )
|
|
{
|
|
// TODO - extract segment and update trims's proxy information
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static bool IsSlitTrim(const ON_BrepTrim& T)
|
|
|
|
{
|
|
int tid = T.m_trim_index;
|
|
if (tid < 0)
|
|
return false;
|
|
|
|
const ON_BrepLoop* pL = T.Loop();
|
|
if (!pL)
|
|
return false;
|
|
|
|
const ON_Brep* pB = T.Brep();
|
|
if (!pB)
|
|
return false;
|
|
|
|
const ON_BrepEdge* pE = T.Edge();
|
|
if (!pE || pE->m_edge_index < 0 || pE->m_ti.Count() != 2)
|
|
return false;
|
|
|
|
int atid = (pE->m_ti[0] == tid) ? pE->m_ti[1] : pE->m_ti[0];
|
|
if (atid < 0)
|
|
return false;
|
|
|
|
const ON_BrepTrim& AT = pB->m_T[atid];
|
|
if (AT.m_trim_index < 0)
|
|
return false;
|
|
|
|
if (AT.Loop() != pL)
|
|
return false;
|
|
|
|
const ON_Surface* pSrf = T.SurfaceOf();
|
|
if (!pSrf)
|
|
return false;
|
|
|
|
double utol = 0.25*pSrf->Domain(0).Length();
|
|
double vtol = 0.25*pSrf->Domain(1).Length();
|
|
|
|
bool bRev = (T.m_bRev3d == AT.m_bRev3d) ? false : true;
|
|
|
|
ON_2dPoint P(T.PointAtStart());
|
|
ON_2dPoint AP((bRev) ? AT.PointAtEnd() : AT.PointAtStart());
|
|
|
|
if (fabs(P[0] - AP[0]) > utol)
|
|
return false;
|
|
if (fabs(P[1] - AP[1]) > vtol)
|
|
return false;
|
|
|
|
P = T.PointAtEnd();
|
|
AP = (bRev) ? AT.PointAtStart() : AT.PointAtEnd();
|
|
|
|
if (fabs(P[0] - AP[0]) > utol)
|
|
return false;
|
|
if (fabs(P[1] - AP[1]) > vtol)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ON_BrepRemoveSlits(ON_BrepLoop& L)
|
|
|
|
{
|
|
if (L.m_loop_index < 0)
|
|
return false;
|
|
ON_BrepFace* pF = L.Face();
|
|
if (!pF)
|
|
return false;
|
|
ON_Brep* pB = L.Brep();
|
|
if (!pB)
|
|
return false;
|
|
//Check if anything or everything can be removed.
|
|
ON_SimpleArray<bool> bIsSlit(L.m_ti.Count());
|
|
ON_SimpleArray<int> slits(L.m_ti.Count());
|
|
bool all_slits = true;
|
|
bool some_slits = false;
|
|
int tcount = L.m_ti.Count();
|
|
int i;
|
|
for (i=0; i<tcount; i++){
|
|
ON_BrepTrim& T = pB->m_T[L.m_ti[i]];
|
|
if (IsSlitTrim(T)){
|
|
bIsSlit.Append(true);
|
|
slits.Append(T.m_trim_index);
|
|
some_slits = true;
|
|
}
|
|
else {
|
|
bIsSlit.Append(false);
|
|
all_slits = false;
|
|
}
|
|
}
|
|
|
|
if (all_slits){
|
|
pB->DeleteLoop(L, true);
|
|
return true;
|
|
}
|
|
|
|
if (!some_slits)
|
|
return false;
|
|
|
|
ON_SimpleArray<bool> bUsed = bIsSlit;
|
|
|
|
ON_ClassArray<ON_SimpleArray<int> > NewLoops;
|
|
|
|
//bool done = false;
|
|
int b = 0;
|
|
while (b < tcount){
|
|
int start_trim = -1;
|
|
for (i=0; i<tcount; i++){
|
|
if (!bUsed[i]){
|
|
start_trim = i;
|
|
break;
|
|
}
|
|
}
|
|
if (start_trim < 0)
|
|
break;
|
|
ON_SimpleArray<int>& nl = NewLoops.AppendNew();
|
|
b++;
|
|
nl.Append(start_trim);
|
|
bUsed[start_trim] = true;
|
|
int next_trim = (start_trim+1)%tcount;
|
|
int c = 0;
|
|
while (c < tcount){
|
|
if (!bUsed[next_trim]){
|
|
nl.Append(next_trim);
|
|
bUsed[next_trim] = true;
|
|
next_trim = (next_trim+1)%tcount;
|
|
c++;
|
|
continue;
|
|
}
|
|
if (next_trim == start_trim)
|
|
break;
|
|
if (bIsSlit[next_trim]){
|
|
int this_trim = next_trim;
|
|
ON_BrepTrim& T = pB->m_T[L.m_ti[next_trim]];
|
|
ON_BrepEdge* pE = T.Edge();
|
|
int atid = (pE->m_ti[0] == T.m_trim_index) ? pE->m_ti[1] : pE->m_ti[0];
|
|
next_trim = -1;
|
|
for (i=0; i<tcount; i++){
|
|
if (L.m_ti[i] == atid){
|
|
next_trim = i;
|
|
break;
|
|
}
|
|
}
|
|
if (next_trim == -1)
|
|
return false;
|
|
if (next_trim > this_trim)
|
|
c += next_trim - this_trim;
|
|
else c += tcount - this_trim + next_trim;
|
|
next_trim = (next_trim+1)%tcount;
|
|
c++;
|
|
}
|
|
}
|
|
if (c >= tcount)
|
|
return false;
|
|
}
|
|
if (b >= tcount)
|
|
return false;
|
|
|
|
for (i=0; i<NewLoops.Count(); i++){
|
|
ON_SimpleArray<int>& nl = NewLoops[i];
|
|
int j;
|
|
for (j=0; j<nl.Count(); j++)
|
|
nl[j] = L.m_ti[nl[j]];
|
|
}
|
|
|
|
bool bOuter = (L.m_type == ON_BrepLoop::outer) ? true : false;
|
|
|
|
for (i=0; i<slits.Count(); i++){
|
|
ON_BrepTrim& T = pB->m_T[slits[i]];
|
|
T.m_li = -1;
|
|
pB->DeleteTrim(T, true);
|
|
}
|
|
|
|
//int loop_count = pB->m_L.Count();
|
|
|
|
L.m_ti.SetCount(0);
|
|
pB->DeleteLoop(L, true);
|
|
|
|
for (i=0; i<NewLoops.Count(); i++){
|
|
ON_BrepLoop& nL = pB->NewLoop(ON_BrepLoop::unknown, *pF);
|
|
ON_SimpleArray<int>& nl = NewLoops[i];
|
|
nL.m_ti = nl;
|
|
int j;
|
|
for (j=0; j<nl.Count(); j++){
|
|
ON_BrepTrim& T = pB->m_T[nl[j]];
|
|
T.m_li = nL.m_loop_index;
|
|
}
|
|
nL.m_type = pB->ComputeLoopType(nL);
|
|
if (bOuter && nL.m_type == ON_BrepLoop::outer){
|
|
int a = pF->m_li[0];
|
|
pF->m_li[0] = nL.m_loop_index;
|
|
for (j=pF->m_li.Count()-1; j>0; j--){
|
|
if (pF->m_li[j] == nL.m_loop_index){
|
|
pF->m_li[j] = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pB->MatchTrimEnds(nL);
|
|
pB->SetTrimBoundingBoxes(nL, true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//This removes all slit trims from F that are not joined to another face.
|
|
//Unlike ON_Brep::RemoveSlits(), this will remove slit pairs from a loop in cases
|
|
//that will result in the creation of more loops. Caller is responsible for calling
|
|
//ON_Brep::Compact() to get rid of deleted trims and loops.
|
|
|
|
bool ON_BrepRemoveSlits(ON_BrepFace& F)
|
|
|
|
{
|
|
//For each loop, look for slit pairs that fall between non slits and
|
|
//break the loop at the pair.
|
|
//After all loops have been split, call ON_Brep::RemoveSlits() on the result.
|
|
|
|
if (F.m_face_index < 0)
|
|
return false;
|
|
ON_Brep* pB = F.Brep();
|
|
if (!pB)
|
|
return false;
|
|
bool rc = false;
|
|
int loop_count = F.m_li.Count();
|
|
int i;
|
|
for (i=0; i<loop_count; i++){
|
|
ON_BrepLoop& L = pB->m_L[F.m_li[i]];
|
|
if (L.m_loop_index < 0)
|
|
continue;
|
|
if (ON_BrepRemoveSlits(L))
|
|
rc = true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
static void CreateNewTrimList(const ON_BrepLoop& L0, int tid0,//into L0.m_ti
|
|
const ON_BrepLoop& L1, int tid1,//into L1.m_ti
|
|
ON_SimpleArray<int>& new_tids //into brep.m_T
|
|
)
|
|
|
|
{
|
|
new_tids.Reserve(L0.m_ti.Count() + L1.m_ti.Count() - 2);
|
|
|
|
int count = L0.m_ti.Count();
|
|
int i;
|
|
for (i=0; i<count-1; i++)
|
|
new_tids.Append(L0.m_ti[(tid0+1+i)%count]);
|
|
|
|
count = L1.m_ti.Count();
|
|
for (i=0; i<count-1; i++)
|
|
new_tids.Append(L1.m_ti[(tid1+1+i)%count]);
|
|
|
|
return;
|
|
}
|
|
|
|
int ON_BrepMergeFaces(ON_Brep& B, int fid0, int fid1)
|
|
|
|
{
|
|
if (fid0 == fid1)
|
|
return -1;
|
|
|
|
if (fid0 < 0 || fid0 >= B.m_F.Count())
|
|
return -1;
|
|
ON_BrepFace& F0 = B.m_F[fid0];
|
|
if (F0.m_face_index < 0)
|
|
return -1;
|
|
|
|
if (fid1 < 0 || fid1 >= B.m_F.Count())
|
|
return -1;
|
|
ON_BrepFace& F1 = B.m_F[fid1];
|
|
if (F1.m_face_index < 0)
|
|
return -1;
|
|
|
|
if (F0.m_si != F1.m_si)
|
|
return -1;
|
|
|
|
//Find a manifold edge that joins the two faces and combine the loops by removing
|
|
//the trims at that edge.
|
|
|
|
ON_BrepEdge* pE = 0;
|
|
|
|
int li;
|
|
int tid0 = -1, tid1 = -1;
|
|
for (li=0; li<F0.m_li.Count() && !pE; li++){
|
|
ON_BrepLoop& L = B.m_L[F0.m_li[li]];
|
|
int ti;
|
|
for (ti=0; ti<L.m_ti.Count() && !pE; ti++){
|
|
ON_BrepTrim& T0 = B.m_T[L.m_ti[ti]];
|
|
ON_BrepEdge* pEE = T0.Edge();
|
|
if (!pEE || pEE->m_ti.Count() != 2)
|
|
continue;
|
|
tid0 =T0.m_trim_index;
|
|
tid1 = (pEE->m_ti[0] == tid0) ? pEE->m_ti[1] : pEE->m_ti[0];
|
|
if (tid0 < 0 || tid1 < 0)
|
|
continue;
|
|
ON_BrepTrim& T1 = B.m_T[tid1];
|
|
if (T1.FaceIndexOf() == fid1 && T0.m_bRev3d != T1.m_bRev3d
|
|
&& T0.m_iso == T1.m_iso){//Don't combine across seams.
|
|
pE = pEE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pE || tid0 < 0 || tid1 < 0)
|
|
return -1;
|
|
|
|
ON_BrepTrim& T0 = B.m_T[tid0];
|
|
ON_BrepTrim& T1 = B.m_T[tid1];
|
|
|
|
int lid0 = T0.m_li;
|
|
if (lid0 < 0)
|
|
return -1;
|
|
ON_BrepLoop& L0 = B.m_L[lid0];
|
|
if (L0.m_loop_index < 0)
|
|
return -1;
|
|
if (L0.Face() != &F0)
|
|
return -1;
|
|
int i;
|
|
int ti0 = -1;
|
|
for (i=0; i<L0.m_ti.Count(); i++){
|
|
const ON_BrepTrim& T = B.m_T[L0.m_ti[i]];
|
|
if (T.m_trim_index == tid0){
|
|
ti0 = i;
|
|
break;
|
|
}
|
|
}
|
|
if (ti0 < 0)
|
|
return -1;
|
|
|
|
int lid1 = T1.m_li;
|
|
if (lid1 < 0)
|
|
return -1;
|
|
ON_BrepLoop& L1 = B.m_L[lid1];
|
|
if (L1.m_loop_index < 0)
|
|
return -1;
|
|
if (L1.Face() != &F1)
|
|
return -1;
|
|
int ti1 = -1;
|
|
for (i=0; i<L1.m_ti.Count(); i++){
|
|
const ON_BrepTrim& T = B.m_T[L1.m_ti[i]];
|
|
if (T.m_trim_index == tid1){
|
|
ti1 = i;
|
|
break;
|
|
}
|
|
}
|
|
if (ti1 < 0)
|
|
return -1;
|
|
|
|
|
|
ON_SimpleArray<int> new_tids;
|
|
CreateNewTrimList(L0, ti0, L1, ti1, new_tids);
|
|
|
|
ON_BrepLoop* pL;
|
|
ON_BrepLoop* pD;
|
|
ON_BrepFace* pF;
|
|
ON_BrepFace* pDF;
|
|
int rc;
|
|
if (L1.m_type != ON_BrepLoop::inner){
|
|
pL = &L0;
|
|
pD = &L1;
|
|
rc = fid0;
|
|
pF = &F0;
|
|
pDF = &F1;
|
|
}
|
|
else {
|
|
pL = &L1;
|
|
pD = &L0;
|
|
rc = fid1;
|
|
pF = &F1;
|
|
pDF = &F0;
|
|
}
|
|
pL->m_ti = new_tids;
|
|
pL->m_pbox.Destroy();
|
|
pD->m_ti.SetCount(0);
|
|
T0.m_li = -1;
|
|
T1.m_li = -1;
|
|
B.DeleteTrim(T0, true);
|
|
B.DeleteTrim(T1, true);
|
|
B.DeleteLoop(*pD, true);
|
|
for (i=0; i<pL->m_ti.Count(); i++)
|
|
B.m_T[pL->m_ti[i]].m_li = pL->m_loop_index;
|
|
|
|
B.MatchTrimEnds(*pL);
|
|
|
|
for (i=0; i<pDF->m_li.Count(); i++){
|
|
ON_BrepLoop& ML = B.m_L[pDF->m_li[i]];
|
|
ML.m_fi = rc;
|
|
pF->m_li.Append(ML.m_loop_index);
|
|
}
|
|
pDF->m_li.SetCount(0);
|
|
B.DeleteFace(*pDF, true);
|
|
const ON_Surface* pSrf = B.m_F[rc].SurfaceOf();
|
|
if (pSrf->IsClosed(0) || pSrf->IsClosed(1))
|
|
B.SetTrimTypeFlags(B.m_F[rc]);//Some mateds may have become seams.
|
|
ON_BrepRemoveSlits(B.m_F[rc]);
|
|
|
|
B.SetTrimBoundingBoxes(B.m_F[rc], true);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
typedef int srf_face[2];
|
|
|
|
static int sfsort(const srf_face* a, const srf_face* b)
|
|
{
|
|
if ((*a)[0] < (*b)[0])
|
|
return -1;
|
|
if ((*b)[0] < (*a)[0])
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
bool ON_BrepMergeFaces(ON_Brep& B)
|
|
|
|
{
|
|
bool rc = false;
|
|
ON_SimpleArray<srf_face> SF(B.m_F.Count());
|
|
int i;
|
|
for (i=0; i<B.m_F.Count(); i++){
|
|
const ON_BrepFace& F = B.m_F[i];
|
|
if (F.m_face_index < 0)
|
|
continue;
|
|
if (F.m_si < 0)
|
|
continue;
|
|
srf_face& sf = SF.AppendNew();
|
|
sf[0] = F.m_si;
|
|
sf[1] = i;
|
|
}
|
|
if (SF.Count() < 2)
|
|
return false;
|
|
SF.QuickSort(sfsort);
|
|
//int si = SF[0][0];
|
|
int start_i = 0;
|
|
while (start_i<SF.Count()){
|
|
int next_i = start_i+1;
|
|
while (next_i<SF.Count() && SF[next_i][0] == SF[start_i][0])
|
|
next_i++;
|
|
if (next_i == start_i+1){
|
|
start_i++;
|
|
continue;
|
|
}
|
|
for (i=start_i; i<next_i-1; i++){
|
|
int j;
|
|
for (j=i+1; j<next_i; j++){
|
|
int new_id = ON_BrepMergeFaces(B, SF[i][1], SF[j][1]);
|
|
if (new_id < 0)
|
|
continue;
|
|
SF[j][1] = new_id;
|
|
rc = true;
|
|
break;
|
|
}
|
|
}
|
|
start_i = next_i;
|
|
}
|
|
|
|
ON_BrepMergeAllEdges(B);
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int MergeAdjacentEdge(ON_Brep& B, int eid)
|
|
|
|
{
|
|
ON_BrepEdge& E = B.m_E[eid];
|
|
if (!E.IsValid())
|
|
return -1;
|
|
|
|
/*
|
|
if (E.m_edge_user.i >= 0)
|
|
return -1;
|
|
*/
|
|
|
|
if (E.m_ti.Count() == 0)
|
|
return -1;
|
|
|
|
int i;
|
|
for (i=0; i<2; i++){
|
|
int neid = B.NextEdge(eid, i);
|
|
if (neid >= 0){
|
|
ON_BrepEdge* pE = B.CombineContiguousEdges(eid, neid);
|
|
if (pE)
|
|
return pE->m_edge_index;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//Merges all possible edges
|
|
void ON_BrepMergeAllEdges(ON_Brep& B)
|
|
|
|
{
|
|
int i;
|
|
int count = B.m_E.Count();
|
|
for (i=0; i<count; i++){
|
|
int eid = i;
|
|
int j = 0;
|
|
while (eid >= 0 && j < count){
|
|
eid = MergeAdjacentEdge(B, eid);
|
|
j++;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//returns false if a naked edge is found.
|
|
static bool OrderEdgesAroundClosedVertex(const ON_Brep& B, int vid, ON_2dex* trim_ends)
|
|
|
|
{
|
|
if (vid<0)
|
|
return false;
|
|
const ON_BrepVertex& V = B.m_V[vid];
|
|
if (V.m_vertex_index < 0)
|
|
return false;
|
|
if (V.m_ei.Count() < 1)
|
|
return false;
|
|
//trim_ends.SetCount(0);
|
|
//trim_ends.Reserve(V.m_ei.Count());
|
|
ON_2dex& first_te = trim_ends[0];
|
|
const ON_BrepEdge& FirstEdge = B.m_E[V.m_ei[0]];
|
|
if (FirstEdge.m_ti.Count() != 2)
|
|
return false;
|
|
first_te.i = FirstEdge.m_ti[0];
|
|
const ON_BrepTrim& FirstTrim = B.m_T[FirstEdge.m_ti[0]];
|
|
int first_edge_end = (FirstEdge.m_vi[0] == vid) ? 0 : 1;
|
|
first_te.j = (FirstTrim.m_bRev3d) ? 1-first_edge_end : first_edge_end;
|
|
int count = 0;
|
|
while (count < V.m_ei.Count()){
|
|
const ON_2dex& lte = trim_ends[count];
|
|
count++;
|
|
int next_ti = (lte.j) ? B.NextNonsingularTrim(lte.i) : B.PrevNonsingularTrim(lte.i);
|
|
if (next_ti<0)
|
|
return false;
|
|
const ON_BrepTrim& NT = B.m_T[next_ti];
|
|
const ON_BrepEdge* pNE = NT.Edge();
|
|
if (!pNE)
|
|
return false;
|
|
if (pNE->m_ti.Count() != 2)
|
|
return false;
|
|
ON_2dex nte;
|
|
nte.i = (pNE->m_ti[0] == next_ti) ? pNE->m_ti[1] : pNE->m_ti[0];
|
|
const ON_BrepTrim& NTi = B.m_T[nte.i];
|
|
nte.j = (NTi.m_bRev3d == NT.m_bRev3d) ? 1-lte.j : lte.j;
|
|
if (nte.i == first_te.i && nte.j == first_te.j)
|
|
return (count == V.m_ei.Count()) ? true : false;
|
|
int j;
|
|
for (j=1; j<count; j++){
|
|
if (nte.i == trim_ends[j].i && nte.j == trim_ends[j].j)
|
|
return false;
|
|
}
|
|
trim_ends[count] = nte;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//returns false if there are not exactly 2 naked edge ends at the vertex.
|
|
//trim_ends will be pairs of trim ids and ends. First and last will be naked.
|
|
//trim_ends at least as big as vertex's edge count
|
|
bool OrderEdgesAroundOpenVertex(const ON_Brep& B, int vid, ON_2dex* trim_ends)
|
|
|
|
{
|
|
if (vid<0)
|
|
return false;
|
|
const ON_BrepVertex& V = B.m_V[vid];
|
|
if (V.m_vertex_index < 0)
|
|
return false;
|
|
if (V.m_ei.Count() < 2)
|
|
return false;
|
|
int i;
|
|
int start = -1;
|
|
int end = -1;
|
|
for (i=0; i<V.m_ei.Count(); i++){
|
|
const ON_BrepEdge& E = B.m_E[V.m_ei[i]];
|
|
if (E.m_edge_index < 0)
|
|
return false;
|
|
if (E.m_ti.Count() == 1){
|
|
if (start < 0)
|
|
start = i;
|
|
else if (end < 0)
|
|
end = i;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
if (start < 0 || end < 0)
|
|
return false;
|
|
const ON_BrepEdge& StartE = B.m_E[V.m_ei[start]];
|
|
bool bAtStart = (StartE.m_vi[0] == vid) ? true : false;
|
|
const ON_BrepTrim& StartT = B.m_T[StartE.m_ti[0]];
|
|
ON_2dex& start_te = trim_ends[0];
|
|
start_te.i = StartE.m_ti[0];
|
|
start_te.j = (bAtStart == StartT.m_bRev3d) ? 1 : 0;
|
|
int count = 0;
|
|
while (count < V.m_ei.Count()){
|
|
const ON_2dex& lte = trim_ends[count];
|
|
count++;
|
|
int next_ti = (lte.j) ? B.NextNonsingularTrim(lte.i) : B.PrevNonsingularTrim(lte.i);
|
|
if (next_ti<0)
|
|
return false;
|
|
const ON_BrepTrim& NT = B.m_T[next_ti];
|
|
const ON_BrepEdge* pNE = NT.Edge();
|
|
if (!pNE)
|
|
return false;
|
|
if (pNE->m_ti.Count() > 2)
|
|
return false;
|
|
if (pNE->m_ti.Count() == 1){
|
|
if (NT.m_ei == V.m_ei[end]){
|
|
if (count != V.m_ei.Count()-1)
|
|
return false;
|
|
ON_2dex& end_te = trim_ends[count];
|
|
end_te.i = next_ti;
|
|
end_te.j = 1-lte.j;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
ON_2dex& nte = trim_ends[count];
|
|
nte.i = (pNE->m_ti[0] == next_ti) ? pNE->m_ti[1] : pNE->m_ti[0];
|
|
const ON_BrepTrim& NTi = B.m_T[nte.i];
|
|
nte.j = (NTi.m_bRev3d == NT.m_bRev3d) ? 1-lte.j : lte.j;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ON_OrderEdgesAroundVertex(const ON_Brep& B, int vid,
|
|
ON_SimpleArray<ON_2dex>& trim_ends,
|
|
bool& bClosed)
|
|
|
|
{
|
|
if(vid<0)
|
|
return false;
|
|
const ON_BrepVertex& V = B.m_V[vid];
|
|
if(V.m_vertex_index < 0)
|
|
return false;
|
|
trim_ends.Reserve(V.m_ei.Count());
|
|
trim_ends.SetCount(V.m_ei.Count());
|
|
return ON_OrderEdgesAroundVertex(B, vid, trim_ends.Array(), bClosed);
|
|
}
|
|
|
|
bool ON_OrderEdgesAroundVertex(const ON_Brep& B, int vid,
|
|
ON_2dex* trim_ends,//Must be at as big as the edge count at the vertex
|
|
bool& bClosed)
|
|
|
|
{
|
|
bClosed = false;
|
|
if (vid<0)
|
|
return false;
|
|
const ON_BrepVertex& V = B.m_V[vid];
|
|
if (V.m_vertex_index < 0)
|
|
return false;
|
|
int i;
|
|
bClosed = true;
|
|
for (i=0; i<V.m_ei.Count(); i++){
|
|
const ON_BrepEdge& E = B.m_E[V.m_ei[i]];
|
|
if (E.m_ti.Count() == 2)
|
|
continue;
|
|
if (E.m_ti.Count() == 1){
|
|
bClosed = false;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
return (bClosed) ?
|
|
OrderEdgesAroundClosedVertex(B, vid, trim_ends) : OrderEdgesAroundOpenVertex(B, vid, trim_ends);
|
|
}
|
|
|
|
|
|
|