Commit 0d56213d authored by Kirill Terekhov's avatar Kirill Terekhov

fix normal orientation loss during mesh modification; function to check for...

fix normal orientation loss during mesh modification; function to check for cell convexity; add topology check for cell convexity; topology checks for modified elemetns; faster algorithms for orientation calculation; fixes for algorithms in modification state
parent 204f4cf8
This diff is collapsed.
......@@ -19,6 +19,7 @@ namespace INMOST
/// Prepare sets for coarsements.
/// Do not do this in constructor, since mesh may contain no cells.
void PrepareSet();
void CheckClosure(std::string file, int line);
//void PrintSetLocal(std::string offset, ElementSet it, std::stringstream& ss);
//void SynchronizeIndicated(TagInteger& indicator);
public:
......
......@@ -6,7 +6,7 @@ bool output_file = true;
bool balance_mesh = true;
bool balance_mesh_refine = false;
bool balance_mesh_coarse = false;
std::string file_format = ".pmf";
std::string file_format = ".pvtu";
#ifndef M_PI
#define M_PI 3.1415926535897932
......@@ -26,21 +26,31 @@ int main(int argc, char ** argv)
else if( m.GetProcessorRank() == 0 )
m.Load(argv[1]);
//m.SetTopologyCheck(PROHIBIT_MULTIPOLYGON | PROHIBIT_MULTILINE
// | DEGENERATE_CELL | DEGENERATE_EDGE | DEGENERATE_FACE
// | PRINT_NOTIFY | TRIPLE_SHARED_FACE | FLATTENED_CELL
// | INTERLEAVED_FACES | NEED_TEST_CLOSURE
// | DUPLICATE_EDGE | DUPLICATE_FACE | DUPLICATE_CELL
// | ADJACENT_DUPLICATE | ADJACENT_HIDDEN | ADJACENT_VALID | ADJACENT_DIMENSION);
//~ m.SetTopologyCheck(PROHIBIT_MULTIPOLYGON | PROHIBIT_MULTILINE
//~ | PROHIBIT_CONCAVE_CELL
//~ | FACE_EDGES_ORDER
//~ | DEGENERATE_CELL | DEGENERATE_EDGE | DEGENERATE_FACE
//~ | PRINT_NOTIFY | TRIPLE_SHARED_FACE | FLATTENED_CELL
//~ | INTERLEAVED_FACES | NEED_TEST_CLOSURE
//~ | DUPLICATE_EDGE | DUPLICATE_FACE | DUPLICATE_CELL
//~ | ADJACENT_DUPLICATE | ADJACENT_HIDDEN | ADJACENT_VALID | ADJACENT_DIMENSION);
//m.RemTopologyCheck(THROW_EXCEPTION);
{
Mesh::GeomParam table;
table[ORIENTATION] = FACE;
table[NORMAL] = FACE;
table[CENTROID] = CELL | FACE;
m.PrepareGeometricData(table);
}
#if defined(USE_PARTITIONER)
std::vector<Storage::integer> nc(m.GetProcessorsNumber());
Partitioner p(&m);
if( true )
{
std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "init before "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
p.SetMethod(Partitioner::INNER_KMEANS,Partitioner::Partition);
//p.SetMethod(Partitioner::Parmetis,Partitioner::Partition);
//p.SetMethod(Partitioner::INNER_KMEANS,Partitioner::Partition);
p.SetMethod(Partitioner::Parmetis,Partitioner::Partition);
//p.SetMethod(Partitioner::Parmetis,Partitioner::Refine);
p.Evaluate();
m.Redistribute();
......@@ -48,7 +58,7 @@ int main(int argc, char ** argv)
std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "init after "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
m.Barrier();
//p.SetMethod(Partitioner::Parmetis,Partitioner::Repartition);
p.SetMethod(Partitioner::Parmetis,Partitioner::Repartition);
}
#endif
m.ExchangeGhost(1,FACE);
......@@ -61,6 +71,9 @@ int main(int argc, char ** argv)
#if defined(USE_PARTITIONER)
p.SetWeight(wgt);
#endif
//m.Save("init"+file_format);
/*
for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it)
indicator[*it] = 1;
......@@ -112,7 +125,7 @@ int main(int argc, char ** argv)
m.ClearFile();
//std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "start "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "start "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
ref_time = Timer();
Storage::integer numref;
......@@ -142,6 +155,7 @@ int main(int argc, char ** argv)
numref = m.Integrate(numref);
if( numref )
{
//~ std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "refine_" << k << "_" << refcnt << " "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
tmp_time = Timer();
#if defined(USE_PARTITIONER)
if( balance_mesh_refine && refcnt == 0)
......@@ -224,6 +238,7 @@ int main(int argc, char ** argv)
numref = m.Integrate(numref);
if( numref )
{
//~ std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "coarse_" << k << "_" << refcnt << " "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
tmp_time = Timer();
#if defined(USE_PARTITIONER)
if( balance_mesh_coarse && refcnt == 0)
......@@ -286,20 +301,20 @@ int main(int argc, char ** argv)
{
//m.Barrier();
p.SetWeight(Tag());
//std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish before "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
//~ std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish before "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
if( m.GetProcessorRank() == 0 ) std::cout << "call Evaluate" << std::endl;
p.Evaluate();
if( m.GetProcessorRank() == 0 ) std::cout << "call Redistribute" << std::endl;
m.Redistribute();
if( m.GetProcessorRank() == 0 ) std::cout << "balance done" << std::endl;
//std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish after "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
//~ std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish after "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
//m.Barrier();
}
#endif
tmp_time = Timer() - tmp_time;
redist_time += tmp_time;
//std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
std::fill(nc.begin(),nc.end(),0); nc[m.GetProcessorRank()] = m.NumberOfCells(); m.Integrate(&nc[0],nc.size()); if( !m.GetProcessorRank() ) {std::cout << "finish "; for(unsigned q = 0; q < nc.size(); ++q) std::cout << nc[q] << " "; std::cout << std::endl;}
......@@ -314,16 +329,28 @@ int main(int argc, char ** argv)
tag_owner[*it] = tag_owner0[*it];
tag_stat[*it] = it->GetStatus();
}
{
std::stringstream file;
file << "step_" << k << file_format;
m.Save(file.str());
if( m.GetProcessorRank() == 0 )
std::cout << "Save " << file.str() << std::endl;
}
if( false )
{
std::stringstream file;
file << "step_" << k << ".pmf";
m.Save(file.str());
if( m.GetProcessorRank() == 0 )
std::cout << "Save " << file.str() << std::endl;
}
}
else if( m.GetProcessorRank() == 0 ) std::cout << "step " << k << std::endl;
step_time = Timer() - step_time;
if( m.GetProcessorRank() == 0 ) std::cout << "step time " << step_time << " refine " << ref_time << " coarse " << crs_time << " balance " << redist_time << std::endl;
//~ MPI_Barrier(MPI_COMM_WORLD);
//~ MPI_Abort(MPI_COMM_WORLD,-1);
}
......
......@@ -59,7 +59,7 @@
// output xml files for debugging of parallel algorithms
// search for style.xsl within examples for comfortable
// view of generated xml files
//~ #define USE_PARALLEL_WRITE_TIME
#define USE_PARALLEL_WRITE_TIME
// this will revert Mesh::PrepareReceiveInner to always
// use MPI point to point functionality disregarding problem type
......
......@@ -641,7 +641,7 @@ namespace INMOST
void UnitNormal (real * nrm) const;
void OrientedNormal (Cell c, real * nrm) const;
void OrientedUnitNormal (Cell c, real * nrm) const;
bool FixNormalOrientation () const; //returns true if orientation was corrected, otherwise returns false
bool FixNormalOrientation (bool allow_swap = true) const; //returns true if orientation was corrected, otherwise returns false
bool CheckNormalOrientation () const; //returns true if orientation is correct, otherwise returns false
bool Closure () const; // test integrity of polygon
bool Inside (const real * point) const; //is point inside face
......@@ -938,6 +938,8 @@ namespace INMOST
bool Closure () const;
/// For each adjacent cell make me a front cell and fix normal orientation accordingly.
void SwapBackCell () const;
bool CheckConvexity () const;
};
///
......@@ -3239,6 +3241,7 @@ namespace INMOST
/// If marker is set then face is reversed.
/// Then all faces are oriented either inside or outside of the cell.
void FacesOrientation(ElementArray<Face> & faces, MarkerType rev);
bool CheckConvexity(const ElementArray<Face> & faces) const;
void PrepareGeometricData(GeomParam table);
void RemoveGeometricData(GeomParam table);
bool HaveGeometricData (GeometricData type, ElementType mask) const {return remember[type][ElementNum(mask)-1];} // requests to only one geometric and element type allowed
......@@ -3350,7 +3353,7 @@ namespace INMOST
///
/// \todo
/// list checks performed inside in description.
TopologyCheck EndTopologyCheck (HandleType e); //check created element
bool EndTopologyCheck (HandleType e, TopologyCheck begin_check); //check created element
/// This will return tag by which you can retrieve error mark to any element on which topogy check failed.
/// As this is sparse tag you can check presence of error by Element::HaveData or Mesh::HaveData check.
/// This tag will be valid only if you pass MARK_ON_ERROR to Mesh::GetTopologyCheck
......
......@@ -645,7 +645,7 @@ namespace INMOST
buconv.read_iByteOrder(header);
buconv.read_iByteSize(header);
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(uconv.get_iByteOrder()));
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(buconv.get_iByteOrder()));
REPORT_VAL("integer_byte_size",(int)buconv.get_iByteSize());
......@@ -777,7 +777,7 @@ namespace INMOST
REPORT_VAL("file position",fin.tellg());
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(uconv.get_iByteOrder()));
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(buconv.get_iByteOrder()));
REPORT_VAL("integer_byte_size",(int)buconv.get_iByteSize());
......@@ -924,7 +924,7 @@ namespace INMOST
REPORT_VAL("file position",fin.tellg());
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(uconv.get_iByteOrder()));
REPORT_VAL("integer_byte_order",buconv.str_iByteOrder(buconv.get_iByteOrder()));
REPORT_VAL("integer_byte_size",(int)buconv.get_iByteSize());
INMOST_DATA_ENUM_TYPE datanum,k;
......
......@@ -68,7 +68,9 @@ namespace INMOST
else if ( !(last == rlc[k1] || last == rlc[k2]) )
return false;
adj_type::size_type it = 1, iend = lc.size()-1;
while(it != iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
while(it != iend)
{
if( !m->GetMarker(lc[it],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
k1 = ENUMUNDEF;
......@@ -77,6 +79,7 @@ namespace INMOST
if( last == ilc[k1] ) last = ilc[k2];
else if( last == ilc[k2] ) last = ilc[k1];
else return false;
}
++it;
}
}
......@@ -215,7 +218,9 @@ namespace INMOST
else if( !(last == rlc[k1] || last == rlc[k2]) )
{
adj_type::size_type jt = i+1, jend = lc.size();
while(jt < jend) if( !m->GetMarker(lc[jt],hm) ) //loop over edges
while(jt < jend)
{
if( !m->GetMarker(lc[jt],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[jt]);
if( m->Count(ilc.data(),ilc.size(),hm) != 2 ) return false;
......@@ -239,6 +244,7 @@ namespace INMOST
lc[jt] = temp;
break;
}
}
++jt;
}
if( jt == jend ) return false; //no matching edge
......@@ -281,7 +287,7 @@ namespace INMOST
}
if( jt == jend ) return false; //no matching edge
}
}
} else ++it;
//check that the loop is closed
adj_type const & ilc = m->LowConn(lc[iend]);
if(m->Count(ilc.data(),ilc.size(),hm)!=2) return false;
......@@ -447,7 +453,9 @@ namespace INMOST
}
}
adj_type::size_type it = 1, iend = lc.size()-1;
while(it < iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
while(it < iend)
{
if( !m->GetMarker(lc[it],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
k1 = ENUMUNDEF;
......@@ -457,6 +465,7 @@ namespace INMOST
aret.push_back(ilc[k2]);
else
aret.push_back(ilc[k1]);
}
++it;
}
}
......@@ -579,7 +588,9 @@ namespace INMOST
}
}
adj_type::size_type it = 1, iend = lc.size()-1;
while(it != iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
while(it != iend)
{
if( !m->GetMarker(lc[it],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
k1 = ENUMUNDEF;
......@@ -589,6 +600,7 @@ namespace INMOST
last = ilc[k2];
else last = ilc[k1];
if( invert ^ m->GetPrivateMarker(last,mask) ) aret.push_back(last);
}
++it;
}
}
......@@ -703,7 +715,9 @@ namespace INMOST
}
}
adj_type::size_type it = 1, iend = lc.size()-1;
while(it != iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
while(it != iend)
{
if( !m->GetMarker(lc[it],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
k1 = ENUMUNDEF;
......@@ -713,6 +727,7 @@ namespace INMOST
last = ilc[k2];
else last = ilc[k1];
if( invert ^ m->GetMarker(last,mask) ) aret.push_back(last);
}
++it;
}
}
......
......@@ -191,6 +191,7 @@ namespace INMOST
while(it < iend) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
if( ilc.size() != 2 ) return false;
if( last == ilc[0] ) last = ilc[1];
else if( last == ilc[1] ) last = ilc[0];
else return false;
......@@ -233,15 +234,20 @@ namespace INMOST
else if ( !(last == rlc[k1] || last == rlc[k2]) )
return false;
adj_type::size_type it = 1, iend = lc.size()-1;
while(it != iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
while(it != iend)
{
if( !m->GetMarker(lc[it],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[it]);
if( m->Count(ilc.data(),ilc.size(),hm) != 2 ) return false;
k1 = ENUMUNDEF;
k1 = m->getNext(ilc.data(),static_cast<enumerator>(ilc.size()),k1,hm);
k2 = m->getNext(ilc.data(),static_cast<enumerator>(ilc.size()),k1,hm);
if( k1 == ilc.size() || k2 == ilc.size() ) return false;
if( last == ilc[k1] ) last = ilc[k2];
else if( last == ilc[k2] ) last = ilc[k1];
else return false;
}
++it;
}
}
......@@ -378,7 +384,9 @@ namespace INMOST
else if( !(last == rlc[k1] || last == rlc[k2]) )
{
adj_type::size_type jt = i+1, jend = lc.size();
while(jt < jend) if( !m->GetMarker(lc[jt],hm) ) //loop over edges
while(jt < jend)
{
if( !m->GetMarker(lc[jt],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[jt]);
if( m->Count(ilc.data(),ilc.size(),hm) != 2 ) return false;
......@@ -402,6 +410,7 @@ namespace INMOST
lc[jt] = temp;
break;
}
}
++jt;
}
if( jt == jend ) return false; //no matching edge
......@@ -427,7 +436,9 @@ namespace INMOST
else//search for the connected edge and swap with current
{
adj_type::size_type jt = it+1, jend = lc.size();
while(jt < jend) if( !m->GetMarker(lc[jt],hm) ) //loop over edges
while(jt < jend)
{
if( !m->GetMarker(lc[jt],hm) ) //loop over edges
{
adj_type const & ilc = m->LowConn(lc[jt]);
if(m->Count(ilc.data(),ilc.size(),hm)!=2) return false;
......@@ -441,11 +452,12 @@ namespace INMOST
lc[jt] = temp;
break;
}
}
++jt;
}
if( jt == jend ) return false; //no matching edge
}
}
} else ++it;
//check that the loop is closed
adj_type const & ilc = m->LowConn(lc[iend]);
if(m->Count(ilc.data(),ilc.size(),hm)!=2) return false;
......@@ -698,7 +710,7 @@ namespace INMOST
last = ilc[k1];
}
++it;
}
} else ++it;
}
}
......
......@@ -616,15 +616,23 @@ namespace INMOST
}
if( GetHandleElementType(e) == CELL && HaveGeometricData(ORIENTATION,FACE)) //then correct the normal
if( HaveGeometricData(ORIENTATION,FACE) )
{
if( GetHandleElementType(e) == CELL ) //then correct the normal
{
Element::adj_type & lc = LowConn(e);
for(Element::adj_type::iterator it = lc.begin(); it != lc.end(); ++it)
if( !GetMarker(*it,HideMarker()) && HighConn(*it).size() == 1 )
if( !GetMarker(*it,HideMarker()) )
{
//Element::adj_type & hc = HighConn(e);
//if( Mesh::Count(&hc[0],hc.size(),HideMarker()) == 1 )
Face(this,*it)->FixNormalOrientation();
}
}
else if( GetHandleElementType(e) == FACE )
Face(this,e)->FixNormalOrientation();
}
for(d = MEASURE; d <= BARYCENTER; d++) // compute the rest
{
if( HaveGeometricData(d,GetHandleElementType(e)) )
......@@ -636,6 +644,11 @@ namespace INMOST
ShowGeometricData(d,GetHandleElementType(e));
}
}
if( GetHandleElementType(e) == CELL ) //then correct the normal
{
}
}
......@@ -907,12 +920,80 @@ namespace INMOST
}
}
bool Cell::CheckConvexity() const {return GetMeshLink()->CheckConvexity(getFaces());}
bool Mesh::CheckConvexity(const ElementArray<Face> & faces) const
{
if( !faces.empty() )
{
std::vector<Storage::real> x(faces.size()*6,0.0);
Storage::real * n = &x[faces.size()*3];
Storage::real eps = GetEpsilon();
//precompute data for all faces
#if defined(USE_OMP)
#pragma omp critical (reorder_edges)
#endif
{ //collect data safely so that nobody changes it
for(ElementArray<Face>::size_type j = 0; j != faces.size(); ++j)
{
faces[j].Centroid(&x[j*3]);
faces[j].UnitNormal(&n[j*3]);
}
}
//run comparison
for(ElementArray<Face>::size_type j = 0; j != faces.size(); ++j)
{
Storage::real dota = 0, dots = 0, dotv, v[3] = {0.,0.,0.};
for(ElementArray<Face>::size_type m = 0; m != faces.size(); ++m)
{
vec_diff(&x[m*3],&x[j*3],v,3);
dotv = vec_dot_product(&n[j*3],v,3);
dots += dotv;
dota += fabs(dotv);
}
if( fabs(fabs(dots) - dota) > eps )
return false;
}
}
return true;
}
void Mesh::FacesOrientation(ElementArray<Face> & faces, MarkerType rev)
{
//can copy orientation-independent algorithm from
//incident_matrix.hpp: incident_matrix::compute_measure
//assume mdim is of size 3 at most
if( !faces.empty() )
{
if( CheckConvexity(faces) ) //simpler algorithm
{
std::vector<Storage::real> x(faces.size()*6);
Storage::real * n = &x[faces.size()*3];
Storage::real xc[3] = {0.,0.,0.}, v[3] = {0.,0.,0.};
for(ElementArray<Face>::size_type j = 0; j != faces.size(); ++j)
{
faces[j].Centroid(&x[j*3]);
faces[j].UnitNormal(&n[j*3]);
xc[0] += x[j*3+0];
xc[1] += x[j*3+1];
xc[2] += x[j*3+2];
}
xc[0] /= (Storage::real)faces.size();
xc[1] /= (Storage::real)faces.size();
xc[2] /= (Storage::real)faces.size();
for(ElementArray<Face>::size_type j = 0; j != faces.size(); ++j)
{
vec_diff(&x[j*3],xc,v,3);
if( vec_dot_product(&n[j*3],v,3) < 0 )
{
if( isPrivate(rev) )
faces[j].SetPrivateMarker(rev);
else
faces[j].SetMarker(rev);
}
}
}
else
{
//real was = *ret/3.0;
Face cur = faces[0];
......@@ -1010,6 +1091,7 @@ namespace INMOST
//faces.RemPrivateMarker(rev);
}
}
}
void Mesh::GetGeometricData(HandleType e, GeometricData type, Storage::real * ret)
{
......@@ -1099,7 +1181,9 @@ namespace INMOST
//redo:
Cell me = Cell(this,e);
ElementArray<Face> faces = me->getFaces();
bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
//bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
bool ornt = !HaveGeometricData(ORIENTATION,FACE);
//bool ornt = !CheckConvexity(faces);
MarkerType rev = 0;
if( ornt )
{
......@@ -1270,7 +1354,9 @@ namespace INMOST
{
Cell me = Cell(this,e);
ElementArray<Face> faces = me->getFaces();
bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
//bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
//bool ornt = !CheckConvexity(faces);
bool ornt = !HaveGeometricData(ORIENTATION,FACE);
MarkerType rev = 0;
if( ornt )
{
......@@ -1521,6 +1607,21 @@ namespace INMOST
//integer dim = mesh->GetDimensions();
Cell c1 = BackCell();
if( c1.isValid() )
{
if( c1.CheckConvexity() ) //simpler algorithm
{
Storage::real xc[3] = {0.,0.,0.};
Storage::real xf[3] = {0.,0.,0.};
Storage::real nf[3] = {0.,0.,0.};
Storage::real v[3] = {0.,0.,0.};
c1.Centroid(xc);
Centroid(xf);
UnitNormal(nf);
vec_diff(xf,xc,v,3);
if( vec_dot_product(nf,v,3) < 0 )
return false;
}
else
{
MarkerType mrk = mesh->CreatePrivateMarker();
MarkerType rev = mesh->CreatePrivateMarker(); //reverse orientation
......@@ -1634,14 +1735,15 @@ namespace INMOST
if( (measure < 0 ))// && !have_rev) || (measure > 0 && have_rev))
return false;
}
}
return true;
}
bool Face::FixNormalOrientation() const
bool Face::FixNormalOrientation(bool allow_swap) const
{
if( !CheckNormalOrientation() )
{
if( FrontCell().isValid() )
if( allow_swap && FrontCell().isValid() )
SwapCells();
else
{
......
......@@ -985,6 +985,14 @@ namespace INMOST
if( GetTopologyCheck(PRINT_NOTIFY) ) std::cerr << TopologyCheckNotifyString(DEGENERATE_CELL) << std::endl;
}
}
if( GetTopologyCheck(PROHIBIT_CONCAVE_CELL) )
{
if( !CheckConvexity(ElementArray<Face>(this,adj,adj+s)) )
{
chk |= PROHIBIT_CONCAVE_CELL;
if( GetTopologyCheck(PRINT_NOTIFY) ) std::cerr << TopologyCheckNotifyString(PROHIBIT_CONCAVE_CELL) << std::endl;
}
}
break;
}
}
......@@ -1035,9 +1043,9 @@ namespace INMOST
return chk;
}
TopologyCheck Mesh::EndTopologyCheck(HandleType he)
bool Mesh::EndTopologyCheck(HandleType he, TopologyCheck begin_checks)
{
TopologyCheck chk = 0;
TopologyCheck chk = begin_checks;
Element e = ElementByHandle(he);
switch(e->GetGeometricDimension(e->GetGeometricType()))
{
......@@ -1121,7 +1129,14 @@ namespace INMOST
}
}
errorset |= chk;
return chk;
if( chk != 0 )
{
if( GetTopologyCheck(MARK_ON_ERROR) ) Integer(he,TopologyErrorTag()) = chk;
if( GetTopologyCheck(DELETE_ON_ERROR) ) { Destroy(he); he = InvalidHandle();}
if( GetTopologyCheck(THROW_EXCEPTION) ) throw TopologyCheckError;
return false;
}
return true;
}
Node Mesh::CreateNode(const real * coords)
......@@ -1220,6 +1235,8 @@ namespace INMOST
ComputeGeometricType(he);
SetMarker(he,NewMarker());
RecomputeGeometricData(he);
EndTopologyCheck(he,chk);
/*
chk |= EndTopologyCheck(he);
if( chk != 0 )
{
......@@ -1227,6 +1244,7 @@ namespace INMOST
if( GetTopologyCheck(DELETE_ON_ERROR) ) { Destroy(he); he = InvalidHandle();}
if( GetTopologyCheck(THROW_EXCEPTION) ) throw TopologyCheckError;
}
*/
}
return std::make_pair(Edge(this,he),true);
}
......@@ -1316,6 +1334,8 @@ namespace INMOST
ComputeGeometricType(he);
SetMarker(he,NewMarker());
RecomputeGeometricData(he);
EndTopologyCheck(he,chk);
/*
chk |= EndTopologyCheck(he);
if( chk != 0 )
{
......@@ -1323,6 +1343,7 @@ namespace INMOST
if( GetTopologyCheck(DELETE_ON_ERROR) ) { Destroy(he); he = InvalidHandle();}
if( GetTopologyCheck(THROW_EXCEPTION) ) throw TopologyCheckError;
}
*/
}
return std::make_pair(Face(this,he),true);
}
......@@ -1741,6 +1762,8 @@ namespace INMOST
//END DEBUG
SetMarker(he,NewMarker());
RecomputeGeometricData(he);
EndTopologyCheck(he,chk);
/*
chk |= EndTopologyCheck(he);
if( chk != 0 )
{
......@@ -1748,6 +1771,7 @@ namespace INMOST
if( GetTopologyCheck(DELETE_ON_ERROR) ) { Destroy(he); he = InvalidHandle();}
if( GetTopologyCheck(THROW_EXCEPTION) ) throw TopologyCheckError;
}
*/
}
......
......@@ -657,6 +657,7 @@ namespace INMOST
hc.replace(hc.begin(),hc.end(),nodes.begin(),nodes.end());
//recompute geometric data
m->RecomputeGeometricData(cells[it]);
m->EndTopologyCheck(cells[it],0);
}
return ret;
......@@ -928,10 +929,48 @@ namespace INMOST
for(dynarray<adj_type::size_type,64>::size_type k = 0; k < insert_pos.size(); k++)
{
adj_type & lc = m->LowConn(faces[k]);
std::vector<HandleType> tlc(lc.begin(),lc.end());
lc.insert(lc.begin()+insert_pos[k],e->GetHandle());
ehc.push_back(faces[k]);
m->ComputeGeometricType(faces[k]);
m->RecomputeGeometricData(faces[k]);
m->EndTopologyCheck(faces[k],0);
/*
if( !m->EndTopologyCheck(faces[k],0) )
{
for(std::map<HandleType,int>::iterator it = nodes.begin(); it != nodes.end(); it++)
{
Storage::real_array c = m->NodeByLocalID(GetHandleID(it->first)).Coords();
std::cout << "node " << it->first << " at " << c[0] << " " << c[1] << " " << c[2] << " dup " << it->second << std::endl;