/usr/include/psurface/Node.h is in libpsurface-dev 2.0.0-1.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | #ifndef NODE_H
#define NODE_H
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include <stdio.h>
#include "StaticVector.h"
#include <vector>
namespace psurface {
typedef int NodeIdx;
/** \brief The parametrization of a single point from the plane into space
*
* There are five different types of nodes:
* <ul>
* <li> <b> Interior Nodes: </b> This is the mapping from a point on the interior of a base
* grid triangle
* onto a vertex of the target surface. Thus it exists once on the base grid, having
* unique barycentric coordinates on its triangle. The target is specified using
* the number of the target vertex.
* <li> <b> Touching Nodes: </b> The mapping from a point on the edge between two base grid
* triangles to a vertex on the target surface.
* <li> <b> Corner Nodes: </b> The mapping from a corner of a base grid
* triangle to a vertex on the target surface.
* <li> <b> Intersection Nodes: </b> When an edge of a target triangle leaves a base triangle
* through an edge, then the intersection points are mapped onto target edge points.
* <li> <b> Ghost Nodes: </b> Each base vertex that is not a Corner node, becomes a ghost node.
* <li> <b> Boundary Nodes: </b> If an edge leaves the image of the projection, e.g. when the domain boundary ends,
* a boundary node is added at the leaving edge. These nodes store the target vertex index
* the edge is pointing to (which is not contained in PSurface) in the member "boundary".
* </ul>
\tparam ctype The type used for coordinates
*/
template <class ctype>
class Node {
public:
/** \brief Encapsulates the neighborhood relationship between a node and others
*
* Encapsulates the neighborhood relationship between a node and others. It's
* basically just an index into the Node array, but it comes with an extra built-in
* flag. This flag specifies whether the graph edge embodied by the reference
* is 'real', i.e. is (part of) the preimage of some edge in the target surface,
* or whether it has just been added to turn the graph into a triangulation.
* Those latter edges form the \em triangular \em closure.
*/
class NeighborReference {
public:
/** \brief Default constructor. Creates an invalid reference.
*/
NeighborReference() : idx(-1), closure(false) {}
NeighborReference(int _idx, bool _closure=false) {
idx = _idx;
closure = _closure;
}
//! Check if edge is real or from triangular closure.
bool isRegular() const {return !closure;}
/** \brief Assignment operator from an integer*/
NeighborReference& operator =(int other) {
idx = other;
return *this;
}
/** \brief Standard assignment operator. IRIX seems to require this... */
NeighborReference& operator =(const NeighborReference& other) {
idx = other.idx;
closure = other.closure;
return *this;
}
NeighborReference& operator +=(int other) {
idx += other;
return *this;
}
NeighborReference& operator -=(int other) {
idx -= other;
return *this;
}
/** \brief Cast to integer */
operator int() const {return idx;}
int idx:31;
bool closure:1;
};
enum NodeType {INTERIOR_NODE=0,
INTERSECTION_NODE=1,
CORNER_NODE=2,
TOUCHING_NODE=3,
GHOST_NODE=4};
///
Node() : valid(true), boundary(-1) {}
/** \brief Construct node from the local coords, the index and the node type. */
Node(const StaticVector<ctype,2> &domain, int number, NodeType nodeType) : valid(true), boundary(-1) {
setDomainPos(domain);
nodeNumber = number;
type = nodeType;
clearNeighbors();
}
/** \brief Destructor. */
~Node() {}
/** \brief Set local coordinates, node index and type. */
void setValue(const StaticVector<ctype,2> &domain, int nN, NodeType nodeType, int targetIndex = -1) {
setDomainPos(domain);
nodeNumber = nN;
type = nodeType;
boundary = targetIndex;
}
void makeInteriorNode() {
assert(!isINTERSECTION_NODE());
type = INTERIOR_NODE;
}
void makeTouchingNode() {
assert(!isINTERSECTION_NODE());
type = TOUCHING_NODE;
}
void makeCornerNode() {
assert(!isINTERSECTION_NODE());
type = CORNER_NODE;
}
/** \brief Set node to be the corner node. */
void makeCornerNode(int corner, int nN) {
assert(corner==0 || corner==1 || corner==2);
type = CORNER_NODE;
nodeNumber = nN;
edge = corner;
if (corner==0)
dP = StaticVector<ctype,2>(1,0);
else if (corner==1)
dP = StaticVector<ctype,2>(0,1);
else
dP = StaticVector<ctype,2>(0,0);
}
/** \brief Make a ghost node. */
void makeGhostNode(int corner, int targetTri, const StaticVector<ctype,2>& localTargetCoords) {
assert(corner==0 || corner==1 || corner==2);
type = GHOST_NODE;
nodeNumber = targetTri;
edge = corner;
dP = localTargetCoords;
}
/** \brief Set the only true neighbor reference if node is an intersection node. */
void setNeighbor(int n) {
assert(isINTERSECTION_NODE());
nbs.resize(1);
nbs[0] = n;
}
/** \brief Is boundary node, i.e. an intersection node on an edge that leaves the image of the projection. */
bool isBoundary() const {
return (boundary>=0);
}
/** \brief Check if the node is on a segment given by local coords of the endpoints. */
bool isOnSegment(const StaticVector<ctype,2>& a, const StaticVector<ctype,2>& b, ctype eps) const {
return ( (domainPos()-a).length() + (domainPos()-b).length()) / (a-b).length() <1.0 +eps;
}
/** \brief Check if node is connected to an other node. */
bool isConnectedTo(const int other) const {
for (int i=0; i<degree(); i++)
if (neighbors(i) == other)
return true;
return false;
}
/** \brief The number of neighbors */
int degree() const {
return nbs.size();
}
/** \brief Remove all neighbors */
void clearNeighbors() {
nbs.clear();
}
/** \brief Erase i'th neighbor reference. */
void removeNeighbor(int i){
nbs.erase(nbs.begin() + i);
}
/** \brief Add new neighbor. */
void appendNeighbor(const NeighborReference& newNeighbor){
nbs.push_back(newNeighbor);
}
/** \brief Remove the reference to the neighbor which has the index 'other' */
void removeReferenceTo(int other){
for (int i=0; i<degree(); i++)
if (neighbors(i) == other){
removeNeighbor(i);
return;
}
}
/** \brief Replaces a reference (faster than remove + append). */
bool replaceReferenceTo(int oldNeighbor, int newNeighbor){
for (int i=0; i<degree(); i++)
if (neighbors(i) == oldNeighbor){
neighbors(i) = newNeighbor;
return true;
}
return false;
}
/** \brief Check if node is valid. */
bool isInvalid() const {return !valid;}
/** \brief Get i'th neighbor reference. */
NeighborReference& neighbors(int i) {return nbs[i];}
/** \brief Get const i'th neighbor reference. */
const NeighborReference& neighbors(int i) const {return nbs[i];}
/** \brief Check if node is the first neighbor. */
bool isFirstNeighbor(NodeIdx n) const {
return (degree() && neighbors(0) == n);
}
/** \brief Check if node is the last neighbor. */
bool isLastNeighbor(NodeIdx n) const {
return (degree() && nbs.back() == n);
}
/** \brief If the node is an intersection node, then it must have
* one neighbor that is not due to the triangluar closure.
*/
const NeighborReference& theInteriorNode() const {
assert(isINTERSECTION_NODE());
for (int i=0; i<degree(); i++)
if (!nbs[i].closure)
return nbs[i];
assert(false);
return nbs[0];
}
/** \brief Swap neighbor references. */
void swapNeighbors(int i, int j) {
assert(0<=i && i<degree());
assert(0<=j && j<degree());
std::swap(nbs[i], nbs[j]);
}
/** \brief Reverse the order of the neighbors. */
void reverseNeighbors() {
std::reverse(nbs.begin(),nbs.end());
}
/** \brief Get node type. */
NodeType getType() const {return type;}
/** \brief Get node index. */
unsigned int getNodeNumber() const {
return nodeNumber;
}
/** \brief If node lives on an edge, return the index of the edge. */
unsigned int getDomainEdge() const {
assert(!isINTERIOR_NODE());
return edge;
}
/** \brief Returns a 1-dimensional coordinate \f$ \lambda \in [0,1] \f$ giving
* the position of an edge node on its edge.
* Is undefined if the node is interior. Is also undefined if the node
* lives on a corner!!!
*/
ctype getDomainEdgeCoord() const {
assert(isINTERSECTION_NODE() || isTOUCHING_NODE());
switch (getDomainEdge()) {
case 0: return domainPos()[1];
case 1: return 1-domainPos()[1];
case 2: return domainPos()[0];
}
print();
throw std::runtime_error("Undefined position");
}
/** \brief Returns a 1-dimensional coordinate \f$ \lambda \in [0,1] \f$ giving
* the position of an edge node on its edge.
* Is undefined if the node is interior. Is also undefined if the node
* lives on a corner!!!
*/
ctype getDomainEdgeCoord(int edge) const {
assert(!isINTERIOR_NODE());
switch (edge) {
case 0: return domainPos()[1];
case 1: return 1-domainPos()[1];
case 2: return domainPos()[0];
}
throw std::runtime_error("Undefined position");
}
/** \brief Returns the index of an edge node resp. to its edgePoint array. */
unsigned int getDomainEdgePosition() const {
// this is how it should be
//assert(isINTERSECTION_NODE() || isTOUCHING_NODE());
return edgePosition;
}
/** If the node is of a type which is located at corners, this method
* returns the corner. If not, the result is undefined.
*/
unsigned int getCorner() const {
assert(isCORNER_NODE() || isGHOST_NODE());
return edge;
}
/** \brief Get the triangle a ghost node points to.
*
* Ghost nodes do not point to vertices of the target surface but
* to a point on a triangle. Thus it makes sense to ask for that
* triangle. Calling this routine for non-ghost nodes results
* in undefined, possibly fatal, behaviour.
*/
int getTargetTriangle () const {
assert(isGHOST_NODE());
return nodeNumber;
}
/** \brief Set the edge index. */
void setDomainEdge(int i) {
assert(!isINTERIOR_NODE());
edge = i;
}
/** \brief Set position of the edge node in the edge point array. */
void setDomainEdgePosition(int i) {
assert(!isINTERIOR_NODE());
edgePosition = i;
}
/** \brief Check if node is a corner node. */
bool isCORNER_NODE() const {return type==CORNER_NODE;}
/** \brief Check if node is an intersection node. */
bool isINTERSECTION_NODE() const {return type==INTERSECTION_NODE;}
/** \brief Check if node is a touching node. */
bool isTOUCHING_NODE() const {return type==TOUCHING_NODE;}
/** \brief Check if node is an interior node. */
bool isINTERIOR_NODE() const {return type==INTERIOR_NODE;}
/** \brief Check if node is a ghost node. */
bool isGHOST_NODE() const {return type==GHOST_NODE;}
/** \brief Checks whether node is on a DomainTriangle edge.
*
* This method returns true if the node is of a type that is by
* definition located on the edge of the supporting base grid
* triangle. <b> Warning: </b> It returns false for nodes
* on corners!
*/
bool isOnEdge() const {return isTOUCHING_NODE() || isINTERSECTION_NODE();}
/** \brief Checks whether node is on a DomainTriangle edge.
*
* Unlike the method isOnEdge without arguments this methods
* also returns true for nodes on corners, given that the corner
* belongs to the correct edge.
*/
bool isOnEdge(unsigned int edge) const {
if (isOnCorner())
return (getCorner()==edge || getCorner()==((edge+1)%3));
else if (isOnEdge())
return getDomainEdge()==edge;
return false;
}
/** \brief Check if node is on a corner. */
bool isOnCorner() const {return isCORNER_NODE() || isGHOST_NODE();}
/** \brief Print node information. */
void print(bool showNeighbors=true) const {
printf("dom (%f %f) ", domainPos()[0], domainPos()[1]);
switch(type){
case INTERIOR_NODE:
printf("INTERIOR_NODE");
break;
case TOUCHING_NODE:
printf("TOUCHING_NODE");
break;
case INTERSECTION_NODE:
printf("INTERSECTION_NODE");
break;
case CORNER_NODE:
printf("CORNER_NODE");
break;
case GHOST_NODE:
printf("GHOST_NODE");
break;
}
printf(" number %d", nodeNumber);
printf(" is Boundary %d", boundary);
if (isOnEdge())
std::cout << " edge: " << getDomainEdge() << " edgePos " << getDomainEdgePosition() << std::endl;
else if (isOnCorner())
printf(" corner: %d\n", getCorner());
else
printf("\n");
if (showNeighbors)
for (int i=0; i<degree(); i++)
printf(" %d %s\n", (int)nbs[i], nbs[i].isRegular() ? " " : "c");
}
/** \brief Get the barycentric coordinates of the node. */
StaticVector<ctype,2> domainPos() const {
if (isGHOST_NODE())
switch (edge) {
case 0: return StaticVector<ctype,2>(1, 0);
case 1: return StaticVector<ctype,2>(0, 1);
case 2: return StaticVector<ctype,2>(0, 0);
}
return dP;
}
/** \brief Set barycentric coordinates of the node. */
void setDomainPos(const StaticVector<ctype,2>& p) {dP = p;}
//private:
//! Local barycentric coordinates of the node within the triangle.
StaticVector<ctype,2> dP;
public:
//!
int valid:1;
//! Type of the node
NodeType type:3;
/** \brief Index of target vertex or triangle
*
* This number has one of two meanings, depending on what type the node is.
* If it is a GHOST_NODE, then the number is the index of the triangle the node
* maps to. In all other case, the is a unique vertex on the target surface
* corresponding to this node, and the nodeNumber field gives the index
* of that vertex.
*/
unsigned int nodeNumber:28;
//! This value is set to the target vertex index for boundary nodes and -1 else
int boundary;
public:
//! Vector containing all nodes that are connected to this one.
std::vector<NeighborReference> nbs;
///////////////////////////////////////
// This is only for nodes on the boundary of a base grid triangle
protected:
//! If the node is on an edge, the index of the edge is stored
unsigned int edge:8;
//! Ordered position on that edge.(0 = 1.Corner, nEdgeNodes-1 = 2.Corner)
unsigned int edgePosition:24;
};
} // namespace psurface
#endif
|