1 // Copyright (C) 2010-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "vtkEDFCutter.h"
22 #include "vtkInformationVector.h"
23 #include "vtkInformation.h"
24 #include "vtkSmartPointer.h"
25 #include "vtkGenericCell.h"
26 #include "vtkPolyData.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkIdTypeArray.h"
29 #include "vtkCellData.h"
30 #include "vtkCellArray.h"
31 #include "vtkIdList.h"
44 vtkEDFEdge(vtkIdType a, vtkIdType b) : v0(a), v1(b){}
48 bool operator == (const vtkEDFEdge& e0, const vtkEDFEdge& e1)
50 return (e0.v0 == e1.v0 && e0.v1 == e1.v1) ||
51 (e0.v1 == e1.v0 && e0.v0 == e1.v1);
54 bool operator != (const vtkEDFEdge& e0, const vtkEDFEdge& e1)
59 bool operator < (const vtkEDFEdge& e0, const vtkEDFEdge& e1)
84 if(the_e0.v0 == the_e1.v0)
85 return (the_e0.v1 < the_e1.v1);
87 return the_e0.v0 < the_e1.v0;
90 vtkStandardNewMacro(vtkEDFCutter);
91 vtkCxxRevisionMacro(vtkEDFCutter, "0.0");
93 vtkEDFCutter::vtkEDFCutter()
95 this->OriginalCellIdsName = NULL;
98 vtkEDFCutter::~vtkEDFCutter()
100 this->SetOriginalCellIdsName(NULL);
103 int vtkEDFCutter::RequestData(vtkInformation * request,
104 vtkInformationVector ** inVector,
105 vtkInformationVector * outVector)
107 // get the info objects
108 vtkInformation *inInfo = inVector[0]->GetInformationObject(0);
109 vtkInformation *outInfo = outVector->GetInformationObject(0);
111 // get the input and output
112 vtkDataSet *input = vtkDataSet::SafeDownCast(
113 inInfo->Get(vtkDataObject::DATA_OBJECT()));
115 vtkSmartPointer<vtkIdTypeArray> cellIdArray =
116 vtkSmartPointer<vtkIdTypeArray>::New();
117 cellIdArray->SetName(this->GetOriginalCellIdsName());
118 cellIdArray->SetNumberOfComponents(1);
119 cellIdArray->SetNumberOfTuples(input->GetNumberOfCells());
120 for(vtkIdType id=0; id < cellIdArray->GetNumberOfTuples(); id++)
122 cellIdArray->SetTuple1(id, id);
124 input->GetCellData()->AddArray(cellIdArray);
126 int ret = this->Superclass::RequestData(request, inVector, outVector);
131 vtkPolyData *output = vtkPolyData::SafeDownCast(
132 outInfo->Get(vtkDataObject::DATA_OBJECT()));
134 vtkSmartPointer<vtkPolyData> tmpOutput;
135 tmpOutput.TakeReference(output->NewInstance());
137 this->AssembleOutputTriangles(output, tmpOutput);
139 output->ShallowCopy(tmpOutput);
145 void vtkEDFCutter::AssembleOutputTriangles(vtkPolyData* inpd,
148 outpd->ShallowCopy(inpd);
150 vtkIdTypeArray* originalCellIds = vtkIdTypeArray::SafeDownCast(
151 inpd->GetCellData()->GetArray(this->GetOriginalCellIdsName()));
153 if(originalCellIds == NULL)
158 outpd->GetCellData()->Initialize();
159 outpd->GetCellData()->CopyAllocate(inpd->GetCellData());
161 vtkSmartPointer<vtkCellArray> verts = vtkSmartPointer<vtkCellArray>::New();
162 vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
163 vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
164 vtkSmartPointer<vtkCellArray> strips = vtkSmartPointer<vtkCellArray>::New();
165 outpd->SetVerts(verts);
166 outpd->SetLines(lines);
167 outpd->SetPolys(polys);
168 outpd->SetStrips(strips);
170 for(vtkIdType cellId=0; cellId<inpd->GetNumberOfCells(); cellId++)
172 unsigned char type = inpd->GetCellType(cellId);
173 if(type != VTK_TRIANGLE)
176 vtkIdType* pts = NULL;
177 inpd->GetCellPoints(cellId, npts, pts);
178 vtkIdType newCellId =
179 outpd->InsertNextCell(type, npts, pts);
180 outpd->GetCellData()->CopyData(inpd->GetCellData(), cellId, newCellId);
184 vtkIdType cellIdEnd = cellId+1;
185 vtkIdType originalCellId = originalCellIds->GetValue(cellId);
186 while(cellIdEnd < inpd->GetNumberOfCells() &&
187 inpd->GetCellType(cellIdEnd) == VTK_TRIANGLE &&
188 originalCellIds->GetValue(cellIdEnd) == originalCellId)
193 // all triangles from cellId to cellIdEnd come from the same
196 // A batch is composed of triangles which are connected by the edges.
197 std::map<vtkIdType, std::set<vtkIdType> > connectedTriangles;
198 for(vtkIdType firstCell = cellId; firstCell < cellIdEnd-1; firstCell++)
201 vtkIdType* pts = NULL;
202 inpd->GetCellPoints(firstCell, npts, pts);
203 vtkEDFEdge fe0 = vtkEDFEdge(pts[0], pts[1]);
204 vtkEDFEdge fe1 = vtkEDFEdge(pts[1], pts[2]);
205 vtkEDFEdge fe2 = vtkEDFEdge(pts[2], pts[0]);
206 for(vtkIdType secondCell = firstCell+1; secondCell < cellIdEnd; secondCell++)
209 vtkIdType* spts = NULL;
210 inpd->GetCellPoints(secondCell, snpts, spts);
211 vtkEDFEdge se0 = vtkEDFEdge(spts[0], spts[1]);
212 vtkEDFEdge se1 = vtkEDFEdge(spts[1], spts[2]);
213 vtkEDFEdge se2 = vtkEDFEdge(spts[2], spts[0]);
215 if(fe0 == se0 || fe0 == se1 || fe0 == se2 ||
216 fe1 == se0 || fe1 == se1 || fe1 == se2 ||
217 fe2 == se0 || fe2 == se1 || fe2 == se2)
219 connectedTriangles[firstCell].insert(secondCell);
220 connectedTriangles[secondCell].insert(firstCell);
225 std::set<vtkIdType> visitedCell;
226 for(vtkIdType id=cellId; id<cellIdEnd; id++)
228 if(visitedCell.find(id) != visitedCell.end())
231 // if this cell has not yet been visited, I create a batch of all
232 // cells connected to this one
234 visitedCell.insert(id);
235 std::set<vtkIdType> batch;
236 std::list<vtkIdType> cellList;
237 cellList.push_back(id);
238 while(cellList.size() > 0)
240 vtkIdType currentId = *(cellList.begin());
241 batch.insert(currentId);
242 cellList.pop_front();
243 if(connectedTriangles.find(currentId) != connectedTriangles.end())
245 const std::set<vtkIdType>& adj = connectedTriangles[currentId];
246 std::set<vtkIdType>::const_iterator it = adj.begin();
247 while(it != adj.end())
249 vtkIdType other = *it;
250 if(visitedCell.find(other) == visitedCell.end())
252 cellList.push_back(other);
253 visitedCell.insert(other);
262 // then I add this batch to the output,
263 // creating a unique cell for the whole batch.
265 if(batch.size() == 1)
267 vtkIdType tid = *(batch.begin());
269 vtkIdType* pts = NULL;
270 inpd->GetCellPoints(tid, npts, pts);
271 vtkIdType newCellId =
272 outpd->InsertNextCell(VTK_TRIANGLE, npts, pts);
273 outpd->GetCellData()->CopyData(inpd->GetCellData(), cellId, newCellId);
275 else if(batch.size() == 2)
276 { // two triangles connected together --> create a VTK_QUAD
277 vtkIdType fid = *(batch.begin());
278 vtkIdType sid = *(batch.rbegin());
280 vtkIdType* fpts = NULL;
281 inpd->GetCellPoints(fid, fnpts, fpts);
283 vtkIdType* spts = NULL;
284 inpd->GetCellPoints(sid, snpts, spts);
287 vtkIdType fv = fpts[findex];
288 while(((fv == spts[0]) ||
290 (fv == spts[2])) && findex < 3)
296 {// this is a degenerate case : one of the triangles use
301 vtkIdType sv = spts[sindex];
302 while(((sv == fpts[0]) ||
304 (sv == fpts[2])) && sindex < 3)
310 {// this is a degenerate case : one of the triangles use
316 pts[0] = fpts[findex];
317 pts[1] = fpts[(findex+1)%3];
318 pts[2] = spts[sindex];
319 pts[3] = fpts[(findex+2)%3];
321 vtkIdType newCellId = outpd->InsertNextCell(VTK_QUAD, 4, pts);
322 outpd->GetCellData()->CopyData(inpd->GetCellData(), cellId, newCellId);
326 std::deque<vtkEDFEdge> contour;
328 std::list<vtkIdType> toVisit;
329 std::set<vtkIdType> visited;
331 toVisit.push_back(*(batch.begin()));
333 std::set<vtkIdType> triedAgain;
335 while(toVisit.size() > 0)
337 vtkIdType currentId = *(toVisit.begin());
339 if(visited.find(currentId) != visited.end())
342 visited.insert(currentId);
343 const std::set<vtkIdType>& adj = connectedTriangles[currentId];
344 std::set<vtkIdType>::const_iterator it = adj.begin();
345 while(it != adj.end())
347 vtkIdType adjid = *it;
349 if(visited.find(adjid) != visited.end())
352 toVisit.push_back(adjid);
356 vtkIdType* pts = NULL;
357 inpd->GetCellPoints(currentId, npts, pts);
358 vtkEDFEdge edge[3] = {vtkEDFEdge(pts[0], pts[1]),
359 vtkEDFEdge(pts[1], pts[2]),
360 vtkEDFEdge(pts[2], pts[0])};
362 // special case : initialization of the contour
363 if(contour.size() == 0)
365 contour.push_back(edge[0]);
366 contour.push_back(edge[1]);
367 contour.push_back(edge[2]);
371 // Find which edge of the contour
372 // is connected to the current triangle
374 std::deque<vtkEDFEdge>::iterator contourit = contour.begin();
376 while(contourit != contour.end())
378 vtkEDFEdge& e = *contourit;
379 for(orient = 0; orient<3; orient++)
381 if(e == edge[orient])
392 if(contourit == contour.end())
393 {// this triangle is not connected to the current contour.
394 // put it back in the queue for later processing
395 if(triedAgain.find(currentId) == triedAgain.end())
397 triedAgain.insert(currentId);
398 toVisit.push_back(currentId);
399 visited.erase(currentId);
404 vtkDebugMacro( << "triangle " << currentId
405 << "could not be added to the contour of the current batch");
409 // if I reach this point, I will add the triangle to the contour
410 // --> the contour will be modified and I can try again
411 // to add the previously rejected triangles
414 // Now, merge the edges of the current triangle with
416 vtkEDFEdge& tbeforeedge = edge[(orient+1)%3];
417 vtkEDFEdge& tafteredge = edge[(orient+2)%3];
419 std::deque<vtkEDFEdge>::iterator beforeit;
420 if(contourit == contour.begin())
421 beforeit = contour.end()-1;
423 beforeit = contourit - 1;
424 vtkEDFEdge& beforeedge = *beforeit;
426 std::deque<vtkEDFEdge>::iterator afterit;
427 if(contourit == contour.end()-1)
428 afterit = contour.begin();
430 afterit = contourit + 1;
431 vtkEDFEdge& afteredge = *afterit;
433 if(beforeedge == tbeforeedge)
435 if(afteredge == tafteredge)
436 {// in this case, I am adding a triangle that is fully inside
437 // the contour. I need to remove the three edges from the
439 if(contour.size() == 3)
445 std::deque<vtkEDFEdge>::iterator lastit;
446 if(afterit == contour.end()-1)
447 lastit = contour.begin();
449 lastit = afterit + 1;
451 if(lastit < beforeit)
453 contour.erase(beforeit, contour.end());
454 contour.erase(contour.begin(), lastit);
458 contour.erase(beforeit, lastit);
463 {// the edge before is the glued, remove the two adjacent edges
464 // and add the edge after
465 if(beforeit == contour.end()-1)
467 contour.erase(beforeit, contour.end());
468 contour.erase(contour.begin(), contour.begin()+1);
469 contour.push_back(tafteredge);
473 int index = beforeit - contour.begin();
474 contour.erase(beforeit, contourit+1);
475 contour.insert(contour.begin()+index, tafteredge);
479 else if(afteredge == tafteredge)
480 {// the edge after is glued, removed the two glued edges and add
482 if(contourit == contour.end() -1)
484 contour.erase(contour.end() - 1);
485 contour.erase(contour.begin());
486 contour.push_back(tbeforeedge);
490 int index = contourit - contour.begin();
491 contour.erase(contourit, afterit+1);
492 contour.insert(contour.begin()+index, tbeforeedge);
497 int index = contourit - contour.begin();
498 contour.erase(contourit);
499 contour.insert(contour.begin()+index, tbeforeedge);
500 contour.insert(contour.begin()+index+1, tafteredge);
503 vtkSmartPointer<vtkIdList> ids = vtkSmartPointer<vtkIdList>::New();
504 std::deque<vtkEDFEdge>::iterator cit = contour.begin();
505 while(cit != contour.end())
507 vtkEDFEdge& e = *cit;
509 ids->InsertNextId(e.v0);
512 vtkIdType newCellId = outpd->InsertNextCell(VTK_POLYGON, ids);
513 outpd->GetCellData()->CopyData(inpd->GetCellData(), cellId, newCellId);
516 cellId = cellIdEnd - 1;
521 void vtkEDFCutter::PrintSelf(ostream& os, vtkIndent indent)
523 this->Superclass::PrintSelf(os, indent);