source: branches/1.2/src/core2/RpMeshTri2D.cc @ 3601

Last change on this file since 3601 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 10.4 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture::MeshTri2D
4 *    This is a non-uniform, triangular mesh for 2-dimensional
5 *    structures.
6 *
7 * ======================================================================
8 *  AUTHOR:  Michael McLennan, Purdue University
9 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15#include <math.h>
16#include <assert.h>
17#include <float.h>
18#include <iostream>
19
20#include "RpMeshTri2D.h"
21
22using namespace Rappture;
23
24CellTri2D::CellTri2D()
25{
26    _cellId = -1;
27    _nodes[0] = NULL;
28    _nodes[1] = NULL;
29    _nodes[2] = NULL;
30}
31
32CellTri2D::CellTri2D(int cellId, Node2D* n1Ptr, Node2D* n2Ptr, Node2D* n3Ptr)
33{
34    _cellId = cellId;
35    _nodes[0] = n1Ptr;
36    _nodes[1] = n2Ptr;
37    _nodes[2] = n3Ptr;
38}
39
40CellTri2D::CellTri2D(const CellTri2D& cell)
41{
42    _cellId = cell._cellId;
43    _nodes[0] = cell._nodes[0];
44    _nodes[1] = cell._nodes[1];
45    _nodes[2] = cell._nodes[2];
46}
47
48CellTri2D&
49CellTri2D::operator=(const CellTri2D& cell)
50{
51    _cellId = cell._cellId;
52    _nodes[0] = cell._nodes[0];
53    _nodes[1] = cell._nodes[1];
54    _nodes[2] = cell._nodes[2];
55    return *this;
56}
57
58int
59CellTri2D::isNull() const
60{
61    return (_nodes[0] == NULL || _nodes[1] == NULL || _nodes[2] == NULL);
62}
63
64int
65CellTri2D::isOutside() const
66{
67    return (_cellId < 0);
68}
69
70void
71CellTri2D::clear()
72{
73    _cellId = -1;
74    _nodes[0] = _nodes[1] = _nodes[2] = NULL;
75}
76
77int
78CellTri2D::cellId() const
79{
80    return _cellId;
81}
82
83int
84CellTri2D::nodeId(int n) const
85{
86    assert(n >= 0 && n <= 2);
87    return _nodes[n]->id();
88}
89
90double
91CellTri2D::x(int n) const
92{
93    assert(n >= 0 && n <= 2);
94    return _nodes[n]->x();
95}
96
97double
98CellTri2D::y(int n) const
99{
100    assert(n >= 0 && n <= 2);
101    return _nodes[n]->y();
102}
103
104void
105CellTri2D::barycentrics(const Node2D& node, double* phi) const
106{
107    assert( _nodes[0] != NULL && _nodes[1] != NULL && _nodes[2] != NULL);
108
109    double x2 = _nodes[1]->x() - _nodes[0]->x();
110    double y2 = _nodes[1]->y() - _nodes[0]->y();
111    double x3 = _nodes[2]->x() - _nodes[0]->x();
112    double y3 = _nodes[2]->y() - _nodes[0]->y();
113    double xr = node.x() - _nodes[0]->x();
114    double yr = node.y() - _nodes[0]->y();
115    double det = x2*y3-x3*y2;
116
117    phi[1] = (xr*y3 - x3*yr)/det;
118    phi[2] = (x2*yr - xr*y2)/det;
119    phi[0] = 1.0-phi[1]-phi[2];
120}
121
122
123Tri2D::Tri2D()
124{
125    nodes[0] = nodes[1] = nodes[2] = -1;
126    neighbors[0] = neighbors[1] = neighbors[2] = -1;
127}
128
129Tri2D::Tri2D(int n1, int n2, int n3)
130{
131    nodes[0] = n1;
132    nodes[1] = n2;
133    nodes[2] = n3;
134    neighbors[0] = neighbors[1] = neighbors[2] = -1;
135}
136
137
138MeshTri2D::MeshTri2D()
139  : _counter(0),
140    _id2nodeDirty(0),
141    _id2node(100,-1)
142{
143    _nodelist.reserve(1024);
144    _min[0] = _min[1] = NAN;
145    _max[0] = _max[1] = NAN;
146}
147
148MeshTri2D::MeshTri2D(const MeshTri2D& mesh)
149  : _nodelist(mesh._nodelist),
150    _counter(mesh._counter),
151    _celllist(mesh._celllist),
152    _id2nodeDirty(mesh._id2nodeDirty),
153    _id2node(mesh._id2node)
154{
155    for (int i=0; i < 2; i++) {
156        _min[i] = mesh._min[i];
157        _max[i] = mesh._max[i];
158    }
159}
160
161MeshTri2D&
162MeshTri2D::operator=(const MeshTri2D& mesh)
163{
164    _nodelist = mesh._nodelist;
165    _counter = mesh._counter;
166    for (int i=0; i < 2; i++) {
167        _min[i] = mesh._min[i];
168        _max[i] = mesh._max[i];
169    }
170    _celllist = mesh._celllist;
171    _id2nodeDirty = mesh._id2nodeDirty;
172    _id2node = mesh._id2node;
173    _lastLocate.clear();
174    return *this;
175}
176
177MeshTri2D::~MeshTri2D()
178{
179}
180
181Node2D&
182MeshTri2D::addNode(const Node2D& nd)
183{
184    Node2D node(nd);
185
186    if (node.id() < 0) {
187        node.id(_counter++);
188    } else {
189        // see if this node already exists
190        Node2D* nptr = _getNodeById(node.id());
191        if (nptr) {
192            return *nptr;
193        }
194    }
195
196    // add this new node
197    _nodelist.push_back(node);
198
199    if (isnan(_min[0])) {
200        _min[0] = _max[0] = node.x();
201        _min[1] = _max[1] = node.y();
202    } else {
203        if (node.x() < _min[0]) { _min[0] = node.x(); }
204        if (node.x() > _max[0]) { _max[0] = node.x(); }
205        if (node.y() < _min[1]) { _min[1] = node.y(); }
206        if (node.y() > _max[1]) { _max[1] = node.y(); }
207    }
208
209    // index of this new node
210    int n = _nodelist.size()-1;
211
212    if (!_id2nodeDirty) {
213        // id2node map up to date?  then keep it up to date
214        if ((unsigned int)node.id() >= _id2node.size()) {
215            int newsize = 2*_id2node.size();
216            for (int i=_id2node.size(); i < newsize; i++) {
217                _id2node.push_back(-1);
218            }
219        }
220        _id2node[node.id()] = n;
221    }
222    return _nodelist[n];
223}
224
225void
226MeshTri2D::addCell(const Node2D& n1, const Node2D& n2, const Node2D& n3)
227{
228    Node2D node1 = addNode(n1);
229    Node2D node2 = addNode(n2);
230    Node2D node3 = addNode(n3);
231    addCell(node1.id(), node2.id(), node3.id());
232}
233
234void
235MeshTri2D::addCell(int nId1, int nId2, int nId3)
236{
237    _celllist.push_back( Tri2D(nId1,nId2,nId3) );
238    int triId = _celllist.size()-1;
239
240    Edge2D edge;
241    int nodes[4];
242    nodes[0] = nId1;
243    nodes[1] = nId2;
244    nodes[2] = nId3;
245    nodes[3] = nId1;
246
247    // update the neighbors for this triangle
248    for (int i=0; i < 3; i++) {
249        int n = (i+2) % 3;    // this is node opposite i/i+1 edge
250
251        // build an edge with nodes in proper order
252        if (nodes[i] < nodes[i+1]) {
253            edge.fromNode = nodes[i];
254            edge.toNode = nodes[i+1];
255        } else {
256            edge.fromNode = nodes[i+1];
257            edge.toNode = nodes[i];
258        }
259
260        Neighbor2D& nbr = _edge2neighbor[edge];
261        if (nbr.triId < 0) {
262            // not found? then register this for later
263            nbr.triId = triId;
264            nbr.index = n;
265        } else {
266            // this triangle points to other one for the edge
267            _celllist[triId].neighbors[n] = nbr.triId;
268            // other triangle points to this one for the same edge
269            _celllist[nbr.triId].neighbors[nbr.index] = triId;
270            _edge2neighbor.erase(edge);
271        }
272    }
273}
274
275MeshTri2D&
276MeshTri2D::clear()
277{
278    _nodelist.clear();
279    _counter = 0;
280    _id2nodeDirty = 0;
281    _id2node.assign(100, -1);
282    _lastLocate.clear();
283    return *this;
284}
285
286int
287MeshTri2D::sizeNodes() const
288{
289    return _nodelist.size();
290}
291
292Node2D&
293MeshTri2D::atNode(int pos)
294{
295    assert(pos >= 0 && (unsigned int)(pos) < _nodelist.size());
296    return _nodelist.at(pos);
297}
298
299int
300MeshTri2D::sizeCells() const
301{
302    return _celllist.size();
303}
304
305CellTri2D
306MeshTri2D::atCell(int pos)
307{
308    assert(pos >= 0 && (unsigned int)(pos) < _celllist.size());
309
310    Tri2D& cell = _celllist[pos];
311    Node2D* n1Ptr = _getNodeById(cell.nodes[0]);
312    Node2D* n2Ptr = _getNodeById(cell.nodes[1]);
313    Node2D* n3Ptr = _getNodeById(cell.nodes[2]);
314    assert(n1Ptr && n2Ptr && n3Ptr);
315
316    CellTri2D rval(pos, n1Ptr, n2Ptr, n3Ptr);
317    return rval;
318}
319
320double
321MeshTri2D::rangeMin(Axis which) const
322{
323    assert(which != Rappture::zaxis);
324    return _min[which];
325}
326
327double
328MeshTri2D::rangeMax(Axis which) const
329{
330    assert(which != Rappture::zaxis);
331    return _max[which];
332}
333
334CellTri2D
335MeshTri2D::locate(const Node2D& node) const
336{
337    MeshTri2D* nonconst = (MeshTri2D*)this;
338    CellTri2D cell = _lastLocate;
339
340    if (cell.isNull() && _celllist.size() > 0) {
341        Tri2D& tri = nonconst->_celllist[0];
342        cell = CellTri2D(0, &nonconst->_nodelist[tri.nodes[0]],
343                            &nonconst->_nodelist[tri.nodes[1]],
344                            &nonconst->_nodelist[tri.nodes[2]]);
345    }
346
347    while (!cell.isNull()) {
348        double phi[3];
349
350        // compute barycentric coords
351        // if all are >= 0, then this tri contains node
352        // Check against -DBL_EPSILON to handle precision issues at boundaries
353        cell.barycentrics(node, phi);
354        if (phi[0] > -DBL_EPSILON &&
355            phi[1] > -DBL_EPSILON &&
356            phi[2] > -DBL_EPSILON) {
357            break;
358        }
359
360        // find the smallest (most negative) coord phi, and search that dir
361        int dir = 0;
362        for (int i=1; i <= 2; i++) {
363            if (phi[i] < phi[dir]) {
364                dir = i;
365            }
366        }
367
368        Tri2D& tri = nonconst->_celllist[ cell.cellId() ];
369        int neighborId = tri.neighbors[dir];
370        if (neighborId < 0) {
371            cell.clear();
372            return cell;
373        }
374
375        Tri2D& tri2 = nonconst->_celllist[neighborId];
376        Node2D *n1Ptr = &nonconst->_nodelist[tri2.nodes[0]];
377        Node2D *n2Ptr = &nonconst->_nodelist[tri2.nodes[1]];
378        Node2D *n3Ptr = &nonconst->_nodelist[tri2.nodes[2]];
379        cell = CellTri2D(neighborId, n1Ptr, n2Ptr, n3Ptr);
380    }
381
382    nonconst->_lastLocate = cell;
383    return cell;
384}
385
386Ptr<Serializable>
387MeshTri2D::create()
388{
389    return Ptr<Serializable>( (Serializable*) new MeshTri2D() );
390}
391
392void
393MeshTri2D::serialize_A(SerialBuffer& buffer) const
394{
395}
396
397Outcome
398deserialize_A(SerialBuffer& buffer)
399{
400    Outcome status;
401    return status;
402}
403
404Node2D*
405MeshTri2D::_getNodeById(int nodeId)
406{
407    MeshTri2D* nonconst = (MeshTri2D*)this;
408    Node2D *rptr = NULL;
409    nonconst->_rebuildNodeIdMap();
410
411    if ((unsigned int)nodeId < _id2node.size()) {
412        int n = _id2node[nodeId];
413        if (n >= 0) {
414            return &_nodelist[n];
415        }
416    }
417    return rptr;
418}
419
420void
421MeshTri2D::_rebuildNodeIdMap()
422{
423    if (_id2nodeDirty) {
424        _min[0] = _min[1] = NAN;
425        _max[0] = _max[1] = NAN;
426
427        // figure out how big the _id2node array should be
428        int maxId = -1;
429        std::vector<Node2D>::iterator n = _nodelist.begin();
430        while (n != _nodelist.end()) {
431            if (n->id() > maxId) {
432                maxId = n->id();
433            }
434            ++n;
435        }
436        if (maxId > 0) {
437            _id2node.assign(maxId+1, -1);
438        }
439
440        // scan through and map id -> node index
441        int i = 0;
442        n = _nodelist.begin();
443        while (n != _nodelist.end()) {
444            _id2node[n->id()] = i++;
445
446            if (isnan(_min[0])) {
447                _min[0] = _max[0] = n->x();
448                _min[1] = _max[1] = n->y();
449            } else {
450                if (n->x() < _min[0]) { _min[0] = n->x(); }
451                if (n->x() > _max[0]) { _max[0] = n->x(); }
452                if (n->y() < _min[1]) { _min[1] = n->y(); }
453                if (n->y() > _max[1]) { _max[1] = n->y(); }
454            }
455            ++n;
456        }
457        _id2nodeDirty = 0;
458    }
459}
Note: See TracBrowser for help on using the repository browser.