Branch data Line data Source code
1 : : /* *****************************************************************
2 : : MESQUITE -- The Mesh Quality Improvement Toolkit
3 : :
4 : : Copyright 2007 Sandia National Laboratories. Developed at the
5 : : University of Wisconsin--Madison under SNL contract number
6 : : 624796. The U.S. Government and the University of Wisconsin
7 : : retain certain rights to this software.
8 : :
9 : : This library is free software; you can redistribute it and/or
10 : : modify it under the terms of the GNU Lesser General Public
11 : : License as published by the Free Software Foundation; either
12 : : version 2.1 of the License, or (at your option) any later version.
13 : :
14 : : This library is distributed in the hope that it will be useful,
15 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : Lesser General Public License for more details.
18 : :
19 : : You should have received a copy of the GNU Lesser General Public License
20 : : (lgpl.txt) along with this library; if not, write to the Free Software
21 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 : :
23 : : (2007) [email protected]
24 : :
25 : : ***************************************************************** */
26 : :
27 : : /** \file ArrayMesh.cpp
28 : : * \brief
29 : : * \author Jason Kraftcheck
30 : : */
31 : :
32 : : #include "Mesquite.hpp"
33 : : #include "ArrayMesh.hpp"
34 : : #include "TopologyInfo.hpp"
35 : : #include "MsqError.hpp"
36 : : #include "MsqVertex.hpp"
37 : :
38 : : #include <iostream>
39 : :
40 : : namespace MBMesquite
41 : : {
42 : :
43 : : class IndexIterator : public EntityIterator
44 : : {
45 : : public:
46 : 0 : IndexIterator( size_t pStart, size_t pEnd ) : mStart( pStart ), mEnd( pEnd ), mCurrent( pStart ) {}
47 [ # # ]: 0 : virtual ~IndexIterator() {}
48 : 0 : virtual void restart()
49 : : {
50 : 0 : mCurrent = mStart;
51 : 0 : }
52 : 0 : virtual Mesh::EntityHandle operator*() const
53 : : {
54 : 0 : return (Mesh::EntityHandle)mCurrent;
55 : : }
56 : 0 : virtual void operator++()
57 : : {
58 : 0 : ++mCurrent;
59 : 0 : }
60 : 0 : virtual bool is_at_end() const
61 : : {
62 : 0 : return mEnd - mCurrent <= 1;
63 : : }
64 : :
65 : : private:
66 : : size_t mStart, mEnd, mCurrent;
67 : : };
68 : :
69 : 0 : ArrayMesh::ArrayMesh()
70 : : : mDimension( 0 ), vertexCount( 0 ), coordArray( 0 ), fixedFlags( 0 ), slavedFlags( 0 ), vertexByteArray( 0 ),
71 : : elementCount( 0 ), connArray( 0 ), connOffsets( 0 ), allocConnOffsets( 0 ), elementType( MIXED ),
72 : : elementTypes( 0 ), nodesPerElement( 0 ), oneBasedArrays( false ), vertexAdjacencyList( 0 ),
73 : 0 : vertexAdjacencyOffsets( 0 ), tagList( 0 )
74 : : {
75 : 0 : }
76 : :
77 : 1 : ArrayMesh::ArrayMesh( int coords_per_vertex, unsigned long num_vertices, double* interleaved_vertex_coords,
78 : : const int* vertex_fixed_flags, unsigned long num_elements, EntityTopology element_type,
79 : : const unsigned long* element_connectivity_array, bool one_based_conn_indices,
80 : : unsigned nodes_per_element, const int* vertex_slaved_flags )
81 : : : mDimension( coords_per_vertex ), vertexCount( num_vertices ), coordArray( interleaved_vertex_coords ),
82 : : fixedFlags( vertex_fixed_flags ), slavedFlags( vertex_slaved_flags ),
83 [ + - ]: 1 : vertexByteArray( new unsigned char[num_vertices + one_based_conn_indices] ), elementCount( num_elements ),
84 : : connArray( element_connectivity_array ), connOffsets( 0 ), allocConnOffsets( 0 ), elementType( element_type ),
85 : : elementTypes( 0 ), nodesPerElement( nodes_per_element ), oneBasedArrays( one_based_conn_indices ),
86 : 1 : vertexAdjacencyList( 0 ), vertexAdjacencyOffsets( 0 ), tagList( 0 )
87 : : {
88 [ - + ]: 1 : if( oneBasedArrays )
89 : : {
90 : 0 : coordArray -= mDimension;
91 : 0 : --fixedFlags;
92 : : }
93 : :
94 [ + - ][ + - ]: 1 : if( nodesPerElement < 2 ) nodesPerElement = TopologyInfo::corners( element_type );
95 : :
96 [ + - ][ - + ]: 1 : assert( valid() );
97 : 1 : memset( vertexByteArray, 0, num_vertices + one_based_conn_indices );
98 : 1 : }
99 : :
100 : 0 : ArrayMesh::ArrayMesh( int coords_per_vertex, unsigned long num_vertices, double* interleaved_vertex_coords,
101 : : const int* vertex_fixed_flags, unsigned long num_elements, const EntityTopology* element_types,
102 : : const unsigned long* element_connectivity_array,
103 : : const unsigned long* element_connectivity_offsets, bool one_based_conn_indices,
104 : : const int* vertex_slaved_flags )
105 : : : mDimension( coords_per_vertex ), vertexCount( num_vertices ), coordArray( interleaved_vertex_coords ),
106 : : fixedFlags( vertex_fixed_flags ), slavedFlags( vertex_slaved_flags ),
107 [ # # ]: 0 : vertexByteArray( new unsigned char[num_vertices + one_based_conn_indices] ), elementCount( num_elements ),
108 : : connArray( element_connectivity_array ), connOffsets( element_connectivity_offsets ), allocConnOffsets( 0 ),
109 : : elementType( MIXED ), elementTypes( element_types ), nodesPerElement( 0 ),
110 : 0 : oneBasedArrays( one_based_conn_indices ), vertexAdjacencyList( 0 ), vertexAdjacencyOffsets( 0 ), tagList( 0 )
111 : : {
112 [ # # ]: 0 : if( oneBasedArrays )
113 : : {
114 : 0 : coordArray -= mDimension;
115 : 0 : --fixedFlags;
116 [ # # ]: 0 : if( element_connectivity_offsets ) --connArray;
117 : : }
118 : :
119 [ # # ]: 0 : if( !element_connectivity_offsets )
120 : : {
121 [ # # ][ # # ]: 0 : connOffsets = allocConnOffsets = new unsigned long[num_elements + 1];
122 : 0 : allocConnOffsets[0] = 0;
123 [ # # ]: 0 : for( unsigned long i = 1; i <= num_elements; ++i )
124 [ # # ]: 0 : allocConnOffsets[i] = allocConnOffsets[i - 1] + TopologyInfo::corners( elementTypes[i - 1] );
125 : : }
126 : :
127 [ # # ][ # # ]: 0 : assert( valid() );
128 : 0 : memset( vertexByteArray, 0, num_vertices + one_based_conn_indices );
129 : 0 : }
130 : :
131 : 1 : bool ArrayMesh::valid() const
132 : : {
133 [ - + ]: 1 : unsigned long off = oneBasedArrays ? 1 : 0;
134 [ + + ]: 17 : for( unsigned long i = off; i < vertexCount + off; ++i )
135 : : {
136 [ + + ][ - + ]: 16 : if( fixedFlags[i] != 0 && fixedFlags[i] != 1 )
137 : : {
138 : 0 : std::cerr << "Invalid vertex fixed flag at index " << i << std::endl;
139 : 0 : return false;
140 : : }
141 : : }
142 : :
143 [ + + ]: 37 : for( unsigned long i = 0; i < elementCount * nodesPerElement; ++i )
144 : : {
145 : 36 : unsigned long j = connArray[i] - oneBasedArrays;
146 [ - + ]: 36 : if( j >= vertexCount )
147 : : {
148 : 0 : std::cerr << "Invalid connectivity index at index " << j << "(element " << j / elementCount << " node "
149 : 0 : << j % elementCount << ')' << std::endl;
150 : 0 : return false;
151 : : }
152 : : }
153 : :
154 : 1 : return true;
155 : : }
156 : :
157 : 1 : void ArrayMesh::clear_mesh()
158 : : {
159 [ + - ]: 1 : delete[] vertexByteArray;
160 [ + - ]: 1 : delete[] vertexAdjacencyList;
161 [ + - ]: 1 : delete[] vertexAdjacencyOffsets;
162 [ - + ]: 1 : delete[] allocConnOffsets;
163 [ - + ]: 1 : while( tagList )
164 : : {
165 : 0 : Tag* dead = tagList;
166 : 0 : tagList = tagList->next;
167 [ # # ]: 0 : delete[] dead->name;
168 [ # # ]: 0 : delete[] dead->defaultValue;
169 [ # # ]: 0 : if( dead->owned )
170 : : {
171 [ # # ]: 0 : delete[] dead->vtxWritePtr;
172 [ # # ]: 0 : delete[] dead->eleWritePtr;
173 : : }
174 : 0 : delete dead;
175 : : }
176 : 1 : mDimension = 0;
177 : 1 : vertexCount = 0;
178 : 1 : coordArray = 0;
179 : 1 : connOffsets = 0;
180 : 1 : allocConnOffsets = 0;
181 : 1 : fixedFlags = 0;
182 : 1 : vertexByteArray = 0;
183 : 1 : elementCount = 0;
184 : 1 : elementType = MIXED;
185 : 1 : elementTypes = 0;
186 : 1 : nodesPerElement = 0;
187 : 1 : oneBasedArrays = false;
188 : 1 : vertexAdjacencyList = 0;
189 : 1 : vertexAdjacencyOffsets = 0;
190 : 1 : }
191 : :
192 : 0 : void ArrayMesh::set_mesh( int coords_per_vertex, unsigned long num_vertices, double* interleaved_vertex_coords,
193 : : const int* vertex_fixed_flags, unsigned long num_elements, EntityTopology element_type,
194 : : const unsigned long* element_connectivity_array, bool one_based_conn_indices,
195 : : unsigned nodes_per_element, const int* vertex_slaved_flags )
196 : : {
197 : 0 : clear_mesh();
198 : 0 : mDimension = coords_per_vertex;
199 : 0 : vertexCount = num_vertices;
200 : 0 : coordArray = interleaved_vertex_coords;
201 : 0 : fixedFlags = vertex_fixed_flags;
202 : 0 : slavedFlags = vertex_slaved_flags;
203 : 0 : elementCount = num_elements;
204 : 0 : connArray = element_connectivity_array;
205 : 0 : elementType = element_type;
206 : 0 : oneBasedArrays = one_based_conn_indices;
207 : :
208 [ # # ]: 0 : if( oneBasedArrays )
209 : : {
210 : 0 : coordArray -= mDimension;
211 : 0 : --fixedFlags;
212 : : }
213 : :
214 [ # # ]: 0 : if( nodes_per_element < 2 )
215 : 0 : nodesPerElement = TopologyInfo::corners( element_type );
216 : : else
217 : 0 : nodesPerElement = nodes_per_element;
218 : :
219 : 0 : vertexByteArray = new unsigned char[num_vertices + one_based_conn_indices];
220 [ # # ]: 0 : assert( valid() );
221 : 0 : memset( vertexByteArray, 0, num_vertices + one_based_conn_indices );
222 : 0 : }
223 : :
224 : 2 : ArrayMesh::~ArrayMesh()
225 : : {
226 : 1 : clear_mesh();
227 [ - + ]: 1 : }
228 : :
229 : 95 : inline const unsigned long* ArrayMesh::elem_verts( size_t e, int& n ) const
230 : : {
231 [ - + ]: 95 : assert( e < elementCount );
232 [ - + ]: 95 : if( connOffsets )
233 : : {
234 : 0 : n = connOffsets[e + 1] - connOffsets[e];
235 : 0 : return connArray + connOffsets[e];
236 : : }
237 : : else
238 : : {
239 : 95 : n = nodesPerElement;
240 : 95 : return connArray + nodesPerElement * e;
241 : : }
242 : : }
243 : :
244 : 0 : int ArrayMesh::get_geometric_dimension( MsqError& )
245 : : {
246 : 0 : return mDimension;
247 : : }
248 : :
249 : 5 : void ArrayMesh::get_all_elements( std::vector< ElementHandle >& elements, MsqError& )
250 : : {
251 : 5 : elements.resize( elementCount );
252 [ + + ]: 50 : for( unsigned long i = 0; i < elementCount; ++i )
253 : 45 : elements[i] = (Mesh::ElementHandle)i;
254 : 5 : }
255 : :
256 : 7 : void ArrayMesh::get_all_vertices( std::vector< VertexHandle >& vertices, MsqError& )
257 : : {
258 : 7 : vertices.resize( vertexCount );
259 [ + + ]: 119 : for( unsigned long i = 0; i < vertexCount; ++i )
260 : 112 : vertices[i] = ( Mesh::VertexHandle )( i + oneBasedArrays );
261 : 7 : }
262 : :
263 : 0 : VertexIterator* ArrayMesh::vertex_iterator( MsqError& )
264 : : {
265 [ # # ]: 0 : return new IndexIterator( oneBasedArrays, vertexCount + oneBasedArrays );
266 : : }
267 : :
268 : 0 : ElementIterator* ArrayMesh::element_iterator( MsqError& )
269 : : {
270 [ # # ]: 0 : return new IndexIterator( 0, elementCount );
271 : : }
272 : :
273 : 5 : void ArrayMesh::vertices_get_fixed_flag( const VertexHandle vert_array[], std::vector< bool >& fixed_flag_array,
274 : : size_t num_vtx, MsqError& )
275 : : {
276 : 5 : fixed_flag_array.resize( num_vtx );
277 : 5 : const size_t* indices = (const size_t*)vert_array;
278 [ + + ]: 85 : for( size_t i = 0; i < num_vtx; ++i )
279 : : {
280 [ - + ]: 80 : assert( indices[i] < vertexCount );
281 : 80 : fixed_flag_array[i] = !!fixedFlags[indices[i]];
282 : : }
283 : 5 : }
284 : :
285 : 0 : void ArrayMesh::vertices_get_slaved_flag( const VertexHandle* vert_array, std::vector< bool >& slaved_flags,
286 : : size_t num_vtx, MsqError& err )
287 : : {
288 [ # # ]: 0 : if( !slavedFlags )
289 : : {
290 : : MSQ_SETERR( err )
291 [ # # ]: 0 : ( "No data provided to ArrayMesh for Settings::SLAVE_FLAG", MsqError::INVALID_STATE );
292 : 0 : return;
293 : : }
294 : :
295 : 0 : slaved_flags.resize( num_vtx );
296 : 0 : const size_t* indices = (const size_t*)vert_array;
297 [ # # ]: 0 : for( size_t i = 0; i < num_vtx; ++i )
298 : : {
299 [ # # ]: 0 : assert( indices[i] < vertexCount );
300 : 0 : slaved_flags[i] = !!slavedFlags[indices[i]];
301 : : }
302 : : }
303 : :
304 : 28 : void ArrayMesh::vertices_get_coordinates( const VertexHandle vert_array[], MsqVertex* coordinates, size_t num_vtx,
305 : : MsqError& err )
306 : : {
307 : 28 : const size_t* indices = (const size_t*)vert_array;
308 [ + - ]: 28 : if( mDimension == 3 )
309 [ + + ]: 177 : for( size_t i = 0; i < num_vtx; ++i )
310 : : {
311 [ - + ]: 149 : assert( indices[i] < vertexCount + oneBasedArrays );
312 : 149 : coordinates[i].set( coordArray + 3 * indices[i] );
313 : : }
314 [ # # ]: 0 : else if( mDimension == 2 )
315 [ # # ]: 0 : for( size_t i = 0; i < num_vtx; ++i )
316 : : {
317 [ # # ]: 0 : assert( indices[i] < vertexCount + oneBasedArrays );
318 : 0 : coordinates[i].set( coordArray[2 * indices[i]], coordArray[2 * indices[i] + 1], 0.0 );
319 : : }
320 : : else
321 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::INVALID_STATE );
322 : 28 : }
323 : :
324 : 4 : void ArrayMesh::vertex_set_coordinates( VertexHandle vert, const Vector3D& coordinates, MsqError& err )
325 : : {
326 : 4 : size_t i = (size_t)vert;
327 [ - + ]: 4 : assert( i < vertexCount + oneBasedArrays );
328 [ + - ]: 4 : if( mDimension == 3 )
329 : 4 : coordinates.get_coordinates( coordArray + 3 * i );
330 [ # # ]: 0 : else if( mDimension == 2 )
331 : : {
332 : 0 : coordArray[2 * i] = coordinates[0];
333 : 0 : coordArray[2 * i + 1] = coordinates[1];
334 : : }
335 : : else
336 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::INVALID_STATE );
337 : 4 : }
338 : :
339 : 36 : void ArrayMesh::vertex_set_byte( VertexHandle vertex, unsigned char byte, MsqError& )
340 : : {
341 [ - + ]: 36 : assert( (size_t)vertex < vertexCount + oneBasedArrays );
342 : 36 : vertexByteArray[(size_t)vertex] = byte;
343 : 36 : }
344 : :
345 : 30 : void ArrayMesh::vertices_set_byte( const VertexHandle* vert_array, const unsigned char* byte_array, size_t array_size,
346 : : MsqError& )
347 : : {
348 : 30 : const size_t* indices = (const size_t*)vert_array;
349 [ + + ]: 186 : for( size_t i = 0; i < array_size; ++i )
350 : : {
351 [ - + ]: 156 : assert( indices[i] < vertexCount + oneBasedArrays );
352 : 156 : vertexByteArray[indices[i]] = byte_array[i];
353 : : }
354 : 30 : }
355 : :
356 : 0 : void ArrayMesh::vertex_get_byte( VertexHandle vertex, unsigned char* byte, MsqError& )
357 : : {
358 [ # # ]: 0 : assert( (size_t)vertex < vertexCount + oneBasedArrays );
359 : 0 : *byte = vertexByteArray[(size_t)vertex];
360 : 0 : }
361 : :
362 : 35 : void ArrayMesh::vertices_get_byte( const VertexHandle* vert_array, unsigned char* byte_array, size_t array_size,
363 : : MsqError& )
364 : : {
365 : 35 : const size_t* indices = (const size_t*)vert_array;
366 [ + + ]: 203 : for( size_t i = 0; i < array_size; ++i )
367 : : {
368 [ - + ]: 168 : assert( indices[i] < vertexCount + oneBasedArrays );
369 : 168 : byte_array[i] = vertexByteArray[indices[i]];
370 : : }
371 : 35 : }
372 : :
373 : 8 : void ArrayMesh::vertices_get_attached_elements( const VertexHandle* vertex_array, size_t num_vertex,
374 : : std::vector< ElementHandle >& elements, std::vector< size_t >& offsets,
375 : : MsqError& )
376 : : {
377 : 8 : const size_t* indices = (const size_t*)vertex_array;
378 [ + + ]: 8 : if( !vertexAdjacencyList ) build_vertex_adjacency_list();
379 : :
380 : 8 : elements.clear();
381 : 8 : offsets.resize( num_vertex + 1 );
382 [ + + ]: 16 : for( size_t i = 0; i < num_vertex; ++i )
383 : : {
384 : 8 : offsets[i] = elements.size();
385 [ - + ]: 8 : assert( indices[i] < vertexCount + oneBasedArrays );
386 [ + + ]: 40 : for( size_t j = vertexAdjacencyOffsets[indices[i]]; j < vertexAdjacencyOffsets[indices[i] + 1]; ++j )
387 [ + - ]: 32 : elements.push_back( (ElementHandle)vertexAdjacencyList[j] );
388 : : }
389 : 8 : offsets[num_vertex] = elements.size();
390 : 8 : }
391 : :
392 : 53 : void ArrayMesh::elements_get_attached_vertices( const ElementHandle* elem_handles, size_t num_elems,
393 : : std::vector< VertexHandle >& vert_handles,
394 : : std::vector< size_t >& offsets, MsqError& )
395 : : {
396 : 53 : const size_t* indices = (const size_t*)elem_handles;
397 : 53 : offsets.resize( num_elems + 1 );
398 : 53 : vert_handles.clear();
399 [ + + ]: 130 : for( size_t i = 0; i < num_elems; ++i )
400 : : {
401 [ - + ]: 77 : assert( indices[i] < elementCount );
402 : : int count;
403 [ + - ]: 77 : const unsigned long* conn = elem_verts( indices[i], count );
404 : 77 : size_t prev_size = vert_handles.size();
405 [ + - ]: 77 : offsets[i] = prev_size;
406 [ + - ]: 77 : vert_handles.resize( prev_size + count );
407 [ + - ][ + - ]: 77 : std::copy( conn, conn + count, (size_t*)( &vert_handles[prev_size] ) );
408 : : }
409 : 53 : offsets[num_elems] = vert_handles.size();
410 : 53 : }
411 : :
412 : 53 : void ArrayMesh::elements_get_topologies( const ElementHandle* handles, EntityTopology* element_topologies,
413 : : size_t num_elements, MsqError& )
414 : : {
415 : 53 : const size_t* indices = (const size_t*)handles;
416 [ - + ]: 53 : if( elementType == MIXED )
417 [ # # ]: 0 : for( size_t i = 0; i < num_elements; ++i )
418 : : {
419 [ # # ]: 0 : assert( indices[i] < elementCount );
420 : 0 : element_topologies[i] = elementTypes[indices[i]];
421 : : }
422 : : else
423 [ + + ]: 130 : for( size_t i = 0; i < num_elements; ++i )
424 : : {
425 [ - + ]: 77 : assert( indices[i] < elementCount );
426 : 77 : element_topologies[i] = elementType;
427 : : }
428 : 53 : }
429 : :
430 : 0 : void ArrayMesh::release_entity_handles( const EntityHandle*, size_t, MsqError& err )
431 : : {
432 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::NOT_IMPLEMENTED );
433 : 0 : }
434 : :
435 : 0 : void ArrayMesh::release() {}
436 : :
437 : 1 : void ArrayMesh::build_vertex_adjacency_list()
438 : : {
439 [ - + ]: 1 : delete[] vertexAdjacencyList;
440 [ - + ]: 1 : delete[] vertexAdjacencyOffsets;
441 [ + - ]: 1 : vertexAdjacencyOffsets = new unsigned long[vertexCount + oneBasedArrays + 1];
442 : :
443 : : // for each vertex, store the number of elements the previous
444 : : // vertex occurs in.
445 : 1 : memset( vertexAdjacencyOffsets, 0, sizeof( unsigned long ) * ( vertexCount + oneBasedArrays + 1 ) );
446 [ + + ]: 10 : for( size_t i = 0; i < elementCount; ++i )
447 : : {
448 : : int n;
449 [ + - ]: 9 : const unsigned long* conn = elem_verts( i, n );
450 [ + + ]: 45 : for( int j = 0; j < n; ++j )
451 : 36 : ++vertexAdjacencyOffsets[conn[j] + 1];
452 : : }
453 : :
454 : : // convert vertexAdjacencyOffsets from a shifted list of counts
455 : : // to a list of offsts
456 [ + + ]: 17 : for( size_t i = 1; i <= vertexCount + oneBasedArrays; ++i )
457 : 16 : vertexAdjacencyOffsets[i] += vertexAdjacencyOffsets[i - 1];
458 : :
459 : : // allocate space and populate with reverse connectivity
460 [ + - ]: 1 : vertexAdjacencyList = new unsigned long[vertexAdjacencyOffsets[vertexCount + oneBasedArrays]];
461 [ + + ]: 10 : for( size_t i = 0; i < elementCount; ++i )
462 : : {
463 : : int n;
464 [ + - ]: 9 : const unsigned long* conn = elem_verts( i, n );
465 [ + + ]: 45 : for( int j = 0; j < n; ++j )
466 : 36 : vertexAdjacencyList[vertexAdjacencyOffsets[conn[j]]++] = i;
467 : : }
468 : :
469 [ + + ]: 17 : for( size_t i = vertexCount + oneBasedArrays; i > 0; --i )
470 : 16 : vertexAdjacencyOffsets[i] = vertexAdjacencyOffsets[i - 1];
471 : 1 : vertexAdjacencyOffsets[0] = 0;
472 : 1 : }
473 : :
474 : 1 : unsigned ArrayMesh::bytes( TagType type )
475 : : {
476 [ - - + - : 1 : switch( type )
- ]
477 : : {
478 : : case BYTE:
479 : : case BOOL:
480 : 0 : return 1;
481 : : case INT:
482 : 0 : return sizeof( int );
483 : : case DOUBLE:
484 : 1 : return sizeof( double );
485 : : case HANDLE:
486 : 0 : return sizeof( EntityHandle );
487 : : }
488 : 0 : return 0;
489 : : }
490 : :
491 : 1 : void ArrayMesh::fill( unsigned char* buffer, const unsigned char* value, size_t size, size_t count )
492 : : {
493 [ + - ]: 1 : if( !value )
494 : : {
495 : 1 : memset( buffer, 0, size * count );
496 : 1 : return;
497 : : }
498 : :
499 : 0 : unsigned char* const end = buffer + size * count;
500 [ # # ]: 0 : for( unsigned char* iter = buffer; iter != end; iter += size )
501 : 0 : memcpy( iter, value, size );
502 : : }
503 : :
504 : 1 : ArrayMesh::Tag* ArrayMesh::allocate_tag( const char* name, bool owned, TagType type, unsigned size,
505 : : const void* vertex_ro_data, void* vertex_rw_data, const void* element_ro_data,
506 : : void* element_rw_data, const void* default_value, MsqError& err )
507 : : {
508 : : // check if name is already in use
509 [ - + ]: 1 : for( Tag* iter = tagList; iter; iter = iter->next )
510 : : {
511 [ # # ]: 0 : if( !strcmp( iter->name, name ) )
512 : : {
513 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::TAG_ALREADY_EXISTS );
514 : 0 : return 0;
515 : : }
516 : : }
517 : :
518 : : // allocate object
519 : 1 : Tag* result = new Tag;
520 : :
521 : : // initialize members
522 : 1 : result->type = type;
523 : 1 : result->size = size * bytes( type );
524 : 1 : result->owned = owned;
525 : 1 : result->name = new char[strlen( name ) + 1];
526 : 1 : strcpy( result->name, name );
527 : :
528 : 1 : result->vtxWritePtr = reinterpret_cast< unsigned char* >( vertex_rw_data );
529 [ - + ]: 1 : if( vertex_rw_data )
530 : 0 : result->vtxReadPtr = reinterpret_cast< unsigned char* >( vertex_rw_data );
531 : : else
532 : 1 : result->vtxReadPtr = reinterpret_cast< const unsigned char* >( vertex_ro_data );
533 : :
534 : 1 : result->eleWritePtr = reinterpret_cast< unsigned char* >( element_rw_data );
535 [ - + ]: 1 : if( element_rw_data )
536 : 0 : result->eleReadPtr = reinterpret_cast< unsigned char* >( element_rw_data );
537 : : else
538 : 1 : result->eleReadPtr = reinterpret_cast< const unsigned char* >( element_ro_data );
539 : :
540 [ - + ]: 1 : if( default_value )
541 : : {
542 : 0 : result->defaultValue = new unsigned char[result->size];
543 : 0 : memcpy( result->defaultValue, default_value, result->size );
544 : : }
545 : : else
546 : : {
547 : 1 : result->defaultValue = 0;
548 : : }
549 : :
550 : : // prepend to tag list
551 : 1 : result->next = tagList;
552 : 1 : tagList = result;
553 : :
554 : 1 : return result;
555 : : }
556 : :
557 : 0 : TagHandle ArrayMesh::add_read_only_tag_data( const char* tag_name, TagType data_type, int vals_per_entity,
558 : : const void* vertex_data, const void* element_data,
559 : : const void* default_value, MsqError& err )
560 : : {
561 : : Tag* tag = allocate_tag( tag_name, false, data_type, vals_per_entity, vertex_data, 0, element_data, 0,
562 : 0 : default_value, err );
563 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ]
564 : 0 : return reinterpret_cast< TagHandle >( tag );
565 : : }
566 : :
567 : 0 : TagHandle ArrayMesh::add_writable_tag_data( const char* tag_name, TagType data_type, int vals_per_entity,
568 : : void* vertex_data, void* element_data, const void* default_value,
569 : : MsqError& err )
570 : : {
571 : : Tag* tag = allocate_tag( tag_name, false, data_type, vals_per_entity, 0, vertex_data, 0, element_data,
572 : 0 : default_value, err );
573 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ]
574 : 0 : return reinterpret_cast< TagHandle >( tag );
575 : : }
576 : :
577 : 1 : TagHandle ArrayMesh::tag_create( const std::string& tag_name, TagType data_type, unsigned size,
578 : : const void* default_value, MsqError& err )
579 : : {
580 : 1 : Tag* tag = allocate_tag( tag_name.c_str(), true, data_type, size, 0, 0, 0, 0, default_value, err );
581 [ - + ][ # # ]: 1 : MSQ_ERRZERO( err );
[ - + ]
582 : 1 : return reinterpret_cast< TagHandle >( tag );
583 : : }
584 : :
585 : 1 : void ArrayMesh::tag_delete( TagHandle handle, MsqError& err )
586 : : {
587 : 1 : Tag* ptr = reinterpret_cast< Tag* >( handle );
588 : : // find previous tag pointer in list
589 [ - + ]: 1 : if( !tagList )
590 : : {
591 [ # # ]: 0 : MSQ_SETERR( err )( "Invalid tag handle", MsqError::TAG_NOT_FOUND );
592 : 0 : return;
593 : : }
594 : 1 : Tag* prev = 0;
595 [ + + ][ + - ]: 2 : for( prev = tagList; prev && prev->next != ptr; prev = prev->next )
596 : : ;
597 [ + - ][ - + ]: 1 : if( !prev && tagList != ptr )
598 : : {
599 [ # # ]: 0 : MSQ_SETERR( err )( "Invalid tag handle", MsqError::TAG_NOT_FOUND );
600 : 0 : return;
601 : : }
602 [ + - ]: 1 : delete[] ptr->name;
603 [ - + ]: 1 : delete[] ptr->defaultValue;
604 [ + - ]: 1 : if( ptr->owned )
605 : : {
606 [ + - ]: 1 : delete[] ptr->vtxWritePtr;
607 [ - + ]: 1 : delete[] ptr->eleWritePtr;
608 : : }
609 [ - + ]: 1 : if( prev )
610 : 0 : prev->next = ptr->next;
611 : : else
612 : 1 : tagList = ptr->next;
613 : 1 : delete ptr;
614 : : }
615 : :
616 : 0 : TagHandle ArrayMesh::tag_get( const std::string& name, MsqError& err )
617 : : {
618 [ # # ]: 0 : for( Tag* iter = tagList; iter; iter = iter->next )
619 [ # # ]: 0 : if( name == iter->name ) return reinterpret_cast< TagHandle >( iter );
620 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::TAG_NOT_FOUND );
621 : 0 : return 0;
622 : : }
623 : :
624 : 0 : void ArrayMesh::tag_properties( TagHandle handle, std::string& name, TagType& type, unsigned& size, MsqError& )
625 : : {
626 : 0 : const Tag* ptr = reinterpret_cast< const Tag* >( handle );
627 : 0 : name = ptr->name;
628 : 0 : type = ptr->type;
629 : 0 : size = ptr->size / bytes( ptr->type );
630 : 0 : }
631 : :
632 : 0 : void ArrayMesh::tag_set_element_data( TagHandle handle, size_t count, const ElementHandle* entities, const void* data,
633 : : MsqError& err )
634 : : {
635 : 0 : Tag* tag = reinterpret_cast< Tag* >( handle );
636 [ # # ]: 0 : if( !tag->eleWritePtr )
637 : : {
638 [ # # ]: 0 : if( !tag->owned )
639 : : {
640 : : MSQ_SETERR( err )
641 [ # # ]: 0 : ( "Attempt to set non-writeable (application owned) tag data", MsqError::TAG_ALREADY_EXISTS );
642 : 0 : return;
643 : : }
644 : : else
645 : : {
646 [ # # ]: 0 : assert( !tag->eleReadPtr );
647 : 0 : tag->eleReadPtr = tag->eleWritePtr = new unsigned char[elementCount * tag->size];
648 : 0 : fill( tag->eleWritePtr, tag->defaultValue, tag->size, elementCount );
649 : : }
650 : : }
651 : 0 : const unsigned char* ptr = reinterpret_cast< const unsigned char* >( data );
652 : : // as we're working with user-supplied arrays, make sure we're not
653 : : // memcpying overlapping regions
654 [ # # ][ # # ]: 0 : assert( ptr + tag->size * elementCount <= tag->eleWritePtr || tag->eleWritePtr + tag->size * elementCount <= ptr );
655 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
656 : : {
657 : 0 : size_t idx = reinterpret_cast< size_t >( entities[i] );
658 : 0 : memcpy( tag->eleWritePtr + idx * tag->size, ptr + i * tag->size, tag->size );
659 : : }
660 : : }
661 : :
662 : 5 : void ArrayMesh::tag_set_vertex_data( TagHandle handle, size_t count, const VertexHandle* entities, const void* data,
663 : : MsqError& err )
664 : : {
665 : 5 : Tag* tag = reinterpret_cast< Tag* >( handle );
666 [ + + ]: 5 : if( !tag->vtxWritePtr )
667 : : {
668 [ - + ]: 1 : if( !tag->owned )
669 : : {
670 : : MSQ_SETERR( err )
671 [ # # ]: 0 : ( "Attempt to set non-writeable (application owned) tag data", MsqError::TAG_ALREADY_EXISTS );
672 : 5 : return;
673 : : }
674 : : else
675 : : {
676 [ - + ]: 1 : assert( !tag->vtxReadPtr );
677 : 1 : tag->vtxReadPtr = tag->vtxWritePtr = new unsigned char[vertexCount * tag->size];
678 : 1 : fill( tag->vtxWritePtr, tag->defaultValue, tag->size, vertexCount );
679 : : }
680 : : }
681 : 5 : const unsigned char* ptr = reinterpret_cast< const unsigned char* >( data );
682 : : // as we're working with user-supplied arrays, make sure we're not
683 : : // memcpying overlapping regions
684 [ + + ][ - + ]: 5 : assert( ptr + tag->size * vertexCount <= tag->vtxWritePtr || tag->vtxWritePtr + tag->size * vertexCount <= ptr );
685 [ + + ]: 13 : for( size_t i = 0; i < count; ++i )
686 : : {
687 : 8 : size_t idx = reinterpret_cast< size_t >( entities[i] ) - oneBasedArrays;
688 : 8 : memcpy( tag->vtxWritePtr + idx * tag->size, ptr + i * tag->size, tag->size );
689 : : }
690 : : }
691 : :
692 : 0 : void ArrayMesh::tag_get_element_data( TagHandle handle, size_t count, const ElementHandle* entities, void* data,
693 : : MsqError& err )
694 : : {
695 : 0 : unsigned char* ptr = reinterpret_cast< unsigned char* >( data );
696 : 0 : const Tag* tag = reinterpret_cast< const Tag* >( handle );
697 [ # # ]: 0 : if( tag->eleReadPtr )
698 : : {
699 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
700 : : {
701 : 0 : size_t idx = reinterpret_cast< size_t >( entities[i] );
702 : 0 : memcpy( ptr + i * tag->size, tag->eleReadPtr + idx * tag->size, tag->size );
703 : : }
704 : : }
705 [ # # ]: 0 : else if( tag->defaultValue )
706 : : {
707 : 0 : fill( ptr, tag->defaultValue, tag->size, count );
708 : : }
709 : : else
710 : : {
711 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::TAG_NOT_FOUND );
712 : : }
713 : 0 : }
714 : :
715 : 4 : void ArrayMesh::tag_get_vertex_data( TagHandle handle, size_t count, const VertexHandle* entities, void* data,
716 : : MsqError& err )
717 : : {
718 : 4 : unsigned char* ptr = reinterpret_cast< unsigned char* >( data );
719 : 4 : const Tag* tag = reinterpret_cast< const Tag* >( handle );
720 [ + - ]: 4 : if( tag->vtxReadPtr )
721 : : {
722 [ + + ]: 8 : for( size_t i = 0; i < count; ++i )
723 : : {
724 : 4 : size_t idx = reinterpret_cast< size_t >( entities[i] ) - oneBasedArrays;
725 : 4 : memcpy( ptr + i * tag->size, tag->vtxReadPtr + idx * tag->size, tag->size );
726 : : }
727 : : }
728 [ # # ]: 0 : else if( tag->defaultValue )
729 : : {
730 : 0 : fill( ptr, tag->defaultValue, tag->size, count );
731 : : }
732 : : else
733 : : {
734 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::TAG_NOT_FOUND );
735 : : }
736 : 4 : }
737 : :
738 [ + - ][ + - ]: 4 : } // namespace MBMesquite
|