You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2937 lines
92 KiB
2937 lines
92 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkSimpleCellTessellator.cxx,v $
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
#include "vtkSimpleCellTessellator.h"
|
|
#include "vtkObjectFactory.h"
|
|
|
|
#include "vtkCellArray.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkGenericAdaptorCell.h"
|
|
#include "vtkGenericAttributeCollection.h"
|
|
#include "vtkGenericAttribute.h"
|
|
#include "vtkGenericCellIterator.h"
|
|
#include "vtkGenericDataSet.h"
|
|
#include "vtkGenericEdgeTable.h"
|
|
#include "vtkGenericSubdivisionErrorMetric.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkPoints.h"
|
|
|
|
#include "vtkOrderedTriangulator.h"
|
|
#include "vtkPolygon.h"
|
|
#include "vtkTetra.h"
|
|
|
|
#include <vtkstd/queue>
|
|
#include <vtkstd/stack>
|
|
#include <assert.h>
|
|
|
|
// format of the arrays LeftPoint, MidPoint, RightPoint is global, parametric,
|
|
// attributes: xyz rst [abc de...]
|
|
const int PARAMETRIC_OFFSET = 3;
|
|
const int ATTRIBUTES_OFFSET = 6;
|
|
|
|
// Pre computed table for the point to edge equivalence:
|
|
// [edge][point]
|
|
static int TRIANGLE_EDGES_TABLE[3][2] = {{0, 1}, {1, 2}, {2, 0}};
|
|
|
|
|
|
// Pre computed table for the tessellation of triangles
|
|
#define NO_TRIAN {-1,-1,-1}
|
|
|
|
// Each edge can either be split or not therefore there is
|
|
// 2^3 = 8 differents cases of tessellation
|
|
// The last case is only a sentinel to avoid stepping out of table
|
|
// If we consider edge 3 the first edge, 4 the second and 5 the last one
|
|
// 'Index' can be computed by the decimal evaluation of the binary representing
|
|
// which is is split ex: 3 and 5 are split is noted:
|
|
// {1, 0, 1} = 1*2^0 + 0*2^1 + 1*2^2 = 5
|
|
// [case][triangle][vertex]
|
|
static signed char vtkTessellatorTriangleCases[9][4][3] = {
|
|
// Index = 0, Case where no edges are split
|
|
{ NO_TRIAN, NO_TRIAN, NO_TRIAN, NO_TRIAN},
|
|
// Index = 1, Case where edges 3 are split
|
|
{{0, 3, 2},{1, 2, 3}, NO_TRIAN, NO_TRIAN},
|
|
// Index = 2, Case where edges 4 are split
|
|
{{0, 1, 4},{0, 4, 2}, NO_TRIAN, NO_TRIAN},
|
|
// Index = 3, Case where edges 3,4 are split
|
|
{{0, 3, 2},{1, 4, 3},{3, 4, 2}, NO_TRIAN},
|
|
// Index = 4, Case where edges 5 are split
|
|
{{0, 1, 5},{1, 2, 5}, NO_TRIAN, NO_TRIAN},
|
|
// Index = 5, Case where edges 3,5 are split
|
|
{{0, 3, 5},{1, 5, 3},{1, 2, 5}, NO_TRIAN},
|
|
// Index = 6, Case where edges 4,5 are split
|
|
{{0, 4, 5},{0, 1, 4},{2, 5, 4}, NO_TRIAN},
|
|
// Index = 7, Case where edges 4,5,6 are split
|
|
{{0, 3, 5},{3, 4, 5},{1, 4, 3},{2, 5, 4}},
|
|
// In case we reach outside the table
|
|
{ NO_TRIAN, NO_TRIAN, NO_TRIAN, NO_TRIAN},
|
|
};
|
|
|
|
// Pre computed table for the point to edge equivalence:
|
|
// [edge][point]
|
|
static int TETRA_EDGES_TABLE[6][2] = {
|
|
{0, 1}, {1, 2}, {2, 0}, {0, 3}, {1, 3}, {2, 3}
|
|
};
|
|
|
|
// Pre computed table for the tessellation of tetras
|
|
// There is two cases for the tessellation of a tetra, it is either oriented
|
|
// with the right hand rule or with the left hand rule
|
|
#define NO_TETRA {-1,-1,-1,-1}
|
|
|
|
|
|
// Each edge can either be split or not therefore there is
|
|
// 2^6 = 64 differents cases of tessellation
|
|
// The last case is only a sentinel to avoid stepping out of table
|
|
// [case][tetra][vertex]
|
|
static signed char vtkTessellatorTetraCasesRight[65][8][4] = {
|
|
// Index = 0, Case where no edges are split
|
|
{{0,1,2,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 1, Case where edges: 4 are split
|
|
{{0,2,3,4},{1,2,4,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 2, Case where edges: 5 are split
|
|
{{0,1,5,3},{0,2,3,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 3, Case where edges: 4,5 are split
|
|
{{0,2,3,5},{0,3,4,5},{1,3,5,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 4, Case where edges: 6 are split
|
|
{{0,1,6,3},{1,2,6,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 5, Case where edges: 4,6 are split
|
|
{{0,3,4,6},{1,2,6,3},{1,3,6,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 6, Case where edges: 5,6 are split
|
|
{{0,1,5,3},{0,3,5,6},{2,3,6,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 7, Case where edges: 4,5,6 are split
|
|
{{0,3,4,6},{1,3,5,4},{2,3,6,5},{3,4,6,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 8, Case where edges: 7 are split
|
|
{{0,1,2,7},{1,2,7,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 9, Case where edges: 4,7 are split
|
|
{{0,2,7,4},{1,2,4,7},{1,2,7,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 10, Case where edges: 5,7 are split
|
|
{{0,1,5,7},{0,2,7,5},{1,3,5,7},{2,3,7,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 11, Case where edges: 4,5,7 are split
|
|
{{0,2,7,5},{0,4,5,7},{1,3,5,7},{1,4,7,5},{2,3,7,5}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 12, Case where edges: 6,7 are split
|
|
{{0,1,6,7},{1,2,6,7},{1,2,7,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 13, Case where edges: 4,6,7 are split
|
|
{{0,4,6,7},{1,2,6,7},{1,2,7,3},{1,4,7,6}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 14, Case where edges: 5,6,7 are split
|
|
{{0,1,5,7},{0,5,6,7},{1,3,5,7},{2,3,7,5},{2,5,7,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 15, Case where edges: 4,5,6,7 are split
|
|
{{0,4,6,7},{1,3,5,7},{1,4,7,5},{2,3,7,5},{2,5,7,6},{4,5,6,7}, NO_TETRA, NO_TETRA},
|
|
// Index = 16, Case where edges: 8 are split
|
|
{{0,1,2,8},{0,2,3,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 17, Case where edges: 4,8 are split
|
|
{{0,2,3,8},{0,2,8,4},{1,2,4,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 18, Case where edges: 5,8 are split
|
|
{{0,1,5,8},{0,2,3,8},{0,2,8,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 19, Case where edges: 4,5,8 are split
|
|
{{0,2,3,8},{0,2,8,5},{0,4,5,8},{1,4,8,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 20, Case where edges: 6,8 are split
|
|
{{0,1,6,8},{0,3,8,6},{1,2,6,8},{2,3,6,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 21, Case where edges: 4,6,8 are split
|
|
{{0,3,8,6},{0,4,6,8},{1,2,6,8},{1,4,8,6},{2,3,6,8}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 22, Case where edges: 5,6,8 are split
|
|
{{0,1,5,8},{0,3,8,6},{0,5,6,8},{2,3,6,8},{2,5,8,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 23, Case where edges: 4,5,6,8 are split
|
|
{{0,3,8,6},{0,4,6,8},{1,4,8,5},{2,3,6,8},{2,5,8,6},{4,5,6,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 24, Case where edges: 7,8 are split
|
|
{{0,1,2,8},{0,2,7,8},{2,3,7,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 25, Case where edges: 4,7,8 are split
|
|
{{0,2,7,4},{1,2,4,8},{2,3,7,8},{2,4,8,7}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 26, Case where edges: 5,7,8 are split
|
|
{{0,1,5,8},{0,2,7,5},{0,5,7,8},{2,3,7,8},{2,5,8,7}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 27, Case where edges: 4,5,7,8 are split
|
|
{{0,2,7,5},{0,4,5,7},{1,4,8,5},{2,3,7,8},{2,5,8,7},{4,5,7,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 28, Case where edges: 6,7,8 are split
|
|
{{0,1,6,8},{0,6,7,8},{1,2,6,8},{2,3,7,8},{2,6,8,7}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 29, Case where edges: 4,6,7,8 are split
|
|
{{0,4,6,7},{1,2,6,8},{1,4,8,6},{2,3,7,8},{2,6,8,7},{4,6,7,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 30, Case where edges: 5,6,7,8 are split
|
|
{{0,1,5,8},{0,5,6,7},{0,5,7,8},{2,3,7,8},{2,5,7,6},{2,5,8,7}, NO_TETRA, NO_TETRA},
|
|
// Index = 31, Case where edges: 4,5,6,7,8 are split
|
|
{{0,4,6,7},{1,4,8,5},{2,3,7,8},{2,5,7,6},{2,5,8,7},{4,5,6,7},{4,5,7,8}, NO_TETRA},
|
|
// Index = 32, Case where edges: are split
|
|
{{0,1,2,9},{0,1,9,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 33, Case where edges: 4 are split
|
|
{{0,2,9,4},{0,3,4,9},{1,2,4,9},{1,3,9,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 34, Case where edges: 5 are split
|
|
{{0,1,5,9},{0,1,9,3},{0,2,9,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 35, Case where edges: 4,5 are split
|
|
{{0,2,9,5},{0,3,4,9},{0,4,5,9},{1,3,9,4},{1,4,9,5}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 36, Case where edges: 6 are split
|
|
{{0,1,6,9},{0,1,9,3},{1,2,6,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 37, Case where edges: 4,6 are split
|
|
{{0,3,4,9},{0,4,6,9},{1,2,6,9},{1,3,9,4},{1,4,9,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 38, Case where edges: 5,6 are split
|
|
{{0,1,5,9},{0,1,9,3},{0,5,6,9},{2,5,9,6}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 39, Case where edges: 4,5,6 are split
|
|
{{0,3,4,9},{0,4,6,9},{1,3,9,4},{1,4,9,5},{2,5,9,6},{4,5,6,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 40, Case where edges: 7 are split
|
|
{{0,1,2,9},{0,1,9,7},{1,3,9,7}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 41, Case where edges: 4,7 are split
|
|
{{0,2,9,4},{0,4,9,7},{1,2,4,9},{1,3,9,7},{1,4,7,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 42, Case where edges: 5,7 are split
|
|
{{0,1,5,7},{0,2,9,5},{0,5,9,7},{1,3,9,7},{1,5,7,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 43, Case where edges: 4,5,7 are split
|
|
{{0,2,9,5},{0,4,5,7},{0,5,9,7},{1,3,9,7},{1,4,7,5},{1,5,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 44, Case where edges: 6,7 are split
|
|
{{0,1,6,7},{1,2,6,9},{1,3,9,7},{1,6,7,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 45, Case where edges: 4,6,7 are split
|
|
{{0,4,6,7},{1,2,6,9},{1,3,9,7},{1,4,7,9},{1,4,9,6},{4,6,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 46, Case where edges: 5,6,7 are split
|
|
{{0,1,5,7},{0,5,6,7},{1,3,9,7},{1,5,7,9},{2,5,9,6},{5,6,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 47, Case where edges: 4,5,6,7 are split
|
|
{{0,4,6,7},{1,3,9,7},{1,4,7,5},{1,5,7,9},{2,5,9,6},{4,5,6,7},{5,6,7,9}, NO_TETRA},
|
|
// Index = 48, Case where edges: 8 are split
|
|
{{0,1,2,9},{0,1,9,8},{0,3,8,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 49, Case where edges: 4,8 are split
|
|
{{0,2,9,4},{0,3,8,9},{0,4,9,8},{1,2,4,9},{1,4,8,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 50, Case where edges: 5,8 are split
|
|
{{0,1,5,8},{0,2,9,5},{0,3,8,9},{0,5,9,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 51, Case where edges: 4,5,8 are split
|
|
{{0,2,9,5},{0,3,8,9},{0,4,5,9},{0,4,9,8},{1,4,8,5},{4,5,9,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 52, Case where edges: 6,8 are split
|
|
{{0,1,6,8},{0,3,8,9},{0,6,9,8},{1,2,6,9},{1,6,8,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 53, Case where edges: 4,6,8 are split
|
|
{{0,3,8,9},{0,4,6,8},{0,6,9,8},{1,2,6,9},{1,4,8,6},{1,6,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 54, Case where edges: 5,6,8 are split
|
|
{{0,1,5,8},{0,3,8,9},{0,5,6,8},{0,6,9,8},{2,5,9,6},{5,6,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 55, Case where edges: 4,5,6,8 are split
|
|
{{0,3,8,9},{0,4,6,8},{0,6,9,8},{1,4,8,5},{2,5,9,6},{4,5,6,8},{5,6,8,9}, NO_TETRA},
|
|
// Index = 56, Case where edges: 7,8 are split
|
|
{{0,1,2,9},{0,1,9,8},{0,7,8,9},{3,7,9,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 57, Case where edges: 4,7,8 are split
|
|
{{0,2,9,4},{0,4,9,7},{1,2,4,9},{1,4,8,9},{3,7,9,8},{4,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 58, Case where edges: 5,7,8 are split
|
|
{{0,1,5,8},{0,2,9,5},{0,5,7,8},{0,5,9,7},{3,7,9,8},{5,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 59, Case where edges: 4,5,7,8 are split
|
|
{{0,2,9,5},{0,4,5,7},{0,5,9,7},{1,4,8,5},{3,7,9,8},{4,5,7,8},{5,7,8,9}, NO_TETRA},
|
|
// Index = 60, Case where edges: 6,7,8 are split
|
|
{{0,1,6,8},{0,6,7,8},{1,2,6,9},{1,6,8,9},{3,7,9,8},{6,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 61, Case where edges: 4,6,7,8 are split
|
|
{{0,4,6,7},{1,2,6,9},{1,4,8,6},{1,6,8,9},{3,7,9,8},{4,6,7,8},{6,7,8,9}, NO_TETRA},
|
|
// Index = 62, Case where edges: 5,6,7,8 are split
|
|
{{0,1,5,8},{0,5,6,7},{0,5,7,8},{2,5,9,6},{3,7,9,8},{5,6,7,9},{5,7,8,9}, NO_TETRA},
|
|
// Index = 63, Case where edges: 4,5,6,7,8 are split
|
|
{{0,4,6,7},{1,4,8,5},{2,5,9,6},{3,7,9,8},{4,5,6,7},{4,5,7,8},{5,6,7,9},{5,7,8,9}},
|
|
// In case we reach outside the table
|
|
{ NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// This table is for the case where the 'last edge' of the tetra could not be order
|
|
// properly, then we need a different case table
|
|
//
|
|
static signed char vtkTessellatorTetraCasesLeft[65][8][4] = {
|
|
// Index = 0, Case where no edges are split
|
|
{{0,1,2,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 1, Case where edges: 4 are split
|
|
{{0,2,3,4},{1,2,4,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 2, Case where edges: 5 are split
|
|
{{0,1,5,3},{0,2,3,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 3, Case where edges: 4,5 are split
|
|
{{0,2,3,5},{0,3,4,5},{1,3,5,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 4, Case where edges: 6 are split
|
|
{{0,1,6,3},{1,2,6,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 5, Case where edges: 4,6 are split
|
|
{{0,3,4,6},{1,2,6,3},{1,3,6,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 6, Case where edges: 5,6 are split
|
|
{{0,1,5,3},{0,3,5,6},{2,3,6,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 7, Case where edges: 4,5,6 are split
|
|
{{0,3,4,6},{1,3,5,4},{2,3,6,5},{3,4,6,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 8, Case where edges: 7 are split
|
|
{{0,1,2,7},{1,2,7,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 9, Case where edges: 4,7 are split
|
|
{{0,2,7,4},{1,2,4,7},{1,2,7,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 10, Case where edges: 5,7 are split
|
|
{{0,1,5,7},{0,2,7,5},{1,3,5,7},{2,3,7,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 11, Case where edges: 4,5,7 are split
|
|
{{0,2,7,5},{0,4,5,7},{1,3,5,7},{1,4,7,5},{2,3,7,5}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 12, Case where edges: 6,7 are split
|
|
{{0,1,6,7},{1,2,6,3},{1,3,6,7}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 13, Case where edges: 4,6,7 are split
|
|
{{0,4,6,7},{1,2,6,3},{1,3,6,7},{1,4,7,6}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 14, Case where edges: 5,6,7 are split
|
|
{{0,1,5,7},{0,5,6,7},{1,3,5,7},{2,3,6,5},{3,5,7,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 15, Case where edges: 4,5,6,7 are split
|
|
{{0,4,6,7},{1,3,5,7},{1,4,7,5},{2,3,6,5},{3,5,7,6},{4,5,6,7}, NO_TETRA, NO_TETRA},
|
|
// Index = 16, Case where edges: 8 are split
|
|
{{0,1,2,8},{0,2,3,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 17, Case where edges: 4,8 are split
|
|
{{0,2,3,8},{0,2,8,4},{1,2,4,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 18, Case where edges: 5,8 are split
|
|
{{0,1,5,8},{0,2,3,5},{0,3,8,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 19, Case where edges: 4,5,8 are split
|
|
{{0,2,3,5},{0,3,8,5},{0,4,5,8},{1,4,8,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 20, Case where edges: 6,8 are split
|
|
{{0,1,6,8},{0,3,8,6},{1,2,6,8},{2,3,6,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 21, Case where edges: 4,6,8 are split
|
|
{{0,3,8,6},{0,4,6,8},{1,2,6,8},{1,4,8,6},{2,3,6,8}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 22, Case where edges: 5,6,8 are split
|
|
{{0,1,5,8},{0,3,8,6},{0,5,6,8},{2,3,6,5},{3,5,8,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 23, Case where edges: 4,5,6,8 are split
|
|
{{0,3,8,6},{0,4,6,8},{1,4,8,5},{2,3,6,5},{3,5,8,6},{4,5,6,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 24, Case where edges: 7,8 are split
|
|
{{0,1,2,8},{0,2,7,8},{2,3,7,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 25, Case where edges: 4,7,8 are split
|
|
{{0,2,7,4},{1,2,4,8},{2,3,7,8},{2,4,8,7}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 26, Case where edges: 5,7,8 are split
|
|
{{0,1,5,8},{0,2,7,5},{0,5,7,8},{2,3,7,5},{3,5,8,7}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 27, Case where edges: 4,5,7,8 are split
|
|
{{0,2,7,5},{0,4,5,7},{1,4,8,5},{2,3,7,5},{3,5,8,7},{4,5,7,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 28, Case where edges: 6,7,8 are split
|
|
{{0,1,6,8},{0,6,7,8},{1,2,6,8},{2,3,6,8},{3,6,8,7}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 29, Case where edges: 4,6,7,8 are split
|
|
{{0,4,6,7},{1,2,6,8},{1,4,8,6},{2,3,6,8},{3,6,8,7},{4,6,7,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 30, Case where edges: 5,6,7,8 are split
|
|
{{0,1,5,8},{0,5,6,7},{0,5,7,8},{2,3,6,5},{3,5,7,6},{3,5,8,7}, NO_TETRA, NO_TETRA},
|
|
// Index = 31, Case where edges: 4,5,6,7,8 are split
|
|
{{0,4,6,7},{1,4,8,5},{2,3,6,5},{3,5,7,6},{3,5,8,7},{4,5,6,7},{4,5,7,8}, NO_TETRA},
|
|
// Index = 32, Case where edges: are split
|
|
{{0,1,2,9},{0,1,9,3}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 33, Case where edges: 4 are split
|
|
{{0,2,9,4},{0,3,4,9},{1,2,4,9},{1,3,9,4}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 34, Case where edges: 5 are split
|
|
{{0,1,5,9},{0,1,9,3},{0,2,9,5}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 35, Case where edges: 4,5 are split
|
|
{{0,2,9,5},{0,3,4,9},{0,4,5,9},{1,3,9,4},{1,4,9,5}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 36, Case where edges: 6 are split
|
|
{{0,1,6,9},{0,1,9,3},{1,2,6,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 37, Case where edges: 4,6 are split
|
|
{{0,3,4,9},{0,4,6,9},{1,2,6,9},{1,3,9,4},{1,4,9,6}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 38, Case where edges: 5,6 are split
|
|
{{0,1,5,9},{0,1,9,3},{0,5,6,9},{2,5,9,6}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 39, Case where edges: 4,5,6 are split
|
|
{{0,3,4,9},{0,4,6,9},{1,3,9,4},{1,4,9,5},{2,5,9,6},{4,5,6,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 40, Case where edges: 7 are split
|
|
{{0,1,2,9},{0,1,9,7},{1,3,9,7}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 41, Case where edges: 4,7 are split
|
|
{{0,2,9,4},{0,4,9,7},{1,2,4,9},{1,3,9,7},{1,4,7,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 42, Case where edges: 5,7 are split
|
|
{{0,1,5,7},{0,2,9,5},{0,5,9,7},{1,3,9,7},{1,5,7,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 43, Case where edges: 4,5,7 are split
|
|
{{0,2,9,5},{0,4,5,7},{0,5,9,7},{1,3,9,7},{1,4,7,5},{1,5,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 44, Case where edges: 6,7 are split
|
|
{{0,1,6,7},{1,2,6,9},{1,3,9,7},{1,6,7,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 45, Case where edges: 4,6,7 are split
|
|
{{0,4,6,7},{1,2,6,9},{1,3,9,7},{1,4,7,9},{1,4,9,6},{4,6,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 46, Case where edges: 5,6,7 are split
|
|
{{0,1,5,7},{0,5,6,7},{1,3,9,7},{1,5,7,9},{2,5,9,6},{5,6,7,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 47, Case where edges: 4,5,6,7 are split
|
|
{{0,4,6,7},{1,3,9,7},{1,4,7,5},{1,5,7,9},{2,5,9,6},{4,5,6,7},{5,6,7,9}, NO_TETRA},
|
|
// Index = 48, Case where edges: 8 are split
|
|
{{0,1,2,9},{0,1,9,8},{0,3,8,9}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 49, Case where edges: 4,8 are split
|
|
{{0,2,9,4},{0,3,8,9},{0,4,9,8},{1,2,4,9},{1,4,8,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 50, Case where edges: 5,8 are split
|
|
{{0,1,5,8},{0,2,9,5},{0,3,8,9},{0,5,9,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 51, Case where edges: 4,5,8 are split
|
|
{{0,2,9,5},{0,3,8,9},{0,4,5,9},{0,4,9,8},{1,4,8,5},{4,5,9,8}, NO_TETRA, NO_TETRA},
|
|
// Index = 52, Case where edges: 6,8 are split
|
|
{{0,1,6,8},{0,3,8,9},{0,6,9,8},{1,2,6,9},{1,6,8,9}, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 53, Case where edges: 4,6,8 are split
|
|
{{0,3,8,9},{0,4,6,8},{0,6,9,8},{1,2,6,9},{1,4,8,6},{1,6,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 54, Case where edges: 5,6,8 are split
|
|
{{0,1,5,8},{0,3,8,9},{0,5,6,8},{0,6,9,8},{2,5,9,6},{5,6,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 55, Case where edges: 4,5,6,8 are split
|
|
{{0,3,8,9},{0,4,6,8},{0,6,9,8},{1,4,8,5},{2,5,9,6},{4,5,6,8},{5,6,8,9}, NO_TETRA},
|
|
// Index = 56, Case where edges: 7,8 are split
|
|
{{0,1,2,9},{0,1,9,8},{0,7,8,9},{3,7,9,8}, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
// Index = 57, Case where edges: 4,7,8 are split
|
|
{{0,2,9,4},{0,4,9,7},{1,2,4,9},{1,4,8,9},{3,7,9,8},{4,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 58, Case where edges: 5,7,8 are split
|
|
{{0,1,5,8},{0,2,9,5},{0,5,7,8},{0,5,9,7},{3,7,9,8},{5,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 59, Case where edges: 4,5,7,8 are split
|
|
{{0,2,9,5},{0,4,5,7},{0,5,9,7},{1,4,8,5},{3,7,9,8},{4,5,7,8},{5,7,8,9}, NO_TETRA},
|
|
// Index = 60, Case where edges: 6,7,8 are split
|
|
{{0,1,6,8},{0,6,7,8},{1,2,6,9},{1,6,8,9},{3,7,9,8},{6,7,8,9}, NO_TETRA, NO_TETRA},
|
|
// Index = 61, Case where edges: 4,6,7,8 are split
|
|
{{0,4,6,7},{1,2,6,9},{1,4,8,6},{1,6,8,9},{3,7,9,8},{4,6,7,8},{6,7,8,9}, NO_TETRA},
|
|
// Index = 62, Case where edges: 5,6,7,8 are split
|
|
{{0,1,5,8},{0,5,6,7},{0,5,7,8},{2,5,9,6},{3,7,9,8},{5,6,7,9},{5,7,8,9}, NO_TETRA},
|
|
// Index = 63, Case where edges: 4,5,6,7,8 are split
|
|
{{0,4,6,7},{1,4,8,5},{2,5,9,6},{3,7,9,8},{4,5,6,7},{4,5,7,8},{5,6,7,9},{5,7,8,9}},
|
|
// In case we reach outside the table
|
|
{ NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA, NO_TETRA},
|
|
};
|
|
|
|
|
|
vtkCxxRevisionMacro(vtkSimpleCellTessellator, "$Revision: 1.21 $");
|
|
vtkStandardNewMacro(vtkSimpleCellTessellator);
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// vtkTriangleTile
|
|
//
|
|
|
|
class vtkTriangleTile;
|
|
|
|
class vtkTriangleTile
|
|
{
|
|
public:
|
|
vtkTriangleTile()
|
|
{
|
|
#ifndef NDEBUG
|
|
for(int i=0;i<6;i++)
|
|
{
|
|
this->PointId[i] = -1;
|
|
this->Vertex[i][0] = -100;
|
|
this->Vertex[i][1] = -100;
|
|
this->Vertex[i][2] = -100;
|
|
}
|
|
#endif
|
|
this->SubdivisionLevel = 0;
|
|
assert("inv: " && this->ClassInvariant());
|
|
}
|
|
~vtkTriangleTile() {};
|
|
|
|
#if 0
|
|
int DifferentFromOriginals(double local[3])
|
|
{
|
|
int result = 1;
|
|
int k = 0;
|
|
while(k<3 && result)
|
|
{
|
|
result = !((local[0] == this->Vertex[k][0])
|
|
&& (local[1] == this->Vertex[k][1])
|
|
&& (local[2] == this->Vertex[k][2]));
|
|
++k;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
int ClassInvariant()
|
|
{
|
|
// Mid point are different from all original points.
|
|
int isValid = 1;
|
|
int j = 3;
|
|
int k;
|
|
while(j<6 && isValid)
|
|
{
|
|
// Don't even look at original points if the mid-point is not
|
|
// initialized
|
|
isValid = (this->Vertex[j][0] == -100)
|
|
&& (this->Vertex[j][1] == -100)
|
|
&& (this->Vertex[j][2] == -100);
|
|
if(!isValid)
|
|
{
|
|
k = 0;
|
|
isValid = 1;
|
|
while(k<3 && isValid)
|
|
{
|
|
isValid = !((this->Vertex[j][0] == this->Vertex[k][0])
|
|
&& (this->Vertex[j][1] == this->Vertex[k][1])
|
|
&& (this->Vertex[j][2] == this->Vertex[k][2]));
|
|
++k;
|
|
}
|
|
}
|
|
++j;
|
|
}
|
|
return isValid;
|
|
}
|
|
#endif
|
|
|
|
void SetSubdivisionLevel(int level)
|
|
{
|
|
assert("pre: positive_level" && level>=0);
|
|
this->SubdivisionLevel = level;
|
|
}
|
|
|
|
int GetSubdivisionLevel()
|
|
{
|
|
return this->SubdivisionLevel;
|
|
}
|
|
|
|
void SetVertex( int i , double v[3] )
|
|
{
|
|
this->Vertex[i][0] = v[0];
|
|
this->Vertex[i][1] = v[1];
|
|
this->Vertex[i][2] = v[2];
|
|
}
|
|
|
|
void SetPointId(int i, vtkIdType id) {this->PointId[i] = id;}
|
|
|
|
void SetPointIds(vtkIdType id[3])
|
|
{
|
|
this->PointId[0] = id[0];
|
|
this->PointId[1] = id[1];
|
|
this->PointId[2] = id[2];
|
|
}
|
|
|
|
double *GetVertex( int i )
|
|
{
|
|
return this->Vertex[i];
|
|
}
|
|
|
|
vtkIdType GetPointId( int i )
|
|
{
|
|
return this->PointId[i];
|
|
}
|
|
|
|
// Return true if (e1, e2) is an edge of the tri:
|
|
int IsAnEdge(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
int sum = 0;
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
if(e1 == this->PointId[i] || e2 == this->PointId[i])
|
|
{
|
|
sum++;
|
|
}
|
|
}
|
|
return sum == 2;
|
|
}
|
|
|
|
// Description:
|
|
// Copy point j of source into point i of the current tile.
|
|
void CopyPoint(int i,
|
|
vtkTriangleTile *source,
|
|
int j)
|
|
{
|
|
assert("pre: primary_i" && i>=0 && i<=2);
|
|
assert("pre: source_exists" && source!=0);
|
|
assert("pre: valid_j" && j>=0 && j<=5);
|
|
|
|
this->PointId[i] = source->PointId[j];
|
|
|
|
this->Vertex[i][0] = source->Vertex[j][0];
|
|
this->Vertex[i][1] = source->Vertex[j][1];
|
|
this->Vertex[i][2] = source->Vertex[j][2];
|
|
|
|
this->Edges[i][0]=source->Edges[j][0];
|
|
this->Edges[i][1]=source->Edges[j][1];
|
|
|
|
assert("inv: " && this->ClassInvariant());
|
|
}
|
|
|
|
|
|
|
|
// can tile be split; if so, return TessellatePointsing tiles
|
|
// vtkTriangleTile res[4]
|
|
int Refine( vtkSimpleCellTessellator* tess, vtkTriangleTile *res );
|
|
|
|
// Description:
|
|
// Initialize the Edges array as for a root triangle
|
|
void SetOriginal()
|
|
{
|
|
// key note: for each vertex, the edges number it belongs to are
|
|
// given in increasing order.
|
|
// vertex 0
|
|
this->Edges[0][0]=0;
|
|
this->Edges[0][1]=2;
|
|
// vertex 1
|
|
this->Edges[1][0]=0;
|
|
this->Edges[1][1]=1;
|
|
// vertex 2
|
|
this->Edges[2][0]=1;
|
|
this->Edges[2][1]=2;
|
|
}
|
|
|
|
// Description:
|
|
// Find the parent (if any) of the edge defined by the local point ids i and
|
|
// j. Return the local id of the parent edge, -1 otherwise.
|
|
signed char FindEdgeParent(int p1,
|
|
int p2)
|
|
{
|
|
assert("pre: primary point" && p1>=0 && p1<=2 && p2>=0 && p2<=2);
|
|
int p;
|
|
int q;
|
|
|
|
// choose the point with minimal edge id.
|
|
if(this->Edges[p1][0]<=this->Edges[p2][0])
|
|
{
|
|
p=p1;
|
|
q=p2;
|
|
}
|
|
else
|
|
{
|
|
p=p2;
|
|
q=p1;
|
|
}
|
|
int i=0;
|
|
signed char result=-1;
|
|
|
|
while(result==-1 && i<2)
|
|
{
|
|
if(this->Edges[p][i]<0)
|
|
{
|
|
i=2;
|
|
}
|
|
else
|
|
{
|
|
int j=0;
|
|
while(result==-1 && j<2)
|
|
{
|
|
if(this->Edges[q][j]<0)
|
|
{
|
|
j=2;
|
|
}
|
|
else
|
|
{
|
|
if(this->Edges[p][i]==this->Edges[q][j])
|
|
{
|
|
result=this->Edges[p][i];
|
|
}
|
|
else
|
|
{
|
|
if(this->Edges[p][i]<this->Edges[q][j])
|
|
{
|
|
j=2; // no way to find a common edge
|
|
}
|
|
else
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Description:
|
|
// Set the edge parent of mid as parentEdge.
|
|
void SetEdgeParent(int mid,
|
|
signed char parentEdge)
|
|
{
|
|
assert("pre: mid-point" && mid>=3 && mid<=5);
|
|
this->Edges[mid][0]=parentEdge;
|
|
this->Edges[mid][1]=-1; // always for mid-points
|
|
}
|
|
|
|
private:
|
|
// Keep track of local coordinate in order to evaluate shape function
|
|
double Vertex[3+3][3]; //3 points + 3 mid edge points
|
|
vtkIdType PointId[3+3];
|
|
int SubdivisionLevel;
|
|
|
|
// local ids (-1 to 2) of the original edges on which the points are.
|
|
// a point can be on almost 2 edges:
|
|
// * only a vertex of the original triangle is on 2 edges
|
|
// * the mid-points can be only on 1 edge
|
|
// * -1 encodes no edge
|
|
// * each array is an increasing list of ids terminated by -1 is no edge
|
|
signed char Edges[3+3][2];
|
|
};
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// vtkTetraTile
|
|
//
|
|
|
|
class vtkTetraTile;
|
|
|
|
// For each of the 4 original vertices, list of the 3 edges it belongs to
|
|
// each sub-array is in increasing order.
|
|
// [vertex][edge]
|
|
static int VERTEX_EDGES[4][3]={{0,2,3},{0,1,4},{1,2,5},{3,4,5}};
|
|
// For each of the 4 original vertices, list of the 3 faces it belongs to
|
|
// each sub-array is in increasing order.
|
|
// [vertex][face]
|
|
static int VERTEX_FACES[4][3]={{0,2,3},{0,1,3},{1,2,3},{0,1,2}};
|
|
|
|
class vtkTetraTile
|
|
{
|
|
public:
|
|
vtkTetraTile()
|
|
{
|
|
#ifndef NDEBUG
|
|
for(int i=0;i<10;i++)
|
|
{
|
|
this->PointId[i] = -1;
|
|
this->Vertex[i][0] = -100;
|
|
this->Vertex[i][1] = -100;
|
|
this->Vertex[i][2] = -100;
|
|
}
|
|
#endif
|
|
this->SubdivisionLevel = 0;
|
|
assert("inv: " && this->ClassInvariant());
|
|
}
|
|
~vtkTetraTile() {};
|
|
|
|
#if 0
|
|
int DifferentFromOriginals(double local[3])
|
|
{
|
|
int result=1;
|
|
int k=0;
|
|
while(k<4 && result)
|
|
{
|
|
result=!((local[0] ==this->Vertex[k][0]) &&
|
|
(local[1] == this->Vertex[k][1])
|
|
&& (local[2] == this->Vertex[k][2]));
|
|
++k;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
int ClassInvariant()
|
|
{
|
|
// Mid point are different from all original points.
|
|
int isValid = 1;
|
|
int j = 4;
|
|
int k;
|
|
while(j<10 && isValid)
|
|
{
|
|
// Don't even look at original points if the mid-point is not
|
|
// initialized
|
|
isValid = (this->Vertex[j][0] == -100)
|
|
&& (this->Vertex[j][1] == -100)
|
|
&& (this->Vertex[j][2] == -100);
|
|
if(!isValid)
|
|
{
|
|
k = 0;
|
|
isValid = 1;
|
|
while(k<4 && isValid)
|
|
{
|
|
isValid = !((this->Vertex[j][0] == this->Vertex[k][0])
|
|
&& (this->Vertex[j][1] == this->Vertex[k][1])
|
|
&& (this->Vertex[j][2] == this->Vertex[k][2]));
|
|
++k;
|
|
}
|
|
}
|
|
++j;
|
|
}
|
|
return isValid;
|
|
}
|
|
#endif
|
|
|
|
void SetSubdivisionLevel(int level)
|
|
{
|
|
assert("pre: positive_level" && level>=0);
|
|
this->SubdivisionLevel=level;
|
|
}
|
|
|
|
int GetSubdivisionLevel()
|
|
{
|
|
return this->SubdivisionLevel;
|
|
}
|
|
|
|
void SetVertex( int i, double v[3] )
|
|
{
|
|
this->Vertex[i][0] = v[0];
|
|
this->Vertex[i][1] = v[1];
|
|
this->Vertex[i][2] = v[2];
|
|
assert("inv: " && this->ClassInvariant());
|
|
}
|
|
|
|
void SetPointId(int i, vtkIdType id) { this->PointId[i] = id; }
|
|
|
|
void SetPointIds(vtkIdType id[4])
|
|
{
|
|
this->PointId[0] = id[0];
|
|
this->PointId[1] = id[1];
|
|
this->PointId[2] = id[2];
|
|
this->PointId[3] = id[3];
|
|
}
|
|
|
|
void GetVertex( int i, double pt[3] )
|
|
{
|
|
pt[0] = this->Vertex[i][0];
|
|
pt[1] = this->Vertex[i][1];
|
|
pt[2] = this->Vertex[i][2];
|
|
}
|
|
|
|
double *GetVertex( int i ) { return Vertex[i]; }
|
|
|
|
vtkIdType GetPointId( int i ) { return this->PointId[i]; }
|
|
|
|
// Return true if (e1, e2) is an edge of the tetra:
|
|
int IsAnEdge(vtkIdType e1, vtkIdType e2)
|
|
{
|
|
int sum = 0;
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
if(e1 == this->PointId[i] || e2 == this->PointId[i])
|
|
{
|
|
sum++;
|
|
}
|
|
}
|
|
return sum == 2;
|
|
}
|
|
|
|
// Description:
|
|
// Copy point j of source into point i of the current tile.
|
|
void CopyPoint(int i,
|
|
vtkTetraTile *source,
|
|
int j)
|
|
{
|
|
assert("pre: primary_i" && i>=0 && i<=3);
|
|
assert("pre: source_exists" && source!=0);
|
|
assert("pre: valid_j" && j>=0 && j<=9);
|
|
|
|
this->PointId[i] = source->PointId[j];
|
|
|
|
this->Vertex[i][0] = source->Vertex[j][0];
|
|
this->Vertex[i][1] = source->Vertex[j][1];
|
|
this->Vertex[i][2] = source->Vertex[j][2];
|
|
|
|
this->Edges[i][0]=source->Edges[j][0];
|
|
this->Edges[i][1]=source->Edges[j][1];
|
|
this->Edges[i][2]=source->Edges[j][2];
|
|
this->Faces[i][0]=source->Faces[j][0];
|
|
this->Faces[i][1]=source->Faces[j][1];
|
|
this->Faces[i][2]=source->Faces[j][2];
|
|
|
|
assert("inv: " && this->ClassInvariant());
|
|
}
|
|
|
|
// Description:
|
|
// Copy the pointer to the Edge and Face Ids on the
|
|
// top-level sub-tetrahedron.
|
|
void CopyEdgeAndFaceIds(vtkTetraTile *source)
|
|
{
|
|
assert("pre: source_exists" && source!=0);
|
|
this->EdgeIds= source->EdgeIds;
|
|
this->FaceIds= source->FaceIds;
|
|
}
|
|
|
|
// Description:
|
|
// Return the local edge id the complex cell from the local edge id
|
|
// of the top-level subtetra
|
|
int GetEdgeIds(int idx)
|
|
{
|
|
assert("pre:" && idx>=0); // <=number of edges on a complex cell
|
|
return this->EdgeIds[idx];
|
|
}
|
|
|
|
// Description:
|
|
// Return the local face id the complex cell from the local face id
|
|
// of the top-level subtetra
|
|
int GetFaceIds(int idx)
|
|
{
|
|
assert("pre:" && idx>=0);// <=number of faces on a complex cell
|
|
return this->FaceIds[idx];
|
|
}
|
|
|
|
// can tile be split; if so, return TessellatePointsing tiles
|
|
// There can't be more than 8 tetras as it corresponds to the splitting
|
|
// of all edges
|
|
// vtkTetraTile res[8]
|
|
int Refine( vtkSimpleCellTessellator* tess, vtkTetraTile *res);
|
|
|
|
// Description:
|
|
// Initialize the Edges and Faces arrays as for a root tetrahedron
|
|
void SetOriginal(vtkIdType order[4],
|
|
int *edgeIds, //6
|
|
int *faceIds) // 4
|
|
{
|
|
this->EdgeIds=edgeIds;
|
|
this->FaceIds=faceIds;
|
|
|
|
int i=0;
|
|
while(i<4) // for each vertex
|
|
{
|
|
int j=order[i];
|
|
int k=0;
|
|
int n=0;
|
|
int tmp;
|
|
while(n<3) // copy each edge
|
|
{
|
|
tmp=VERTEX_EDGES[j][n];
|
|
if(edgeIds[tmp]!=-1)
|
|
{
|
|
this->Edges[i][k]=tmp;
|
|
++k;
|
|
}
|
|
++n;
|
|
}
|
|
while(k<3)
|
|
{
|
|
this->Edges[i][k]=-1;
|
|
++k;
|
|
}
|
|
|
|
k=0;
|
|
n=0;
|
|
while(n<3) // copy each face
|
|
{
|
|
tmp=VERTEX_FACES[j][n];
|
|
if(faceIds[tmp]!=-1)
|
|
{
|
|
this->Faces[i][k]=tmp;
|
|
++k;
|
|
}
|
|
++n;
|
|
}
|
|
while(k<3)
|
|
{
|
|
this->Faces[i][k]=-1;
|
|
++k;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// Description:
|
|
// Find the parent (if any) of the edge defined by the local point ids i and
|
|
// j. Return the local id of the parent edge, -1 otherwise.
|
|
int FindEdgeParent(int p1,
|
|
int p2,
|
|
signed char &parentId)
|
|
{
|
|
assert("pre: primary point" && p1>=0 && p1<=3 && p2>=0 && p2<=3);
|
|
|
|
int p;
|
|
int q;
|
|
// choose the point with minimal edge id.
|
|
if(this->Edges[p1][0]<=this->Edges[p2][0])
|
|
{
|
|
p=p1;
|
|
q=p2;
|
|
}
|
|
else
|
|
{
|
|
p=p2;
|
|
q=p1;
|
|
}
|
|
int i=0;
|
|
int result=3;
|
|
parentId=-1;
|
|
|
|
while(result==3 && i<3)
|
|
{
|
|
if(this->Edges[p][i]<0)
|
|
{
|
|
i=3; //done
|
|
}
|
|
else
|
|
{
|
|
int j=0;
|
|
while(result==3 && j<3)
|
|
{
|
|
if(this->Edges[q][j]<0)
|
|
{
|
|
j=3; // end of the edges of q, skip to next i
|
|
}
|
|
else
|
|
{
|
|
if(this->Edges[p][i]==this->Edges[q][j])
|
|
{
|
|
parentId=this->Edges[p][i];
|
|
result=1;
|
|
}
|
|
else
|
|
{
|
|
if(this->Edges[p][i]<this->Edges[q][j])
|
|
{
|
|
j=3; // no way to find a common face for this i, skip to next i
|
|
}
|
|
else
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
|
|
if(result==3) // there is no common edge
|
|
{
|
|
// it seems there is at most one common face
|
|
// choose the point with minimal face id.
|
|
if(this->Faces[p1][0]<=this->Faces[p2][0])
|
|
{
|
|
p=p1;
|
|
q=p2;
|
|
}
|
|
else
|
|
{
|
|
p=p2;
|
|
q=p1;
|
|
}
|
|
i=0;
|
|
while(result==3 && i<3)
|
|
{
|
|
if(this->Faces[p][i]<0)
|
|
{
|
|
i=3; // no common face
|
|
}
|
|
else
|
|
{
|
|
int j=0;
|
|
while(result==3 && j<3)
|
|
{
|
|
if(this->Faces[q][j]<0)
|
|
{
|
|
j=3; // end of the edges of q, skip to next i
|
|
}
|
|
else
|
|
{
|
|
if(this->Faces[p][i]==this->Faces[q][j])
|
|
{
|
|
parentId=this->Faces[p][i];
|
|
result=2;
|
|
}
|
|
else
|
|
{
|
|
if(this->Faces[p][i]<this->Faces[q][j])
|
|
{
|
|
j=3; // no way to find a common face for this i, skip to next i
|
|
}
|
|
else
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
// Description:
|
|
// Set the edge parent of mid as parentEdge.
|
|
void SetParent(int mid,
|
|
signed char parentId,
|
|
int type)
|
|
{
|
|
assert("pre: mid-point" && mid>=4 && mid<=9);
|
|
assert("pre: valid_type" && type>=1 && type<=3);
|
|
assert("pre: id_match_type" &&
|
|
( (type==1 && parentId>=0 && parentId<=5) ||
|
|
(type==2 && parentId>=0 && parentId<=3) ||
|
|
(type==3 && parentId==-1) ) );
|
|
|
|
if(type==1) // edge
|
|
{
|
|
this->Edges[mid][0]=parentId;
|
|
// it means also that the point belongs to two faces
|
|
// the id of the faces can be found thanks to the edge id
|
|
switch(parentId)
|
|
{
|
|
case 0:
|
|
this->Faces[mid][0]=0;
|
|
this->Faces[mid][1]=3;
|
|
break;
|
|
case 1:
|
|
this->Faces[mid][0]=1;
|
|
this->Faces[mid][1]=3;
|
|
break;
|
|
case 2:
|
|
this->Faces[mid][0]=2;
|
|
this->Faces[mid][1]=3;
|
|
break;
|
|
case 3:
|
|
this->Faces[mid][0]=0;
|
|
this->Faces[mid][1]=2;
|
|
break;
|
|
case 4:
|
|
this->Faces[mid][0]=0;
|
|
this->Faces[mid][1]=1;
|
|
break;
|
|
case 5:
|
|
this->Faces[mid][0]=1;
|
|
this->Faces[mid][1]=2;
|
|
break;
|
|
default:
|
|
assert("check: impossible case" && 0);
|
|
}
|
|
|
|
}
|
|
else // face (type==2 parentId!=-1) or no parent (parentId==-1 type==3)
|
|
{
|
|
this->Edges[mid][0]=-1;
|
|
this->Faces[mid][0]=parentId;
|
|
this->Faces[mid][1]=-1;
|
|
}
|
|
this->Edges[mid][1]=-1; // always for mid-points
|
|
this->Edges[mid][2]=-1; // always for mid-points
|
|
this->Faces[mid][2]=-1; // always for mid-points
|
|
}
|
|
|
|
// Description:
|
|
// Return if the four corner points of the tetra are all differents
|
|
#ifndef NDEBUG
|
|
int PointsDifferents()
|
|
{
|
|
int result=1;
|
|
int i;
|
|
int j;
|
|
int k;
|
|
|
|
i = 0;
|
|
while(i<3 && result)
|
|
{
|
|
j = i+1;
|
|
while(j<4 && result)
|
|
{
|
|
result = this->PointId[i] != this->PointId[j];
|
|
++j;
|
|
}
|
|
++i;
|
|
}
|
|
if(result) // point id are ok, now test the coordinates
|
|
{
|
|
i = 0;
|
|
while(i<3 && result)
|
|
{
|
|
j = i+1;
|
|
while(j<4 && result)
|
|
{
|
|
k = 0;
|
|
result = 0;
|
|
while(k<3)
|
|
{
|
|
result = result || (this->Vertex[i][k] != this->Vertex[j][k]);
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
// Need to keep track of local coordinate to evaluate shape functions
|
|
// So all work is done in parametric coordinate
|
|
|
|
double Vertex[4+6][3]; // 4 tetra points + 6 mid edge points
|
|
vtkIdType PointId[4+6];
|
|
int SubdivisionLevel;
|
|
|
|
// local ids (-1 to 5) of the original edges on which the points are.
|
|
// a point can be on almost 3 edges:
|
|
// * only a vertex of the original tetrahedron is on 3 edges
|
|
// * the mid-points can be only on 1 edge
|
|
// * -1 encodes no edge
|
|
// * each array is an increasing list of ids terminated by -1 is no edge
|
|
signed char Edges[4+6][3];
|
|
// local ids (-1 to 3) of the original faces on which the points are.
|
|
// a point can be on almost 3 faces:
|
|
// * only a vertex of the original tetrahedron is on 3 faces
|
|
// * the mid-points can be only on 2 faces
|
|
// * a mid-point which is on two faces is also on one edge.
|
|
// * -1 encodes no face
|
|
// * each array is an increasing list of ids terminated by -1 is no face
|
|
signed char Faces[4+6][3];
|
|
|
|
int *EdgeIds;
|
|
int *FaceIds;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkTriangleTile::Refine(vtkSimpleCellTessellator* tess,
|
|
vtkTriangleTile *res )
|
|
{
|
|
// The output will contain a maximum of 4 vtkTriangleTiles
|
|
int i, index;
|
|
int numTriangleCreated = 0;
|
|
|
|
double edgeSplitList[3];
|
|
vtkIdType ptId = 0;
|
|
int l, r;
|
|
|
|
if(this->SubdivisionLevel < tess->GetMaxSubdivisionLevel())
|
|
{
|
|
// loop over edges
|
|
for(i=0, index=0; i<3; i++)
|
|
{
|
|
// we have to calculate mid point between edge TRIANGLE_EDGES_TABLE[i][0]
|
|
// and TRIANGLE_EDGES_TABLE[i][1]
|
|
l = TRIANGLE_EDGES_TABLE[i][0];
|
|
r = TRIANGLE_EDGES_TABLE[i][1];
|
|
|
|
edgeSplitList[i] = tess->EdgeTable->CheckEdge(this->PointId[l],
|
|
this->PointId[r], ptId);
|
|
|
|
// On previous step we made sure to prepare the hash table
|
|
assert("check: edge table prepared" && edgeSplitList[i] != -1);
|
|
|
|
// Build the case table
|
|
if (edgeSplitList[i])
|
|
{
|
|
index |= 1 << i;
|
|
}
|
|
}
|
|
|
|
if( index )
|
|
{
|
|
// That mean at least one edge was split and thus index != 0
|
|
signed char *cases = **(vtkTessellatorTriangleCases + index);
|
|
|
|
for(; cases[0] > -1; cases+=3)
|
|
{
|
|
for(int j=0; j<3; j++)
|
|
{
|
|
res[numTriangleCreated].CopyPoint(j,this,cases[j]);
|
|
// res[numTriangleCreated].SetPointId( j, this->PointId[cases[j]] );
|
|
// res[numTriangleCreated].SetVertex( j, this->Vertex[cases[j]] );
|
|
}
|
|
//update number of triangles
|
|
numTriangleCreated++;
|
|
}
|
|
//Insert edges from new triangle into hash table:
|
|
for(int k=0; k < numTriangleCreated; k++)
|
|
{
|
|
res[k].SubdivisionLevel = this->SubdivisionLevel + 1;
|
|
tess->InsertEdgesIntoEdgeTable( res[k] );
|
|
}
|
|
}
|
|
}
|
|
|
|
if(numTriangleCreated == 0)
|
|
{
|
|
// no edge were split so recursion is done
|
|
// add the cell array to the list
|
|
tess->TessellateCellArray->InsertNextCell(3, this->PointId);
|
|
|
|
for(int j=0; j<3; j++)
|
|
{
|
|
tess->CopyPoint(this->PointId[j]);
|
|
}
|
|
}
|
|
|
|
return numTriangleCreated;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Extract point `pointId' from the edge table to the output point and output
|
|
// point data.
|
|
void vtkSimpleCellTessellator::CopyPoint(vtkIdType pointId)
|
|
{
|
|
double point[3];
|
|
double *p = this->Scalars;
|
|
|
|
this->EdgeTable->CheckPoint(pointId, point, p);
|
|
// There will some be duplicate points during a while but
|
|
// this is the cost for speed:
|
|
this->TessellatePoints->InsertNextTuple( point );
|
|
// this->TessellatePointData->InsertNextTuple( tess->Scalars );
|
|
|
|
int c = this->TessellatePointData->GetNumberOfArrays();
|
|
vtkDataArray *attribute;
|
|
|
|
for(int i=0; i<c; i++)
|
|
{
|
|
attribute = this->TessellatePointData->GetArray(i);
|
|
attribute->InsertNextTuple(p);
|
|
p += attribute->GetNumberOfComponents();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
static void Reorder(vtkIdType in[4], vtkIdType order[4])
|
|
{
|
|
// Input: in[4] contains pointId of a tetra in right hand rule.
|
|
// Output: this function reorders so that:
|
|
// out[0] < out[1]
|
|
// out[0] < out[2]
|
|
// out[0] < out[3]
|
|
// out[1] < out[2]
|
|
// out[1] < out[3]
|
|
// and still respect the right hand rule for tetra:
|
|
|
|
|
|
vtkIdType min1 = in[0];
|
|
vtkIdType min2 = in[1];
|
|
vtkIdType idx1 = 0;
|
|
vtkIdType idx2 = 1;
|
|
for(int i=1;i<4;i++)
|
|
{
|
|
if(min1 > in[i])
|
|
{
|
|
min2 = min1;
|
|
idx2 = idx1;
|
|
min1 = in[i];
|
|
idx1 = i;
|
|
}
|
|
else if(min2 > in[i])
|
|
{
|
|
min2 = in[i];
|
|
idx2 = i;
|
|
}
|
|
}
|
|
|
|
// For debug:
|
|
// order[0] = order[1] = order[2] = order[3] = -1;
|
|
order[0] = idx1;
|
|
order[1] = idx2;
|
|
|
|
if(idx1 == 0)
|
|
{
|
|
if(idx2 == 1)
|
|
{
|
|
order[2] = 2;
|
|
order[3] = 3;
|
|
}
|
|
else if(idx2 == 2)
|
|
{
|
|
order[2] = 3;
|
|
order[3] = 1;
|
|
}
|
|
else if(idx2 == 3)
|
|
{
|
|
order[2] = 1;
|
|
order[3] = 2;
|
|
}
|
|
}
|
|
else if(idx1 == 1)
|
|
{
|
|
if(idx2 == 0)
|
|
{
|
|
order[2] = 3;
|
|
order[3] = 2;
|
|
}
|
|
else if(idx2 == 2)
|
|
{
|
|
order[2] = 0;
|
|
order[3] = 3;
|
|
}
|
|
else if(idx2 == 3)
|
|
{
|
|
order[2] = 2;
|
|
order[3] = 0;
|
|
}
|
|
}
|
|
else if(idx1 == 2)
|
|
{
|
|
if(idx2 == 0)
|
|
{
|
|
order[2] = 1;
|
|
order[3] = 3;
|
|
}
|
|
else if(idx2 == 1)
|
|
{
|
|
order[2] = 3;
|
|
order[3] = 0;
|
|
}
|
|
else if(idx2 == 3)
|
|
{
|
|
order[2] = 0;
|
|
order[3] = 1;
|
|
}
|
|
}
|
|
else if(idx1 == 3)
|
|
{
|
|
if(idx2 == 0)
|
|
{
|
|
order[2] = 2;
|
|
order[3] = 1;
|
|
}
|
|
else if(idx2 == 1)
|
|
{
|
|
order[2] = 0;
|
|
order[3] = 2;
|
|
}
|
|
else if(idx2 == 2)
|
|
{
|
|
order[2] = 1;
|
|
order[3] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkTetraTile::Refine(vtkSimpleCellTessellator* tess,
|
|
vtkTetraTile *res)
|
|
{
|
|
// The output will contains a maximum of 8 vtkTetraTiles
|
|
int i, index;
|
|
int numTetraCreated = 0;
|
|
|
|
// We need to order the point by lower id first
|
|
// this will create an edge ordering and based on that we can
|
|
// find which edge is split this gives us a mask for the tessellation
|
|
|
|
// There is only 6 edges in a tetra we need this structure to quickly
|
|
// determine in which case we are to tessellate the tetra.
|
|
int edgeSplitList[6];
|
|
vtkIdType ptId = 0;
|
|
int l, r;
|
|
|
|
if(this->SubdivisionLevel < tess->GetMaxSubdivisionLevel())
|
|
{
|
|
// loop over edges:
|
|
for(i=0, index=0; i<6; i++)
|
|
{
|
|
// we have to calculate mid point between edge TETRA_EDGES_TABLE[i][0] and
|
|
// TETRA_EDGES_TABLE[i][1]
|
|
l = TETRA_EDGES_TABLE[i][0];
|
|
r = TETRA_EDGES_TABLE[i][1];
|
|
|
|
edgeSplitList[i] = tess->EdgeTable->CheckEdge(this->PointId[l],
|
|
this->PointId[r], ptId);
|
|
|
|
// On previous step we made sure to prepare the hash table
|
|
assert("check: edge table prepared" && edgeSplitList[i] != -1);
|
|
|
|
// Build the case table
|
|
if (edgeSplitList[i])
|
|
{
|
|
index |= 1 << i;
|
|
}
|
|
}
|
|
|
|
if( index )
|
|
{
|
|
// That mean at least one edge was split and thus index != 0
|
|
vtkIdType tetra[4], order[4];
|
|
signed char *cases;
|
|
|
|
// we compare right away PointId[2] to PointId[3] because we assume
|
|
// input tetra is already ordered properly (cf. Reorder previous step)
|
|
if(this->PointId[2] < this->PointId[3])
|
|
{
|
|
cases = **(vtkTessellatorTetraCasesRight + index);
|
|
}
|
|
else
|
|
{
|
|
cases = **(vtkTessellatorTetraCasesLeft + index);
|
|
}
|
|
|
|
// For each sub-tetra, increment number of tetra created
|
|
// And check each of its edges if its in the hash table
|
|
int k;
|
|
|
|
for(; cases[0]> -1; cases+=4)
|
|
{
|
|
for(k=0; k<4; k++)
|
|
{
|
|
tetra[k] = this->PointId[cases[k]];
|
|
}
|
|
|
|
// The whole purpose of Reorder is really to classify the tetra, the
|
|
// reordering is only useful for quick testing. The tet will either
|
|
// classify as Right ordered or Left ordered
|
|
Reorder(tetra, order);
|
|
|
|
// Set the tetras point for the next recursion
|
|
for(int j=0;j<4;j++)
|
|
{
|
|
res[numTetraCreated].CopyPoint(j,this,cases[order[j]]);
|
|
}
|
|
res[numTetraCreated].CopyEdgeAndFaceIds(this);
|
|
numTetraCreated++;
|
|
}
|
|
k = 0;
|
|
while(k < numTetraCreated)
|
|
{
|
|
res[k].SubdivisionLevel = this->SubdivisionLevel + 1;
|
|
tess->InsertEdgesIntoEdgeTable( res[k] );
|
|
++k;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(numTetraCreated == 0)
|
|
{
|
|
// no edge were split so recursion is done
|
|
// add the cell array to the list
|
|
tess->TessellateCellArray->InsertNextCell(4, this->PointId);
|
|
|
|
for(int j=0; j<4; j++)
|
|
{
|
|
tess->CopyPoint(this->PointId[j]);
|
|
}
|
|
}
|
|
|
|
return numTetraCreated;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create the tessellator helper with a default of 0.25 for threshold
|
|
//
|
|
vtkSimpleCellTessellator::vtkSimpleCellTessellator()
|
|
{
|
|
this->GenericCell = NULL;
|
|
|
|
this->TessellatePoints = NULL;
|
|
this->TessellateCellArray = NULL;
|
|
this->TessellatePointData = NULL;
|
|
|
|
this->EdgeTable = vtkGenericEdgeTable::New();
|
|
|
|
this->AttributeCollection = NULL;
|
|
|
|
this->CellIterator = 0;
|
|
this->Scalars = 0;
|
|
this->ScalarsCapacity = 0;
|
|
this->PointOffset = 0;
|
|
|
|
this->DataSet = 0;
|
|
|
|
this->FixedSubdivisions = 0; // 0 means no fixed subdivision
|
|
this->MaxSubdivisionLevel = 0; // 0 means no subdivision at all
|
|
this->CurrentSubdivisionLevel = 0;
|
|
|
|
|
|
this->Triangulator=vtkOrderedTriangulator::New();
|
|
this->Triangulator->UseTemplatesOn();
|
|
|
|
this->PointIds=0;
|
|
this->PointIdsCapacity=0;
|
|
|
|
this->Connectivity=vtkCellArray::New();
|
|
this->Polygon=vtkPolygon::New();
|
|
this->TriangleIds=vtkIdList::New();
|
|
this->TriangleIds->Allocate(VTK_CELL_SIZE);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkSimpleCellTessellator::~vtkSimpleCellTessellator()
|
|
{
|
|
this->EdgeTable->Delete();
|
|
if(this->CellIterator)
|
|
{
|
|
this->CellIterator->Delete();
|
|
}
|
|
if(this->Scalars)
|
|
{
|
|
delete[] this->Scalars;
|
|
}
|
|
|
|
this->Triangulator->Delete();
|
|
if(this->PointIds!=0)
|
|
{
|
|
delete[] this->PointIds;
|
|
}
|
|
this->Connectivity->Delete();
|
|
this->Polygon->Delete();
|
|
this->TriangleIds->Delete();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function is supposed to be called only at toplevel (for passing data
|
|
// from third party to the hash point table)
|
|
void vtkSimpleCellTessellator::InsertPointsIntoEdgeTable(vtkTriangleTile &tri)
|
|
{
|
|
double global[3];
|
|
|
|
for(int j=0; j<3; j++)
|
|
{
|
|
// Need to check first if point is not already in the hash table
|
|
// since EvaluateLocation / EvaluateTuple are expensive calls
|
|
if( !this->EdgeTable->CheckPoint(tri.GetPointId(j)) )
|
|
{
|
|
// it's real space coordinate:
|
|
this->GenericCell->EvaluateLocation(0,tri.GetVertex(j), global);
|
|
|
|
// Then scalar value associated with point:
|
|
this->GenericCell->InterpolateTuple(this->AttributeCollection,
|
|
tri.GetVertex(j), this->Scalars);
|
|
|
|
//Put everything in ths point hash table
|
|
this->EdgeTable->InsertPointAndScalar(tri.GetPointId(j), global,
|
|
this->Scalars);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void vtkSimpleCellTessellator::InsertEdgesIntoEdgeTable(vtkTriangleTile &tri )
|
|
{
|
|
double *local = 0;
|
|
vtkIdType tmp;
|
|
vtkIdType l, r;
|
|
vtkIdType cellId = this->GenericCell->GetId();
|
|
|
|
const double alpha = 0.5;
|
|
assert("check: normalized alpha" && alpha>0 && alpha<1);
|
|
|
|
//First setup the point reference count:
|
|
for(int i = 0; i<3; i++)
|
|
{
|
|
this->EdgeTable->IncrementPointReferenceCount(tri.GetPointId(i));
|
|
}
|
|
|
|
double *leftPoint = this->Scalars;
|
|
double *midPoint = this->Scalars + this->PointOffset;
|
|
double *rightPoint = midPoint + this->PointOffset;
|
|
|
|
|
|
// Loop over all edges:
|
|
// For each edge:
|
|
// if in hash table: incr ref
|
|
// else: evaluate & put in table ref = 1
|
|
for(int j=0; j<3; j++)
|
|
{
|
|
l = TRIANGLE_EDGES_TABLE[j][0];
|
|
r = TRIANGLE_EDGES_TABLE[j][1];
|
|
|
|
vtkIdType leftId = tri.GetPointId(l);
|
|
vtkIdType rightId = tri.GetPointId(r);
|
|
|
|
if(leftId > rightId)
|
|
{
|
|
// ensure that the left point has the smallest id
|
|
// hence, evaluation occurs in the same direction in any case
|
|
// the computations of error and interpolation will not suffer from
|
|
// numerical precision.
|
|
tmp = leftId;
|
|
leftId = rightId;
|
|
rightId = tmp;
|
|
|
|
tmp = l;
|
|
l = r;
|
|
r = tmp;
|
|
}
|
|
|
|
double *left = tri.GetVertex(l);
|
|
double *right = tri.GetVertex(r);
|
|
|
|
memcpy(leftPoint + PARAMETRIC_OFFSET, left, sizeof(double)*3);
|
|
memcpy(rightPoint + PARAMETRIC_OFFSET, right, sizeof(double)*3);
|
|
|
|
//Check first in the hash table
|
|
vtkIdType ptId = -1;
|
|
|
|
// To calculate the edge ref count, we either:
|
|
// - find it in the hash table
|
|
// - calculate from higher order cell:
|
|
|
|
int toSplit = this->EdgeTable->CheckEdge(leftId, rightId, ptId);
|
|
int doSubdivision;
|
|
|
|
if( toSplit == -1)
|
|
{
|
|
// The edge was not found in the hash table, that mean we have to
|
|
// determine it's reference counting from the higher order cell:
|
|
|
|
signed char parentEdge=tri.FindEdgeParent(l,r);
|
|
int refCount;
|
|
if(parentEdge==-1)
|
|
{
|
|
// no parent
|
|
refCount = 1;
|
|
}
|
|
else
|
|
{
|
|
refCount = this->GetNumberOfCellsUsingEdge(parentEdge);
|
|
}
|
|
|
|
doSubdivision = tri.GetSubdivisionLevel() < this->GetMaxSubdivisionLevel();
|
|
|
|
//
|
|
// For measurement of the quality of a fixed subdivision.
|
|
//
|
|
if(!doSubdivision) // done
|
|
{
|
|
if(this->GetMaxSubdivisionLevel()==this->GetFixedSubdivisions())
|
|
{
|
|
// fixed subdivision only
|
|
if(this->GetMeasurement())
|
|
{
|
|
// global position and attributes at the left vertex
|
|
this->EdgeTable->CheckPoint(leftId,leftPoint,
|
|
leftPoint + ATTRIBUTES_OFFSET);
|
|
// global position and attributes at the right vertex
|
|
this->EdgeTable->CheckPoint(rightId,rightPoint,
|
|
rightPoint + ATTRIBUTES_OFFSET);
|
|
|
|
// parametric center of the edge
|
|
local = midPoint + PARAMETRIC_OFFSET;
|
|
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
local[i] = left[i] + alpha*(right[i] - left[i]);
|
|
}
|
|
// global position of the center
|
|
this->GenericCell->EvaluateLocation(0,local,midPoint);
|
|
|
|
// attributes at the center
|
|
this->GenericCell->InterpolateTuple(this->AttributeCollection,
|
|
local,
|
|
midPoint+ATTRIBUTES_OFFSET);
|
|
this->UpdateMaxError(leftPoint,midPoint,rightPoint,alpha);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
if(doSubdivision)
|
|
{
|
|
// global position and attributes at the left vertex
|
|
this->EdgeTable->CheckPoint(leftId, leftPoint,
|
|
leftPoint + ATTRIBUTES_OFFSET);
|
|
// global position and attributes at the right vertex
|
|
this->EdgeTable->CheckPoint(rightId, rightPoint,
|
|
rightPoint + ATTRIBUTES_OFFSET);
|
|
|
|
// parametric center of the edge
|
|
local = midPoint + PARAMETRIC_OFFSET;
|
|
for(int i=0; i < 3; i++)
|
|
{
|
|
local[i] = left[i] + alpha*(right[i] - left[i]);
|
|
}
|
|
// is the mid point different from both the left and right point?
|
|
// if not, we do not subdivide, it is a degenerated case.
|
|
//doSubdivision = tri.DifferentFromOriginals(local);
|
|
doSubdivision = (alpha != 0.0 && alpha != 1.0);
|
|
|
|
if(doSubdivision)
|
|
{
|
|
// global position of the center
|
|
this->GenericCell->EvaluateLocation(0,local,midPoint);
|
|
|
|
// attributes at the center
|
|
this->GenericCell->InterpolateTuple(this->AttributeCollection, local,
|
|
midPoint + ATTRIBUTES_OFFSET);
|
|
|
|
doSubdivision = tri.GetSubdivisionLevel() < this->GetFixedSubdivisions();
|
|
if(!doSubdivision) // fixed subdivision is done, need adaptive one?
|
|
{
|
|
doSubdivision = this->RequiresEdgeSubdivision(leftPoint,midPoint,
|
|
rightPoint,alpha);
|
|
}
|
|
}
|
|
} // first doSubdivision
|
|
|
|
if(doSubdivision)
|
|
{
|
|
this->EdgeTable->InsertEdge(leftId, rightId, cellId, refCount, ptId);
|
|
assert("check: id exists" && ptId != -1 );
|
|
|
|
// And also the value we'll have to put to avoid recomputing them later:
|
|
|
|
//Save mid point:
|
|
tri.SetVertex(j+3, local);
|
|
tri.SetPointId(j+3, ptId);
|
|
tri.SetEdgeParent(j+3,parentEdge);
|
|
|
|
//Put everything in ths point hash table
|
|
this->EdgeTable->InsertPointAndScalar(ptId, midPoint,
|
|
midPoint + ATTRIBUTES_OFFSET);
|
|
}
|
|
else
|
|
{
|
|
// The edge does not need to be split simply insert it
|
|
this->EdgeTable->InsertEdge(leftId, rightId, cellId, refCount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// else the edge is in the table we need to increment its ref count.
|
|
// This becomes tricky when we are incrementing an edge shared across
|
|
// cell, we should not increment edge ref count when first time in a cell
|
|
// Precondition third package have unique cellId.
|
|
this->EdgeTable->IncrementEdgeReferenceCount(leftId, rightId, cellId);
|
|
|
|
if(toSplit == 1) // we cannot just right if(toSplit) because it can be -1
|
|
{
|
|
tri.SetPointId(j+3, ptId);
|
|
|
|
double pcoords[3];
|
|
pcoords[0] = tri.GetVertex(l)[0] + alpha*(tri.GetVertex(r)[0] - tri.GetVertex(l)[0]);
|
|
pcoords[1] = tri.GetVertex(l)[1] + alpha*(tri.GetVertex(r)[1] - tri.GetVertex(l)[1]);
|
|
pcoords[2] = tri.GetVertex(l)[2] + alpha*(tri.GetVertex(r)[2] - tri.GetVertex(l)[2]);
|
|
|
|
tri.SetVertex(j+3, pcoords);
|
|
// note we dont need to call SetEdgeParent() because
|
|
// if the edge is already in the hashtable it means that
|
|
// it is already tessellated. All other point using this
|
|
// edge will come from either inside the triangle either from
|
|
// and another edge. For sur the resulting edge will be inside (-1)
|
|
tri.SetEdgeParent(j+3,-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void vtkSimpleCellTessellator::InsertEdgesIntoEdgeTable( vtkTetraTile &tetra )
|
|
{
|
|
double *local = 0;
|
|
|
|
vtkIdType tmp;
|
|
vtkIdType l, r;
|
|
const vtkIdType cellId = this->GenericCell->GetId();
|
|
|
|
// double alpha=0.5+0.02*(rand()/(RAND_MAX+1.0)-0.5);
|
|
const double alpha = 0.5;
|
|
assert("check: normalized alpha" && alpha>0 && alpha<1);
|
|
|
|
//First setup the point reference count:
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
this->EdgeTable->IncrementPointReferenceCount(tetra.GetPointId(i));
|
|
}
|
|
|
|
double *leftPoint = this->Scalars;
|
|
double *midPoint = this->Scalars + this->PointOffset;
|
|
double *rightPoint = midPoint + this->PointOffset;
|
|
|
|
// Loop over all edges:
|
|
// For each edge:
|
|
// if in hash table: incr ref
|
|
// else: evaluate & put in table ref = 1
|
|
for(int j=0; j<6; j++)
|
|
{
|
|
l = TETRA_EDGES_TABLE[j][0];
|
|
r = TETRA_EDGES_TABLE[j][1];
|
|
|
|
vtkIdType leftId = tetra.GetPointId(l);
|
|
vtkIdType rightId = tetra.GetPointId(r);
|
|
|
|
if(leftId > rightId)
|
|
{
|
|
// ensure that the left point has the smallest id
|
|
// hence, evaluation occurs in the same direction in any case
|
|
// the computations of error and interpolation will not suffer from
|
|
// numerical precision.
|
|
tmp = leftId;
|
|
leftId = rightId;
|
|
rightId = tmp;
|
|
|
|
tmp = l;
|
|
l = r;
|
|
r = tmp;
|
|
}
|
|
|
|
double *left = tetra.GetVertex(l);
|
|
double *right = tetra.GetVertex(r);
|
|
|
|
memcpy(leftPoint + PARAMETRIC_OFFSET, left, sizeof(double)*3);
|
|
memcpy(rightPoint + PARAMETRIC_OFFSET, right, sizeof(double)*3);
|
|
|
|
//Check first in the hash table
|
|
vtkIdType ptId = -1;
|
|
int refCount = 1;
|
|
|
|
//vtkDebugMacro( << "InsertEdgesIntoEdgeTable:" << leftId << "," << rightId );
|
|
|
|
// To calculate the edge ref count, we either:
|
|
// - find it in the hash table
|
|
// - calculate from higher order cell:
|
|
|
|
int toSplit = this->EdgeTable->CheckEdge(leftId, rightId, ptId);
|
|
int doSubdivision;
|
|
|
|
if( toSplit == -1)
|
|
{
|
|
// The edge was not found in the hash table, that mean we have to
|
|
// determine it's reference counting from the higher order cell:
|
|
|
|
|
|
signed char parentId;
|
|
int type=tetra.FindEdgeParent(l,r,parentId);
|
|
if(type == 1)
|
|
{
|
|
// On edge:
|
|
refCount = this->GetNumberOfCellsUsingEdge( tetra.GetEdgeIds(parentId) );
|
|
}
|
|
else if(type == 2)
|
|
{
|
|
//On face:
|
|
refCount = this->GetNumberOfCellsUsingFace( tetra.GetFaceIds(parentId) );
|
|
}
|
|
else if(type == 3)
|
|
{
|
|
// Inside:
|
|
refCount = 1;
|
|
}
|
|
|
|
doSubdivision = tetra.GetSubdivisionLevel() < this->GetMaxSubdivisionLevel();
|
|
|
|
//
|
|
// For measurement of the quality of a fixed subdivision.
|
|
//
|
|
if(!doSubdivision) // done
|
|
{
|
|
if(this->GetMaxSubdivisionLevel()==this->GetFixedSubdivisions())
|
|
{
|
|
// fixed subdivision only
|
|
if(this->GetMeasurement())
|
|
{
|
|
// global position and attributes at the left vertex
|
|
this->EdgeTable->CheckPoint(leftId,leftPoint,
|
|
leftPoint + ATTRIBUTES_OFFSET);
|
|
// global position and attributes at the right vertex
|
|
this->EdgeTable->CheckPoint(rightId,rightPoint,
|
|
rightPoint + ATTRIBUTES_OFFSET);
|
|
|
|
// parametric center of the edge
|
|
local = midPoint + PARAMETRIC_OFFSET;
|
|
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
local[i] = left[i] + alpha*(right[i] - left[i]);
|
|
}
|
|
// global position of the center
|
|
this->GenericCell->EvaluateLocation(0,local,midPoint);
|
|
|
|
// attributes at the center
|
|
this->GenericCell->InterpolateTuple(this->AttributeCollection,
|
|
local,
|
|
midPoint+ATTRIBUTES_OFFSET);
|
|
this->UpdateMaxError(leftPoint,midPoint,rightPoint,alpha);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
//
|
|
//
|
|
|
|
if(doSubdivision)
|
|
{
|
|
// global position and attributes at the left vertex
|
|
this->EdgeTable->CheckPoint(leftId,leftPoint,
|
|
leftPoint + ATTRIBUTES_OFFSET);
|
|
// global position and attributes at the right vertex
|
|
this->EdgeTable->CheckPoint(rightId,rightPoint,
|
|
rightPoint + ATTRIBUTES_OFFSET);
|
|
|
|
// parametric center of the edge
|
|
local = midPoint + PARAMETRIC_OFFSET;
|
|
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
local[i] = left[i] + alpha*(right[i] - left[i]);
|
|
}
|
|
// is the mid point different from both the left and right point?
|
|
// if not, we do not subdivide, it is a degenerated case.
|
|
//doSubdivision=tetra.DifferentFromOriginals(local);
|
|
doSubdivision = (alpha != 0.0 && alpha != 1.0);
|
|
|
|
if(doSubdivision)
|
|
{
|
|
// global position of the center
|
|
this->GenericCell->EvaluateLocation(0,local,midPoint);
|
|
|
|
// attributes at the center
|
|
this->GenericCell->InterpolateTuple(this->AttributeCollection, local,
|
|
midPoint + ATTRIBUTES_OFFSET);
|
|
|
|
doSubdivision = tetra.GetSubdivisionLevel() < this->GetFixedSubdivisions();
|
|
if(!doSubdivision) // fixed subdivision is done, need adaptive one?
|
|
{
|
|
doSubdivision = this->RequiresEdgeSubdivision(leftPoint,midPoint,
|
|
rightPoint,alpha);
|
|
}
|
|
}
|
|
|
|
} // first doSubdivision
|
|
|
|
if(doSubdivision)
|
|
{
|
|
this->EdgeTable->InsertEdge(leftId, rightId, cellId, refCount, ptId);
|
|
assert("check: id exists" && ptId != -1 );
|
|
|
|
// And also the value we'll have to put to avoid recomputing them later:
|
|
//Save mid point:
|
|
tetra.SetVertex(j+4, local);
|
|
tetra.SetPointId(j+4, ptId);
|
|
tetra.SetParent(j+4,parentId,type);
|
|
|
|
//Put everything in the point hash table
|
|
this->EdgeTable->InsertPointAndScalar(ptId, midPoint,
|
|
midPoint + ATTRIBUTES_OFFSET);
|
|
}
|
|
else
|
|
{
|
|
// The edge does not need to be split simply insert it
|
|
this->EdgeTable->InsertEdge(leftId, rightId, cellId, refCount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// else the edge is in the table we need to increment its ref count.
|
|
// This becomes tricky when we are incrementing an edge shared across
|
|
// cell, we should not increment edge ref count when first time in a cell
|
|
// Precondition third package have unique cellId.
|
|
this->EdgeTable->IncrementEdgeReferenceCount(leftId, rightId, cellId);
|
|
|
|
//vtkDebugMacro( << "IncrementEdgeReferenceCount:" << ptId );
|
|
|
|
if(toSplit == 1) // we cannot just right if(toSplit) because it can be -1
|
|
{
|
|
tetra.SetPointId(j+4, ptId);
|
|
|
|
double pcoords[3];
|
|
pcoords[0] = tetra.GetVertex(l)[0]+ alpha*(tetra.GetVertex(r)[0] - tetra.GetVertex(l)[0]);
|
|
pcoords[1] = tetra.GetVertex(l)[1]+ alpha*(tetra.GetVertex(r)[1] - tetra.GetVertex(l)[1]);
|
|
pcoords[2] = tetra.GetVertex(l)[2]+ alpha*(tetra.GetVertex(r)[2] - tetra.GetVertex(l)[2]);
|
|
assert("not degenerated" && !(((left[0] == pcoords[0])
|
|
&& (left[1] == pcoords[1])
|
|
&& (left[2] == pcoords[2]))
|
|
|| ((right[0] == pcoords[0])
|
|
&& (right[1] == pcoords[1])
|
|
&& (right[2] == pcoords[2]))));
|
|
|
|
tetra.SetVertex(j+4, pcoords);
|
|
|
|
signed char parentId;
|
|
int type=tetra.FindEdgeParent(l,r,parentId);
|
|
|
|
tetra.SetParent(j+4,parentId,type); //tetra.SetParent(j+4,-1,3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::RemoveEdgesFromEdgeTable( vtkTriangleTile &tri )
|
|
{
|
|
vtkIdType l,r;
|
|
int i;
|
|
|
|
// First setup the point reference count:
|
|
for(i=0; i<3; i++)
|
|
{
|
|
this->EdgeTable->RemovePoint( tri.GetPointId(i));
|
|
}
|
|
|
|
// Clean the hash table by removing all edges from this tet, loop over edges:
|
|
for(i=0; i<3; i++)
|
|
{
|
|
l = TRIANGLE_EDGES_TABLE[i][0];
|
|
r = TRIANGLE_EDGES_TABLE[i][1];
|
|
|
|
this->EdgeTable->RemoveEdge(tri.GetPointId(l), tri.GetPointId(r));
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::RemoveEdgesFromEdgeTable( vtkTetraTile &tetra )
|
|
{
|
|
vtkIdType l,r;
|
|
int i;
|
|
|
|
// First setup the point reference count:
|
|
for(i=0; i<4; i++)
|
|
{
|
|
this->EdgeTable->RemovePoint( tetra.GetPointId(i));
|
|
}
|
|
|
|
// Clean the hash table by removing all edges from this tet, loop over edges:
|
|
for(i=0; i<6; i++)
|
|
{
|
|
l = TETRA_EDGES_TABLE[i][0];
|
|
r = TETRA_EDGES_TABLE[i][1];
|
|
|
|
vtkIdType ll = tetra.GetPointId(l);
|
|
vtkIdType rr = tetra.GetPointId(r);
|
|
|
|
this->EdgeTable->RemoveEdge(ll, rr);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::Reset()
|
|
{
|
|
// No memory deletion should happen here, as one cell to another there
|
|
// should be the same amount of points to tessellate
|
|
this->TessellatePoints->Reset();
|
|
this->TessellateCellArray->Reset();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Initialize the tessellator with a data set `ds'.
|
|
void vtkSimpleCellTessellator::Initialize(vtkGenericDataSet *ds)
|
|
{
|
|
this->DataSet = ds;
|
|
|
|
if(this->DataSet)
|
|
{
|
|
this->NumberOfPoints = this->DataSet->GetNumberOfPoints();
|
|
this->EdgeTable->Initialize(this->NumberOfPoints);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::Tessellate(vtkGenericAdaptorCell *cell,
|
|
vtkGenericAttributeCollection *att,
|
|
vtkDoubleArray *points,
|
|
vtkCellArray *cellArray,
|
|
vtkPointData *internalPd )
|
|
{
|
|
assert("pre: cell_exists" && cell!=0);
|
|
assert("pre: valid_dimension" && cell->GetDimension()==3);
|
|
assert("pre: att_exists" && att!=0);
|
|
assert("pre: points_exists" && points!=0);
|
|
assert("pre: cellArray_exists" && cellArray!=0);
|
|
assert("pre: internalPd_exists" && internalPd!=0);
|
|
|
|
int j;
|
|
int numVertices;
|
|
|
|
// Save parameter for later use
|
|
this->GenericCell = cell;
|
|
this->TessellatePoints = points;
|
|
this->TessellateCellArray = cellArray;
|
|
this->TessellatePointData = internalPd;
|
|
this->AttributeCollection = att;
|
|
if(this->CellIterator==0)
|
|
{
|
|
this->CellIterator = cell->NewCellIterator();
|
|
}
|
|
|
|
// send the cell to the error metrics
|
|
this->SetGenericCell( cell );
|
|
|
|
int complexCell=cell->GetType()!=VTK_HIGHER_ORDER_TETRAHEDRON;
|
|
|
|
if(complexCell)
|
|
{
|
|
numVertices=cell->GetNumberOfBoundaries(0);
|
|
}
|
|
else
|
|
{
|
|
numVertices=4;
|
|
}
|
|
|
|
this->AllocatePointIds(numVertices);
|
|
cell->GetPointIds(this->PointIds);
|
|
|
|
|
|
// Init the edge table
|
|
this->EdgeTable->SetNumberOfComponents(internalPd->GetNumberOfComponents());
|
|
this->PointOffset = internalPd->GetNumberOfComponents()+6;
|
|
this->AllocateScalars(this->PointOffset*3);
|
|
|
|
// Insert the points of the complex cell into the hashtable
|
|
double global[3];
|
|
for(j=0; j<numVertices; j++)
|
|
{
|
|
// Need to check first if point is not already in the hash table
|
|
// since EvaluateLocation / EvaluateTuple are expensive calls
|
|
if( !this->EdgeTable->CheckPoint(this->PointIds[j]) )
|
|
{
|
|
double *pcoords=cell->GetParametricCoords() + 3*j;
|
|
// its real space coordinate:
|
|
cell->EvaluateLocation(0,pcoords, global);
|
|
|
|
// Then scalar value associated with point:
|
|
cell->InterpolateTuple(this->AttributeCollection,
|
|
pcoords, this->Scalars);
|
|
|
|
//Put everything in the point hash table
|
|
this->EdgeTable->InsertPointAndScalar(this->PointIds[j], global,
|
|
this->Scalars);
|
|
}
|
|
}
|
|
|
|
vtkstd::queue<vtkTetraTile> work;
|
|
vtkTetraTile roots[10]; // up to 10 top-level sub-tetra
|
|
|
|
// Put the top-levels subtetra in the work queue.
|
|
|
|
if(complexCell)
|
|
{
|
|
this->Triangulator->PreSortedOff();
|
|
this->Triangulator->InitTriangulation(0,1,0,1,0,1,numVertices);
|
|
int i=0;
|
|
double *pcoords=cell->GetParametricCoords();
|
|
while(i<numVertices)
|
|
{
|
|
// we feed the triangulator with dummy global coordinates
|
|
// because we just care about the connectivity
|
|
this->Triangulator->InsertPoint(i,pcoords,pcoords,0); // 2
|
|
++i;
|
|
pcoords+=3;
|
|
}
|
|
this->Triangulator->Triangulate();
|
|
this->Connectivity->Reset();
|
|
this->Triangulator->AddTetras(0,this->Connectivity); // 1
|
|
this->Connectivity->InitTraversal();
|
|
vtkIdType npts=0;
|
|
vtkIdType *pts=0;
|
|
vtkIdType ids[4];
|
|
|
|
int numEdges=cell->GetNumberOfBoundaries(1);
|
|
int numFaces=cell->GetNumberOfBoundaries(2);
|
|
|
|
int edgesIdsArray[6*10]; // 6 edges per sub-tetra, max of 10 sub-tetra
|
|
int faceIdsArray[4*10]; // 4 faces per sub-tetra, max of 10 sub-tetra
|
|
int *edgeIds=edgesIdsArray;
|
|
int *faceIds=faceIdsArray;
|
|
|
|
int tetraId=0;
|
|
while(this->Connectivity->GetNextCell(npts,pts))
|
|
{
|
|
assert("check: is a tetra" && npts==4);
|
|
// Get the point Ids (global)
|
|
j=0;
|
|
while(j<4)
|
|
{
|
|
ids[j]=this->PointIds[pts[j]];
|
|
++j;
|
|
}
|
|
// Get the edges Ids (local)
|
|
// int edgeIds[6];
|
|
int *originalEdge;
|
|
int edge[2];
|
|
j=0;
|
|
while(j<6)
|
|
{
|
|
edge[0]=pts[vtkTetra::GetEdgeArray(j)[0]];
|
|
edge[1]=pts[vtkTetra::GetEdgeArray(j)[1]];
|
|
int k=0;
|
|
edgeIds[j]=-1;
|
|
while(k<numEdges&&(edgeIds[j]==-1))
|
|
{
|
|
originalEdge=cell->GetEdgeArray(k);
|
|
if((originalEdge[0]==edge[0]&&originalEdge[1]==edge[1])||
|
|
(originalEdge[0]==edge[1]&&originalEdge[1]==edge[0]))
|
|
{
|
|
edgeIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// Get the face Ids (local)
|
|
// int faceIds[4];
|
|
int *originalFace;
|
|
int face[3];
|
|
j=0;
|
|
while(j<4)
|
|
{
|
|
face[0]=pts[vtkTetra::GetFaceArray(j)[0]];
|
|
face[1]=pts[vtkTetra::GetFaceArray(j)[1]];
|
|
face[2]=pts[vtkTetra::GetFaceArray(j)[2]];
|
|
int k=0;
|
|
faceIds[j]=-1;
|
|
while(k<numFaces&&(faceIds[j]==-1))
|
|
{
|
|
originalFace=cell->GetFaceArray(k);
|
|
|
|
if(this->FacesAreEqual(originalFace,face))
|
|
{
|
|
faceIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
this->InitTetraTile(roots[tetraId],pts,ids,edgeIds, faceIds);
|
|
work.push(roots[tetraId]);
|
|
|
|
edgeIds=edgeIds+6;
|
|
faceIds=faceIds+4;
|
|
++tetraId;
|
|
} // while(connectivity)
|
|
}
|
|
else
|
|
{
|
|
vtkIdType pts[4]={0,1,2,3}; // from sub-tetra tessellation
|
|
|
|
//
|
|
// Get the edges Ids (local)
|
|
int edgeIds[6];
|
|
int *originalEdge;
|
|
int edge[2];
|
|
j=0;
|
|
while(j<6)
|
|
{
|
|
edge[0]=vtkTetra::GetEdgeArray(j)[0]; // faster that edge[0]=pts[vtkTetra::GetEdgeArray(j)[0]]
|
|
edge[1]=vtkTetra::GetEdgeArray(j)[1];
|
|
int k=0;
|
|
edgeIds[j]=-1;
|
|
while(edgeIds[j]==-1)
|
|
{
|
|
originalEdge=cell->GetEdgeArray(k);
|
|
if((originalEdge[0]==edge[0]&&originalEdge[1]==edge[1])||
|
|
(originalEdge[0]==edge[1]&&originalEdge[1]==edge[0]))
|
|
{
|
|
edgeIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// Get the face Ids (local)
|
|
int faceIds[4];
|
|
int *originalFace;
|
|
int face[3];
|
|
int numFaces=cell->GetNumberOfBoundaries(2);
|
|
j=0;
|
|
while(j<4)
|
|
{
|
|
face[0]=pts[vtkTetra::GetFaceArray(j)[0]];
|
|
face[1]=pts[vtkTetra::GetFaceArray(j)[1]];
|
|
face[2]=pts[vtkTetra::GetFaceArray(j)[2]];
|
|
int k=0;
|
|
faceIds[j]=-1;
|
|
// k<this->GetNumberOfBoundaries(2) is not required because with no tessellation
|
|
// all the faceIds array has to match with the original faces
|
|
while(k<numFaces&&(faceIds[j]==-1))
|
|
{
|
|
originalFace=cell->GetFaceArray(k);
|
|
if(this->FacesAreEqual(originalFace,face))
|
|
{
|
|
faceIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
this->InitTetraTile(roots[0],pts,this->PointIds,edgeIds, faceIds);
|
|
work.push(roots[0]);
|
|
}
|
|
|
|
// refine loop
|
|
int count=0;
|
|
while( !work.empty() )
|
|
{
|
|
vtkTetraTile piece[8];
|
|
vtkTetraTile curr = work.front();
|
|
work.pop();
|
|
|
|
int n = curr.Refine( this, piece);
|
|
|
|
for(int i = 0; i<n; i++)
|
|
{
|
|
work.push( piece[i] );
|
|
}
|
|
|
|
// We are done we should clean ourself from the hash table:
|
|
this->RemoveEdgesFromEdgeTable( curr );
|
|
++count;
|
|
}
|
|
|
|
// remove the points of the complex cell from the hashtable
|
|
for(j=0; j<numVertices; j++)
|
|
{
|
|
this->EdgeTable->RemovePoint(this->PointIds[j]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::InitTetraTile(vtkTetraTile &root,
|
|
vtkIdType *localIds,
|
|
vtkIdType *ids,
|
|
int *edgeIds,
|
|
int *faceIds)
|
|
{
|
|
assert("pre: cell_exists" && this->GenericCell!=0);
|
|
assert("pre: localIds_exists" && localIds!=0);
|
|
assert("pre: ids_exists" && ids!=0);
|
|
assert("pre: edgeIds_exists" && edgeIds!=0);
|
|
assert("pre: faceIds_exists" && faceIds!=0);
|
|
|
|
#ifndef NDEBUG
|
|
vtkIdType order[4] = {-1,-1,-1,-1};
|
|
#else
|
|
vtkIdType order[4];
|
|
#endif
|
|
int i;
|
|
double *point;
|
|
|
|
Reorder(ids, order);
|
|
for(i=0; i<4; i++)
|
|
{
|
|
point = this->GenericCell->GetParametricCoords() + 3*localIds[order[i]];
|
|
root.SetVertex(i, point);
|
|
root.SetPointId(i, ids[order[i]]);
|
|
}
|
|
root.SetOriginal(order,edgeIds,faceIds);
|
|
|
|
//Prepare the hash table with the top-level edges:
|
|
this->InsertEdgesIntoEdgeTable( root );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "GenericCell: " << this->GenericCell << endl;
|
|
os << indent << "TessellatePointData: "
|
|
<< this->TessellatePointData << endl;
|
|
os << indent << "TessellateCellArray: "
|
|
<< this->TessellateCellArray << endl;
|
|
os << indent << "TessellatePoints: "
|
|
<< this->TessellatePoints << endl;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
vtkSimpleCellTessellator::TessellateFace(vtkGenericAdaptorCell *cell,
|
|
vtkGenericAttributeCollection *att,
|
|
vtkIdType index,
|
|
vtkDoubleArray *points,
|
|
vtkCellArray *cellArray,
|
|
vtkPointData *internalPd)
|
|
{
|
|
assert("pre: cell_exists" && cell!=0);
|
|
assert("pre: valid_dimension" && cell->GetDimension()==3);
|
|
assert("pre: valid_index_range" && (index>=0) && (index<cell->GetNumberOfBoundaries(2)));
|
|
assert("pre: att_exists" && att!=0);
|
|
assert("pre: points_exists" && points!=0);
|
|
assert("pre: cellArray_exists" && cellArray!=0);
|
|
assert("pre: internalPd_exists" && internalPd!=0);
|
|
|
|
int j;
|
|
if(cell->GetType()!=VTK_HIGHER_ORDER_TETRAHEDRON)
|
|
{
|
|
// build a linear polygon, call tessellate() on it and iterate over each triangle
|
|
// by sending it to the tessellator
|
|
|
|
int *faceVerts=cell->GetFaceArray(index);
|
|
int numVerts=cell->GetNumberOfVerticesOnFace(index);
|
|
this->Polygon->PointIds->SetNumberOfIds(numVerts);
|
|
this->Polygon->Points->SetNumberOfPoints(numVerts);
|
|
|
|
this->AllocatePointIds(cell->GetNumberOfBoundaries(0));
|
|
cell->GetPointIds(this->PointIds);
|
|
double *pcoords=cell->GetParametricCoords();
|
|
|
|
int i=0;
|
|
while(i<numVerts)
|
|
{
|
|
this->Polygon->PointIds->SetId(i,i); // this->PointIds[i]
|
|
this->Polygon->Points->SetPoint(i, pcoords+3*faceVerts[i]); // should be global?
|
|
++i;
|
|
}
|
|
|
|
this->Polygon->Triangulate(this->TriangleIds);
|
|
|
|
// now iterate over any sub-triangle and call triangulateface on it
|
|
vtkIdType pts[3];
|
|
vtkIdType ids[3];
|
|
int c=this->TriangleIds->GetNumberOfIds();
|
|
i=0;
|
|
while(i<c)
|
|
{
|
|
// Build the next sub-triangle
|
|
j=0;
|
|
while(j<3)
|
|
{
|
|
pts[j]=faceVerts[this->TriangleIds->GetId(i)];
|
|
// Get the point Ids (global)
|
|
ids[j]=this->PointIds[pts[j]];
|
|
++j;
|
|
++i;
|
|
}
|
|
|
|
//
|
|
// Get the edges Ids (local)
|
|
int edgeIds[3];
|
|
int *originalEdge;
|
|
int edge[2];
|
|
j=0;
|
|
int numEdges=cell->GetNumberOfBoundaries(1);
|
|
|
|
while(j<3)
|
|
{
|
|
edge[0]=pts[TRIANGLE_EDGES_TABLE[j][0]];
|
|
edge[1]=pts[TRIANGLE_EDGES_TABLE[j][1]];
|
|
int k=0;
|
|
edgeIds[j]=-1;
|
|
while(k<numEdges&&(edgeIds[j]==-1))
|
|
{
|
|
originalEdge=cell->GetEdgeArray(k);
|
|
if((originalEdge[0]==edge[0]&&originalEdge[1]==edge[1])||
|
|
(originalEdge[0]==edge[1]&&originalEdge[1]==edge[0]))
|
|
{
|
|
edgeIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// index is not used in the tessellator.
|
|
this->TriangulateTriangle(cell, pts,ids,edgeIds,att,points,cellArray, internalPd);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
vtkIdType pts[3]; // from sub-tetra tessellation
|
|
|
|
this->AllocatePointIds(4); // tetra
|
|
cell->GetPointIds(this->PointIds);
|
|
|
|
int *facepts = cell->GetFaceArray(index);
|
|
// we know we are using a tetra.
|
|
pts[0]=facepts[0];
|
|
pts[1]=facepts[1];
|
|
pts[2]=facepts[2];
|
|
|
|
vtkIdType ids[3];
|
|
// Get the point Ids (global)
|
|
j=0;
|
|
while(j<3)
|
|
{
|
|
ids[j]=this->PointIds[pts[j]];
|
|
++j;
|
|
}
|
|
|
|
//
|
|
// Get the edges Ids (local)
|
|
int edgeIds[3];
|
|
int *originalEdge;
|
|
int edge[2];
|
|
j=0;
|
|
while(j<3)
|
|
{
|
|
edge[0]=pts[TRIANGLE_EDGES_TABLE[j][0]];
|
|
edge[1]=pts[TRIANGLE_EDGES_TABLE[j][1]];
|
|
int k=0;
|
|
edgeIds[j]=-1;
|
|
while(edgeIds[j]==-1)
|
|
{
|
|
originalEdge=cell->GetEdgeArray(k);
|
|
if((originalEdge[0]==edge[0]&&originalEdge[1]==edge[1])||
|
|
(originalEdge[0]==edge[1]&&originalEdge[1]==edge[0]))
|
|
{
|
|
edgeIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// index is not used in the tessellator.
|
|
this->TriangulateTriangle(cell, pts,ids,edgeIds,att,points,cellArray, internalPd);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::Triangulate(vtkGenericAdaptorCell *cell,
|
|
vtkGenericAttributeCollection *att,
|
|
vtkDoubleArray *points,
|
|
vtkCellArray *cellArray,
|
|
vtkPointData *internalPd)
|
|
{
|
|
assert("pre: cell_exists" && cell!=0);
|
|
assert("pre: valid_dimension" && cell->GetDimension()==2);
|
|
assert("pre: att_exists" && att!=0);
|
|
assert("pre: points_exists" && points!=0);
|
|
assert("pre: cellArray_exists" && cellArray!=0);
|
|
assert("pre: internalPd_exists" && internalPd!=0);
|
|
|
|
int j;
|
|
|
|
if(cell->GetType()!=VTK_HIGHER_ORDER_TRIANGLE)
|
|
{
|
|
// build a linear polygon, call tessellate() on it and iterate over each triangle
|
|
// by sending it to the tessellator
|
|
|
|
// int *faceVerts=cell->GetFaceArray(index); // implicit
|
|
// int numVerts=cell->GetNumberOfVerticesOnFace(index);
|
|
int numVerts=cell->GetNumberOfBoundaries(0);
|
|
|
|
this->Polygon->PointIds->SetNumberOfIds(numVerts);
|
|
this->Polygon->Points->SetNumberOfPoints(numVerts);
|
|
|
|
this->AllocatePointIds(cell->GetNumberOfBoundaries(0));
|
|
cell->GetPointIds(this->PointIds);
|
|
double *pcoords=cell->GetParametricCoords();
|
|
|
|
int i=0;
|
|
while(i<numVerts)
|
|
{
|
|
this->Polygon->PointIds->SetId(i,i); // this->PointIds[i]
|
|
this->Polygon->Points->SetPoint(i, pcoords+3*i); // should be global?
|
|
++i;
|
|
}
|
|
|
|
this->Polygon->Triangulate(this->TriangleIds);
|
|
|
|
// now iterate over any sub-triangle and call triangulateface on it
|
|
vtkIdType pts[3];
|
|
vtkIdType ids[3];
|
|
int c=this->TriangleIds->GetNumberOfIds();
|
|
i=0;
|
|
while(i<c)
|
|
{
|
|
// Build the next sub-triangle
|
|
j=0;
|
|
while(j<3)
|
|
{
|
|
pts[j]=this->TriangleIds->GetId(i);
|
|
// Get the point Ids (global)
|
|
ids[j]=this->PointIds[pts[j]];
|
|
++j;
|
|
++i;
|
|
}
|
|
|
|
//
|
|
// Get the edges Ids (local)
|
|
int edgeIds[3];
|
|
int *originalEdge;
|
|
int edge[2];
|
|
j=0;
|
|
int numEdges=cell->GetNumberOfBoundaries(1);
|
|
|
|
while(j<3)
|
|
{
|
|
edge[0]=pts[TRIANGLE_EDGES_TABLE[j][0]];
|
|
edge[1]=pts[TRIANGLE_EDGES_TABLE[j][1]];
|
|
int k=0;
|
|
edgeIds[j]=-1;
|
|
while(k<numEdges&&(edgeIds[j]==-1))
|
|
{
|
|
originalEdge=cell->GetEdgeArray(k);
|
|
if((originalEdge[0]==edge[0]&&originalEdge[1]==edge[1])||
|
|
(originalEdge[0]==edge[1]&&originalEdge[1]==edge[0]))
|
|
{
|
|
edgeIds[j]=k;
|
|
}
|
|
++k;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// index is not used in the tessellator.
|
|
this->TriangulateTriangle(cell, pts,ids,edgeIds,att,points,cellArray, internalPd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vtkIdType pts[3]={0,1,2};
|
|
int edgeIds[3]={0,1,2};
|
|
this->AllocatePointIds(cell->GetNumberOfBoundaries(0));
|
|
cell->GetPointIds(this->PointIds);
|
|
this->TriangulateTriangle(cell, pts, this->PointIds, edgeIds, att,
|
|
points, cellArray,internalPd);
|
|
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkSimpleCellTessellator::TriangulateTriangle(vtkGenericAdaptorCell *cell,
|
|
vtkIdType *localIds,
|
|
vtkIdType *ids,
|
|
int *edgeIds,
|
|
vtkGenericAttributeCollection *att,
|
|
vtkDoubleArray *points,
|
|
vtkCellArray *cellArray,
|
|
vtkPointData *internalPd)
|
|
{
|
|
assert("pre: cell_exixts" && cell!=0);
|
|
assert("pre: localIds_exists" && localIds!=0);
|
|
assert("pre: ids_exists" && ids!=0);
|
|
assert("pre: edgeIds_exists" && edgeIds!=0);
|
|
|
|
// Save parameter for later use
|
|
this->GenericCell = cell;
|
|
|
|
this->TessellatePoints = points;
|
|
this->TessellateCellArray = cellArray;
|
|
this->TessellatePointData = internalPd;
|
|
|
|
this->AttributeCollection = att;
|
|
|
|
if(this->CellIterator==0)
|
|
{
|
|
this->CellIterator = cell->NewCellIterator();
|
|
}
|
|
this->EdgeIds=edgeIds;
|
|
|
|
this->SetGenericCell( cell );
|
|
|
|
vtkTriangleTile root;
|
|
double *point;
|
|
|
|
int i;
|
|
for(i=0; i<3; i++)
|
|
{
|
|
point = this->GenericCell->GetParametricCoords() + 3*localIds[i];
|
|
root.SetVertex(i, point);
|
|
root.SetPointId(i, ids[i]);
|
|
}
|
|
root.SetOriginal();
|
|
|
|
// Init the edge table
|
|
this->EdgeTable->SetNumberOfComponents(internalPd->GetNumberOfComponents());
|
|
|
|
this->PointOffset = internalPd->GetNumberOfComponents() + 6;
|
|
this->AllocateScalars(this->PointOffset*3);
|
|
|
|
this->InsertPointsIntoEdgeTable( root );
|
|
|
|
//Prepare the hash table with the top-level edges:
|
|
this->InsertEdgesIntoEdgeTable( root );
|
|
|
|
vtkstd::queue< vtkTriangleTile > work;
|
|
vtkTriangleTile begin = vtkTriangleTile(root);
|
|
work.push( begin );
|
|
|
|
while( !work.empty() )
|
|
{
|
|
vtkTriangleTile piece[4];
|
|
vtkTriangleTile curr = work.front();
|
|
work.pop();
|
|
|
|
int n = curr.Refine( this, piece );
|
|
|
|
for(i = 0; i<n; i++)
|
|
{
|
|
work.push( piece[i] );
|
|
}
|
|
// We are done we should clean ourself from the hash table:
|
|
this->RemoveEdgesFromEdgeTable( curr );
|
|
}
|
|
|
|
// remove top level points
|
|
for(i = 0; i<3; i++)
|
|
{
|
|
this->EdgeTable->RemovePoint( root.GetPointId(i) );
|
|
}
|
|
|
|
//this->EdgeTable->LoadFactor();
|
|
//this->EdgeTable->DumpTable();
|
|
}
|
|
|
|
//#define SLOW_API 1
|
|
//-----------------------------------------------------------------------------
|
|
// Return number of cells using edge #edgeId
|
|
int vtkSimpleCellTessellator::GetNumberOfCellsUsingEdge( int edgeId )
|
|
{
|
|
assert("pre: valid_range" && edgeId>=0 ); // && edgeId<=5);
|
|
#if SLOW_API
|
|
int result = 0;
|
|
this->GenericCell->GetBoundaryIterator(this->CellIterator, 1);
|
|
this->CellIterator->Begin();
|
|
|
|
int i = 0;
|
|
while(!this->CellIterator->IsAtEnd() && (i < edgeId) )
|
|
{
|
|
this->CellIterator->Next();
|
|
++i;
|
|
}
|
|
|
|
assert("check: cell_found" && i==edgeId);
|
|
// +1 because CountNeighbors does not include the cell itself.
|
|
result = this->GenericCell->CountNeighbors(this->CellIterator->GetCell())+1;
|
|
return result;
|
|
#else
|
|
// The cell with the greatest number of edges is the hexagonal prism
|
|
// 6*2+6
|
|
int edgeSharing[18];
|
|
this->GenericCell->CountEdgeNeighbors( edgeSharing );
|
|
return edgeSharing[edgeId]+1;
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Return number of cells using face #faceId
|
|
int vtkSimpleCellTessellator::GetNumberOfCellsUsingFace( int faceId )
|
|
{
|
|
#if SLOW_API
|
|
int result=0;
|
|
this->GenericCell->GetBoundaryIterator(this->CellIterator, 2);
|
|
this->CellIterator->Begin();
|
|
|
|
int i = 0;
|
|
while(!this->CellIterator->IsAtEnd() && ( i < faceId) )
|
|
{
|
|
this->CellIterator->Next();
|
|
++i;
|
|
}
|
|
|
|
assert("check: cell_found" && i==faceId);
|
|
// +1 because CountNeighbors does not include the cell itself.
|
|
result = this->GenericCell->CountNeighbors(this->CellIterator->GetCell())+1;
|
|
|
|
return result;
|
|
#else
|
|
if( this->GenericCell->IsFaceOnBoundary( faceId ) )
|
|
{
|
|
// So no other cell is using it:
|
|
return 1;
|
|
}
|
|
|
|
//else this face is used by another cell
|
|
return 2;
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Allocate some memory if Scalars does not exists or is smaller than size.
|
|
// \pre positive_size: size>0
|
|
void vtkSimpleCellTessellator::AllocateScalars(int size)
|
|
{
|
|
assert("pre: positive_size" && size > 0);
|
|
|
|
if(this->Scalars == 0)
|
|
{
|
|
this->Scalars = new double[size];
|
|
this->ScalarsCapacity = size;
|
|
}
|
|
else
|
|
{
|
|
if(this->ScalarsCapacity < size)
|
|
{
|
|
delete[] this->Scalars;
|
|
this->Scalars = new double[size];
|
|
this->ScalarsCapacity = size;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Return the number of fixed subdivisions. It is used to prevent from
|
|
// infinite loop in degenerated cases. For order 3 or higher, if the
|
|
// inflection point is exactly on the mid-point, error metric will not
|
|
// detect that a subdivision is required. 0 means no fixed subdivision:
|
|
// there will be only adaptive subdivisions.
|
|
//
|
|
// The algorithm first performs `GetFixedSubdivisions' non adaptive
|
|
// subdivisions followed by at most `GetMaxAdaptiveSubdivisions' adaptive
|
|
// subdivisions. Hence, there are at most `GetMaxSubdivisionLevel'
|
|
// subdivisions.
|
|
// \post positive_result: result>=0 && result<=GetMaxSubdivisionLevel()
|
|
int vtkSimpleCellTessellator::GetFixedSubdivisions()
|
|
{
|
|
assert("post: positive_result" && this->FixedSubdivisions >= 0 && this->FixedSubdivisions <= this->MaxSubdivisionLevel);
|
|
return this->FixedSubdivisions;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Return the maximum level of subdivision. It is used to prevent from
|
|
// infinite loop in degenerated cases. For order 3 or higher, if the
|
|
// inflection point is exactly on the mid-point, error metric will not
|
|
// detect that a subdivision is required. 0 means no subdivision,
|
|
// neither fixed nor adaptive.
|
|
// \post positive_result: result>=GetFixedSubdivisions()
|
|
int vtkSimpleCellTessellator::GetMaxSubdivisionLevel()
|
|
{
|
|
assert("post: positive_result" && this->MaxSubdivisionLevel >= this->FixedSubdivisions);
|
|
return this->MaxSubdivisionLevel;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Return the maximum number of adaptive subdivisions.
|
|
// \post valid_result: result==GetMaxSubdivisionLevel()-GetFixedSubdivisions()
|
|
int vtkSimpleCellTessellator::GetMaxAdaptiveSubdivisions()
|
|
{
|
|
return this->MaxSubdivisionLevel - this->FixedSubdivisions;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Set the number of fixed subdivisions. See GetFixedSubdivisions() for
|
|
// more explanations.
|
|
// \pre positive_level: level>=0 && level<=GetMaxSubdivisionLevel()
|
|
// \post is_set: GetFixedSubdivisions()==level
|
|
void vtkSimpleCellTessellator::SetFixedSubdivisions(int level)
|
|
{
|
|
assert("pre: positive_level" && level >= 0 && level <= this->GetMaxSubdivisionLevel());
|
|
this->FixedSubdivisions = level;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Set the maximum level of subdivision. See GetMaxSubdivisionLevel() for
|
|
// more explanations.
|
|
// \pre positive_level: level>=GetFixedSubdivisions()
|
|
// \post is_set: level==GetMaxSubdivisionLevel()
|
|
void vtkSimpleCellTessellator::SetMaxSubdivisionLevel(int level)
|
|
{
|
|
assert("pre: positive_level" && level >= this->GetFixedSubdivisions());
|
|
this->MaxSubdivisionLevel = level;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Set both the number of fixed subdivisions and the maximum level of
|
|
// subdivisions. See GetFixedSubdivisions(), GetMaxSubdivisionLevel() and
|
|
// GetMaxAdaptiveSubdivisions() for more explanations.
|
|
// \pre positive_fixed: fixed>=0
|
|
// \pre valid_range: fixed<=maxLevel
|
|
// \post fixed_is_set: fixed==GetFixedSubdivisions()
|
|
// \post maxLevel_is_set: maxLevel==GetMaxSubdivisionLevel()
|
|
void vtkSimpleCellTessellator::SetSubdivisionLevels(int fixed,
|
|
int maxLevel)
|
|
{
|
|
assert("pre: positive_fixed" && fixed >= 0);
|
|
assert("pre: valid_range" && fixed <= maxLevel);
|
|
this->FixedSubdivisions = fixed;
|
|
this->MaxSubdivisionLevel = maxLevel;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Description:
|
|
// Allocate some memory if PointIds does not exist or is smaller than size.
|
|
// \pre positive_size: size>0
|
|
void vtkSimpleCellTessellator::AllocatePointIds(int size)
|
|
{
|
|
assert("pre: positive_size" && size>0);
|
|
|
|
if(this->PointIdsCapacity<size)
|
|
{
|
|
if(this->PointIds!=0)
|
|
{
|
|
delete[] this->PointIds;
|
|
}
|
|
this->PointIds=new vtkIdType[size];
|
|
this->PointIdsCapacity=size;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Description:
|
|
// Are the faces `originalFace' and `face' equal?
|
|
// The result is independent from any order or orientation.
|
|
// \pre originalFace_exists: originalFace!=0
|
|
int vtkSimpleCellTessellator::FacesAreEqual(int *originalFace,
|
|
int face[3])
|
|
{
|
|
assert("pre: originalFace_exists" && originalFace!=0);
|
|
|
|
int result=0;
|
|
int i=0;
|
|
int j=1;
|
|
int k=2;
|
|
while(!result && i<3)
|
|
{
|
|
// counterclockwise
|
|
result=originalFace[0]==face[i]
|
|
&& originalFace[1]==face[j]
|
|
&& originalFace[2]==face[k];
|
|
// clockwise
|
|
if(!result)
|
|
{
|
|
result=originalFace[0]==face[i]
|
|
&& originalFace[2]==face[j]
|
|
&& originalFace[1]==face[k];
|
|
}
|
|
++i;
|
|
++j;
|
|
++k;
|
|
|
|
if(j>2)
|
|
{
|
|
j=0;
|
|
}
|
|
else
|
|
{
|
|
if(k>2)
|
|
{
|
|
k=0;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|