From e47149e7845c3d740ce32f2740efa97355869828 Mon Sep 17 00:00:00 2001 From: Yen Date: Thu, 24 Dec 2015 16:09:16 +0800 Subject: [PATCH 01/53] delete deprecated library --- src/scanner/PoissonRecon/Makefile | 70 - src/scanner/PoissonRecon/Src/Allocator.h | 163 - src/scanner/PoissonRecon/Src/Array.h | 108 - src/scanner/PoissonRecon/Src/Array.inl | 658 ---- src/scanner/PoissonRecon/Src/BSplineData.h | 191 -- src/scanner/PoissonRecon/Src/BSplineData.inl | 733 ----- src/scanner/PoissonRecon/Src/BinaryNode.h | 78 - src/scanner/PoissonRecon/Src/CMakeLists.txt | 20 - .../PoissonRecon/Src/CmdLineParser.cpp | 279 -- src/scanner/PoissonRecon/Src/CmdLineParser.h | 120 - .../PoissonRecon/Src/CmdLineParser.inl | 141 - src/scanner/PoissonRecon/Src/Factor.cpp | 264 -- src/scanner/PoissonRecon/Src/Factor.h | 50 - src/scanner/PoissonRecon/Src/FunctionData.h | 109 - src/scanner/PoissonRecon/Src/FunctionData.inl | 415 --- src/scanner/PoissonRecon/Src/Geometry.cpp | 124 - src/scanner/PoissonRecon/Src/Geometry.h | 385 --- src/scanner/PoissonRecon/Src/Geometry.inl | 623 ---- src/scanner/PoissonRecon/Src/Hash.h | 29 - src/scanner/PoissonRecon/Src/MAT.h | 48 - src/scanner/PoissonRecon/Src/MAT.inl | 213 -- .../PoissonRecon/Src/MarchingCubes.cpp | 1029 ------- src/scanner/PoissonRecon/Src/MarchingCubes.h | 147 - src/scanner/PoissonRecon/Src/MemoryUsage.h | 200 -- .../Src/MultiGridOctreeData.IsoSurface.inl | 1121 ------- .../MultiGridOctreeData.SortedTreeNodes.inl | 348 --- .../PoissonRecon/Src/MultiGridOctreeData.h | 451 --- .../PoissonRecon/Src/MultiGridOctreeData.inl | 2645 ---------------- src/scanner/PoissonRecon/Src/MyTime.h | 51 - src/scanner/PoissonRecon/Src/Octree.h | 292 -- src/scanner/PoissonRecon/Src/Octree.inl | 2349 -------------- src/scanner/PoissonRecon/Src/PPolynomial.h | 113 - src/scanner/PoissonRecon/Src/PPolynomial.inl | 431 --- src/scanner/PoissonRecon/Src/Ply.h | 678 ---- src/scanner/PoissonRecon/Src/PlyFile.cpp | 2727 ----------------- src/scanner/PoissonRecon/Src/PointStream.h | 125 - src/scanner/PoissonRecon/Src/PointStream.inl | 271 -- src/scanner/PoissonRecon/Src/PoissonRecon.cpp | 481 --- src/scanner/PoissonRecon/Src/Polynomial.h | 93 - src/scanner/PoissonRecon/Src/Polynomial.inl | 332 -- src/scanner/PoissonRecon/Src/SparseMatrix.h | 210 -- src/scanner/PoissonRecon/Src/SparseMatrix.inl | 1343 -------- .../PoissonRecon/Src/SurfaceTrimmer.cpp | 428 --- src/scanner/PoissonRecon/Src/Time.cpp | 46 - src/scanner/PoissonRecon/Src/Time.h | 32 - src/scanner/PoissonRecon/Src/Vector.h | 111 - src/scanner/PoissonRecon/Src/Vector.inl | 304 -- 47 files changed, 21179 deletions(-) delete mode 100755 src/scanner/PoissonRecon/Makefile delete mode 100755 src/scanner/PoissonRecon/Src/Allocator.h delete mode 100755 src/scanner/PoissonRecon/Src/Array.h delete mode 100755 src/scanner/PoissonRecon/Src/Array.inl delete mode 100755 src/scanner/PoissonRecon/Src/BSplineData.h delete mode 100755 src/scanner/PoissonRecon/Src/BSplineData.inl delete mode 100755 src/scanner/PoissonRecon/Src/BinaryNode.h delete mode 100644 src/scanner/PoissonRecon/Src/CMakeLists.txt delete mode 100755 src/scanner/PoissonRecon/Src/CmdLineParser.cpp delete mode 100755 src/scanner/PoissonRecon/Src/CmdLineParser.h delete mode 100755 src/scanner/PoissonRecon/Src/CmdLineParser.inl delete mode 100755 src/scanner/PoissonRecon/Src/Factor.cpp delete mode 100755 src/scanner/PoissonRecon/Src/Factor.h delete mode 100755 src/scanner/PoissonRecon/Src/FunctionData.h delete mode 100755 src/scanner/PoissonRecon/Src/FunctionData.inl delete mode 100755 src/scanner/PoissonRecon/Src/Geometry.cpp delete mode 100755 src/scanner/PoissonRecon/Src/Geometry.h delete mode 100755 src/scanner/PoissonRecon/Src/Geometry.inl delete mode 100755 src/scanner/PoissonRecon/Src/Hash.h delete mode 100755 src/scanner/PoissonRecon/Src/MAT.h delete mode 100755 src/scanner/PoissonRecon/Src/MAT.inl delete mode 100755 src/scanner/PoissonRecon/Src/MarchingCubes.cpp delete mode 100755 src/scanner/PoissonRecon/Src/MarchingCubes.h delete mode 100755 src/scanner/PoissonRecon/Src/MemoryUsage.h delete mode 100755 src/scanner/PoissonRecon/Src/MultiGridOctreeData.IsoSurface.inl delete mode 100755 src/scanner/PoissonRecon/Src/MultiGridOctreeData.SortedTreeNodes.inl delete mode 100755 src/scanner/PoissonRecon/Src/MultiGridOctreeData.h delete mode 100755 src/scanner/PoissonRecon/Src/MultiGridOctreeData.inl delete mode 100755 src/scanner/PoissonRecon/Src/MyTime.h delete mode 100755 src/scanner/PoissonRecon/Src/Octree.h delete mode 100755 src/scanner/PoissonRecon/Src/Octree.inl delete mode 100755 src/scanner/PoissonRecon/Src/PPolynomial.h delete mode 100755 src/scanner/PoissonRecon/Src/PPolynomial.inl delete mode 100755 src/scanner/PoissonRecon/Src/Ply.h delete mode 100755 src/scanner/PoissonRecon/Src/PlyFile.cpp delete mode 100755 src/scanner/PoissonRecon/Src/PointStream.h delete mode 100755 src/scanner/PoissonRecon/Src/PointStream.inl delete mode 100755 src/scanner/PoissonRecon/Src/PoissonRecon.cpp delete mode 100755 src/scanner/PoissonRecon/Src/Polynomial.h delete mode 100755 src/scanner/PoissonRecon/Src/Polynomial.inl delete mode 100755 src/scanner/PoissonRecon/Src/SparseMatrix.h delete mode 100755 src/scanner/PoissonRecon/Src/SparseMatrix.inl delete mode 100755 src/scanner/PoissonRecon/Src/SurfaceTrimmer.cpp delete mode 100755 src/scanner/PoissonRecon/Src/Time.cpp delete mode 100755 src/scanner/PoissonRecon/Src/Time.h delete mode 100755 src/scanner/PoissonRecon/Src/Vector.h delete mode 100755 src/scanner/PoissonRecon/Src/Vector.inl diff --git a/src/scanner/PoissonRecon/Makefile b/src/scanner/PoissonRecon/Makefile deleted file mode 100755 index c64a158..0000000 --- a/src/scanner/PoissonRecon/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# /******************************************************************************************** -# * File: Makefile -# * Author: $LastChangedBy: matthew $ -# * Revision: $Revision: 233 $ -# * Last Updated: $LastChangedDate: 2006-11-10 15:03:28 -0500 (Fri, 10 Nov 2006) $ -# * Version: 6.13 -# ********************************************************************************************/ - -PR_TARGET=PoissonRecon -ST_TARGET=SurfaceTrimmer -PR_SOURCE=CmdLineParser.cpp Factor.cpp Geometry.cpp MarchingCubes.cpp PlyFile.cpp PoissonRecon.cpp -ST_SOURCE=CmdLineParser.cpp Factor.cpp Geometry.cpp MarchingCubes.cpp PlyFile.cpp SurfaceTrimmer.cpp - -# CFLAGS += -fopenmp -Wno-deprecated -CFLAGS += -Wno-deprecated -# LFLAGS += -lgomp - -CFLAGS_DEBUG = -DDEBUG -g3 -LFLAGS_DEBUG = - -CFLAGS_RELEASE = -O3 -DRELEASE -funroll-loops -ffast-math -LFLAGS_RELEASE = -O3 - -SRC = Src/ -BIN = Bin/Linux/ -INCLUDE = /usr/include/ - -CC=gcc -CXX=g++ -MD=mkdir - -PR_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PR_SOURCE)))) -ST_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(ST_SOURCE)))) - - -all: CFLAGS += $(CFLAGS_DEBUG) -all: LFLAGS += $(LFLAGS_DEBUG) -all: $(BIN) -all: $(BIN)$(PR_TARGET) -all: $(BIN)$(ST_TARGET) - -release: CFLAGS += $(CFLAGS_RELEASE) -release: LFLAGS += $(LFLAGS_RELEASE) -release: $(BIN) -release: $(BIN)$(PR_TARGET) -release: $(BIN)$(ST_TARGET) - -clean: - rm -f $(BIN)$(PR_TARGET) - rm -f $(BIN)$(ST_TARGET) - rm -f $(PR_OBJECTS) - rm -f $(ST_OBJECTS) - -$(BIN): - $(MD) -p $(BIN) - -$(BIN)$(PR_TARGET): $(PR_OBJECTS) - $(CXX) -o $@ $(PR_OBJECTS) $(LFLAGS) - -$(BIN)$(ST_TARGET): $(ST_OBJECTS) - $(CXX) -o $@ $(ST_OBJECTS) $(LFLAGS) - -$(BIN)%.o: $(SRC)%.c - mkdir -p $(BIN) - $(CC) -c -o $@ $(CFLAGS) -I$(INCLUDE) $< - -$(BIN)%.o: $(SRC)%.cpp - mkdir -p $(BIN) - $(CXX) -c -o $@ $(CFLAGS) -I$(INCLUDE) $< - diff --git a/src/scanner/PoissonRecon/Src/Allocator.h b/src/scanner/PoissonRecon/Src/Allocator.h deleted file mode 100755 index 3df4a86..0000000 --- a/src/scanner/PoissonRecon/Src/Allocator.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef ALLOCATOR_INCLUDED -#define ALLOCATOR_INCLUDED -#include - -class AllocatorState{ -public: - int index,remains; -}; -/** This templated class assists in memory allocation and is well suited for instances - * when it is known that the sequence of memory allocations is performed in a stack-based - * manner, so that memory allocated last is released first. It also preallocates memory - * in chunks so that multiple requests for small chunks of memory do not require separate - * system calls to the memory manager. - * The allocator is templated off of the class of objects that we would like it to allocate, - * ensuring that appropriate constructors and destructors are called as necessary. - */ -template -class Allocator -{ - int blockSize; - int index , remains; - std::vector< T* > memory; -public: - Allocator( void ){ blockSize = index = remains = 0; } - ~Allocator( void ){ reset(); } - - /** This method is the allocators destructor. It frees up any of the memory that - * it has allocated. */ - void reset( void ) - { - for(size_t i=0;iblockSize = blockSize; - index=-1; - remains=0; - } - - /** This method returns a pointer to an array of elements objects. If there is left over pre-allocated - * memory, this method simply returns a pointer to the next free piece of memory, otherwise it pre-allocates - * more memory. Note that if the number of objects requested is larger than the value blockSize with which - * the allocator was initialized, the request for memory will fail. - */ - T* newElements( int elements=1 ) - { - T* mem; - if( !elements ) return NULL; - if( elements>blockSize ) fprintf( stderr , "[ERROR] Allocator: elements bigger than block-size: %d>%d\n" , elements , blockSize ) , exit( 0 ); - if( remains - -#define ARRAY_DEBUG 0 -#ifdef _WIN64 -#define ASSERT( x ) { if( !( x ) ) __debugbreak(); } -#else // !_WIN64 -#ifdef _WIN32 -#define ASSERT( x ) { if( !( x ) ) _asm{ int 0x03 } } -#else // !_WIN32 -#define ASSERT( x ) { if( !( x ) ) exit(0); } -#endif // _WIN32 -#endif // _WIN64 - -// Code from http://stackoverflow.com -void* aligned_malloc( size_t size , size_t align ) -{ - // Align enough for the data, the alignment padding, and room to store a pointer to the actual start of the memory - void* mem = malloc( size + align + sizeof( void* ) ); - // The position at which we could potentially start addressing - char* amem = ( (char*)mem ) + sizeof( void* ); - // Add align-1 to the start of the address and then zero out at most of the first align-1 bits. - amem = ( char* )( ( (size_t)( ( (char*)amem ) + (align-1) ) ) & ~( align-1 ) ); - // Pre-write the actual address - ( ( void** ) amem )[-1] = mem; - return amem; -} -void aligned_free_avoid_pcl( void* mem ) { free( ( ( void** )mem )[-1] ); } -// void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } -//avoiding pcl name collision - -#if ARRAY_DEBUG -#pragma message ( "[WARNING] Array debugging is enabled" ) -#include "Array.inl" -#define Pointer( ... ) Array< __VA_ARGS__ > -#define ConstPointer( ... ) ConstArray< __VA_ARGS__ > -template< class C > void FreePointer( Array< C >& a ){ a.Free( ); } -template< class C > void AlignedFreePointer( Array< C >& a ){ a.Free( ); } -template< class C > void VFreePointer( Array< C >& a ){ a.Free( ); } -template< class C > void DeletePointer( Array< C >& a ){ a.Delete( ); } - -template< class C > Array< C > NewPointer( size_t size , const char* name=NULL ){ return Array< C >::New ( size , name ); } -template< class C > Array< C > AllocPointer( size_t size , const char* name=NULL ){ return Array< C >::Alloc ( size , false , name ); } -template< class C > Array< C > AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ return Array< C >::AlignedAlloc( size , alignment , false , name ); } -template< class C > Array< C > ReAllocPointer( Array< C >& a , size_t size , const char* name=NULL ){ return Array< C >::ReAlloc ( a , size , false , name ); } - -template< class C > Array< C > NullPointer( void ){ return Array< C >( ); } - -template< class C > C* PointerAddress( Array< C >& a ) { return a.pointer(); } -template< class C > const C* PointerAddress( ConstArray< C >& a ) { return a.pointer(); } -template< class C > Array< C > GetPointer( C& c ) { return Array< C >::FromPointer( &c , 1 ); } -template< class C > ConstArray< C > GetPointer( const C& c ) { return ConstArray< C >::FromPointer( &c , 1 ); } -template< class C > Array< C > GetPointer( std::vector< C >& v ){ return Array< C >::FromPointer( &v[0] , v.size() ); } -template< class C > ConstArray< C > GetPointer( const std::vector< C >& v ){ return ConstArray< C >::FromPointer( &v[0] , v.size() ); } - -#else // !ARRAY_DEBUG -#define Pointer( ... ) __VA_ARGS__* -#define ConstPointer( ... ) const __VA_ARGS__* - -#define FreePointer( ... ) { if( __VA_ARGS__ ) free( __VA_ARGS__ ) , __VA_ARGS__ = NULL; } -#define AlignedFreePointer( ... ) { if( __VA_ARGS__ ) aligned_free_avoid_pcl( __VA_ARGS__ ) , __VA_ARGS__ = NULL; } -#define DeletePointer( ... ) { if( __VA_ARGS__ ) delete[] __VA_ARGS__ , __VA_ARGS__ = NULL; } - -template< class C > C* NewPointer( size_t size , const char* name=NULL ){ return new C[size]; } -template< class C > C* AllocPointer( size_t size , const char* name=NULL ){ return (C*) malloc( sizeof(C) * size ); } -template< class C > C* AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ return (C*)aligned_malloc( sizeof(C) * size , alignment ); } -template< class C > C* ReAllocPointer( C* c , size_t size , const char* name=NULL ){ return (C*) realloc( c , sizeof(C) * size ); } - -template< class C > C* NullPointer( void ){ return NULL; } - -template< class C > C* PointerAddress( C* c ){ return c; } -template< class C > const C* PointerAddress( const C* c ){ return c; } -template< class C > C* GetPointer( C& c ){ return &c; } -template< class C > const C* GetPointer( const C& c ){ return &c; } -template< class C > C* GetPointer( std::vector< C >& v ){ return &v[0]; } -template< class C > const C* GetPointer( const std::vector< C >& v ){ return &v[0]; } -#endif // ARRAY_DEBUG -#endif // ARRAY_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/Array.inl b/src/scanner/PoissonRecon/Src/Array.inl deleted file mode 100755 index fc16659..0000000 --- a/src/scanner/PoissonRecon/Src/Array.inl +++ /dev/null @@ -1,658 +0,0 @@ -/* -Copyright (c) 2011, Michael Kazhdan and Ming Chuang -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#define FULL_ARRAY_DEBUG 0 // Note that this is not thread-safe - -#include -#include -#include -#ifdef _WIN32 -#include -#endif // _WIN32 -#include - -inline bool isfinitef( float fp ){ float f=fp; return ((*(unsigned *)&f)&0x7f800000)!=0x7f800000; } - - -template< class C > bool IsValid( const C& c ); -#if _DEBUG -template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ) && ( f==0.f || abs(f)>1e-31f ); } -#else // !_DEBUG -template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ); } -#endif // _DEBUG -template< > inline bool IsValid< __m128 >( const __m128& m ) -{ - const __m128* addr = &m; - if( size_t(addr) & 15 ) return false; - else return true; -} -template< class C > inline bool IsValid( const C& c ){ return true; } - - -#if FULL_ARRAY_DEBUG -class DebugMemoryInfo -{ -public: - const void* address; - char name[512]; -}; -static std::vector< DebugMemoryInfo > memoryInfo; -#endif // FULL_ARRAY_DEBUG - -template< class C > -class Array -{ - void _assertBounds( long long idx ) const - { - if( idx=max ) - { - fprintf( stderr , "Array index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); - ASSERT( 0 ); - exit( 0 ); - } - } -protected: - C *data , *_data; - long long min , max; -#if FULL_ARRAY_DEBUG - static void _AddMemoryInfo( const void* ptr , const char* name ) - { - size_t sz = memoryInfo.size(); - memoryInfo.resize( sz + 1 ); - memoryInfo[sz].address = ptr; - if( name ) strcpy( memoryInfo[sz].name , name ); - else memoryInfo[sz].name[0] = 0; - } - static void _RemoveMemoryInfo( const void* ptr ) - { - { - size_t idx; - for( idx=0 ; idx - Array( Array< D >& a ) - { - _data = NULL; - if( !a ) - { - data = NULL; - min = max = 0; - } - else - { - // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. - long long szC = sizeof( C ); - long long szD = sizeof( D ); - data = (C*)&a[0]; - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { - fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - } - static Array FromPointer( C* data , long long max ) - { - Array a; - a._data = NULL; - a.data = data; - a.min = 0; - a.max = max; - return a; - } - static Array FromPointer( C* data , long long min , long long max ) - { - Array a; - a._data = NULL; - a.data = data; - a.min = min; - a.max = max; - return a; - } - inline bool operator == ( const Array< C >& a ) const { return data==a.data; } - inline bool operator != ( const Array< C >& a ) const { return data!=a.data; } - inline bool operator == ( const C* c ) const { return data==c; } - inline bool operator != ( const C* c ) const { return data!=c; } - inline C* operator -> ( void ) - { - _assertBounds( 0 ); - return data; - } - inline const C* operator -> ( ) const - { - _assertBounds( 0 ); - return data; - } - inline C& operator[]( long long idx ) - { - _assertBounds( idx ); - return data[idx]; - } - inline const C& operator[]( long long idx ) const - { - _assertBounds( idx ); - return data[idx]; - } - inline Array operator + ( int idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( long long idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( unsigned int idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( unsigned long long idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array& operator += ( int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( unsigned int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( unsigned long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator ++ ( void ) { return (*this) += 1; } - Array operator - ( int idx ) const { return (*this) + (-idx); } - Array operator - ( long long idx ) const { return (*this) + (-idx); } - Array operator - ( unsigned int idx ) const { return (*this) + (-idx); } - Array operator - ( unsigned long long idx ) const { return (*this) + (-idx); } - Array& operator -= ( int idx ) { return (*this) += (-idx); } - Array& operator -= ( long long idx ) { return (*this) += (-idx); } - Array& operator -= ( unsigned int idx ) { return (*this) += (-idx); } - Array& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } - Array& operator -- ( void ) { return (*this) -= 1; } - long long operator - ( const Array& a ) const { return ( long long )( data - a.data ); } - - void Free( void ) - { - if( _data ) - { - free( _data ); -#if FULL_ARRAY_DEBUG - _RemoveMemoryInfo( _data ); -#endif // FULL_ARRAY_DEBUG - } - (*this) = Array( ); - } - void Delete( void ) - { - if( _data ) - { - delete[] _data; -#if FULL_ARRAY_DEBUG - _RemoveMemoryInfo( _data ); -#endif // FULL_ARRAY_DEBUG - } - (*this) = Array( ); - } - C* pointer( void ){ return data; } - const C* pointer( void ) const { return data; } - bool operator !( void ) const { return data==NULL; } - operator bool( ) const { return data!=NULL; } -}; - -template< class C > -class ConstArray -{ - void _assertBounds( long long idx ) const - { - if( idx=max ) - { - fprintf( stderr , "ConstArray index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); - ASSERT( 0 ); - exit( 0 ); - } - } -protected: - const C *data; - long long min , max; -public: - long long minimum( void ) const { return min; } - long long maximum( void ) const { return max; } - - inline ConstArray( void ) - { - data = NULL; - min = max = 0; - } - inline ConstArray( const Array< C >& a ) - { - // [WARNING] Changing szC and szD to size_t causes some really strange behavior. - data = ( const C* )a.pointer( ); - min = a.minimum(); - max = a.maximum(); - } - template< class D > - inline ConstArray( const Array< D >& a ) - { - // [WARNING] Changing szC and szD to size_t causes some really strange behavior. - long long szC = ( long long ) sizeof( C ); - long long szD = ( long long ) sizeof( D ); - data = ( const C* )a.pointer( ); - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { -// fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n %lld %lld %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC , a.minimum() , a.minimum()*szD , (a.minimum()*szD)/szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - template< class D > - inline ConstArray( const ConstArray< D >& a ) - { - // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. - long long szC = sizeof( C ); - long long szD = sizeof( D ); - data = ( const C*)a.pointer( ); - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { - fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - static ConstArray FromPointer( const C* data , long long max ) - { - ConstArray a; - a.data = data; - a.min = 0; - a.max = max; - return a; - } - static ConstArray FromPointer( const C* data , long long min , long long max ) - { - ConstArray a; - a.data = data; - a.min = min; - a.max = max; - return a; - } - - inline bool operator == ( const ConstArray< C >& a ) const { return data==a.data; } - inline bool operator != ( const ConstArray< C >& a ) const { return data!=a.data; } - inline bool operator == ( const C* c ) const { return data==c; } - inline bool operator != ( const C* c ) const { return data!=c; } - inline const C* operator -> ( void ) - { - _assertBounds( 0 ); - return data; - } - inline const C& operator[]( long long idx ) const - { - _assertBounds( idx ); - return data[idx]; - } - inline ConstArray operator + ( int idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( long long idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( unsigned int idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( unsigned long long idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray& operator += ( int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( unsigned int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( unsigned long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator ++ ( void ) { return (*this) += 1; } - ConstArray operator - ( int idx ) const { return (*this) + (-idx); } - ConstArray operator - ( long long idx ) const { return (*this) + (-idx); } - ConstArray operator - ( unsigned int idx ) const { return (*this) + (-idx); } - ConstArray operator - ( unsigned long long idx ) const { return (*this) + (-idx); } - ConstArray& operator -= ( int idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( long long idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( unsigned int idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } - ConstArray& operator -- ( void ) { return (*this) -= 1; } - long long operator - ( const ConstArray& a ) const { return ( long long )( data - a.data ); } - long long operator - ( const Array< C >& a ) const { return ( long long )( data - a.pointer() ); } - - const C* pointer( void ) const { return data; } - bool operator !( void ) { return data==NULL; } - operator bool( ) { return data!=NULL; } -}; - -#if FULL_ARRAY_DEBUG -inline void PrintMemoryInfo( void ){ for( size_t i=0 ; i -Array< C > memcpy( Array< C > destination , const void* source , size_t size ) -{ - if( size>destination.maximum()*sizeof(C) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , source , size ); - return destination; -} -template< class C , class D > -Array< C > memcpy( Array< C > destination , Array< D > source , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , &source[0] , size ); - return destination; -} -template< class C , class D > -Array< C > memcpy( Array< C > destination , ConstArray< D > source , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , &source[0] , size ); - return destination; -} -template< class D > -void* memcpy( void* destination , Array< D > source , size_t size ) -{ - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( destination , &source[0] , size ); - return destination; -} -template< class D > -void* memcpy( void* destination , ConstArray< D > source , size_t size ) -{ - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( destination , &source[0] , size ); - return destination; -} -template< class C > -Array< C > memset( Array< C > destination , int value , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of set exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memset( &destination[0] , value , size ); - return destination; -} - -template< class C > -size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of read exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fread( &destination[0] , eSize , count , fp ); -} -template< class C > -size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>source.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fwrite( &source[0] , eSize , count , fp ); -} -template< class C > -size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>source.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fwrite( &source[0] , eSize , count , fp ); -} -template< class C > -void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) -{ - if( sizeof(C)!=elementSize ) - { - fprintf( stderr , "Element sizes differ: %lld != %lld\n" , ( long long )( sizeof(C) ) , ( long long )( elementSize ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( base.minimum()>0 || base.maximum() -struct BSplineElementCoefficients -{ - int coeffs[Degree+1]; - BSplineElementCoefficients( void ){ memset( coeffs , 0 , sizeof( int ) * ( Degree+1 ) ); } - int& operator[]( int idx ){ return coeffs[idx]; } - const int& operator[]( int idx ) const { return coeffs[idx]; } -}; -template< int Degree > -struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree > > -{ - static const int _off = (Degree+1)/2; - void _addLeft ( int offset , int boundary ); - void _addRight( int offset , int boundary ); -public: - enum - { - NONE = 0, - DIRICHLET = -1, - NEUMANN = 1 - }; - // Coefficients are ordered as "/" "-" "\" - int denominator; - - BSplineElements( void ) { denominator = 1; } - BSplineElements( int res , int offset , int boundary=NONE , int inset=0 ); - - void upSample( BSplineElements& high ) const; - void differentiate( BSplineElements< Degree-1 >& d ) const; - - void print( FILE* fp=stdout ) const - { - for( int i=0 ; i >::size() ; i++ ) - { - printf( "%d]" , i ); - for( int j=0 ; j<=Degree ; j++ ) printf( " %d" , (*this)[i][j] ); - printf( " (%d)\n" , denominator ); - } - } -}; - -template< int Degree > -class BSplineData -{ - int _boundaryType; - double _vvIntegrals[Degree+1][Degree+1]; - double _vdIntegrals[Degree+1][Degree ]; - double _dvIntegrals[Degree ][Degree+1]; - double _ddIntegrals[Degree ][Degree ]; - -public: - struct Integrator - { - struct IntegralTables - { - double vv_ccIntegrals[2*Degree+1][2*Degree+1] , vv_cpIntegrals[(2*Degree+1)*2][2*Degree+1]; - double dv_ccIntegrals[2*Degree+1][2*Degree+1] , dv_cpIntegrals[(2*Degree+1)*2][2*Degree+1]; - double vd_ccIntegrals[2*Degree+1][2*Degree+1] , vd_cpIntegrals[(2*Degree+1)*2][2*Degree+1]; - double dd_ccIntegrals[2*Degree+1][2*Degree+1] , dd_cpIntegrals[(2*Degree+1)*2][2*Degree+1]; - }; - std::vector< IntegralTables > iTables; - double dot( int depth , int off1 , int off2 , bool d1 , bool d2 , bool childParent=false ) const; - }; - double dot( int depth1 , int off1 , int depth2 , int off2 , bool d1 , bool d2 , bool inset=false ) const; - void setIntegrator( Integrator& integrator , bool inset , bool useDotRatios=false ) const; - template< int Radius > - struct CenterEvaluator - { - struct ValueTables - { - double vValues[2*Degree+1][ 3*(2*Radius+1) ]; - double dValues[2*Degree+1][ 3*(2*Radius+1) ]; - }; - std::vector< ValueTables > vTables; - double value( int depth , int off1 , int off2 , bool d , bool childParent=false ) const; - }; - template< int Radius > - void setCenterEvaluator( CenterEvaluator< Radius >& evaluator , double smoothingRadius , double dSmoothingRadius, bool inset ) const; - double value( int depth , int off , double smoothingRadius , double s , bool d , bool inset=false ) const; - template< int Radius > - struct CornerEvaluator - { - struct ValueTables - { - double vValues[2*Degree+1][4*Radius+3]; - double dValues[2*Degree+1][4*Radius+3]; - }; - std::vector< ValueTables > vTables; - double value( int depth , int off1 , int c1 , int off2 , bool d , bool childParent=false ) const; - }; - template< int Radius > - void setCornerEvaluator( CornerEvaluator< Radius >& evaluator , double smoothingRadius , double dSmoothingRadius, bool inset ) const; - - struct BSplineComponents - { - Polynomial< Degree > polys[Degree+1]; - Polynomial< Degree >& operator[] ( int idx ) { return polys[idx]; } - const Polynomial< Degree >& operator[] ( int idx ) const { return polys[idx]; } - void printnl( void ) const { for( int d=0 ; d<=Degree ; d++ ) polys[d].printnl(); } - BSplineComponents scale( double s ) const { BSplineComponents b ; for( int d=0 ; d<=Degree ; d++ ) b[d] = polys[d].scale(s) ; return b; } - BSplineComponents shift( double s ) const { BSplineComponents b ; for( int d=0 ; d<=Degree ; d++ ) b[d] = polys[d].shift(s) ; return b; } - }; - - int depth; - size_t functionCount , sampleCount; - PPolynomial< Degree > baseFunction , leftBaseFunction , rightBaseFunction , leftRightBaseFunction; - PPolynomial< Degree-1 > dBaseFunction , dLeftBaseFunction , dRightBaseFunction , dLeftRightBaseFunction; - BSplineComponents baseBSpline , leftBSpline , rightBSpline , leftRightBSpline; - Pointer( PPolynomial< Degree > ) baseFunctions; - Pointer( BSplineComponents ) baseBSplines; - - BSplineData( void ); - - const static int VV_DOT_FLAG = 1; - const static int DV_DOT_FLAG = 2; - const static int DD_DOT_FLAG = 4; - const static int VALUE_FLAG = 1; - const static int D_VALUE_FLAG = 2; - template< class Real > - struct DotTables - { - size_t functionCount; - Pointer( Real ) vvDotTable; - Pointer( Real ) dvDotTable; - Pointer( Real ) ddDotTable; - - DotTables( void ); - ~DotTables( void ); - - inline size_t Index( int i1 , int i2 ) const; - static inline size_t SymmetricIndex( int i1 , int i2 ); - static inline int SymmetricIndex( int i1 , int i2 , size_t& index ); - }; - template< class Real > - struct ValueTables - { - size_t functionCount , sampleCount; - Pointer( Real ) valueTable; - Pointer( Real ) dValueTable; - - ValueTables( void ); - ~ValueTables( void ); - - inline size_t Index( int i1 , int i2 ) const; - void setSampleSpan( int idx , int& start , int& end , double smooth=0 ) const; - }; - void set( int maxDepth , int boundaryType=BSplineElements< Degree >::NONE ); - template< class Real > - typename BSplineData< Degree >::template DotTables< Real > getDotTables( int flags , bool useDotRatios=true , bool inset=false ) const; - template< class Real > - typename BSplineData< Degree >::template ValueTables< Real > getValueTables( int flags , double valueSmooth=0 , double normalSmooth=0 ) const; -}; - -template< int Degree1 , int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); - -#include "BSplineData.inl" -#endif // BSPLINE_DATA_INCLUDED \ No newline at end of file diff --git a/src/scanner/PoissonRecon/Src/BSplineData.inl b/src/scanner/PoissonRecon/Src/BSplineData.inl deleted file mode 100755 index 655e976..0000000 --- a/src/scanner/PoissonRecon/Src/BSplineData.inl +++ /dev/null @@ -1,733 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -///////////////// -// BSplineData // -///////////////// -// Support[i]: -// Odd: i +/- 0.5 * ( 1 + Degree ) -// i - 0.5 * ( 1 + Degree ) < 0 -// <=> i < 0.5 * ( 1 + Degree ) -// i + 0.5 * ( 1 + Degree ) > 0 -// <=> i > - 0.5 * ( 1 + Degree ) -// i + 0.5 * ( 1 + Degree ) > r -// <=> i > r - 0.5 * ( 1 + Degree ) -// i - 0.5 * ( 1 + Degree ) < r -// <=> i < r + 0.5 * ( 1 + Degree ) -// Even: i + 0.5 +/- 0.5 * ( 1 + Degree ) -// i - 0.5 * Degree < 0 -// <=> i < 0.5 * Degree -// i + 1 + 0.5 * Degree > 0 -// <=> i > -1 - 0.5 * Degree -// i + 1 + 0.5 * Degree > r -// <=> i > r - 1 - 0.5 * Degree -// i - 0.5 * Degree < r -// <=> i < r + 0.5 * Degree -template< int Degree > inline bool LeftOverlap( unsigned int depth , int offset ) -{ - offset <<= 1; - if( Degree & 1 ) return (offset < 1+Degree) && (offset > -1-Degree ); - else return (offset < Degree) && (offset > -2-Degree ); -} -template< int Degree > inline bool RightOverlap( unsigned int depth , int offset ) -{ - offset <<= 1; - int r = 1<<(depth+1); - if( Degree & 1 ) return (offset > 2-1-Degree) && (offset < 2+1+Degree ); - else return (offset > 2-2-Degree) && (offset < 2+ Degree ); -} -template< int Degree > inline int ReflectLeft( unsigned int depth , int offset ) -{ - if( Degree&1 ) return -offset; - else return -1-offset; -} -template< int Degree > inline int ReflectRight( unsigned int depth , int offset ) -{ - int r = 1<<(depth+1); - if( Degree&1 ) return r -offset; - else return r-1-offset; -} - -template< int Degree > -BSplineData< Degree >::BSplineData( void ) -{ - functionCount = sampleCount = 0; - SetBSplineElementIntegrals< Degree , Degree >( _vvIntegrals ); - SetBSplineElementIntegrals< Degree , Degree-1 >( _vdIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree >( _dvIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree-1 >( _ddIntegrals ); -} - -template< int Degree > -double BSplineData< Degree >::Integrator::dot( int depth , int off1 , int off2 , bool d1 , bool d2 , bool childParent ) const -{ - if( depth<0 || depth>=int( iTables.size() ) ) return 0.; - const typename Integrator::IntegralTables& iTable = iTables[depth]; - if( childParent ) - { - int c = off1&1; - off1 >>= 1 , depth--; - int ii , d = off2-off1 , res = (1<=res || off2>=res || d<-Degree || d>Degree ) return 0; - if ( off1< Degree ) ii = off1; - else if( off1>=res-Degree ) ii = 2*Degree + off1 - (res-1); - else ii = Degree; - if ( d1 && d2 ) return iTable.dd_cpIntegrals[2*ii+c][d+Degree]; - else if( d1 ) return iTable.dv_cpIntegrals[2*ii+c][d+Degree]; - else if( d2 ) return iTable.vd_cpIntegrals[2*ii+c][d+Degree]; - else return iTable.vv_cpIntegrals[2*ii+c][d+Degree]; - } - else - { - int ii , d = off2-off1 , res = (1<=res || off2>=res || d<-Degree || d>Degree ) return 0; - if ( off1< Degree ) ii = off1; - else if( off1>=res-Degree ) ii = 2*Degree + off1 - (res-1); - else ii = Degree; - if ( d1 && d2 ) return iTable.dd_ccIntegrals[ii][d+Degree]; - else if( d1 ) return iTable.dv_ccIntegrals[ii][d+Degree]; - else if( d2 ) return iTable.vd_ccIntegrals[ii][d+Degree]; - else return iTable.vv_ccIntegrals[ii][d+Degree]; - } -} -template< int Degree > -template< int Radius > -double BSplineData< Degree >::CenterEvaluator< Radius >::value( int depth , int off1 , int off2 , bool d , bool childParent ) const -{ - if( depth<0 || depth>=int( vTables.size() ) ) return 0.; - if( childParent ) - { - int c = off1&1; - off1 >>= 1 , depth--; - const typename CenterEvaluator::ValueTables& vTable = vTables[depth]; - int ii , dd = off1-off2 , res = (1<=res || off2>=res || dd<-Radius || dd>Radius ) return 0; - if ( off2< Degree ) ii = off2; - else if( off2>=res-Degree ) ii = 2*Degree + off2 - (res-1); - else ii = Degree; - if( d ) return vTable.dValues[ii][(dd+Radius)*3+2*c]; - else return vTable.vValues[ii][(dd+Radius)*3+2*c]; - } - else - { - const typename CenterEvaluator::ValueTables& vTable = vTables[depth]; - int ii , dd = off1-off2 , res = (1<=res || off2>=res || dd<-Radius || dd>Radius ) return 0; - if ( off2< Degree ) ii = off2; - else if( off2>=res-Degree ) ii = 2*Degree + off2 - (res-1); - else ii = Degree; - if( d ) return vTable.dValues[ii][(dd+Radius)*3+1]; - else return vTable.vValues[ii][(dd+Radius)*3+1]; - } -} -template< int Degree > -template< int Radius > -double BSplineData< Degree >::CornerEvaluator< Radius >::value( int depth , int off1 , int c1 , int off2 , bool d , bool childParent ) const -{ - if( c1<0 || c1>=2 ) - { - fprintf( stderr , "[WARNING] Clamping corner to {0,1}\n" ); - c1 = std::max< int >( 0 , std::min< int >( c1 , 1 ) ); - } - if( depth<0 || depth>=int( vTables.size() ) ) return 0.; - if( childParent ) - { - int c = off1&1; - off1 >>= 1 , depth--; - const typename CornerEvaluator::ValueTables& vTable = vTables[depth]; - int ii , dd = off1-off2 , res = (1<=res || off2>=res || dd<-Radius || dd>Radius ) return 0; - if ( off2< Degree ) ii = off2; - else if( off2>=res-Degree ) ii = 2*Degree + off2 - (res-1); - else ii = Degree; - if( d ) return vTable.dValues[ii][(dd+Radius)*2+c+c1]; - else return vTable.vValues[ii][(dd+Radius)*2+c+c1]; - } - else - { - const typename CornerEvaluator::ValueTables& vTable = vTables[depth]; - int ii , dd = off1-off2 , res = (1<=res || off2>=res || dd<-Radius || dd>Radius ) return 0; - if ( off2< Degree ) ii = off2; - else if( off2>=res-Degree ) ii = 2*Degree + off2 - (res-1); - else ii = Degree; - if( d ) return vTable.dValues[ii][(dd+Radius)*2+2*c1]; - else return vTable.vValues[ii][(dd+Radius)*2+2*c1]; - } -} -template< int Degree > -void BSplineData< Degree >::set( int maxDepth , int boundaryType ) -{ - _boundaryType = boundaryType; - - depth = maxDepth; - // [Warning] This assumes that the functions spacing is dual - functionCount = BinaryNode::CumulativeCenterCount( depth ); - sampleCount = BinaryNode::CenterCount( depth ) + BinaryNode::CornerCount( depth ); - baseFunctions = NewPointer< PPolynomial< Degree > >( functionCount ); - baseBSplines = NewPointer< BSplineComponents >( functionCount ); - - baseFunction = PPolynomial< Degree >::BSpline(); - for( int i=0 ; i<=Degree ; i++ ) baseBSpline[i] = Polynomial< Degree >::BSplineComponent( i ).shift( double(-(Degree+1)/2) + i - 0.5 ); - dBaseFunction = baseFunction.derivative(); - StartingPolynomial< Degree > sPolys[Degree+4]; - - for( int i=0 ; i=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1]; - for( int j=0 ; j=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1].shift( 1 ) * _boundaryType; - for( int j=0 ; j=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1]; // The centered B-Spline - if( i>=2 && i<=Degree+2 ) sPolys[i].p += baseBSpline[i-2].shift( 1 ) * _boundaryType; // The right-shifted B-spline - for( int j=0 ; j -double BSplineData< Degree >::dot( int depth1 , int off1 , int depth2 , int off2 , bool d1 , bool d2 , bool inset ) const -{ - const int _Degree1 = (d1 ? (Degree-1) : Degree) , _Degree2 = (d2 ? (Degree-1) : Degree); - int sums[ Degree+1 ][ Degree+1 ]; - - int depth = std::max< int >( depth1 , depth2 ); - - BSplineElements< Degree > b1( 1< b; - while( depth1 db1 , db2; - b1.differentiate( db1 ) , b2.differentiate( db2 ); - - int start1=-1 , end1=-1 , start2=-1 , end2=-1; - for( int i=0 ; i=end2 || start2>=end1 ) return 0.; - int start = std::max< int >( start1 , start2 ) , end = std::min< int >( end1 , end2 ); - memset( sums , 0 , sizeof( sums ) ); - for( int i=start ; i -double BSplineData< Degree >::value( int depth , int off , double smoothingRadius , double s , bool d , bool inset ) const -{ - PPolynomial< Degree+1 > function; - PPolynomial< Degree > dFunction; - - if( off<0 || off>=(1<0 ) function = baseFunctions[idx].MovingAverage( smoothingRadius ); - else function = baseFunctions[idx]; - dFunction = function.derivative(); - - if( d ) return dFunction(s); - else return function(s); -} -template< int Degree > -void BSplineData< Degree >::setIntegrator( Integrator& integrator , bool inset , bool useDotRatios ) const -{ - integrator.iTables.resize( depth+1 ); - for( int d=0 ; d<=depth ; d++ ) for( int i=0 ; i<=2*Degree ; i++ ) for( int j=-Degree ; j<=Degree ; j++ ) - { - int res = 1< -template< int Radius > -void BSplineData< Degree >::setCenterEvaluator( CenterEvaluator< Radius >& evaluator , double smoothingRadius , double dSmoothingRadius , bool inset ) const -{ - evaluator.vTables.resize( depth+1 ); - for( int d=0 ; d<=depth ; d++ ) for( int i=0 ; i<=2*Degree ; i++ ) for( int j=-Radius ; j<=Radius ; j++ ) for( int k=-1 ; k<=1 ; k++ ) - { - int res = 1< -template< int Radius > -void BSplineData< Degree >::setCornerEvaluator( CornerEvaluator< Radius >& evaluator , double smoothingRadius , double dSmoothingRadius , bool inset ) const -{ - evaluator.vTables.resize( depth+1 ); - for( int d=0 ; d<=depth ; d++ ) for( int i=0 ; i<=2*Degree ; i++ ) for( int j=-Radius ; j<=Radius ; j++ ) for( int k=0 ; k<=2 ; k++ ) - { - int res = 1< -template< class Real > -BSplineData< Degree >::DotTables< Real >::DotTables( void ) -{ - vvDotTable = NullPointer< Real >(); - dvDotTable = NullPointer< Real >(); - ddDotTable = NullPointer< Real >(); -} -template< int Degree > -template< class Real > -BSplineData< Degree >::DotTables< Real >::~DotTables( void ) -{ - DeletePointer( vvDotTable ); - DeletePointer( dvDotTable ); - DeletePointer( ddDotTable ); -} -template< int Degree > -template< class Real > -inline size_t BSplineData< Degree >::DotTables< Real >::Index( int i1 , int i2 ) const { return size_t(i1)*functionCount + size_t(i2); } -template< int Degree > -template< class Real > -inline size_t BSplineData< Degree >::DotTables< Real >::SymmetricIndex( int i1 , int i2 ) -{ - size_t _i1 = i1 , _i2 = i2; - if( i1>i2 ) return ((_i1*_i1+i1)>>1)+_i2; - else return ((_i2*_i2+i2)>>1)+_i1; -} -template< int Degree > -template< class Real > -inline int BSplineData< Degree >::DotTables< Real >::SymmetricIndex( int i1 , int i2 , size_t& index ) -{ - size_t _i1 = i1 , _i2 = i2; - if( i1>1)+_i1; - return 1; - } - else - { - index = ((_i1*_i1+_i1)>>1)+_i2; - return 0; - } -} -template< int Degree > -template< class Real > -typename BSplineData< Degree >::template DotTables< Real > BSplineData< Degree >::getDotTables( int flags , bool useDotRatios , bool inset ) const -{ - typename BSplineData< Degree >::template DotTables< Real > dTables; - dTables.functionCount = functionCount; - - size_t size = ( functionCount*functionCount + functionCount )>>1; - size_t fullSize = functionCount*functionCount; - if( flags & VV_DOT_FLAG ) - { - dTables.vvDotTable = NewPointer< Real >( size ); - memset( dTables.vvDotTable , 0 , sizeof(Real)*size ); - } - if( flags & DV_DOT_FLAG ) - { - dTables.dvDotTable = NewPointer< Real >( fullSize ); - memset( dTables.dvDotTable , 0 , sizeof(Real)*fullSize ); - } - if( flags & DD_DOT_FLAG ) - { - dTables.ddDotTable = NewPointer< Real >( size ); - memset( dTables.ddDotTable , 0 , sizeof(Real)*size ); - } - int vvSums[Degree+1][Degree+1]; - int vdSums[Degree+1][Degree ]; - int dvSums[Degree ][Degree+1]; - int ddSums[Degree ][Degree ]; - double vvIntegrals[Degree+1][Degree+1]; - double vdIntegrals[Degree+1][Degree ]; - double dvIntegrals[Degree ][Degree+1]; - double ddIntegrals[Degree ][Degree ]; - SetBSplineElementIntegrals< Degree , Degree >( vvIntegrals ); - SetBSplineElementIntegrals< Degree , Degree-1 >( vdIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree >( dvIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree-1 >( ddIntegrals ); - - for( int d1=0 ; d1<=depth ; d1++ ) for( int off1=0 ; off1<(1< b1( 1< db1; - b1.differentiate( db1 ); - int start1 , end1; - - start1 = -1 , end1 = -1; - for( int i=0 ; i=end1 || start1>=end2 ) continue; - start2 = std::max< int >( start1 , start2 ); - end2 = std::min< int >( end1 , end2 ); - if( d1==d2 && off2 b2( 1< db2; - b2.differentiate( db2 ); - - size_t idx = DotTables< Real >::SymmetricIndex( ii , jj ); - size_t idx1 = DotTables< Real >::Index( ii , jj ) , idx2 = DotTables< Real >::Index( jj , ii ); - - memset( vvSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree+1 ) ); - memset( vdSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree ) ); - memset( dvSums , 0 , sizeof( int ) * ( Degree ) * ( Degree+1 ) ); - memset( ddSums , 0 , sizeof( int ) * ( Degree ) * ( Degree ) ); - for( int i=start2 ; i b; - b = b1; - b.upSample( b1 ); - b1.differentiate( db1 ); - start1 = -1; - for( int i=0 ; i -template< class Real > -BSplineData< Degree >::ValueTables< Real >::ValueTables( void ) -{ - valueTable = NullPointer< Real >(); - dValueTable = NullPointer< Real >(); -} -template< int Degree > -template< class Real > -BSplineData< Degree >::ValueTables< Real >::~ValueTables( void ) -{ - DeletePointer( valueTable ); - DeletePointer( dValueTable ); -} -template< int Degree > -template< class Real > -inline size_t BSplineData< Degree >::ValueTables< Real >::Index( int i1 , int i2 ) const { return size_t(i1)*functionCount + size_t(i2); } -template< int Degree > -template< class Real > -typename BSplineData< Degree >::template ValueTables< Real > BSplineData< Degree >::getValueTables( int flags , double valueSmooth , double derivativeSmooth ) const -{ - typename BSplineData< Degree >::template ValueTables< Real > vTables; - vTables.functionCount = functionCount; - vTables.sampleCount = sampleCount; - - if( flags & VALUE_FLAG ) vTables.valueTable = NewPointer< Real >( functionCount*sampleCount ); - if( flags & D_VALUE_FLAG ) vTables.dValueTable = NewPointer< Real >( functionCount*sampleCount ); - PPolynomial< Degree+1 > function; - PPolynomial< Degree > dFunction; - for( size_t i=0 ; i0 ) function=baseFunctions[i].MovingAverage( valueSmooth ); - else function=baseFunctions[i]; - if( derivativeSmooth>0 ) dFunction=baseFunctions[i].derivative().MovingAverage( derivativeSmooth ); - else dFunction=baseFunctions[i].derivative(); - - for( size_t j=0 ; j -template< class Real > -void BSplineData< Degree >::ValueTables< Real >::setSampleSpan( int idx , int& start , int& end , double smooth ) const -{ - int d , off , res; - BinaryNode::DepthAndOffset( idx , d , off ); - res = 1<_start && (start-1)/(sampleCount-1)<=_start - // => start > _start * (sampleCount-1 ) && start <= _start*(sampleCount-1) + 1 - // => _start * (sampleCount-1) + 1 >= start > _start * (sampleCount-1) - start = int( floor( _start * (sampleCount-1) + 1 ) ); - if( start<0 ) start = 0; - // (end)/(sampleCount-1)<_end && (end+1)/(sampleCount-1)>=_end - // => end < _end * (sampleCount-1 ) && end >= _end*(sampleCount-1) - 1 - // => _end * (sampleCount-1) > end >= _end * (sampleCount-1) - 1 - end = int( ceil( _end * (sampleCount-1) - 1 ) ); - if( end>=int(sampleCount) ) end = int(sampleCount)-1; -} - - -///////////////////// -// BSplineElements // -///////////////////// -template< int Degree > -BSplineElements< Degree >::BSplineElements( int res , int offset , int boundary , int inset ) -{ - denominator = 1; - std::vector< BSplineElementCoefficients< Degree > >::resize( res , BSplineElementCoefficients< Degree >() ); - - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx -void BSplineElements< Degree >::_addLeft( int offset , int boundary ) -{ - int res = int( std::vector< BSplineElementCoefficients< Degree > >::size() ); - bool set = false; - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx -void BSplineElements< Degree >::_addRight( int offset , int boundary ) -{ - int res = int( std::vector< BSplineElementCoefficients< Degree > >::size() ); - bool set = false; - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx -void BSplineElements< Degree >::upSample( BSplineElements< Degree >& high ) const -{ - fprintf( stderr , "[ERROR] B-spline up-sampling not supported for degree %d\n" , Degree ); - exit( 0 ); -} -template<> -void BSplineElements< 1 >::upSample( BSplineElements< 1 >& high ) const -{ - high.resize( size()*2 ); - high.assign( high.size() , BSplineElementCoefficients<1>() ); - for( int i=0 ; i -void BSplineElements< 2 >::upSample( BSplineElements< 2 >& high ) const -{ - // /----\ - // / \ - // / \ = 1 /--\ +3 /--\ +3 /--\ +1 /--\ - // / \ / \ / \ / \ / \ - // |----------| |----------| |----------| |----------| |----------| - - high.resize( size()*2 ); - high.assign( high.size() , BSplineElementCoefficients<2>() ); - for( int i=0 ; i -void BSplineElements< Degree >::differentiate( BSplineElements< Degree-1 >& d ) const -{ - d.resize( std::vector< BSplineElementCoefficients< Degree > >::size() ); - d.assign( d.size() , BSplineElementCoefficients< Degree-1 >() ); - for( int i=0 ; i >::size()) ; i++ ) for( int j=0 ; j<=Degree ; j++ ) - { - if( j-1>=0 ) d[i][j-1] -= (*this)[i][j]; - if( j -void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ) -{ - for( int i=0 ; i<=Degree1 ; i++ ) - { - Polynomial< Degree1 > p1 = Polynomial< Degree1 >::BSplineComponent( i ); - for( int j=0 ; j<=Degree2 ; j++ ) - { - Polynomial< Degree2 > p2 = Polynomial< Degree2 >::BSplineComponent( j ); - integrals[i][j] = ( p1 * p2 ).integral( 0 , 1 ); - } - } -} diff --git a/src/scanner/PoissonRecon/Src/BinaryNode.h b/src/scanner/PoissonRecon/Src/BinaryNode.h deleted file mode 100755 index 36928e5..0000000 --- a/src/scanner/PoissonRecon/Src/BinaryNode.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef BINARY_NODE_INCLUDED -#define BINARY_NODE_INCLUDED - -#define MSVC_2010_FIX 1 - - -class BinaryNode -{ -public: - static inline int CenterCount( int depth ) { return 1< static inline Real CornerIndexPosition(int index,int maxDepth){ return Real(index)/(1< static inline Real Width(int depth){ return Real(1.0/(1< static inline void CenterAndWidth( int depth , int offset , Real& center , Real& width ) - { - width=Real (1.0/(1< static inline void CenterAndWidth( int idx , Real& center , Real& width ) - { - int depth , offset; - DepthAndOffset( idx , depth , offset ); - CenterAndWidth( depth , offset , center , width ); - } - static inline void DepthAndOffset( int idx , int& depth , int& offset ) - { - int i=idx+1; -#if MSVC_2010_FIX - depth = 0; -#else // !MSVC_2010_FIX - depth = -1; -#endif // MSVC_2010_FIX - while( i ) - { - i >>= 1; - depth++; - } -#if MSVC_2010_FIX - depth--; -#endif // MSVC_2010_FIX - offset = ( idx+1 ) - (1< -#include -#include -#include -#include "CmdLineParser.h" - - -#ifdef WIN32 -int strcasecmp(char* c1,char* c2){return _stricmp(c1,c2);} -#endif - -cmdLineReadable::cmdLineReadable(const char* name) -{ - set=false; - this->name=new char[strlen(name)+1]; - strcpy(this->name,name); -} -cmdLineReadable::~cmdLineReadable(void) -{ - if(name) delete[] name; - name=NULL; -} -int cmdLineReadable::read(char**,int){ - set=true; - return 0; -} -void cmdLineReadable::writeValue(char* str) -{ - str[0] = 0; -} - -//////////////// -// cmdLineInt // -//////////////// -cmdLineInt::cmdLineInt(const char* name) : cmdLineReadable(name) {value=0;} -cmdLineInt::cmdLineInt(const char* name,const int& v) : cmdLineReadable(name) {value=v;} -int cmdLineInt::read(char** argv,int argc){ - if(argc>0){ - value=atoi(argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineInt::writeValue(char* str) -{ - sprintf(str,"%d",value); -} - -////////////////// -// cmdLineFloat // -////////////////// -cmdLineFloat::cmdLineFloat(const char* name) : cmdLineReadable(name) {value=0;} -cmdLineFloat::cmdLineFloat(const char* name, const float& v) : cmdLineReadable(name) {value=v;} -int cmdLineFloat::read(char** argv,int argc){ - if(argc>0){ - value=(float)atof(argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineFloat::writeValue(char* str) -{ - sprintf(str,"%f",value); -} - -/////////////////// -// cmdLineString // -/////////////////// -cmdLineString::cmdLineString(const char* name) : cmdLineReadable(name) {value=NULL;} -cmdLineString::~cmdLineString(void) -{ - if(value) delete[] value; - value=NULL; -} -int cmdLineString::read(char** argv,int argc){ - if(argc>0) - { - value=new char[strlen(argv[0])+1]; - strcpy(value,argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineString::writeValue(char* str) -{ - sprintf(str,"%s",value); -} - -//////////////////// -// cmdLineStrings // -//////////////////// -cmdLineStrings::cmdLineStrings(const char* name,int Dim) : cmdLineReadable(name) -{ - this->Dim=Dim; - values=new char*[Dim]; - for(int i=0;i=Dim) - { - for(int i=0;i 0) - { - if (argv[0][0] == '-' && argv[0][1]=='-') - { - for(i=0;iname)) - { - argv++, argc--; - j=readable[i]->read(argv,argc); - argv+=j,argc-=j; - break; - } - } - if(i==num){ - if(dumpError) - { - fprintf(stderr, "invalid option: %s\n",*argv); - fprintf(stderr, "possible options are:\n"); - for(i=0;iname); - } - argv++, argc--; - } - } - else - { - if(dumpError) - { - fprintf(stderr, "invalid option: %s\n", *argv); - fprintf(stderr, " options must start with a \'--\'\n"); - } - argv++, argc--; - } - } -} -char** ReadWords(const char* fileName,int& cnt) -{ - char** names; - char temp[500]; - FILE* fp; - - fp=fopen(fileName,"r"); - if(!fp){return NULL;} - cnt=0; - while(fscanf(fp," %s ",temp)==1){cnt++;} - fclose(fp); - - names=new char*[cnt]; - if(!names){return NULL;} - - fp=fopen(fileName,"r"); - if(!fp){ - delete[] names; - cnt=0; - return NULL; - } - cnt=0; - while(fscanf(fp," %s ",temp)==1){ - names[cnt]=new char[strlen(temp)+1]; - if(!names){ - for(int j=0;j -#include - - -#ifdef WIN32 -int strcasecmp(char* c1,char* c2); -#endif - -class cmdLineReadable{ -public: - bool set; - char* name; - cmdLineReadable(const char* name); - virtual ~cmdLineReadable(void); - virtual int read(char** argv,int argc); - virtual void writeValue(char* str); -}; - -class cmdLineInt : public cmdLineReadable { -public: - int value; - cmdLineInt(const char* name); - cmdLineInt(const char* name,const int& v); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineIntArray : public cmdLineReadable { -public: - int values[Dim]; - cmdLineIntArray(const char* name); - cmdLineIntArray(const char* name,const int v[Dim]); - int read(char** argv,int argc); - void writeValue(char* str); -}; - -class cmdLineFloat : public cmdLineReadable { -public: - float value; - cmdLineFloat(const char* name); - cmdLineFloat(const char* name,const float& f); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineFloatArray : public cmdLineReadable { -public: - float values[Dim]; - cmdLineFloatArray(const char* name); - cmdLineFloatArray(const char* name,const float f[Dim]); - int read(char** argv,int argc); - void writeValue(char* str); -}; -class cmdLineString : public cmdLineReadable { -public: - char* value; - cmdLineString(const char* name); - ~cmdLineString(); - int read(char** argv,int argc); - void writeValue(char* str); -}; -class cmdLineStrings : public cmdLineReadable { - int Dim; -public: - char** values; - cmdLineStrings(const char* name,int Dim); - ~cmdLineStrings(void); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineStringArray : public cmdLineReadable { -public: - char* values[Dim]; - cmdLineStringArray(const char* name); - ~cmdLineStringArray(); - int read(char** argv,int argc); - void writeValue(char* str); -}; - -// This reads the arguments in argc, matches them against "names" and sets -// the values of "r" appropriately. Parameters start with "--" -void cmdLineParse(int argc, char **argv,int num,cmdLineReadable** r,int dumpError=1); - -char* GetFileExtension(char* fileName); -char* GetLocalFileName(char* fileName); -char** ReadWords(const char* fileName,int& cnt); - -#include "CmdLineParser.inl" -#endif // CMD_LINE_PARSER_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/CmdLineParser.inl b/src/scanner/PoissonRecon/Src/CmdLineParser.inl deleted file mode 100755 index 8d0686e..0000000 --- a/src/scanner/PoissonRecon/Src/CmdLineParser.inl +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- C++ -*- -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -///////////////////// -// cmdLineIntArray // -///////////////////// -template -cmdLineIntArray::cmdLineIntArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineIntArray::cmdLineIntArray(const char* name,const int v[Dim]) : cmdLineReadable(name) -{ - for(int i=0;i -int cmdLineIntArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineIntArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -cmdLineFloatArray::cmdLineFloatArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineFloatArray::cmdLineFloatArray(const char* name,const float f[Dim]) : cmdLineReadable(name) -{ - for(int i=0;i -int cmdLineFloatArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineFloatArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -cmdLineStringArray::cmdLineStringArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineStringArray::~cmdLineStringArray(void) -{ - for(int i=0;i -int cmdLineStringArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineStringArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -#include "Factor.h" -int Factor(double a1,double a0,double roots[1][2],double EPS){ - if(fabs(a1)<=EPS){return 0;} - roots[0][0]=-a0/a1; - roots[0][1]=0; - return 1; -} -int Factor(double a2,double a1,double a0,double roots[2][2],double EPS){ - double d; - if(fabs(a2)<=EPS){return Factor(a1,a0,roots,EPS);} - - d=a1*a1-4*a0*a2; - a1/=(2*a2); - if(d<0){ - d=sqrt(-d)/(2*a2); - roots[0][0]=roots[1][0]=-a1; - roots[0][1]=-d; - roots[1][1]= d; - } - else{ - d=sqrt(d)/(2*a2); - roots[0][1]=roots[1][1]=0; - roots[0][0]=-a1-d; - roots[1][0]=-a1+d; - } - return 2; -} -// Solution taken from: http://mathworld.wolfram.com/CubicFormula.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -int Factor(double a3,double a2,double a1,double a0,double roots[3][2],double EPS){ - double q,r,r2,q3; - - if(fabs(a3)<=EPS){return Factor(a2,a1,a0,roots,EPS);} - a2/=a3; - a1/=a3; - a0/=a3; - - q=-(3*a1-a2*a2)/9; - r=-(9*a2*a1-27*a0-2*a2*a2*a2)/54; - r2=r*r; - q3=q*q*q; - - if(r20){return PI/2.0;} - else{return -PI/2.0;} - } - if(x>=0){return atan(y/x);} - else{ - if(y>=0){return atan(y/x)+PI;} - else{return atan(y/x)-PI;} - } -} -double Angle(const double in[2]){ - if((in[0]*in[0]+in[1]*in[1])==0.0){return 0;} - else{return ArcTan2(in[1],in[0]);} -} -void Sqrt(const double in[2],double out[2]){ - double r=sqrt(sqrt(in[0]*in[0]+in[1]*in[1])); - double a=Angle(in)*0.5; - out[0]=r*cos(a); - out[1]=r*sin(a); -} -void Add(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]+in2[0]; - out[1]=in1[1]+in2[1]; -} -void Subtract(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]-in2[0]; - out[1]=in1[1]-in2[1]; -} -void Multiply(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]*in2[0]-in1[1]*in2[1]; - out[1]=in1[0]*in2[1]+in1[1]*in2[0]; -} -void Divide(const double in1[2],const double in2[2],double out[2]){ - double temp[2]; - double l=in2[0]*in2[0]+in2[1]*in2[1]; - temp[0]= in2[0]/l; - temp[1]=-in2[1]/l; - Multiply(in1,temp,out); -} -// Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -int Factor(double a4,double a3,double a2,double a1,double a0,double roots[4][2],double EPS){ - double R[2],D[2],E[2],R2[2]; - - if(fabs(a4)10e-8){ - double temp1[2],temp2[2]; - double p1[2],p2[2]; - - p1[0]=a3*a3*0.75-2.0*a2-R2[0]; - p1[1]=0; - - temp2[0]=((4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0); - temp2[1]=0; - Divide(temp2,R,p2); - - Add (p1,p2,temp1); - Subtract(p1,p2,temp2); - - Sqrt(temp1,D); - Sqrt(temp2,E); - } - else{ - R[0]=R[1]=0; - double temp1[2],temp2[2]; - temp1[0]=roots[0][0]*roots[0][0]-4.0*a0; - temp1[1]=0; - Sqrt(temp1,temp2); - temp1[0]=a3*a3*0.75-2.0*a2+2.0*temp2[0]; - temp1[1]= 2.0*temp2[1]; - Sqrt(temp1,D); - temp1[0]=a3*a3*0.75-2.0*a2-2.0*temp2[0]; - temp1[1]= -2.0*temp2[1]; - Sqrt(temp1,E); - } - - roots[0][0]=-a3/4.0+R[0]/2.0+D[0]/2.0; - roots[0][1]= R[1]/2.0+D[1]/2.0; - - roots[1][0]=-a3/4.0+R[0]/2.0-D[0]/2.0; - roots[1][1]= R[1]/2.0-D[1]/2.0; - - roots[2][0]=-a3/4.0-R[0]/2.0+E[0]/2.0; - roots[2][1]= -R[1]/2.0+E[1]/2.0; - - roots[3][0]=-a3/4.0-R[0]/2.0-E[0]/2.0; - roots[3][1]= -R[1]/2.0-E[1]/2.0; - return 4; -} - -int Solve(const double* eqns,const double* values,double* solutions,int dim){ - int i,j,eIndex; - double v,m; - int *index=new int[dim]; - int *set=new int[dim]; - double* myEqns=new double[dim*dim]; - double* myValues=new double[dim]; - - for(i=0;im){ - m=fabs(myEqns[j*dim+i]); - eIndex=j; - } - } - if(eIndex==-1){ - delete[] index; - delete[] myValues; - delete[] myEqns; - delete[] set; - return 0; - } - // The position in which the solution for the i-th variable can be found - index[i]=eIndex; - set[eIndex]=1; - - // Normalize the equation - v=myEqns[eIndex*dim+i]; - for(j=0;j -class FunctionData{ - bool useDotRatios; - int normalize; -#if BOUNDARY_CONDITIONS - bool reflectBoundary; -#endif // BOUNDARY_CONDITIONS -public: - const static int DOT_FLAG = 1; - const static int D_DOT_FLAG = 2; - const static int D2_DOT_FLAG = 4; - const static int VALUE_FLAG = 1; - const static int D_VALUE_FLAG = 2; - - int depth , res , res2; - Real *dotTable , *dDotTable , *d2DotTable; - Real *valueTables , *dValueTables; -#if BOUNDARY_CONDITIONS - PPolynomial baseFunction , leftBaseFunction , rightBaseFunction; - PPolynomial dBaseFunction , dLeftBaseFunction , dRightBaseFunction; -#else // !BOUNDARY_CONDITIONS - PPolynomial baseFunction; - PPolynomial dBaseFunction; -#endif // BOUNDARY_CONDITIONS - PPolynomial* baseFunctions; - - FunctionData(void); - ~FunctionData(void); - - virtual void setDotTables(const int& flags); - virtual void clearDotTables(const int& flags); - - virtual void setValueTables(const int& flags,const double& smooth=0); - virtual void setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth); - virtual void clearValueTables(void); - - /******************************************************** - * Sets the translates and scales of the basis function - * up to the prescribed depth - * the maximum depth - * the basis function - * how the functions should be scaled - * 0] Value at zero equals 1 - * 1] Integral equals 1 - * 2] L2-norm equals 1 - * specifies if dot-products of derivatives - * should be pre-divided by function integrals - * spcifies if function space should be - * forced to be reflectively symmetric across the boundary - ********************************************************/ -#if BOUNDARY_CONDITIONS - void set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios=true , bool reflectBoundary=false ); -#else // !BOUNDARY_CONDITIONS - void set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios=true ); -#endif // BOUNDARY_CONDITIONS - -#if BOUNDARY_CONDITIONS - Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; - Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; - Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; -#else // !BOUNDARY_CONDITIONS - Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; - Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; - Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; -#endif // BOUNDARY_CONDITIONS - - static inline int SymmetricIndex( const int& i1 , const int& i2 ); - static inline int SymmetricIndex( const int& i1 , const int& i2 , int& index ); -}; - - -#include "FunctionData.inl" -#endif // FUNCTION_DATA_INCLUDED \ No newline at end of file diff --git a/src/scanner/PoissonRecon/Src/FunctionData.inl b/src/scanner/PoissonRecon/Src/FunctionData.inl deleted file mode 100755 index c8d5293..0000000 --- a/src/scanner/PoissonRecon/Src/FunctionData.inl +++ /dev/null @@ -1,415 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -////////////////// -// FunctionData // -////////////////// -template -FunctionData::FunctionData(void) -{ - dotTable=dDotTable=d2DotTable=NULL; - valueTables=dValueTables=NULL; - res=0; -} - -template -FunctionData::~FunctionData(void) -{ - if(res) - { - if( dotTable) delete[] dotTable; - if( dDotTable) delete[] dDotTable; - if(d2DotTable) delete[] d2DotTable; - if( valueTables) delete[] valueTables; - if(dValueTables) delete[] dValueTables; - } - dotTable=dDotTable=d2DotTable=NULL; - valueTables=dValueTables=NULL; - res=0; -} - -template -#if BOUNDARY_CONDITIONS -void FunctionData::set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios , bool reflectBoundary ) -#else // !BOUNDARY_CONDITIONS -void FunctionData::set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios ) -#endif // BOUNDARY_CONDITIONS -{ - this->normalize = normalize; - this->useDotRatios = useDotRatios; -#if BOUNDARY_CONDITIONS - this->reflectBoundary = reflectBoundary; -#endif // BOUNDARY_CONDITIONS - - depth = maxDepth; - res = BinaryNode::CumulativeCenterCount( depth ); - res2 = (1<<(depth+1))+1; - baseFunctions = new PPolynomial[res]; - // Scale the function so that it has: - // 0] Value 1 at 0 - // 1] Integral equal to 1 - // 2] Square integral equal to 1 - switch( normalize ) - { - case 2: - baseFunction=F/sqrt((F*F).integral(F.polys[0].start,F.polys[F.polyCount-1].start)); - break; - case 1: - baseFunction=F/F.integral(F.polys[0].start,F.polys[F.polyCount-1].start); - break; - default: - baseFunction=F/F(0); - } - dBaseFunction = baseFunction.derivative(); -#if BOUNDARY_CONDITIONS - leftBaseFunction = baseFunction + baseFunction.shift( -1 ); - rightBaseFunction = baseFunction + baseFunction.shift( 1 ); - dLeftBaseFunction = leftBaseFunction.derivative(); - dRightBaseFunction = rightBaseFunction.derivative(); -#endif // BOUNDARY_CONDITIONS - double c1,w1; - for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); -#if BOUNDARY_CONDITIONS - if( reflectBoundary ) - { - int d , off; - BinaryNode< double >::DepthAndOffset( i , d , off ); - if ( off==0 ) baseFunctions[i] = leftBaseFunction.scale( w1 ).shift( c1 ); - else if( off==((1< -void FunctionData::setDotTables( const int& flags ) -{ - clearDotTables( flags ); - int size; - size = ( res*res + res )>>1; - if( flags & DOT_FLAG ) - { - dotTable = new Real[size]; - memset( dotTable , 0 , sizeof(Real)*size ); - } - if( flags & D_DOT_FLAG ) - { - dDotTable = new Real[size]; - memset( dDotTable , 0 , sizeof(Real)*size ); - } - if( flags & D2_DOT_FLAG ) - { - d2DotTable = new Real[size]; - memset( d2DotTable , 0 , sizeof(Real)*size ); - } - double t1 , t2; - t1 = baseFunction.polys[0].start; - t2 = baseFunction.polys[baseFunction.polyCount-1].start; - for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); -#if BOUNDARY_CONDITIONS - int d1 , d2 , off1 , off2; - BinaryNode< double >::DepthAndOffset( i , d1 , off1 ); - int boundary1 = 0; - if ( reflectBoundary && off1==0 ) boundary1 = -1; - else if( reflectBoundary && off1==( (1<::CenterAndWidth( j , c2 , w2 ); -#if BOUNDARY_CONDITIONS - BinaryNode< double >::DepthAndOffset( j , d2 , off2 ); - int boundary2 = 0; - if ( reflectBoundary && off2==0 ) boundary2 = -1; - else if( reflectBoundary && off2==( (1<1 ) start = 1; - if( end <0 ) end = 0; - if( end >1 ) end = 1; - } -#endif // BOUNDARY_CONDITIONS - - if( start< start1 ) start = start1; - if( end > end1 ) end = end1; - if( start>= end ) continue; - -#if BOUNDARY_CONDITIONS - Real dot = dotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); -#else // !BOUNDARY_CONDITIONS - Real dot = dotProduct( c1 , w1 , c2 , w2 ); -#endif // BOUNDARY_CONDITIONS - if( fabs(dot)<1e-15 ) continue; - if( flags & DOT_FLAG ) dotTable[idx]=dot; - if( useDotRatios ) - { -#if BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; -#else // !BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct(c1,w1,c2,w2)/dot; - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2)/dot; -#endif // BOUNDARY_CONDITIONS - } - else - { -#if BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); -#else // !BOUNDARY_CONDTIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct(c1,w1,c2,w2); - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2); -#endif // BOUNDARY_CONDITIONS - } - } - } -} -template -void FunctionData::clearDotTables( const int& flags ) -{ - if((flags & DOT_FLAG) && dotTable) - { - delete[] dotTable; - dotTable=NULL; - } - if((flags & D_DOT_FLAG) && dDotTable) - { - delete[] dDotTable; - dDotTable=NULL; - } - if((flags & D2_DOT_FLAG) && d2DotTable) - { - delete[] d2DotTable; - d2DotTable=NULL; - } -} -template -void FunctionData::setValueTables( const int& flags , const double& smooth ) -{ - clearValueTables(); - if( flags & VALUE_FLAG ) valueTables = new Real[res*res2]; - if( flags & D_VALUE_FLAG ) dValueTables = new Real[res*res2]; - PPolynomial function; - PPolynomial dFunction; - for( int i=0 ; i0) - { - function=baseFunctions[i].MovingAverage(smooth); - dFunction=baseFunctions[i].derivative().MovingAverage(smooth); - } - else - { - function=baseFunctions[i]; - dFunction=baseFunctions[i].derivative(); - } - for( int j=0 ; j -void FunctionData::setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth){ - clearValueTables(); - if(flags & VALUE_FLAG){ valueTables=new Real[res*res2];} - if(flags & D_VALUE_FLAG){dValueTables=new Real[res*res2];} - PPolynomial function; - PPolynomial dFunction; - for(int i=0;i0) { function=baseFunctions[i].MovingAverage(valueSmooth);} - else { function=baseFunctions[i];} - if(normalSmooth>0) {dFunction=baseFunctions[i].derivative().MovingAverage(normalSmooth);} - else {dFunction=baseFunctions[i].derivative();} - - for(int j=0;j -void FunctionData::clearValueTables(void){ - if( valueTables){delete[] valueTables;} - if(dValueTables){delete[] dValueTables;} - valueTables=dValueTables=NULL; -} - -#if BOUNDARY_CONDITIONS -template -Real FunctionData::dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const -{ - const PPolynomial< Degree > *b1 , *b2; - if ( boundary1==-1 ) b1 = & leftBaseFunction; - else if( boundary1== 0 ) b1 = & baseFunction; - else if( boundary1== 1 ) b1 = &rightBaseFunction; - if ( boundary2==-1 ) b2 = & leftBaseFunction; - else if( boundary2== 0 ) b2 = & baseFunction; - else if( boundary2== 1 ) b2 = &rightBaseFunction; - double r=fabs( baseFunction.polys[0].start ); - switch( normalize ) - { - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); - } -} -template -Real FunctionData::dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const -{ - const PPolynomial< Degree-1 > *b1; - const PPolynomial< Degree > *b2; - if ( boundary1==-1 ) b1 = & dLeftBaseFunction; - else if( boundary1== 0 ) b1 = & dBaseFunction; - else if( boundary1== 1 ) b1 = &dRightBaseFunction; - if ( boundary2==-1 ) b2 = & leftBaseFunction; - else if( boundary2== 0 ) b2 = & baseFunction; - else if( boundary2== 1 ) b2 = & rightBaseFunction; - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); - } -} -template -Real FunctionData::d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const -{ - const PPolynomial< Degree-1 > *b1 , *b2; - if ( boundary1==-1 ) b1 = & dLeftBaseFunction; - else if( boundary1== 0 ) b1 = & dBaseFunction; - else if( boundary1== 1 ) b1 = &dRightBaseFunction; - if ( boundary2==-1 ) b2 = & dLeftBaseFunction; - else if( boundary2== 0 ) b2 = & dBaseFunction; - else if( boundary2== 1 ) b2 = &dRightBaseFunction; - double r=fabs(baseFunction.polys[0].start); - switch( normalize ) - { - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); - } -} -#else // !BOUNDARY_CONDITIONS -template -Real FunctionData::dotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch( normalize ) - { - case 2: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); - case 1: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); - default: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); - } -} -template -Real FunctionData::dDotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); - case 1: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); - default: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); - } -} -template -Real FunctionData::d2DotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); - case 1: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); - default: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); - } -} -#endif // BOUNDARY_CONDITIONS -template -inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 ) -{ - if( i1>i2 ) return ((i1*i1+i1)>>1)+i2; - else return ((i2*i2+i2)>>1)+i1; -} -template -inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 , int& index ) -{ - if( i1>1)+i1; - return 1; - } - else{ - index = ((i1*i1+i1)>>1)+i2; - return 0; - } -} diff --git a/src/scanner/PoissonRecon/Src/Geometry.cpp b/src/scanner/PoissonRecon/Src/Geometry.cpp deleted file mode 100755 index 4aa681c..0000000 --- a/src/scanner/PoissonRecon/Src/Geometry.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#include "Geometry.h" -#include -#include -#include -#include -#ifdef _WIN32 -#include -#endif // _WIN32 - -/////////////////// -// CoredMeshData // -/////////////////// - -TriangulationEdge::TriangulationEdge(void){pIndex[0]=pIndex[1]=tIndex[0]=tIndex[1]=-1;} -TriangulationTriangle::TriangulationTriangle(void){eIndex[0]=eIndex[1]=eIndex[2]=-1;} - -/////////////////////////// -// BufferedReadWriteFile // -/////////////////////////// -BufferedReadWriteFile::BufferedReadWriteFile( char* fileName , int bufferSize ) -{ - _bufferIndex = 0; - _bufferSize = bufferSize; - if( fileName ) strcpy( _fileName , fileName ) , tempFile = false , _fp = fopen( _fileName , "w+b" ); - else - { - strcpy( _fileName , "PR_XXXXXX" ); -#ifdef _WIN32 - _mktemp( _fileName ); - _fp = fopen( _fileName , "w+b" ); -#else // !_WIN32 - _fp = fdopen( mkstemp( _fileName ) , "w+b" ); -#endif // _WIN32 - tempFile = true; - } - if( !_fp ) fprintf( stderr , "[ERROR] Failed to open file: %s\n" , _fileName ) , exit( 0 ); - _buffer = (char*) malloc( _bufferSize ); -} -BufferedReadWriteFile::~BufferedReadWriteFile( void ) -{ - free( _buffer ); - fclose( _fp ); - if( tempFile ) remove( _fileName ); -} -void BufferedReadWriteFile::reset( void ) -{ - if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); - _bufferIndex = 0; - fseek( _fp , 0 , SEEK_SET ); - _bufferIndex = 0; - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); -} -bool BufferedReadWriteFile::write( const void* data , size_t size ) -{ - if( !size ) return true; - char* _data = (char*) data; - size_t sz = _bufferSize - _bufferIndex; - while( sz<=size ) - { - memcpy( _buffer+_bufferIndex , _data , sz ); - fwrite( _buffer , 1 , _bufferSize , _fp ); - _data += sz; - size -= sz; - _bufferIndex = 0; - sz = _bufferSize; - } - if( size ) - { - memcpy( _buffer+_bufferIndex , _data , size ); - _bufferIndex += size; - } - return true; -} -bool BufferedReadWriteFile::read( void* data , size_t size ) -{ - if( !size ) return true; - char *_data = (char*) data; - size_t sz = _bufferSize - _bufferIndex; - while( sz<=size ) - { - if( size && !_bufferSize ) return false; - memcpy( _data , _buffer+_bufferIndex , sz ); - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); - _data += sz; - size -= sz; - _bufferIndex = 0; - if( !size ) return true; - sz = _bufferSize; - } - if( size ) - { - if( !_bufferSize ) return false; - memcpy( _data , _buffer+_bufferIndex , size ); - _bufferIndex += size; - } - return true; -} \ No newline at end of file diff --git a/src/scanner/PoissonRecon/Src/Geometry.h b/src/scanner/PoissonRecon/Src/Geometry.h deleted file mode 100755 index a2d167c..0000000 --- a/src/scanner/PoissonRecon/Src/Geometry.h +++ /dev/null @@ -1,385 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef GEOMETRY_INCLUDED -#define GEOMETRY_INCLUDED - -#include -#include -#include -#include -#include "Hash.h" - -template -Real Random(void); - -template< class Real > -struct Point3D -{ - Real coords[3]; - Point3D( void ) { coords[0] = coords[1] = coords[2] = Real(0); } - template< class _Real > Point3D( _Real v0 , _Real v1 , _Real v2 ){ coords[0] = Real(v0) , coords[1] = Real(v1) , coords[2] = Real(v2); } - template< class _Real > Point3D( const Point3D< _Real >& p ){ coords[0] = Real( p[0] ) , coords[1] = Real( p[1] ) , coords[2] = Real( p[2] ); } - inline Real& operator[] ( int i ) { return coords[i]; } - inline const Real& operator[] ( int i ) const { return coords[i]; } - inline Point3D operator - ( void ) const { Point3D q ; q.coords[0] = -coords[0] , q.coords[1] = -coords[1] , q.coords[2] = -coords[2] ; return q; } - - template< class _Real > inline Point3D& operator += ( Point3D< _Real > p ){ coords[0] += Real(p.coords[0]) , coords[1] += Real(p.coords[1]) , coords[2] += Real(p.coords[2]) ; return *this; } - template< class _Real > inline Point3D operator + ( Point3D< _Real > p ) const { Point3D q ; q.coords[0] = coords[0] + Real(p.coords[0]) , q.coords[1] = coords[1] + Real(p.coords[1]) , q.coords[2] = coords[2] + Real(p.coords[2]) ; return q; } - template< class _Real > inline Point3D& operator *= ( _Real r ) { coords[0] *= Real(r) , coords[1] *= Real(r) , coords[2] *= Real(r) ; return *this; } - template< class _Real > inline Point3D operator * ( _Real r ) const { Point3D q ; q.coords[0] = coords[0] * Real(r) , q.coords[1] = coords[1] * Real(r) , q.coords[2] = coords[2] * Real(r) ; return q; } - - template< class _Real > inline Point3D& operator -= ( Point3D< _Real > p ){ return ( (*this)+=(-p) ); } - template< class _Real > inline Point3D operator - ( Point3D< _Real > p ) const { return (*this)+(-p); } - template< class _Real > inline Point3D& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } - template< class _Real > inline Point3D operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } - - static Real Dot( const Point3D< Real >& p1 , const Point3D< Real >& p2 ){ return p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2]; } - template< class Real1 , class Real2 > - static Real Dot( const Point3D< Real1 >& p1 , const Point3D< Real2 >& p2 ){ return Real( p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2] ); } -}; - -template< class Real > -struct XForm3x3 -{ - Real coords[3][3]; - XForm3x3( void ) { for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) coords[i][j] = Real(0.); } - static XForm3x3 Identity( void ) - { - XForm3x3 xForm; - xForm(0,0) = xForm(1,1) = xForm(2,2) = Real(1.); - return xForm; - } - Real& operator() ( int i , int j ){ return coords[i][j]; } - const Real& operator() ( int i , int j ) const { return coords[i][j]; } - template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const - { - Point3D< _Real > q; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) q[i] += _Real( coords[j][i] * p[j] ); - return q; - } - XForm3x3 operator * ( const XForm3x3& m ) const - { - XForm3x3 n; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; - return n; - } - XForm3x3 transpose( void ) const - { - XForm3x3 xForm; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) xForm( i , j ) = coords[j][i]; - return xForm; - } - Real subDeterminant( int i , int j ) const - { - int i1 = (i+1)%3 , i2 = (i+2)%3; - int j1 = (j+1)%3 , j2 = (j+2)%3; - return coords[i1][j1] * coords[i2][j2] - coords[i1][j2] * coords[i2][j1]; - } - Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) + coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ); } - XForm3x3 inverse( void ) const - { - XForm3x3 xForm; - Real d = determinant(); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ;j++ ) xForm.coords[j][i] = subDeterminant( i , j ) / d; - return xForm; - } -}; - -template< class Real > -struct XForm4x4 -{ - Real coords[4][4]; - XForm4x4( void ) { for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) coords[i][j] = Real(0.); } - static XForm4x4 Identity( void ) - { - XForm4x4 xForm; - xForm(0,0) = xForm(1,1) = xForm(2,2) = xForm(3,3) = Real(1.); - return xForm; - } - Real& operator() ( int i , int j ){ return coords[i][j]; } - const Real& operator() ( int i , int j ) const { return coords[i][j]; } - template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const - { - Point3D< _Real > q; - for( int i=0 ; i<3 ; i++ ) - { - for( int j=0 ; j<3 ; j++ ) q[i] += (_Real)( coords[j][i] * p[j] ); - q[i] += (_Real)coords[3][i]; - } - return q; - } - XForm4x4 operator * ( const XForm4x4& m ) const - { - XForm4x4 n; - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) for( int k=0 ; k<4 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; - return n; - } - XForm4x4 transpose( void ) const - { - XForm4x4 xForm; - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) xForm( i , j ) = coords[j][i]; - return xForm; - } - Real subDeterminant( int i , int j ) const - { - XForm3x3< Real > xForm; - int ii[] = { (i+1)%4 , (i+2)%4 , (i+3)%4 } , jj[] = { (j+1)%4 , (j+2)%4 , (j+3)%4 }; - for( int _i=0 ; _i<3 ; _i++ ) for( int _j=0 ; _j<3 ; _j++ ) xForm( _i , _j ) = coords[ ii[_i] ][ jj[_j] ]; - return xForm.determinant(); - } - Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) - coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ) - coords[3][0] * subDeterminant( 3 , 0 ); } - XForm4x4 inverse( void ) const - { - XForm4x4 xForm; - Real d = determinant(); - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ;j++ ) - if( (i+j)%2==0 ) xForm.coords[j][i] = subDeterminant( i , j ) / d; - else xForm.coords[j][i] = -subDeterminant( i , j ) / d; - return xForm; - } -}; - - -template -Point3D RandomBallPoint(void); - -template -Point3D RandomSpherePoint(void); - -template -double Length(const Point3D& p); - -template -double SquareLength(const Point3D& p); - -template -double Distance(const Point3D& p1,const Point3D& p2); - -template -double SquareDistance(const Point3D& p1,const Point3D& p2); - -template -void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p); - - -class Edge{ -public: - double p[2][2]; - double Length(void) const{ - double d[2]; - d[0]=p[0][0]-p[1][0]; - d[1]=p[0][1]-p[1][1]; - - return sqrt(d[0]*d[0]+d[1]*d[1]); - } -}; -class Triangle{ -public: - double p[3][3]; - double Area(void) const{ - double v1[3] , v2[3] , v[3]; - for( int d=0 ; d<3 ; d++ ) - { - v1[d] = p[1][d] - p[0][d]; - v2[d] = p[2][d] - p[0][d]; - } - v[0] = v1[1]*v2[2] - v1[2]*v2[1]; - v[1] = -v1[0]*v2[2] + v1[2]*v2[0]; - v[2] = v1[0]*v2[1] - v1[1]*v2[0]; - return sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ) / 2; - } - double AspectRatio(void) const{ - double d=0; - int i,j; - for(i=0;i<3;i++){ - for(i=0;i<3;i++) - for(j=0;j<3;j++){d+=(p[(i+1)%3][j]-p[i][j])*(p[(i+1)%3][j]-p[i][j]);} - } - return Area()/d; - } - -}; -class CoredPointIndex -{ -public: - int index; - char inCore; - - int operator == (const CoredPointIndex& cpi) const {return (index==cpi.index) && (inCore==cpi.inCore);}; - int operator != (const CoredPointIndex& cpi) const {return (index!=cpi.index) || (inCore!=cpi.inCore);}; -}; -class EdgeIndex{ -public: - int idx[2]; -}; -class CoredEdgeIndex -{ -public: - CoredPointIndex idx[2]; -}; -class TriangleIndex{ -public: - int idx[3]; -}; - -class TriangulationEdge -{ -public: - TriangulationEdge(void); - int pIndex[2]; - int tIndex[2]; -}; - -class TriangulationTriangle -{ -public: - TriangulationTriangle(void); - int eIndex[3]; -}; - -template -class Triangulation -{ -public: - - std::vector > points; - std::vector edges; - std::vector triangles; - - int factor( int tIndex,int& p1,int& p2,int& p3); - double area(void); - double area( int tIndex ); - double area( int p1 , int p2 , int p3 ); - int flipMinimize( int eIndex); - int addTriangle( int p1 , int p2 , int p3 ); - -protected: - hash_map edgeMap; - static long long EdgeIndex( int p1 , int p2 ); - double area(const Triangle& t); -}; - - -template -void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector >* normals); -template -void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector >& positions,std::vector >* normals); - -struct CoredVertexIndex -{ - int idx; - bool inCore; -}; -template< class Vertex > -class CoredMeshData -{ -public: - std::vector< Vertex > inCorePoints; - virtual void resetIterator( void ) = 0; - - virtual int addOutOfCorePoint( const Vertex& p ) = 0; - virtual int addPolygon( const std::vector< CoredVertexIndex >& vertices ) = 0; - virtual int addPolygon( const std::vector< int >& vertices ) = 0; - virtual int addOutOfCorePoint_s( const Vertex& p ) = 0; - virtual int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) = 0; - virtual int addPolygon_s( const std::vector< int >& vertices ) = 0; - - virtual int nextOutOfCorePoint( Vertex& p )=0; - virtual int nextPolygon( std::vector< CoredVertexIndex >& vertices ) = 0; - - virtual int outOfCorePointCount(void)=0; - virtual int polygonCount( void ) = 0; -}; - -template< class Vertex > -class CoredVectorMeshData : public CoredMeshData< Vertex > -{ - std::vector< Vertex > oocPoints; - std::vector< std::vector< int > > polygons; - int polygonIndex; - int oocPointIndex; -public: - CoredVectorMeshData(void); - - void resetIterator(void); - - int addOutOfCorePoint( const Vertex& p ); - int addPolygon( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon( const std::vector< int >& vertices ); - int addOutOfCorePoint_s( const Vertex& p ); - int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon_s( const std::vector< int >& vertices ); - - int nextOutOfCorePoint( Vertex& p ); - int nextPolygon( std::vector< CoredVertexIndex >& vertices ); - - int outOfCorePointCount(void); - int polygonCount( void ); -}; -class BufferedReadWriteFile -{ - bool tempFile; - FILE* _fp; - char *_buffer , _fileName[1024]; - size_t _bufferIndex , _bufferSize; -public: - BufferedReadWriteFile( char* fileName=NULL , int bufferSize=(1<<20) ); - ~BufferedReadWriteFile( void ); - bool write( const void* data , size_t size ); - bool read ( void* data , size_t size ); - void reset( void ); -}; -template< class Vertex > -class CoredFileMeshData : public CoredMeshData< Vertex > -{ - char pointFileName[1024] , polygonFileName[1024]; - BufferedReadWriteFile *oocPointFile , *polygonFile; - int oocPoints , polygons; -public: - CoredFileMeshData( void ); - ~CoredFileMeshData( void ); - - void resetIterator( void ); - - int addOutOfCorePoint( const Vertex& p ); - int addPolygon( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon( const std::vector< int >& vertices ); - int addOutOfCorePoint_s( const Vertex& p ); - int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon_s( const std::vector< int >& vertices ); - - int nextOutOfCorePoint( Vertex& p ); - int nextPolygon( std::vector< CoredVertexIndex >& vertices ); - - int outOfCorePointCount( void ); - int polygonCount( void ); -}; -#include "Geometry.inl" - -#endif // GEOMETRY_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/Geometry.inl b/src/scanner/PoissonRecon/Src/Geometry.inl deleted file mode 100755 index 12fb18b..0000000 --- a/src/scanner/PoissonRecon/Src/Geometry.inl +++ /dev/null @@ -1,623 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include - -template -Real Random(void){return Real(rand())/RAND_MAX;} - -template -Point3D RandomBallPoint(void){ - Point3D p; - while(1){ - p.coords[0]=Real(1.0-2.0*Random()); - p.coords[1]=Real(1.0-2.0*Random()); - p.coords[2]=Real(1.0-2.0*Random()); - double l=SquareLength(p); - if(l<=1){return p;} - } -} -template -Point3D RandomSpherePoint(void){ - Point3D p=RandomBallPoint(); - Real l=Real(Length(p)); - p.coords[0]/=l; - p.coords[1]/=l; - p.coords[2]/=l; - return p; -} - -template -double SquareLength(const Point3D& p){return p.coords[0]*p.coords[0]+p.coords[1]*p.coords[1]+p.coords[2]*p.coords[2];} - -template -double Length(const Point3D& p){return sqrt(SquareLength(p));} - -template -double SquareDistance(const Point3D& p1,const Point3D& p2){ - return (p1.coords[0]-p2.coords[0])*(p1.coords[0]-p2.coords[0])+(p1.coords[1]-p2.coords[1])*(p1.coords[1]-p2.coords[1])+(p1.coords[2]-p2.coords[2])*(p1.coords[2]-p2.coords[2]); -} - -template -double Distance(const Point3D& p1,const Point3D& p2){return sqrt(SquareDistance(p1,p2));} - -template -void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p){ - p.coords[0]= p1.coords[1]*p2.coords[2]-p1.coords[2]*p2.coords[1]; - p.coords[1]=-p1.coords[0]*p2.coords[2]+p1.coords[2]*p2.coords[0]; - p.coords[2]= p1.coords[0]*p2.coords[1]-p1.coords[1]*p2.coords[0]; -} -template -void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] -void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] -long long Triangulation::EdgeIndex( int p1 , int p2 ) -{ - if(p1>p2) {return ((long long)(p1)<<32) | ((long long)(p2));} - else {return ((long long)(p2)<<32) | ((long long)(p1));} -} - -template -int Triangulation::factor(int tIndex,int& p1,int& p2,int & p3){ - if(triangles[tIndex].eIndex[0]<0 || triangles[tIndex].eIndex[1]<0 || triangles[tIndex].eIndex[2]<0){return 0;} - if(edges[triangles[tIndex].eIndex[0]].tIndex[0]==tIndex){p1=edges[triangles[tIndex].eIndex[0]].pIndex[0];} - else {p1=edges[triangles[tIndex].eIndex[0]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[1]].tIndex[0]==tIndex){p2=edges[triangles[tIndex].eIndex[1]].pIndex[0];} - else {p2=edges[triangles[tIndex].eIndex[1]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[2]].tIndex[0]==tIndex){p3=edges[triangles[tIndex].eIndex[2]].pIndex[0];} - else {p3=edges[triangles[tIndex].eIndex[2]].pIndex[1];} - return 1; -} -template -double Triangulation::area(int p1,int p2,int p3){ - Point3D q1,q2,q; - for(int i=0;i<3;i++){ - q1.coords[i]=points[p2].coords[i]-points[p1].coords[i]; - q2.coords[i]=points[p3].coords[i]-points[p1].coords[i]; - } - CrossProduct(q1,q2,q); - return Length(q); -} -template -double Triangulation::area(int tIndex){ - int p1,p2,p3; - factor(tIndex,p1,p2,p3); - return area(p1,p2,p3); -} -template -double Triangulation::area(void){ - double a=0; - for(int i=0;i -int Triangulation::addTriangle(int p1,int p2,int p3){ - hash_map::iterator iter; - int tIdx,eIdx,p[3]; - p[0]=p1; - p[1]=p2; - p[2]=p3; - triangles.push_back(TriangulationTriangle()); - tIdx=int(triangles.size())-1; - - for(int i=0;i<3;i++) - { - long long e = EdgeIndex(p[i],p[(i+1)%3]); - iter=edgeMap.find(e); - if(iter==edgeMap.end()) - { - TriangulationEdge edge; - edge.pIndex[0]=p[i]; - edge.pIndex[1]=p[(i+1)%3]; - edges.push_back(edge); - eIdx=int(edges.size())-1; - edgeMap[e]=eIdx; - edges[eIdx].tIndex[0]=tIdx; - } - else{ - eIdx=edgeMap[e]; - if(edges[eIdx].pIndex[0]==p[i]){ - if(edges[eIdx].tIndex[0]<0){edges[eIdx].tIndex[0]=tIdx;} - else{printf("Edge Triangle in use 1\n");return 0;} - } - else{ - if(edges[eIdx].tIndex[1]<0){edges[eIdx].tIndex[1]=tIdx;} - else{printf("Edge Triangle in use 2\n");return 0;} - } - - } - triangles[tIdx].eIndex[i]=eIdx; - } - return tIdx; -} -template -int Triangulation::flipMinimize(int eIndex){ - double oldArea,newArea; - int oldP[3],oldQ[3],newP[3],newQ[3]; - TriangulationEdge newEdge; - - if(edges[eIndex].tIndex[0]<0 || edges[eIndex].tIndex[1]<0){return 0;} - - if(!factor(edges[eIndex].tIndex[0],oldP[0],oldP[1],oldP[2])){return 0;} - if(!factor(edges[eIndex].tIndex[1],oldQ[0],oldQ[1],oldQ[2])){return 0;} - - oldArea=area(oldP[0],oldP[1],oldP[2])+area(oldQ[0],oldQ[1],oldQ[2]); - int idxP,idxQ; - for(idxP=0;idxP<3;idxP++){ - int i; - for(i=0;i<3;i++){if(oldP[idxP]==oldQ[i]){break;}} - if(i==3){break;} - } - for(idxQ=0;idxQ<3;idxQ++){ - int i; - for(i=0;i<3;i++){if(oldP[i]==oldQ[idxQ]){break;}} - if(i==3){break;} - } - if(idxP==3 || idxQ==3){return 0;} - newP[0]=oldP[idxP]; - newP[1]=oldP[(idxP+1)%3]; - newP[2]=oldQ[idxQ]; - newQ[0]=oldQ[idxQ]; - newQ[1]=oldP[(idxP+2)%3]; - newQ[2]=oldP[idxP]; - - newArea=area(newP[0],newP[1],newP[2])+area(newQ[0],newQ[1],newQ[2]); - if(oldArea<=newArea){return 0;} - - // Remove the entry in the hash_table for the old edge - edgeMap.erase(EdgeIndex(edges[eIndex].pIndex[0],edges[eIndex].pIndex[1])); - // Set the new edge so that the zero-side is newQ - edges[eIndex].pIndex[0]=newP[0]; - edges[eIndex].pIndex[1]=newQ[0]; - // Insert the entry into the hash_table for the new edge - edgeMap[EdgeIndex(newP[0],newQ[0])]=eIndex; - // Update the triangle information - for(int i=0;i<3;i++){ - int idx; - idx=edgeMap[EdgeIndex(newQ[i],newQ[(i+1)%3])]; - triangles[edges[eIndex].tIndex[0]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[1]){edges[idx].tIndex[0]=edges[eIndex].tIndex[0];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[1]){edges[idx].tIndex[1]=edges[eIndex].tIndex[0];} - } - - idx=edgeMap[EdgeIndex(newP[i],newP[(i+1)%3])]; - triangles[edges[eIndex].tIndex[1]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[0]){edges[idx].tIndex[0]=edges[eIndex].tIndex[1];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[0]){edges[idx].tIndex[1]=edges[eIndex].tIndex[1];} - } - } - return 1; -} -///////////////////////// -// CoredVectorMeshData // -///////////////////////// -template< class Vertex > -CoredVectorMeshData< Vertex >::CoredVectorMeshData( void ) { oocPointIndex = polygonIndex = 0; } -template< class Vertex > -void CoredVectorMeshData< Vertex >::resetIterator ( void ) { oocPointIndex = polygonIndex = 0; } -template< class Vertex > -int CoredVectorMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) -{ - oocPoints.push_back(p); - return int(oocPoints.size())-1; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon( polygon ); -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon( const std::vector< int >& vertices ) -{ - polygons.push_back( vertices ); - return (int)polygons.size()-1; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) -{ - size_t sz; -#pragma omp critical (CoredVectorMeshData_addOutOfCorePoint_s ) - { - sz = oocPoints.size(); - oocPoints.push_back(p); - } - return (int)sz; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< int >& polygon ) -{ - size_t sz; -#pragma omp critical (CoredVectorMeshData_addPolygon_s) - { - sz = polygon.size(); - polygons.push_back( polygon ); - } - return (int)sz; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon_s( polygon ); -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) -{ - if( oocPointIndex -int CoredVectorMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) -{ - if( polygonIndex& polygon = polygons[ polygonIndex++ ]; - vertices.resize( polygon.size() ); - for( int i=0 ; i -int CoredVectorMeshData< Vertex >::outOfCorePointCount(void){return int(oocPoints.size());} -template< class Vertex > -int CoredVectorMeshData< Vertex >::polygonCount( void ) { return int( polygons.size() ); } - -/////////////////////// -// CoredFileMeshData // -/////////////////////// -template< class Vertex > -CoredFileMeshData< Vertex >::CoredFileMeshData( void ) -{ - oocPoints = polygons = 0; - - oocPointFile = new BufferedReadWriteFile(); - polygonFile = new BufferedReadWriteFile(); -} -template< class Vertex > -CoredFileMeshData< Vertex >::~CoredFileMeshData( void ) -{ - delete oocPointFile; - delete polygonFile; -} -template< class Vertex > -void CoredFileMeshData< Vertex >::resetIterator ( void ) -{ - oocPointFile->reset(); - polygonFile->reset(); -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) -{ - oocPointFile->write( &p , sizeof( Vertex ) ); - oocPoints++; - return oocPoints-1; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon( const std::vector< int >& vertices ) -{ - int vSize = (int)vertices.size(); - polygonFile->write( &vSize , sizeof(int) ); - polygonFile->write( &vertices[0] , sizeof(int)*vSize ); - polygons++; - return polygons-1; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon( polygon ); -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) -{ - int sz; -#pragma omp critical (CoredFileMeshData_addOutOfCorePoint_s) - { - sz = oocPoints; - oocPointFile->write( &p , sizeof( Vertex ) ); - oocPoints++; - } - return sz; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< int >& vertices ) -{ - int sz , vSize = (int)vertices.size(); -#pragma omp critical (CoredFileMeshData_addPolygon_s ) - { - sz = polygons; - polygonFile->write( &vSize , sizeof(int) ); - polygonFile->write( &vertices[0] , sizeof(int) * vSize ); - polygons++; - } - return sz; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon_s( polygon ); -} -template< class Vertex > -int CoredFileMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) -{ - if( oocPointFile->read( &p , sizeof( Vertex ) ) ) return 1; - else return 0; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) -{ - int pSize; - if( polygonFile->read( &pSize , sizeof(int) ) ) - { - std::vector< int > polygon( pSize ); - if( polygonFile->read( &polygon[0] , sizeof(int)*pSize ) ) - { - vertices.resize( pSize ); - for( int i=0 ; i -int CoredFileMeshData< Vertex >::outOfCorePointCount( void ){ return oocPoints; } -template< class Vertex > -int CoredFileMeshData< Vertex >::polygonCount( void ) { return polygons; } diff --git a/src/scanner/PoissonRecon/Src/Hash.h b/src/scanner/PoissonRecon/Src/Hash.h deleted file mode 100755 index 825c4c1..0000000 --- a/src/scanner/PoissonRecon/Src/Hash.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HASH_INCLUDED -#define HASH_INCLUDED -#ifdef WIN32 -#include -using stdext::hash_map; -#else // !WIN32 -#include -using namespace __gnu_cxx; - -namespace __gnu_cxx -{ - template<> struct hash { - size_t operator()(long long __x) const { return __x; } - }; - template<> struct hash { - size_t operator()(const long long __x) const { return __x; } - }; - - - template<> struct hash { - size_t operator()(unsigned long long __x) const { return __x; } - }; - template<> struct hash { - size_t operator()(const unsigned long long __x) const { return __x; } - }; -} -#endif // WIN32 -#endif // HASH_INCLUDED - diff --git a/src/scanner/PoissonRecon/Src/MAT.h b/src/scanner/PoissonRecon/Src/MAT.h deleted file mode 100755 index 1201251..0000000 --- a/src/scanner/PoissonRecon/Src/MAT.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright (c) 2007, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#ifndef MAT_INCLUDED -#define MAT_INCLUDED -#include "Geometry.h" - -template -class MinimalAreaTriangulation -{ - Real* bestTriangulation; - int* midPoint; - Real GetArea(const size_t& i,const size_t& j,const std::vector >& vertices); - void GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles); -public: - MinimalAreaTriangulation(void); - ~MinimalAreaTriangulation(void); - Real GetArea(const std::vector >& vertices); - void GetTriangulation(const std::vector >& vertices,std::vector& triangles); -}; - -#include "MAT.inl" - -#endif // MAT_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/MAT.inl b/src/scanner/PoissonRecon/Src/MAT.inl deleted file mode 100755 index d6f2126..0000000 --- a/src/scanner/PoissonRecon/Src/MAT.inl +++ /dev/null @@ -1,213 +0,0 @@ -/* -Copyright (c) 2007, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -////////////////////////////// -// MinimalAreaTriangulation // -////////////////////////////// -template -MinimalAreaTriangulation::MinimalAreaTriangulation(void) -{ - bestTriangulation=NULL; - midPoint=NULL; -} -template -MinimalAreaTriangulation::~MinimalAreaTriangulation(void) -{ - if(bestTriangulation) - delete[] bestTriangulation; - bestTriangulation=NULL; - if(midPoint) - delete[] midPoint; - midPoint=NULL; -} -template -void MinimalAreaTriangulation::GetTriangulation(const std::vector >& vertices,std::vector& triangles) -{ - if(vertices.size()==3) - { - triangles.resize(1); - triangles[0].idx[0]=0; - triangles[0].idx[1]=1; - triangles[0].idx[2]=2; - return; - } - else if(vertices.size()==4) - { - TriangleIndex tIndex[2][2]; - Real area[2]; - - area[0]=area[1]=0; - triangles.resize(2); - - tIndex[0][0].idx[0]=0; - tIndex[0][0].idx[1]=1; - tIndex[0][0].idx[2]=2; - tIndex[0][1].idx[0]=2; - tIndex[0][1].idx[1]=3; - tIndex[0][1].idx[2]=0; - - tIndex[1][0].idx[0]=0; - tIndex[1][0].idx[1]=1; - tIndex[1][0].idx[2]=3; - tIndex[1][1].idx[0]=3; - tIndex[1][1].idx[1]=1; - tIndex[1][1].idx[2]=2; - - Point3D n,p1,p2; - for(int i=0;i<2;i++) - for(int j=0;j<2;j++) - { - p1=vertices[tIndex[i][j].idx[1]]-vertices[tIndex[i][j].idx[0]]; - p2=vertices[tIndex[i][j].idx[2]]-vertices[tIndex[i][j].idx[0]]; - CrossProduct(p1,p2,n); - area[i] += Real( Length(n) ); - } - if(area[0]>area[1]) - { - triangles[0]=tIndex[1][0]; - triangles[1]=tIndex[1][1]; - } - else - { - triangles[0]=tIndex[0][0]; - triangles[1]=tIndex[0][1]; - } - return; - } - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - size_t eCount=vertices.size(); - bestTriangulation=new Real[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(size_t i=0;i -Real MinimalAreaTriangulation::GetArea(const std::vector >& vertices) -{ - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - int eCount=vertices.size(); - bestTriangulation=new double[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(int i=0;i -void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles) -{ - TriangleIndex tIndex; - size_t eCount=vertices.size(); - size_t ii=i; - if(i=ii) - return; - ii=midPoint[i*eCount+j]; - if(ii>=0) - { - tIndex.idx[0] = int( i ); - tIndex.idx[1] = int( j ); - tIndex.idx[2] = int( ii ); - triangles.push_back(tIndex); - GetTriangulation(i,ii,vertices,triangles); - GetTriangulation(ii,j,vertices,triangles); - } -} - -template -Real MinimalAreaTriangulation::GetArea(const size_t& i,const size_t& j,const std::vector >& vertices) -{ - Real a=FLT_MAX,temp; - size_t eCount=vertices.size(); - size_t idx=i*eCount+j; - size_t ii=i; - if(i=ii) - { - bestTriangulation[idx]=0; - return 0; - } - if(midPoint[idx]!=-1) - return bestTriangulation[idx]; - int mid=-1; - for(size_t r=j+1;r p,p1,p2; - p1=vertices[i]-vertices[rr]; - p2=vertices[j]-vertices[rr]; - CrossProduct(p1,p2,p); - temp = Real( Length(p) ); - if(bestTriangulation[idx1]>=0) - { - temp+=bestTriangulation[idx1]; - if(temp>a) - continue; - if(bestTriangulation[idx2]>0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - } - else - { - if(bestTriangulation[idx2]>=0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - if(temp>a) - continue; - temp+=GetArea(i,rr,vertices); - } - - if(temp -#include "MarchingCubes.h" - -//////////// -// Square // -//////////// -int Square::AntipodalCornerIndex(int idx){ - int x,y; - FactorCornerIndex(idx,x,y); - return CornerIndex( (x+1)%2 , (y+1)%2 ); -} -int Square::CornerIndex( int x , int y ){ return (y<<1)|x; } -void Square::FactorCornerIndex( int idx , int& x , int& y ){ x=(idx>>0)&1 , y=(idx>>1)&1; } -int Square::EdgeIndex( int orientation , int i ) -{ - switch( orientation ) - { - case 0: // x - if( !i ) return 0; // (0,0) -> (1,0) - else return 2; // (0,1) -> (1,1) - case 1: // y - if( !i ) return 3; // (0,0) -> (0,1) - else return 1; // (1,0) -> (1,1) - }; - return -1; -} -void Square::FactorEdgeIndex(int idx,int& orientation,int& i){ - switch(idx){ - case 0: case 2: - orientation=0; - i=idx/2; - return; - case 1: case 3: - orientation=1; - i=((idx/2)+1)%2; - return; - }; -} -void Square::EdgeCorners(int idx,int& c1,int& c2){ - int orientation,i; - FactorEdgeIndex(idx,orientation,i); - switch(orientation){ - case 0: - c1 = CornerIndex(0,i); - c2 = CornerIndex(1,i); - break; - case 1: - c1 = CornerIndex(i,0); - c2 = CornerIndex(i,1); - break; - }; -} -int Square::ReflectEdgeIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int o,i; - FactorEdgeIndex(idx,o,i); - if(o!=orientation){return idx;} - else{return EdgeIndex(o,(i+1)%2);} -} -int Square::ReflectCornerIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int x,y; - FactorCornerIndex(idx,x,y); - switch(orientation){ - case 0: return CornerIndex((x+1)%2,y); - case 1: return CornerIndex(x,(y+1)%2); - }; - return -1; -} - - - -////////// -// Cube // -////////// -int Cube::CornerIndex( int x , int y , int z ){ return (z<<2)|(y<<1)|x; } -void Cube::FactorCornerIndex( int idx , int& x , int& y , int& z ){ x = (idx>>0)&1 , y = (idx>>1)&1 , z = (idx>>2)&1; } -int Cube::EdgeIndex(int orientation,int i,int j){return (i | (j<<1))|(orientation<<2);} -void Cube::FactorEdgeIndex( int idx , int& orientation , int& i , int &j ) -{ - orientation=idx>>2; - i = (idx&1); - j = (idx&2)>>1; -} -int Cube::FaceIndex( int x , int y , int z ) -{ - if ( x<0 ) return 0; - else if( x>0 ) return 1; - else if( y<0 ) return 2; - else if( y>0 ) return 3; - else if( z<0 ) return 4; - else if( z>0 ) return 5; - else return -1; -} -int Cube::FaceIndex( int dir , int offSet ){ return (dir<<1)|offSet; } - -void Cube::FactorFaceIndex( int idx , int& x , int& y , int& z ) -{ - x=y=z=0; - switch( idx ) - { - case 0: x=-1; break; - case 1: x= 1; break; - case 2: y=-1; break; - case 3: y= 1; break; - case 4: z=-1; break; - case 5: z= 1; break; - }; -} -void Cube::FactorFaceIndex( int idx , int& dir , int& offSet ) -{ - dir = idx>>1; - offSet=idx &1; -} -bool Cube::IsEdgeCorner( int cIndex , int e ) -{ - int o , i , j; - FactorEdgeIndex( e , o , i , j ); - switch( o ) - { - // case 0: return (cIndex && 2)==(i<<1) && (cIndex && 4)==(j<<2); - // case 1: return (cIndex && 1)==(i<<0) && (cIndex && 4)==(j<<2); - // case 2: return (cIndex && 4)==(i<<2) && (cIndex && 2)==(j<<1); - case 0: return (cIndex & 2)==(i<<1) && (cIndex & 4)==(j<<2); - case 1: return (cIndex & 1)==(i<<0) && (cIndex & 4)==(j<<2); - case 2: return (cIndex & 4)==(i<<2) && (cIndex & 2)==(j<<1); - - default: return false; - } -} -bool Cube::IsFaceCorner( int cIndex , int f ) -{ - int dir , off; - FactorFaceIndex( f , dir , off ); - return ( cIndex & (1< (1,0) -1} // (1,0) -> (1,1) -2} // (0,1) -> (1,1) -3} // (0,0) -> (0,1) -*/ -const int MarchingSquares::edgeMask[1< -> -> - 9, // 1 -> 0 -> (0,0) -> 0,3 -> 9 - 3, // 2 -> 1 -> (1,0) -> 0,1 -> 3 - 10, // 3 -> 0,1 -> (0,0) (1,0) -> 1,3 -> 10 - 12, // 4 -> 2 -> (0,1) -> 2,3 -> 12 - 5, // 5 -> 0,2 -> (0,0) (0,1) -> 0,2 -> 5 - 15, // 6 -> 1,2 -> (1,0) (0,1) -> 0,1,2,3 -> 15 - 6, // 7 -> 0,1,2 -> (0,0) (1,0) (0,1) -> 1,2 -> 6 - 6, // 8 -> 3 -> (1,1) -> 1,2 -> 6 - 15, // 9 -> 0,3 -> (0,0) (1,1) -> 0,1,2,3 -> 15 - 5, // 10 -> 1,3 -> (1,0) (1,1) -> 0,2 -> 5 - 12, // 11 -> 0,1,3 -> (0,0) (1,0) (1,1) -> 2,3 -> 12 - 10, // 12 -> 2,3 -> (0,1) (1,1) -> 1,3 -> 10 - 3, // 13 -> 0,2,3 -> (0,0) (0,1) (1,1) -> 0,1 -> 3 - 9, // 14 -> 1,2,3 -> (1,0) (0,1) (1,1) -> 0,3 -> 9 - 0, // 15 -> 0,1,2,3 -> (0,0) (1,0) (0,1) (1,1) -> -}; -#if NEW_ORDERING -/* -0} // (0,0) -> (1,0) -1} // (1,0) -> (1,1) -2} // (0,1) -> (1,1) -3} // (0,0) -> (0,1) -*/ -const int MarchingSquares::edges[1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -bool MarchingCubes::IsAmbiguous( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::IsAmbiguous( GetFaceIndex( v , isoValue , faceIndex ) ); } -bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::HasRoots( GetFaceIndex( v , isoValue , faceIndex ) ); } -bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue ){ return HasRoots( GetIndex( v , isoValue ) ); } -bool MarchingCubes::HasRoots( unsigned char mcIndex ){ return !(mcIndex==0 || mcIndex==255); } -int MarchingCubes::AddTriangles( const double v[Cube::CORNERS] , double iso , Triangle* isoTriangles ) -{ - unsigned char idx; - int ntriang=0; - Triangle tri; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask[idx]) return 0; - - /* Find the vertices where the surface intersects the cube */ - int i,j,ii=1; - for(i=0;i<12;i++){ - if(edgeMask[idx] & ii){SetVertex(i,v,iso);} - ii<<=1; - } - /* Create the triangle */ - for( i=0 ; triangles[idx][i]!=-1 ; i+=3 ) - { - for(j=0;j<3;j++){ - tri.p[0][j]=vertexList[triangles[idx][i+0]][j]; - tri.p[1][j]=vertexList[triangles[idx][i+1]][j]; - tri.p[2][j]=vertexList[triangles[idx][i+2]][j]; - } - isoTriangles[ntriang++]=tri; - } - return ntriang; -} - -int MarchingCubes::AddTriangleIndices(const double v[Cube::CORNERS],double iso,int* isoIndices){ - unsigned char idx; - int ntriang=0; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask[idx]) return 0; - - /* Create the triangle */ - for(int i=0;triangles[idx][i]!=-1;i+=3){ - for(int j=0;j<3;j++){isoIndices[i+j]=triangles[idx][i+j];} - ntriang++; - } - return ntriang; -} - -void MarchingCubes::SetVertex( int e , const double values[Cube::CORNERS] , double iso ) -{ - double t; - int o , i1 , i2; - Cube::FactorEdgeIndex( e , o , i1 , i2 ); - switch( o ) - { - case 0: - t = Interpolate( values[ Cube::CornerIndex( 0 , i1 , i2 ) ] - iso , values[ Cube::CornerIndex( 1 , i1 , i2 ) ] - iso ); - vertexList[e][0] = t , vertexList[e][1] = i1 , vertexList[e][2] = i2; - break; - case 1: - t = Interpolate( values[ Cube::CornerIndex( i1 , 0 , i2 ) ] - iso , values[ Cube::CornerIndex( i1 , 1 , i2 ) ] - iso ); - vertexList[e][0] = i1 , vertexList[e][1] = t , vertexList[e][2] = i2; - break; - case 2: - t = Interpolate( values[ Cube::CornerIndex( i1 , i2 , 0 ) ] - iso , values[ Cube::CornerIndex( i1 , i2 , 1 ) ] - iso ); - vertexList[e][0] = i1 , vertexList[e][1] = i2 , vertexList[e][2] = t; - break; - } -} -double MarchingCubes::Interpolate( double v1 , double v2 ) { return v1/(v1-v2); } - - -/////////////////////////////////// -unsigned char MarchingCubes::GetIndex(const float v[Cube::CORNERS],float iso){ - unsigned char idx=0; - if (v[Cube::CornerIndex(0,0,0)] < iso) idx |= 1; - if (v[Cube::CornerIndex(1,0,0)] < iso) idx |= 2; - if (v[Cube::CornerIndex(1,1,0)] < iso) idx |= 4; - if (v[Cube::CornerIndex(0,1,0)] < iso) idx |= 8; - if (v[Cube::CornerIndex(0,0,1)] < iso) idx |= 16; - if (v[Cube::CornerIndex(1,0,1)] < iso) idx |= 32; - if (v[Cube::CornerIndex(1,1,1)] < iso) idx |= 64; - if (v[Cube::CornerIndex(0,1,1)] < iso) idx |= 128; - return idx; -} -unsigned char MarchingCubes::GetFaceIndex( const float values[Cube::CORNERS] , float iso , int faceIndex ) -{ - int i,j,x,y,z; - unsigned char idx=0; - double v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(0,i,j)];}}} - else if (x>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -unsigned char MarchingCubes::GetFaceIndex( unsigned char mcIndex , int faceIndex ) -{ - int i,j,x,y,z; - unsigned char idx=0; - int v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1< -#include "Geometry.h" - -#define NEW_ORDERING 1 - -class Square -{ -public: - const static unsigned int CORNERS=4 , EDGES=4 , FACES=1; - static int CornerIndex (int x,int y); - static int AntipodalCornerIndex(int idx); - static void FactorCornerIndex (int idx,int& x,int& y); - static int EdgeIndex (int orientation,int i); - static void FactorEdgeIndex (int idx,int& orientation,int& i); - - static int ReflectCornerIndex (int idx,int edgeIndex); - static int ReflectEdgeIndex (int idx,int edgeIndex); - - static void EdgeCorners(int idx,int& c1,int &c2); -}; - -class Cube{ -public: - const static unsigned int CORNERS=8 , EDGES=12 , FACES=6; - - static int CornerIndex ( int x , int y , int z ); - static void FactorCornerIndex ( int idx , int& x , int& y , int& z ); - static int EdgeIndex ( int orientation , int i , int j ); - static void FactorEdgeIndex ( int idx , int& orientation , int& i , int &j); - static int FaceIndex ( int dir , int offSet ); - static int FaceIndex ( int x , int y , int z ); - static void FactorFaceIndex ( int idx , int& x , int &y , int& z ); - static void FactorFaceIndex ( int idx , int& dir , int& offSet ); - - static int AntipodalCornerIndex ( int idx ); - static int FaceReflectCornerIndex ( int idx , int faceIndex ); - static int FaceReflectEdgeIndex ( int idx , int faceIndex ); - static int FaceReflectFaceIndex ( int idx , int faceIndex ); - static int EdgeReflectCornerIndex ( int idx , int edgeIndex ); - static int EdgeReflectEdgeIndex ( int edgeIndex ); - - static int FaceAdjacentToEdges ( int eIndex1 , int eIndex2 ); - static void FacesAdjacentToEdge ( int eIndex , int& f1Index , int& f2Index ); - - static void EdgeCorners( int idx , int& c1 , int &c2 ); - static void FaceCorners( int idx , int& c1 , int &c2 , int& c3 , int& c4 ); - - static bool IsEdgeCorner( int cIndex , int e ); - static bool IsFaceCorner( int cIndex , int f ); -}; - -class MarchingSquares -{ - static double Interpolate(double v1,double v2); - static void SetVertex(int e,const double values[Square::CORNERS],double iso); -public: - const static unsigned int MAX_EDGES=2; - static const int edgeMask[1< -class MemoryInfo -{ -public: - size_t TotalPhysicalMemory; - size_t FreePhysicalMemory; - size_t TotalSwapSpace; - size_t FreeSwapSpace; - size_t TotalVirtualAddressSpace; - size_t FreeVirtualAddressSpace; - size_t PageSize; - - void set(void){ - MEMORYSTATUSEX Mem; - SYSTEM_INFO Info; - ZeroMemory( &Mem, sizeof(Mem)); - ZeroMemory( &Info, sizeof(Info)); - Mem.dwLength = sizeof(Mem); - ::GlobalMemoryStatusEx( &Mem ); - ::GetSystemInfo( &Info ); - - TotalPhysicalMemory = (size_t)Mem.ullTotalPhys; - FreePhysicalMemory = (size_t)Mem.ullAvailPhys; - TotalSwapSpace = (size_t)Mem.ullTotalPageFile; - FreeSwapSpace = (size_t)Mem.ullAvailPageFile; - TotalVirtualAddressSpace = (size_t)Mem.ullTotalVirtual; - FreeVirtualAddressSpace = (size_t)Mem.ullAvailVirtual; - PageSize = (size_t)Info.dwPageSize; - } - size_t usage(void) const {return TotalVirtualAddressSpace-FreeVirtualAddressSpace;} - - static size_t Usage(void){ - MEMORY_BASIC_INFORMATION mbi; - size_t dwMemUsed = 0; - PVOID pvAddress = 0; - - - memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION)); - while(VirtualQuery(pvAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION)){ - if(mbi.State == MEM_COMMIT && mbi.Type == MEM_PRIVATE){dwMemUsed += mbi.RegionSize;} - pvAddress = ((BYTE*)mbi.BaseAddress) + mbi.RegionSize; - } - return dwMemUsed; - } -}; - -#else // !WIN32 - -#ifndef __APPLE__ // Linux variants - -#include -#include - -class MemoryInfo -{ - public: - static size_t Usage(void) - { - FILE* f = fopen("/proc/self/stat","rb"); - - int d; - long ld; - unsigned long lu; - unsigned long long llu; - char s[1024]; - char c; - - int pid; - unsigned long vm; - - int n = fscanf(f, "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu" - ,&pid ,s ,&c ,&d ,&d ,&d ,&d ,&d ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&ld ,&ld ,&ld ,&ld ,&d ,&ld ,&llu ,&vm ,&ld ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&d ,&d ,&lu ,&lu ); - - fclose(f); -/* -pid %d -comm %s -state %c -ppid %d -pgrp %d -session %d -tty_nr %d -tpgid %d -flags %lu -minflt %lu -cminflt %lu -majflt %lu -cmajflt %lu -utime %lu -stime %lu -cutime %ld -cstime %ld -priority %ld -nice %ld -0 %ld -itrealvalue %ld -starttime %lu -vsize %lu -rss %ld -rlim %lu -startcode %lu -endcode %lu -startstack %lu -kstkesp %lu -kstkeip %lu -signal %lu -blocked %lu -sigignore %lu -sigcatch %lu -wchan %lu -nswap %lu -cnswap %lu -exit_signal %d -processor %d -rt_priority %lu (since kernel 2.5.19) -policy %lu (since kernel 2.5.19) -*/ - return vm; - } - -}; -#else // __APPLE__: has no "/proc" pseudo-file system - -// Thanks to David O'Gwynn for providing this fix. -// This comes from a post by Michael Knight: -// -// http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html - -#include -#include -#include -#include -#include -#include -#include - -void getres(task_t task, unsigned long *rss, unsigned long *vs) -{ - struct task_basic_info t_info; - mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; - - task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); - *rss = t_info.resident_size; - *vs = t_info.virtual_size; -} - -class MemoryInfo -{ - public: - static size_t Usage(void) - { - unsigned long rss, vs, psize; - task_t task = MACH_PORT_NULL; - - if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS) - abort(); - getres(task, &rss, &vs); - return rss; - } - -}; - -#endif // !__APPLE__ - -#endif // WIN32 - -#endif // MEMORY_USAGE_INCLUDE diff --git a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.IsoSurface.inl b/src/scanner/PoissonRecon/Src/MultiGridOctreeData.IsoSurface.inl deleted file mode 100755 index 60dc17a..0000000 --- a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.IsoSurface.inl +++ /dev/null @@ -1,1121 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "Octree.h" -#include "MyTime.h" -#include "MemoryUsage.h" -#include "MAT.h" - - - -template< class Real > -template< class Vertex > -Octree< Real >::SliceValues< Vertex >::SliceValues( void ) -{ - _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; - cornerValues = NullPointer< Real >() ; cornerNormals = NullPointer< Point3D< Real > >() ; cornerSet = NullPointer< char >(); - edgeKeys = NullPointer< long long >() ; edgeSet = NullPointer< char >(); - faceEdges = NullPointer< FaceEdges >() ; faceSet = NullPointer< char >(); - mcIndices = NullPointer< char >(); -} -template< class Real > -template< class Vertex > -Octree< Real >::SliceValues< Vertex >::~SliceValues( void ) -{ - _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; - FreePointer( cornerValues ) ; FreePointer( cornerNormals ) ; FreePointer( cornerSet ); - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); - FreePointer( mcIndices ); -} -template< class Real > -template< class Vertex > -void Octree< Real >::SliceValues< Vertex >::reset( bool nonLinearFit ) -{ - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - - if( _oldNCount0 ) mcIndices = AllocPointer< char >( _oldNCount ); - } - if( _oldCCount0 ) - { - cornerValues = AllocPointer< Real >( _oldCCount ); - if( nonLinearFit ) cornerNormals = AllocPointer< Point3D< Real > >( _oldCCount ); - cornerSet = AllocPointer< char >( _oldCCount ); - } - } - if( _oldECount( _oldECount ); - edgeSet = AllocPointer< char >( _oldECount ); - } - if( _oldFCount( _oldFCount ); - faceSet = AllocPointer< char >( _oldFCount ); - } - - if( sliceData.cCount>0 ) memset( cornerSet , 0 , sizeof( char ) * sliceData.cCount ); - if( sliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * sliceData.eCount ); - if( sliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * sliceData.fCount ); -} -template< class Real > -template< class Vertex > -Octree< Real >::XSliceValues< Vertex >::XSliceValues( void ) -{ - _oldECount = _oldFCount = 0; - edgeKeys = NullPointer< long long >() ; edgeSet = NullPointer< char >(); - faceEdges = NullPointer< FaceEdges >() ; faceSet = NullPointer< char >(); -} -template< class Real > -template< class Vertex > -Octree< Real >::XSliceValues< Vertex >::~XSliceValues( void ) -{ - _oldECount = _oldFCount = 0; - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); -} -template< class Real > -template< class Vertex > -void Octree< Real >::XSliceValues< Vertex >::reset( void ) -{ - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - - if( _oldECount( _oldECount ); - edgeSet = AllocPointer< char >( _oldECount ); - } - if( _oldFCount( _oldFCount ); - faceSet = AllocPointer< char >( _oldFCount ); - } - if( xSliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * xSliceData.eCount ); - if( xSliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * xSliceData.fCount ); -} - -template< class Real > -template< class Vertex > -void Octree< Real >::GetMCIsoSurface( ConstPointer( Real ) kernelDensityWeights , ConstPointer( Real ) solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit , bool addBarycenter , bool polygonMesh ) -{ - typename BSplineData< 2 >::template CornerEvaluator< 2 > evaluator; - _fData.setCornerEvaluator( evaluator , 0 , 0 , _boundaryType==0 ); - - int maxDepth = tree.maxDepth(); - - std::vector< Real > coarseSolution( _sNodes.nodeCount[maxDepth] , 0 ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[_minDepth] ; i<_sNodes.nodeCount[maxDepth] ; i++ ) coarseSolution[i] = solution[i]; - for( int d=_minDepth ; d vStencils( maxDepth+1 ); - std::vector< CornerNormalStencil > nStencils( maxDepth+1 ); - for( int d=_minDepth ; d<=maxDepth ; d++ ) - { - SetCornerEvaluationStencil ( evaluator , d , vStencils[d].stencil ); - SetCornerEvaluationStencils( evaluator , d , vStencils[d].stencils ); - SetCornerNormalEvaluationStencil ( evaluator , d , nStencils[d].stencil ); - SetCornerNormalEvaluationStencils( evaluator , d , nStencils[d].stencils ); - } - int vertexOffset = 0; - std::vector< SlabValues< Vertex > > slabValues( maxDepth+1 ); - - // Initialize the back slice - for( int d=maxDepth ; d>=_minDepth ; d-- ) - { - _sNodes.setSliceTableData ( slabValues[d].sliceValues(0).sliceData , d , 0 , threads ); - _sNodes.setSliceTableData ( slabValues[d].sliceValues(1).sliceData , d , 1 , threads ); - _sNodes.setXSliceTableData( slabValues[d].xSliceValues(0).xSliceData , d , 0 , threads ); - slabValues[d].sliceValues (0).reset( nonLinearFit ); - slabValues[d].sliceValues (1).reset( nonLinearFit ); - slabValues[d].xSliceValues(0).reset( ); - } - for( int d=maxDepth ; d>=_minDepth ; d-- ) - { - // Copy edges from finer - if( d=_minDepth ; d-- , o>>=1 ) - { - // Copy edges from finer (required to ensure we correctly track edge cancellations) - if( d=_minDepth ; d-- , o>>=1 ) - { - // Initialize for the next pass - if( o<(1< -Real Octree< Real >::GetIsoValue( ConstPointer( Real ) solution , const std::vector< Real >& centerWeights ) -{ - Real isoValue=0 , weightSum=0; - int maxDepth = tree.maxDepth(); - - typename BSplineData< 2 >::template CenterEvaluator< 1 > evaluator; - _fData.setCenterEvaluator( evaluator , 0 , 0 , _boundaryType==0 ); - std::vector< CenterValueStencil > vStencils( maxDepth+1 ); - for( int d=_minDepth ; d<=maxDepth ; d++ ) - { - SetCenterEvaluationStencil ( evaluator , d , vStencils[d].stencil ); - SetCenterEvaluationStencils( evaluator , d , vStencils[d].stencils ); - } - std::vector< Real > metSolution( _sNodes.nodeCount[maxDepth] , 0 ); - std::vector< Real > centerValues( _sNodes.nodeCount[maxDepth+1] ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[_minDepth] ; i<_sNodes.nodeCount[maxDepth] ; i++ ) metSolution[i] = solution[i]; - for( int d=_minDepth ; d=_minDepth ; d-- ) - { - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - for( int c=0 ; cchildren[c].nodeData.nodeIndex ]; - value /= Cube::CORNERS; - } - else - { - neighborKey.getNeighbors( node ); - int c=0 , x , y , z; - if( node->parent ) c = int( node - node->parent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - - int d , off[3]; - node->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2)) : 0; - int mn = 2+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]nodeData.nodeIndex ]; - if( w!=0 ) isoValue += value * w , weightSum += w; - } - } - if( _boundaryType==-1 ) return isoValue/weightSum - Real(0.5); - else return isoValue/weightSum; -} - -template< class Real > -template< class Vertex > -void Octree< Real >::SetSliceIsoCorners( ConstPointer( Real ) solution , ConstPointer( Real ) coarseSolution , Real isoValue , int depth , int slice , std::vector< SlabValues< Vertex > >& slabValues , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 > vStencil[8] , const Stencil< double , 3 > vStencils[8][8] , const Stencil< Point3D< double > , 3 > nStencil[8] , const Stencil< Point3D< double > , 3 > nStencils[8][8] , int threads ) -{ - if( slice>0 ) SetSliceIsoCorners( solution , coarseSolution , isoValue , depth , slice , 1 , slabValues , evaluator , vStencil , vStencils , nStencil , nStencils , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::SetSliceIsoCorners( ConstPointer( Real ) solution , ConstPointer( Real ) coarseSolution , Real isoValue , int depth , int slice , int z , std::vector< SlabValues< Vertex > >& slabValues , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 > vStencil[8] , const Stencil< double , 3 > vStencils[8][8] , const Stencil< Point3D< double > , 3 > nStencil[8] , const Stencil< Point3D< double > , 3 > nStencils[8][8] , int threads ) -{ - typename Octree< Real >::template SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - const typename SortedTreeNodes::SquareCornerIndices& cIndices = sValues.sliceData.cornerIndices( leaf ); - - bool isInterior; - { - int d , off[3]; - leaf->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2)) : 0; - int mn = 2+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2] > p = getCornerValueAndNormal( neighborKey , leaf , cc , solution , coarseSolution , evaluator , vStencil[cc] , vStencils[cc] , nStencil[cc] , nStencils[cc] , isInterior ); - sValues.cornerValues[vIndex] = p.first , sValues.cornerNormals[vIndex] = p.second; - } - else sValues.cornerValues[vIndex] = getCornerValue( neighborKey , leaf , cc , solution , coarseSolution , evaluator , vStencil[cc] , vStencils[cc] , isInterior ); - sValues.cornerSet[vIndex] = 1; - } - squareValues[fc] = sValues.cornerValues[ vIndex ]; - TreeOctNode* node = leaf; - int _depth = depth , _slice = slice; - while( node->parent && (node-node->parent->children)==cc ) - { - node = node->parent , _depth-- , _slice >>= 1; - typename Octree< Real >::template SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); - const typename SortedTreeNodes::SquareCornerIndices& _cIndices = _sValues.sliceData.cornerIndices( node ); - int _vIndex = _cIndices[fc]; - _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; - if( _sValues.cornerNormals ) _sValues.cornerNormals[_vIndex] = sValues.cornerNormals[vIndex]; - _sValues.cornerSet[_vIndex] = 1; - } - } - sValues.mcIndices[ i - sValues.sliceData.nodeOffset ] = MarchingSquares::GetIndex( squareValues , isoValue ); - } - } -} - -template< class Real > -template< class Vertex > -void Octree< Real >::SetSliceIsoVertices( ConstPointer( Real ) kernelDensityWeight , Real isoValue , int depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) SetSliceIsoVertices( kernelDensityWeight , isoValue , depth , slice , 1 , vOffset , mesh , slabValues , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::SetSliceIsoVertices( ConstPointer( Real ) kernelDensityWeight , Real isoValue , int depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree< Real >::template SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - int idx = i - sValues.sliceData.nodeOffset; - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - if( MarchingSquares::HasRoots( sValues.mcIndices[idx] ) ) - { - neighborKey.getNeighbors( leaf ); - for( int e=0 ; e hashed_vertex; -#pragma omp critical (add_point_access) - { - if( !sValues.edgeSet[vIndex] ) - { - mesh.addOutOfCorePoint( vertex ); - sValues.edgeSet[ vIndex ] = 1; - sValues.edgeKeys[ vIndex ] = key; - sValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); - vOffset++; - stillOwner = true; - } - } - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - bool isNeeded; - switch( o ) - { - case 0: isNeeded = ( neighborKey.neighbors[depth].neighbors[1][2*y][1]==NULL || neighborKey.neighbors[depth].neighbors[1][2*y][2*z]==NULL || neighborKey.neighbors[depth].neighbors[1][1][2*z]==NULL ) ; break; - case 1: isNeeded = ( neighborKey.neighbors[depth].neighbors[2*y][1][1]==NULL || neighborKey.neighbors[depth].neighbors[2*y][1][2*z]==NULL || neighborKey.neighbors[depth].neighbors[1][1][2*z]==NULL ) ; break; - } - if( isNeeded ) - { - int f[2]; - Cube::FacesAdjacentToEdge( Cube::EdgeIndex( o , y , z ) , f[0] , f[1] ); - for( int k=0 ; k<2 ; k++ ) - { - TreeOctNode* node = leaf; - int _depth = depth , _slice = slice; - bool _isNeeded = isNeeded; - while( _isNeeded = node->parent && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - typename Octree< Real >::template SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); -#pragma omp critical (add_coarser_point_access) - _sValues.edgeVertexMap[key] = hashed_vertex; - switch( o ) - { - case 0: _isNeeded = ( neighborKey.neighbors[_depth].neighbors[1][2*y][1]==NULL || neighborKey.neighbors[_depth].neighbors[1][2*y][2*z]==NULL || neighborKey.neighbors[_depth].neighbors[1][1][2*z]==NULL ) ; break; - case 1: _isNeeded = ( neighborKey.neighbors[_depth].neighbors[2*y][1][1]==NULL || neighborKey.neighbors[_depth].neighbors[2*y][1][2*z]==NULL || neighborKey.neighbors[_depth].neighbors[1][1][2*z]==NULL ) ; break; - } - } - } - } - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::SetXSliceIsoVertices( ConstPointer( Real ) kernelDensityWeight , Real isoValue , int depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree< Real >::template SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); - typename Octree< Real >::template SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); - typename Octree< Real >::template XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); - - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ] )<<4; - const typename SortedTreeNodes::SquareCornerIndices& eIndices = xValues.xSliceData.edgeIndices( leaf ); - if( MarchingCubes::HasRoots( mcIndex ) ) - { - neighborKey.getNeighbors( leaf ); - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int c = Square::CornerIndex( x , y ); - int e = Cube::EdgeIndex( 2 , x , y ); - if( MarchingCubes::HasEdgeRoots( mcIndex , e ) ) - { - int vIndex = eIndices[c]; - if( !xValues.edgeSet[vIndex] ) - { - Vertex vertex; - long long key = VertexData::EdgeIndex( leaf , e , _sNodes.maxDepth ); - GetIsoVertex( kernelDensityWeight , isoValue , neighborKey , leaf , c , bValues , fValues , vertex ); - vertex.point = vertex.point * _scale + _center; - bool stillOwner = false; - std::pair< int , Vertex > hashed_vertex; -#pragma omp critical (add_x_point_access) - { - if( !xValues.edgeSet[vIndex] ) - { - mesh.addOutOfCorePoint( vertex ); - xValues.edgeSet[ vIndex ] = 1; - xValues.edgeKeys[ vIndex ] = key; - xValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); - stillOwner = true; - vOffset++; - } - } - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - bool isNeeded = ( neighborKey.neighbors[depth].neighbors[2*x][1][1]==NULL || neighborKey.neighbors[depth].neighbors[2*x][2*y][1]==NULL || neighborKey.neighbors[depth].neighbors[1][2*y][1]==NULL ); - if( isNeeded ) - { - int f[2]; - Cube::FacesAdjacentToEdge( e , f[0] , f[1] ); - for( int k=0 ; k<2 ; k++ ) - { - TreeOctNode* node = leaf; - int _depth = depth , _slab = slab; - bool _isNeeded = isNeeded; - while( _isNeeded && node->parent && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) - { - node = node->parent , _depth-- , _slab >>= 1; - typename Octree< Real >::template XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); -#pragma omp critical (add_x_coarser_point_access) - _xValues.edgeVertexMap[key] = hashed_vertex; - _isNeeded = ( neighborKey.neighbors[_depth].neighbors[2*x][1][1]==NULL || neighborKey.neighbors[_depth].neighbors[2*x][2*y][1]==NULL || neighborKey.neighbors[_depth].neighbors[1][2*y][1]==NULL ); - } - } - } - } - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::CopyFinerSliceIsoEdgeKeys( int depth , int slice , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) CopyFinerSliceIsoEdgeKeys( depth , slice , 1 , slabValues , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::CopyFinerSliceIsoEdgeKeys( int depth , int slice , int z , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - SliceValues< Vertex >& pSliceValues = slabValues[depth ].sliceValues(slice ); - SliceValues< Vertex >& cSliceValues = slabValues[depth+1].sliceValues(slice<<1); - typename SortedTreeNodes::SliceTableData& pSliceData = pSliceValues.sliceData; - typename SortedTreeNodes::SliceTableData& cSliceData = cSliceValues.sliceData; -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth] + _sNodes.sliceOffsets[depth][slice-z] ; i<_sNodes.nodeCount[depth] + _sNodes.sliceOffsets[depth][slice-z+1] ; i++ ) - if( _sNodes.treeNodes[i]->children ) - { - typename SortedTreeNodes::SquareEdgeIndices& pIndices = pSliceData.edgeIndices( i ); - // Copy the edges that overlap the coarser edges - for( int orientation=0 ; orientation<2 ; orientation++ ) for( int y=0 ; y<2 ; y++ ) - { - int fe = Square::EdgeIndex( orientation , y ); - int pIndex = pIndices[fe]; - if( !pSliceValues.edgeSet[ pIndex ] ) - { - int ce = Cube::EdgeIndex( orientation , y , z ); - int c1 , c2; - switch( orientation ) - { - case 0: c1 = Cube::CornerIndex( 0 , y , z ) , c2 = Cube::CornerIndex( 1 , y , z ) ; break; - case 1: c1 = Cube::CornerIndex( y , 0 , z ) , c2 = Cube::CornerIndex( y , 1 , z ) ; break; - } - int cIndex1 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fe]; - int cIndex2 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c2 )[fe]; - if( cSliceValues.edgeSet[cIndex1] != cSliceValues.edgeSet[cIndex2] ) - { - long long key; - if( cSliceValues.edgeSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; - else key = cSliceValues.edgeKeys[cIndex2]; - std::pair< int , Vertex > vPair = cSliceValues.edgeVertexMap.find( key )->second; -#pragma omp critical ( copy_finer_edge_keys ) - pSliceValues.edgeVertexMap[key] = vPair; - pSliceValues.edgeKeys[pIndex] = key; - pSliceValues.edgeSet[pIndex] = 1; - } - else if( cSliceValues.edgeSet[cIndex1] && cSliceValues.edgeSet[cIndex2] ) - { - long long key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; -#pragma omp critical ( set_edge_pairs ) - pSliceValues.vertexPairMap[ key1 ] = key2 , pSliceValues.vertexPairMap[ key2 ] = key1; - - const TreeOctNode* node = _sNodes.treeNodes[i]; - int _depth = depth , _slice = slice; - while( node->parent && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slice); -#pragma omp critical ( set_edge_pairs ) - _pSliceValues.vertexPairMap[ key1 ] = key2 , _pSliceValues.vertexPairMap[ key2 ] = key1; - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::CopyFinerXSliceIsoEdgeKeys( int depth , int slab , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - XSliceValues< Vertex >& pSliceValues = slabValues[depth ].xSliceValues(slab); - XSliceValues< Vertex >& cSliceValues0 = slabValues[depth+1].xSliceValues( (slab<<1)|0 ); - XSliceValues< Vertex >& cSliceValues1 = slabValues[depth+1].xSliceValues( (slab<<1)|1 ); - typename SortedTreeNodes::XSliceTableData& pSliceData = pSliceValues.xSliceData; - typename SortedTreeNodes::XSliceTableData& cSliceData0 = cSliceValues0.xSliceData; - typename SortedTreeNodes::XSliceTableData& cSliceData1 = cSliceValues1.xSliceData; -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth] + _sNodes.sliceOffsets[depth][slab] ; i<_sNodes.nodeCount[depth] + _sNodes.sliceOffsets[depth][slab+1] ; i++ ) - if( _sNodes.treeNodes[i]->children ) - { - typename SortedTreeNodes::SquareCornerIndices& pIndices = pSliceData.edgeIndices( i ); - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int fc = Square::CornerIndex( x , y ); - int pIndex = pIndices[fc]; - if( !pSliceValues.edgeSet[pIndex] ) - { - int c0 = Cube::CornerIndex( x , y , 0 ) , c1 = Cube::CornerIndex( x , y , 1 ); - int cIndex0 = cSliceData0.edgeIndices( _sNodes.treeNodes[i]->children + c0 )[fc]; - int cIndex1 = cSliceData1.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fc]; - if( cSliceValues0.edgeSet[cIndex0] != cSliceValues1.edgeSet[cIndex1] ) - { - long long key; - std::pair< int , Vertex > vPair; - if( cSliceValues0.edgeSet[cIndex0] ) key = cSliceValues0.edgeKeys[cIndex0] , vPair = cSliceValues0.edgeVertexMap.find( key )->second; - else key = cSliceValues1.edgeKeys[cIndex1] , vPair = cSliceValues1.edgeVertexMap.find( key )->second; -#pragma omp critical ( copy_finer_x_edge_keys ) - pSliceValues.edgeVertexMap[key] = vPair; - pSliceValues.edgeKeys[ pIndex ] = key; - pSliceValues.edgeSet[ pIndex ] = 1; - } - else if( cSliceValues0.edgeSet[cIndex0] && cSliceValues1.edgeSet[cIndex1] ) - { - long long key0 = cSliceValues0.edgeKeys[cIndex0] , key1 = cSliceValues1.edgeKeys[cIndex1]; -#pragma omp critical ( set_x_edge_pairs ) - pSliceValues.vertexPairMap[ key0 ] = key1 , pSliceValues.vertexPairMap[ key1 ] = key0; - const TreeOctNode* node = _sNodes.treeNodes[i]; - int _depth = depth , _slab = slab , ce = Cube::CornerIndex( 2 , x , y ); - while( node->parent && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) - { - node = node->parent , _depth-- , _slab>>= 1; - SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slab); -#pragma omp critical ( set_x_edge_pairs ) - _pSliceValues.vertexPairMap[ key0 ] = key1 , _pSliceValues.vertexPairMap[ key1 ] = key0; - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::SetSliceIsoEdges( int depth , int slice , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) SetSliceIsoEdges( depth , slice , 1 , slabValues , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::SetSliceIsoEdges( int depth , int slice , int z , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree< Real >::template SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - int idx = i - sValues.sliceData.nodeOffset; - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - const typename SortedTreeNodes::SquareFaceIndices& fIndices = sValues.sliceData.faceIndices( leaf ); - unsigned char mcIndex = sValues.mcIndices[idx]; - if( !sValues.faceSet[ fIndices[0] ] ) - { - neighborKey.getNeighbors( leaf ); - if( !neighborKey.neighbors[depth].neighbors[1][1][2*z] || !neighborKey.neighbors[depth].neighbors[1][1][2*z]->children ) - { - FaceEdges fe; - fe.count = MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); - for( int j=0 ; j edges; - edges.resize( fe.count ); - for( int j=0 ; jparent && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - if( neighborKey.neighbors[_depth].neighbors[1][1][2*z] && neighborKey.neighbors[_depth].neighbors[1][1][2*z]->children ) break; - long long key = VertexData::FaceIndex( node , f , _sNodes.maxDepth ); -#pragma omp critical( add_iso_edge_access ) - { - typename Octree< Real >::template SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); - typename hash_map< long long , std::vector< IsoEdge > >::iterator iter = _sValues.faceEdgeMap.find(key); - if( iter==_sValues.faceEdgeMap.end() ) _sValues.faceEdgeMap[key] = edges; - else for( int j=0 ; jsecond.push_back( fe.edges[j] ); - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::SetXSliceIsoEdges( int depth , int slab , std::vector< SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree< Real >::template SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); - typename Octree< Real >::template SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); - typename Octree< Real >::template XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); - - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; ichildren ) - { - const typename SortedTreeNodes::SquareCornerIndices& cIndices = xValues.xSliceData.edgeIndices( leaf ); - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = xValues.xSliceData.faceIndices( leaf ); - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); - { - neighborKey.getNeighbors( leaf ); - for( int o=0 ; o<2 ; o++ ) for( int x=0 ; x<2 ; x++ ) - { - int e = Square::EdgeIndex( o , x ); - int f = Cube::FaceIndex( 1-o , x ); - unsigned char _mcIndex = MarchingCubes::GetFaceIndex( mcIndex , f ); - int xx = o==1 ? 2*x : 1 , yy = o==0 ? 2*x : 1 , zz = 1; - if( !xValues.faceSet[ eIndices[e] ] && ( !neighborKey.neighbors[depth].neighbors[xx][yy][zz] || !neighborKey.neighbors[depth].neighbors[xx][yy][zz]->children ) ) - { - FaceEdges fe; - fe.count = MarchingSquares::AddEdgeIndices( _mcIndex , isoEdges ); - for( int j=0 ; j::template SliceValues< Vertex >& sValues = (_x==0) ? bValues : fValues; - int idx = sValues.sliceData.edgeIndices(i)[ Square::EdgeIndex(o,x) ]; - if( !sValues.edgeSet[ idx ] ) fprintf( stderr , "[ERROR] Edge not set 5: %d / %d\n" , slab , 1< edges; - edges.resize( fe.count ); - for( int j=0 ; jparent && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) - { - node = node->parent , _depth-- , _slab >>= 1; - if( neighborKey.neighbors[_depth].neighbors[xx][yy][zz] && neighborKey.neighbors[_depth].neighbors[xx][yy][zz]->children ) break; - long long key = VertexData::FaceIndex( node , f , _sNodes.maxDepth ); -#pragma omp critical( add_x_iso_edge_access ) - { - typename Octree< Real >::template XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); - typename hash_map< long long , std::vector< IsoEdge > >::iterator iter = _xValues.faceEdgeMap.find(key); - if( iter==_xValues.faceEdgeMap.end() ) _xValues.faceEdgeMap[key] = edges; - else for( int j=0 ; jsecond.push_back( fe.edges[j] ); - } - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -int Octree< Real >::SetIsoSurface( int depth , int offset , const SliceValues< Vertex >& bValues , const SliceValues< Vertex >& fValues , const XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ) -{ - std::vector< std::pair< int , Vertex > > polygon; - std::vector< typename TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - std::vector< std::vector< IsoEdge > > edgess( std::max< int >( 1 , threads ) ); - for( int i=0 ; i& edges = edgess[ omp_get_thread_num() ]; - TreeOctNode* leaf = _sNodes.treeNodes[i]; - if( !leaf->children ) - { - edges.clear(); - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); - // [WARNING] Just because the node looks empty doesn't mean it doesn't get eges from finer neighbors - { - // Gather the edges from the faces (with the correct orientation) - for( int f=0 ; f& sValues = (o==0) ? bValues : fValues; - int fIdx = sValues.sliceData.faceIndices(i)[0]; - if( sValues.faceSet[fIdx] ) - { - const FaceEdges& fe = sValues.faceEdges[ fIdx ]; - for( int j=0 ; j >::const_iterator iter = sValues.faceEdgeMap.find( key ); - if( iter!=sValues.faceEdgeMap.end() ) - { - const std::vector< IsoEdge >& _edges = iter->second; - for( int j=0 ; j<_edges.size() ; j++ ) edges.push_back( IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); - } - else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); - } - } - else - { - int fIdx = xValues.xSliceData.faceIndices(i)[ Square::EdgeIndex( 1-d , o ) ]; - if( xValues.faceSet[fIdx] ) - { - const FaceEdges& fe = xValues.faceEdges[ fIdx ]; - for( int j=0 ; j >::const_iterator iter = xValues.faceEdgeMap.find( key ); - if( iter!=xValues.faceEdgeMap.end() ) - { - const std::vector< IsoEdge >& _edges = iter->second; - for( int j=0 ; j<_edges.size() ; j++ ) edges.push_back( IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); - } - else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); - } - } - } - // Get the edge loops - std::vector< std::vector< long long > > loops; - while( edges.size() ) - { - loops.resize( loops.size()+1 ); - IsoEdge edge = edges.back(); - edges.pop_back(); - long long start = edge[0] , current = edge[1]; - while( current!=start ) - { - int idx; - for( idx=0 ; idx::const_iterator iter; - if ( (iter=bValues.vertexPairMap.find(current))!=bValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else if( (iter=fValues.vertexPairMap.find(current))!=fValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else fprintf( stderr , "[ERROR] Failed to close loop @ depth %d / %d (%d): %lld\n" , depth , _sNodes.maxDepth-1 , i , current ) , exit( 0 ); - } - else - { - loops.back().push_back( current ); - current = edges[idx][1]; - edges[idx] = edges.back() , edges.pop_back(); - } - } - loops.back().push_back( start ); - } - // Add the loops to the mesh - for( int j=0 ; j > polygon( loops[j].size() ); - for( int k=0 ; k >::const_iterator iter; - if ( ( iter=bValues.edgeVertexMap.find( key ) )!=bValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else if( ( iter=fValues.edgeVertexMap.find( key ) )!=fValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else fprintf( stderr , "[ERROR] Couldn't find vertex in edge map\n" ) , exit( 0 ); - } - AddIsoPolygons( mesh , polygon , polygonMesh , addBarycenter , vOffset ); - } - } - } - } -} -template< class Real > void SetIsoVertexValue( PlyVertex< float >& vertex , Real value ){ ; } -template< class Real > void SetIsoVertexValue( PlyValueVertex< float >& vertex , Real value ){ vertex.value = float(value); } -template< class Real > -template< class Vertex > -bool Octree< Real >::GetIsoVertex( ConstPointer( Real ) kernelDensityWeights , Real isoValue , typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int edgeIndex , int z , const SliceValues< Vertex >& sValues , Vertex& vertex ) -{ - Point3D< Real > position; - int c0 , c1; - Square::EdgeCorners( edgeIndex , c0 , c1 ); - - Real x0 , x1; - Point3D< Real > n0 , n1; - const typename SortedTreeNodes::SquareCornerIndices& idx = sValues.sliceData.cornerIndices( node ); - x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; - if( sValues.cornerNormals ) n0 = sValues.cornerNormals[idx[c0]] , n1 = sValues.cornerNormals[idx[c1]]; - - int o , y; - Square::FactorEdgeIndex( edgeIndex , o , y ); - - Point3D< Real > c; - Real center , width; - node->centerAndWidth( c , width ); - center = c[o]; - for( int i=0 ; i P; - P.coefficients[0] = x0; - P.coefficients[1] = dx0; - P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; - - Real averageRoot=0; - double roots[2]; - int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , EPSILON ); - for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += Real( roots[i] ) , rCount++; - if( rCount && sValues.cornerNormals ) averageRoot /= rCount; - else averageRoot = Real( ( x0-isoValue ) / ( x0-x1 ) ); - if( averageRoot<0 || averageRoot>1 ) - { - fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); - fprintf( stderr , "\t(%f %f) , (%f %f) (%f)\n" , x0 , x1 , dx0 , dx1 , isoValue ); - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[o] = Real( center - width/2 + width*averageRoot ); - vertex.point = position; - if( kernelDensityWeights ) - { - Real depth , weight; - const TreeOctNode* temp = node; - while( temp->depth()>_splatDepth ) temp=temp->parent; - GetSampleDepthAndWeight( kernelDensityWeights , temp , position , neighborKey3 , _samplesPerNode , depth , weight ); - SetIsoVertexValue( vertex , depth ); - } - return true; -} -template< class Real > -template< class Vertex > -bool Octree< Real >::GetIsoVertex( ConstPointer( Real ) kernelDensityWeights , Real isoValue , typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int cornerIndex , const SliceValues< Vertex >& bValues , const SliceValues< Vertex >& fValues , Vertex& vertex ) -{ - Point3D< Real > position; - - Real x0 , x1; - Point3D< Real > n0 , n1; - const typename SortedTreeNodes::SquareCornerIndices& idx0 = bValues.sliceData.cornerIndices( node ); - const typename SortedTreeNodes::SquareCornerIndices& idx1 = fValues.sliceData.cornerIndices( node ); - x0 = bValues.cornerValues[ idx0[cornerIndex] ] , x1 = fValues.cornerValues[ idx1[cornerIndex] ]; - if( bValues.cornerNormals || fValues.cornerNormals ) n0 = bValues.cornerNormals[ idx0[cornerIndex] ] , n1 = fValues.cornerNormals[ idx1[cornerIndex] ]; - - int x , y; - Square::FactorCornerIndex( cornerIndex , x , y ); - - Point3D< Real > c; - Real center , width; - node->centerAndWidth( c , width ); - center = c[2]; - for( int i=0 ; i P; - P.coefficients[0] = x0; - P.coefficients[1] = dx0; - P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; - - Real averageRoot=0; - double roots[2]; - int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , EPSILON ); - for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += Real( roots[i] ) , rCount++; - if( rCount && bValues.cornerNormals && fValues.cornerNormals ) averageRoot /= rCount; - else averageRoot = Real( ( x0-isoValue ) / ( x0-x1 ) ); - if( averageRoot<0 || averageRoot>1 ) - { - fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); - fprintf( stderr , "\t(%f %f) , (%f %f) (%f)\n" , x0 , x1 , dx0 , dx1 , isoValue ); - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[2] = Real( center - width/2 + width*averageRoot ); - vertex.point = position; - if( kernelDensityWeights ) - { - Real depth , weight; - const TreeOctNode* temp = node; - while( temp->depth()>_splatDepth ) temp=temp->parent; - GetSampleDepthAndWeight( kernelDensityWeights , temp , position , neighborKey3 , _samplesPerNode , depth , weight ); - SetIsoVertexValue( vertex , depth ); - } - return true; -} - -template< class Real > -template< class Vertex > -int Octree< Real >::AddIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ) -{ - if( polygonMesh ) - { - std::vector< int > vertices( polygon.size() ); - for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[polygon.size()-1-i].first; - mesh.addPolygon_s( vertices ); - return 1; - } - if( polygon.size()>3 ) - { - bool isCoplanar = false; - std::vector< int > triangle( 3 ); - - if( addBarycenter ) - for( int i=0 ; i<(int)polygon.size() ; i++ ) - for( int j=0 ; j MAT; - std::vector< Point3D< Real > > vertices; - std::vector< TriangleIndex > triangles; - vertices.resize( polygon.size() ); - // Add the points - for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[i].second.point; - MAT.GetTriangulation( vertices , triangles ); - for( int i=0 ; i<(int)triangles.size() ; i++ ) - { - for( int j=0 ; j<3 ; j++ ) triangle[2-j] = polygon[ triangles[i].idx[j] ].first; - mesh.addPolygon_s( triangle ); - } - } - } - else if( polygon.size()==3 ) - { - std::vector< int > vertices( 3 ); - for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; - mesh.addPolygon_s( vertices ); - } - return (int)polygon.size()-2; -} diff --git a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.SortedTreeNodes.inl b/src/scanner/PoissonRecon/Src/MultiGridOctreeData.SortedTreeNodes.inl deleted file mode 100755 index e6e3de6..0000000 --- a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.SortedTreeNodes.inl +++ /dev/null @@ -1,348 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -///////////////////// -// SortedTreeNodes // -///////////////////// -SortedTreeNodes::SortedTreeNodes( void ) -{ - nodeCount = NULL; - treeNodes = NullPointer< TreeOctNode* >(); - maxDepth = 0; - sliceOffsets = NullPointer< Pointer( int ) >(); -} -SortedTreeNodes::~SortedTreeNodes( void ) -{ - if( nodeCount ) delete[] nodeCount , nodeCount = NULL; - if( treeNodes ) DeletePointer( treeNodes ); - if( sliceOffsets ) - { - for( int d=0 ; d* map ) -{ - if( nodeCount ) delete[] nodeCount; - if( treeNodes ) DeletePointer( treeNodes ); - if( sliceOffsets ) - { - for( int d=0 ; d( root.nodes() ); - - int startDepth = 0; - nodeCount[0] = 0 , nodeCount[1] = 1; - treeNodes[0] = &root; - for( int d=startDepth+1 ; dchildren ) for( int c=0 ; c<8 ; c++ ) treeNodes[ nodeCount[d+1]++ ] = temp->children + c; - } - } - _sortByZCoordinate(); - if( map ) - { - map->resize( nodeCount[maxDepth] ); - for( int i=0 ; inodeData.nodeIndex; - } - for( int i=0 ; inodeData.nodeIndex = i; -} -int SortedTreeNodes::Slices( int depth ){ return 1< SortedTreeNodes::sliceSpan( int depth , int off , int d ) const -{ - int dd = d-depth; - return std::pair< int , int >( nodeCount[d] + sliceOffsets[d][off<( maxDepth ); - for( int d=0 ; d( slices+1 ); - memset( sliceOffsets[d] , 0 , sizeof(int)*(slices+1) ); - for( int i=nodeCount[d] ; idepthAndOffset( _d , _off ); - sliceOffsets[d][ _off[2] ]++; - } - for( int i=1 ; i=1 ; i-- ) sliceOffsets[d][i] = sliceOffsets[d][i-1]; - sliceOffsets[d][0] = 0; - } - for( TreeOctNode* node=treeNodes[0]->nextNode() ; node ; node=treeNodes[0]->nextNode( node ) ) - { - int d , off[3]; - node->depthAndOffset( d , off ); - treeNodes[ nodeCount[d] + sliceOffsets[d][ off[2] ] ] = node; - sliceOffsets[d][ off[2] ]++; - } - for( int d=0 ; d=1 ; i-- ) sliceOffsets[d][i] = sliceOffsets[d][i-1]; - sliceOffsets[d][0] = 0; - } -} -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) { return cTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) const { return cTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } - - -void SortedTreeNodes::setSliceTableData( SliceTableData& sData , int depth , int offset , int threads ) const -{ - if( offset<0 || offset>(1< span( nodeCount[depth] + sliceOffsets[depth][ std::max(0,offset-1) ] , nodeCount[depth] + sliceOffsets[depth][ std::min(1< neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepthAndOffset( d , off ); - int z; - if ( off[2]==offset-1 ) z = 1; - else if( off[2]==offset ) z = 0; - else fprintf( stderr , "[ERROR] Node out of bounds: %d %d\n" , offset , off[2] ) , exit( 0 ); - // Process the corners - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int c = Cube::CornerIndex( x , y , z ); - int fc = Square::CornerIndex( x , y ); - bool cornerOwner = true; - int ac = Cube::AntipodalCornerIndex(c); // The index of the node relative to the corner - for( int cc=0 ; cc=(1< span( nodeCount[depth] + sliceOffsets[depth][offset] , nodeCount[depth] + sliceOffsets[depth][offset+1] ); - sData.nodeOffset = span.first; - sData.nodeCount = span.second - span.first; - - sData._eMap.clear() , sData._fMap.clear(); - sData._eMap.resize( sData.nodeCount * Square::CORNERS , 0 ) , sData._fMap.resize( sData.nodeCount * Square::EDGES , 0 ); - sData.eTable.resize( sData.nodeCount ) , sData.fTable.resize( sData.nodeCount ); - std::vector< TreeOctNode::ConstNeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepthAndOffset( d , off ); - // Process the edges - int o=2; - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int fc = Square::CornerIndex( x , y ); - bool edgeOwner = true; - - int ac = Square::AntipodalCornerIndex( Square::CornerIndex( x , y ) ); - for( int cc=0 ; cc - // b_1[i] = < \nabla B_i(p) , V(p) > - // 2] Formulate this as a Poisson equation: - // \sum_i x_i \Delta B_i(p) = \nabla \cdot V(p) - // which is solved by the system A_2x = b_2 where: - // A_2[i,j] = - < \Delta B_i(p) , B_j(p) > - // b_2[i] = - < B_i(p) , \nabla \cdot V(p) > - // Although the two system matrices should be the same (assuming that the B_i satisfy dirichlet/neumann boundary conditions) - // the constraint vectors can differ when V does not satisfy the Neumann boundary conditions: - // A_1[i,j] = \int_R < \nabla B_i(p) , \nabla B_j(p) > - // = \int_R [ \nabla \cdot ( B_i(p) \nabla B_j(p) ) - B_i(p) \Delta B_j(p) ] - // = \int_dR < N(p) , B_i(p) \nabla B_j(p) > + A_2[i,j] - // and the first integral is zero if either f_i is zero on the boundary dR or the derivative of B_i across the boundary is zero. - // However, for the constraints we have: - // b_1(i) = \int_R < \nabla B_i(p) , V(p) > - // = \int_R [ \nabla \cdot ( B_i(p) V(p) ) - B_i(p) \nabla \cdot V(p) ] - // = \int_dR < N(p) , B_i(p) V(p) > + b_2[i] - // In particular, this implies that if the B_i satisfy the Neumann boundary conditions (rather than Dirichlet), - // and V is not zero across the boundary, then the two constraints are different. - // Forcing the < V(p) , N(p) > = 0 on the boundary, by killing off the component of the vector-field in the normal direction - // (FORCE_NEUMANN_FIELD), makes the two systems equal, and the value of this flag should be immaterial. - // Note that under interpretation 1, we have: - // \sum_i b_1(i) = < \nabla \sum_ i B_i(p) , V(p) > = 0 - // because the B_i's sum to one. However, in general, we could have - // \sum_i b_2(i) \neq 0. - // This could cause trouble because the constant functions are in the kernel of the matrix A, so CG will misbehave if the constraint - // has a non-zero DC term. (Again, forcing < V(p) , N(p) > = 0 along the boundary resolves this problem.) - -#define FORCE_NEUMANN_FIELD 1 // This flag forces the normal component across the boundary of the integration domain to be zero. - // This should be enabled if GRADIENT_DOMAIN_SOLUTION is not, so that CG doesn't run into trouble. - -#define ROBERTO_TOLDO_FIX 1 - -#if !FORCE_NEUMANN_FIELD -#pragma message( "[WARNING] Not zeroing out normal component on boundary" ) -#endif // !FORCE_NEUMANN_FIELD - -#include "Hash.h" -#include "BSplineData.h" -#include "PointStream.h" - -#ifndef _OPENMP -int omp_get_num_procs( void ){ return 1; } -int omp_get_thread_num( void ){ return 0; } -#endif // _OPENMP - -class TreeNodeData -{ -public: - static int NodeCount; - int nodeIndex; - - TreeNodeData( void ); - ~TreeNodeData( void ); -}; - -class VertexData -{ - typedef OctNode< TreeNodeData > TreeOctNode; -public: - static const int VERTEX_COORDINATE_SHIFT = ( sizeof( long long ) * 8 ) / 3; - static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth , int index[DIMENSION] ); - static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth ); - static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth,int index[DIMENSION] ); - static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth ); - static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth , int index[DIMENSION] ); - static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth ); - static long long CenterIndex( const TreeOctNode* node , int maxDepth , int index[DIMENSION] ); - static long long CenterIndex( const TreeOctNode* node , int maxDepth ); - static long long CornerIndex( int depth , const int offSet[DIMENSION] , int cIndex , int maxDepth , int index[DIMENSION] ); - static long long CenterIndex( int depth , const int offSet[DIMENSION] , int maxDepth , int index[DIMENSION] ); - static long long CornerIndexKey( const int index[DIMENSION] ); -}; - -class SortedTreeNodes -{ - typedef OctNode< TreeNodeData > TreeOctNode; -protected: - void _sortByZCoordinate( void ); -public: - Pointer( TreeOctNode* ) treeNodes; - int *nodeCount; - int maxDepth; - SortedTreeNodes( void ); - ~SortedTreeNodes( void ); - void set( TreeOctNode& root , std::vector< int >* map ); - Pointer( Pointer( int ) ) sliceOffsets; - static int Slices( int depth ); - std::pair< int , int > sliceSpan( int depth , int off , int d ) const; - - template< int Indices > - struct _Indices - { - int idx[Indices]; - _Indices( void ){ memset( idx , -1 , sizeof( int ) * Indices ); } - int& operator[] ( int i ) { return idx[i]; } - const int& operator[] ( int i ) const { return idx[i]; } - }; - typedef _Indices< Square::CORNERS > SquareCornerIndices; - typedef _Indices< Square::EDGES > SquareEdgeIndices; - typedef _Indices< Square::FACES > SquareFaceIndices; - - struct SliceTableData - { - std::vector< SquareCornerIndices > cTable; - std::vector< SquareEdgeIndices > eTable; - std::vector< SquareFaceIndices > fTable; - int cCount , eCount , fCount , nodeOffset , nodeCount; - SliceTableData( void ){ fCount , eCount = cCount = 0; } - ~SliceTableData( void ){ clear(); } - void clear( void ) { cTable.clear() , eTable.clear() , fTable.clear() , fCount = eCount = cCount = 0; } - SquareCornerIndices& cornerIndices( const TreeOctNode* node ); - SquareCornerIndices& cornerIndices( int idx ); - const SquareCornerIndices& cornerIndices( const TreeOctNode* node ) const; - const SquareCornerIndices& cornerIndices( int idx ) const; - SquareEdgeIndices& edgeIndices( const TreeOctNode* node ); - SquareEdgeIndices& edgeIndices( int idx ); - const SquareEdgeIndices& edgeIndices( const TreeOctNode* node ) const; - const SquareEdgeIndices& edgeIndices( int idx ) const; - SquareFaceIndices& faceIndices( const TreeOctNode* node ); - SquareFaceIndices& faceIndices( int idx ); - const SquareFaceIndices& faceIndices( const TreeOctNode* node ) const; - const SquareFaceIndices& faceIndices( int idx ) const; - protected: - std::vector< int > _cMap , _eMap , _fMap; - friend class SortedTreeNodes; - }; - struct XSliceTableData - { - std::vector< SquareCornerIndices > eTable; - std::vector< SquareEdgeIndices > fTable; - int fCount , eCount , nodeOffset , nodeCount; - XSliceTableData( void ){ fCount , eCount = 0; } - ~XSliceTableData( void ){ clear(); } - void clear( void ) { fTable.clear() , eTable.clear() , fCount = eCount = 0; } - SquareCornerIndices& edgeIndices( const TreeOctNode* node ); - SquareCornerIndices& edgeIndices( int idx ); - const SquareCornerIndices& edgeIndices( const TreeOctNode* node ) const; - const SquareCornerIndices& edgeIndices( int idx ) const; - SquareEdgeIndices& faceIndices( const TreeOctNode* node ); - SquareEdgeIndices& faceIndices( int idx ); - const SquareEdgeIndices& faceIndices( const TreeOctNode* node ) const; - const SquareEdgeIndices& faceIndices( int idx ) const; - protected: - std::vector< int > _eMap , _fMap; - friend class SortedTreeNodes; - }; - void setSliceTableData ( SliceTableData& sData , int depth , int offset , int threads ) const; - void setXSliceTableData( XSliceTableData& sData , int depth , int offset , int threads ) const; -}; - - -template< class Real > -class Octree -{ - typedef OctNode< TreeNodeData > TreeOctNode; - struct _PointData - { - Point3D< Real > position; - Real weightedCoarserValue; - Real weight; - _PointData( Point3D< Real > p=Point3D< Real >() , Real w=0 ) { position = p , weight = w , weightedCoarserValue = Real(0); } - }; -public: - struct NormalInfo - { - std::vector< int > normalIndices; - std::vector< Point3D< Real > > normals; - int normalIndex( const TreeOctNode* node ) const { return node->nodeData.nodeIndex>=normalIndices.size() ? -1 : normalIndices[ node->nodeData.nodeIndex ]; } - }; - struct PointInfo - { - std::vector< int > pointIndices; - std::vector< _PointData > points; - int pointIndex( const TreeOctNode* node ) const { return node->nodeData.nodeIndex>=pointIndices.size() ? -1 : pointIndices[ node->nodeData.nodeIndex ]; } - }; -protected: - SortedTreeNodes _sNodes; - Real _samplesPerNode; - int _splatDepth; - int _minDepth; - int _fullDepth; - bool _constrainValues; - int _boundaryType; - Real _scale; - Point3D< Real > _center; - std::vector< int > _pointCount; - Real _normalSmooth; - BSplineData< 2 > _fData; - - bool _InBounds( Point3D< Real > ) const; - - double GetLaplacian ( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[3] , const int off2[3] , bool childParent ) const; - double GetDivergence1( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[3] , const int off2[3] , bool childParent , const Point3D< Real >& normal1 ) const; - double GetDivergence2( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[3] , const int off2[3] , bool childParent , const Point3D< Real >& normal2 ) const; - Point3D< double > GetDivergence1( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[3] , const int off2[3] , bool childParent ) const; - Point3D< double > GetDivergence2( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[3] , const int off2[3] , bool childParent ) const; - - template< class C , int N > struct Stencil{ C values[N][N][N]; }; - struct CenterValueStencil - { - Stencil< double , 3 > stencil; - Stencil< double , 3 > stencils[8]; - }; - struct CornerValueStencil - { - Stencil< double , 3 > stencil[8]; - Stencil< double , 3 > stencils[8][8]; - }; - struct CornerNormalStencil - { - Stencil< Point3D< double > , 3 > stencil[8]; - Stencil< Point3D< double > , 3 > stencils[8][8]; - }; - - void _setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const; - int _SolveSystemGS( PointInfo& pointInfo , int depth , const typename BSplineData< 2 >::Integrator& integrator , const SortedTreeNodes& sNodes , Pointer( Real ) solution , Pointer( Real ) constraints , Pointer( Real ) metSolutionConstraints , int iters , bool coarseToFine , bool showResidual=false , double* bNorm2=NULL , double* inRNorm2=NULL , double* outRNorm2=NULL , bool forceSilent=false ); - int _SolveSystemCG( PointInfo& pointInfo , int depth , const typename BSplineData< 2 >::Integrator& integrator , const SortedTreeNodes& sNodes , Pointer( Real ) solution , Pointer( Real ) constraints , Pointer( Real ) metSolutionConstraints , int iters , bool coarseToFine , bool showResidual=false , double* bNorm2=NULL , double* inRNorm2=NULL , double* outRNorm2=NULL , double accuracy=0 ); - - int GetMatrixRowSize( const typename TreeOctNode::Neighbors5& neighbors5 , bool symmetric ) const; - int SetMatrixRow( const PointInfo& pointInfo , const typename TreeOctNode::Neighbors5& neighbors5 , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineData< 2 >::Integrator& integrator , const Stencil< double , 5 >& stencil , bool symmetric ) const; - - void SetDivergenceStencil ( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< Point3D< double > , 5 >& stencil , bool scatter ) const; - void SetDivergenceStencils( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< Point3D< double > , 5 > stencil[2][2][2] , bool scatter ) const; - void SetLaplacianStencil ( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< double , 5 >& stencil ) const; - void SetLaplacianStencils ( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< double , 5 > stencil[2][2][2] ) const; - void SetCenterEvaluationStencil ( const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , int depth , Stencil< double , 3 >& stencil ) const; - void SetCenterEvaluationStencils( const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , int depth , Stencil< double , 3 > stencil[8] ) const; - void SetCornerEvaluationStencil ( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< double , 3 > stencil [8] ) const; - void SetCornerEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< double , 3 > stencils[8][8] ) const; - void SetCornerNormalEvaluationStencil ( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 3 > stencil [8] ) const; - void SetCornerNormalEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 3 > stencils[8][8] ) const; - void SetCornerNormalEvaluationStencil ( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 5 > stencil [8] ) const; - void SetCornerNormalEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 5 > stencils[8][8] ) const; - - static void UpdateCoarserSupportBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ); - - void UpdateConstraintsFromCoarser( const PointInfo& pointInfo , const typename TreeOctNode::Neighbors5& neighbors5 , const typename TreeOctNode::Neighbors5& pNeighbors5 , TreeOctNode* node , Pointer( Real ) constraints , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::Integrator& integrator , const Stencil< double , 5 >& stencil ) const; - // Updates the constraints @(depth-1) based on the solution coefficients @(depth) - void UpdateConstraintsFromFiner( const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) fineSolution , Pointer( Real ) coarseConstraints ) const; - // Evaluate the points @(depth) using coefficients @(depth-1) - void SetPointValuesFromCoarser( PointInfo& pointInfo , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) coarseCoefficients ); - // Evalutes the solution @(depth) at the points @(depth-1) and updates the met constraints @(depth-1) - void SetPointConstraintsFromFiner( const PointInfo& pointInfo , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) finerCoefficients , Pointer( Real ) metConstraints) const; - Real _WeightedCoarserFunctionValue( const _PointData& pointData , const typename TreeOctNode::NeighborKey3& neighborKey3 , const TreeOctNode* node , ConstPointer( Real ) coarseCoefficients ) const; - Real _WeightedFinerFunctionValue ( const _PointData& pointData , const typename TreeOctNode::NeighborKey3& neighborKey3 , const TreeOctNode* node , ConstPointer( Real ) finerCoefficients ) const; - - // Down samples constraints @(depth) to constraints @(depth-1) - template< class C > void DownSample( int depth , const SortedTreeNodes& sNodes , ConstPointer( C ) fineConstraints , Pointer( C ) coarseConstraints ) const; - // Up samples solution @(depth-1) to solution @(depth) - template< class C > void UpSample ( int depth , const SortedTreeNodes& sNodes , ConstPointer( C ) coarseCoefficients , Pointer( C ) fineCoefficients ) const; - int GetSliceMatrixAndUpdateConstraints( const PointInfo& pointInfo , SparseMatrix< Real >& matrix , Pointer( Real ) constraints , const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) metSolution , bool coarseToFine , int nStart , int nEnd ); - int GetMatrixAndUpdateConstraints( const PointInfo& pointInfo , SparseSymmetricMatrix< Real >& matrix , Pointer( Real ) constraints , const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) metSolution , bool coarseToFine ); - - - int UpdateWeightContribution( std::vector< Real >& kernelDensityWeights , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , Real weight=Real(1.0) ); - Real GetSampleWeight( ConstPointer( Real ) kernelDensityWeight , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , int splatDepth ); - Real GetSampleWeight( ConstPointer( Real ) kernelDensityWeight , const TreeOctNode* node , const Point3D& position , typename TreeOctNode::ConstNeighborKey3& neighborKey ); - void GetSampleDepthAndWeight( ConstPointer( Real ) kernelDensityWeight , const TreeOctNode* node , const Point3D& position , typename TreeOctNode::ConstNeighborKey3& neighborKey , Real samplesPerNode , Real& depth , Real& weight ); - Real GetSampleWeight( ConstPointer( Real ) kernelDensityWeight , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey ); - void GetSampleDepthAndWeight( ConstPointer( Real ) kernelDensityWeight , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , Real samplesPerNode , Real& depth , Real& weight ); - int SplatOrientedPoint( ConstPointer( Real ) kernelDensityWeights , TreeOctNode* node , const Point3D& point , const Point3D< Real >& normal , NormalInfo& normalInfo , typename TreeOctNode::NeighborKey3& neighborKey ); - Real SplatOrientedPoint( ConstPointer( Real ) kernelDensityWeights , const Point3D& point , const Point3D& normal , NormalInfo& normalInfo , typename TreeOctNode::NeighborKey3& neighborKey , int kernelDepth , Real samplesPerNode , int minDepth , int maxDepth ); - - int HasNormals( TreeOctNode* node , const NormalInfo& normalInfo ); - - /////////////////////////// - // Iso-Surfacing Methods // - /////////////////////////// - struct IsoEdge - { - long long edges[2]; - IsoEdge( void ){ edges[0] = edges[1] = 0; } - IsoEdge( long long v1 , long long v2 ){ edges[0] = v1 , edges[1] = v2; } - long long& operator[]( int idx ){ return edges[idx]; } - const long long& operator[]( int idx ) const { return edges[idx]; } - }; - struct FaceEdges - { - IsoEdge edges[2]; - int count; - }; - template< class Vertex > - struct SliceValues - { - typename SortedTreeNodes::SliceTableData sliceData; - Pointer( Real ) cornerValues ; Pointer( Point3D< Real > ) cornerNormals ; Pointer( char ) cornerSet; - Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( FaceEdges ) faceEdges ; Pointer( char ) faceSet; - Pointer( char ) mcIndices; - hash_map< long long , std::vector< IsoEdge > > faceEdgeMap; - hash_map< long long , std::pair< int , Vertex > > edgeVertexMap; - hash_map< long long , long long > vertexPairMap; - - SliceValues( void ); - ~SliceValues( void ); - void reset( bool nonLinearFit ); - protected: - int _oldCCount , _oldECount , _oldFCount , _oldNCount; - }; - template< class Vertex > - struct XSliceValues - { - typename SortedTreeNodes::XSliceTableData xSliceData; - Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( FaceEdges ) faceEdges ; Pointer( char ) faceSet; - hash_map< long long , std::vector< IsoEdge > > faceEdgeMap; - hash_map< long long , std::pair< int , Vertex > > edgeVertexMap; - hash_map< long long , long long > vertexPairMap; - - XSliceValues( void ); - ~XSliceValues( void ); - void reset( void ); - protected: - int _oldECount , _oldFCount; - }; - template< class Vertex > - struct SlabValues - { - XSliceValues< Vertex > _xSliceValues[2]; - SliceValues< Vertex > _sliceValues[2]; - SliceValues< Vertex >& sliceValues( int idx ){ return _sliceValues[idx&1]; } - const SliceValues< Vertex >& sliceValues( int idx ) const { return _sliceValues[idx&1]; } - XSliceValues< Vertex >& xSliceValues( int idx ){ return _xSliceValues[idx&1]; } - const XSliceValues< Vertex >& xSliceValues( int idx ) const { return _xSliceValues[idx&1]; } - }; - template< class Vertex > - void SetSliceIsoCorners( ConstPointer( Real ) solution , ConstPointer( Real ) coarseSolution , Real isoValue , int depth , int slice , std::vector< SlabValues< Vertex > >& sValues , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 > stencil[8] , const Stencil< double , 3 > stencils[8][8] , const Stencil< Point3D< double > , 3 > nStencil[8] , const Stencil< Point3D< double > , 3 > nStencils[8][8] , int threads ); - template< class Vertex > - void SetSliceIsoCorners( ConstPointer( Real ) solution , ConstPointer( Real ) coarseSolution , Real isoValue , int depth , int slice , int z , std::vector< SlabValues< Vertex > >& sValues , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 > stencil[8] , const Stencil< double , 3 > stencils[8][8] , const Stencil< Point3D< double > , 3 > nStencil[8] , const Stencil< Point3D< double > , 3 > nStencils[8][8] , int threads ); - template< class Vertex > - void SetSliceIsoVertices( ConstPointer( Real ) kernelDensityWeights , Real isoValue , int depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void SetSliceIsoVertices( ConstPointer( Real ) kernelDensityWeights , Real isoValue , int depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void SetXSliceIsoVertices( ConstPointer( Real ) kernelDensityWeights , Real isoValue , int depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void CopyFinerSliceIsoEdgeKeys( int depth , int slice , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void CopyFinerSliceIsoEdgeKeys( int depth , int slice , int z , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void CopyFinerXSliceIsoEdgeKeys( int depth , int slab , std::vector< SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void SetSliceIsoEdges( int depth , int slice , std::vector< SlabValues< Vertex > >& slabValues , int threads ); - template< class Vertex > - void SetSliceIsoEdges( int depth , int slice , int z , std::vector< SlabValues< Vertex > >& slabValues , int threads ); - template< class Vertex > - void SetXSliceIsoEdges( int depth , int slice , std::vector< SlabValues< Vertex > >& slabValues , int threads ); - - template< class Vertex > - int SetIsoSurface( int depth , int offset , const SliceValues< Vertex >& bValues , const SliceValues< Vertex >& fValues , const XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ); - - template< class Vertex > - static int AddIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ); - - template< class Vertex > - bool GetIsoVertex( ConstPointer( Real ) kernelDensityWeights , Real isoValue , typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int edgeIndex , int z , const SliceValues< Vertex >& sValues , Vertex& vertex ); - template< class Vertex > - bool GetIsoVertex( ConstPointer( Real ) kernelDensityWeights , Real isoValue , typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int cornerIndex , const SliceValues< Vertex >& bValues , const SliceValues< Vertex >& fValues , Vertex& vertex ); - - - //////////////////////// - // Evaluation Methods // - //////////////////////// - Real getCornerValue( const typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 >& stencil , const Stencil< double , 3 > stencils[8] , bool isInterior ) const; - Point3D< Real > getCornerNormal( const typename TreeOctNode::ConstNeighbors5& neighbors5 , const typename TreeOctNode::ConstNeighbors5& pNeighbors5 , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< Point3D< double > , 5 >& nStencil , const Stencil< Point3D< double > , 5 > nStencils[8] , bool isInterior ) const; - std::pair< Real , Point3D< Real > > getCornerValueAndNormal( const typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 >& vStencil , const Stencil< double , 3 > vStencils[8] , const Stencil< Point3D< double > , 3 >& nStencil , const Stencil< Point3D< double > , 3 > nStencils[8] , bool isInterior ) const; - Real getCenterValue( const typename TreeOctNode::ConstNeighborKey3& neighborKey3 , const TreeOctNode* node , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , const Stencil< double , 3 >& stencil , const Stencil< double , 3 >& pStencil , bool isInterior ) const; - - static bool _IsInset( const TreeOctNode* node ); - static bool _IsInsetSupported( const TreeOctNode* node ); - - void refineBoundary( std::vector< int >* map ); -public: - int threads; - static double maxMemoryUsage; - TreeOctNode tree; - - static double MemoryUsage( void ); - Octree( void ); - - void MakeComplete( std::vector< int >* map=NULL ); - void Finalize( std::vector< int >* map=NULL ); - void ClipTree( const NormalInfo& normalInfo ); - - Real Evaluate( ConstPointer( Real ) coefficients , Point3D< Real > p , const BSplineData< 2 >* fData=NULL ) const; - Pointer( Real ) Evaluate( ConstPointer( Real ) coefficients , int& res , Real isoValue=0.f , int depth=-1 ); - template< class PointReal > - int SetTree( PointStream< PointReal >* pointStream , int minDepth , int maxDepth , int fullDepth , int splatDepth , Real samplesPerNode , - Real scaleFactor , bool useConfidence , bool useNormalWeight , Real constraintWeight , int adaptiveExponent , - PointInfo& pointInfo , NormalInfo& normalInfo , std::vector< Real >& kernelDensityWeights , std::vector< Real >& centerWeights , - int boundaryType=BSplineElements< 2 >::NONE , XForm4x4< Real > xForm=XForm4x4< Real >::Identity , bool makeComplete=false ); - Pointer( Real ) SetLaplacianConstraints( const NormalInfo& normalInfo ); - Pointer( Real ) SolveSystem( PointInfo& pointInfo , Pointer( Real ) constraints , bool showResidual , int iters , int maxSolveDepth , int cgDepth=0 , double cgAccuracy=0 ); - - Real GetIsoValue( ConstPointer( Real ) solution , const std::vector< Real >& centerWeights ); - template< class Vertex > - void GetMCIsoSurface( ConstPointer( Real ) kernelDensityWeights , ConstPointer( Real ) solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit=true , bool addBarycenter=false , bool polygonMesh=false ); -}; -template< class Real > -void Reset( void ) -{ - TreeNodeData::NodeCount=0; - Octree< Real >::maxMemoryUsage = 0; -} - -#include "MultiGridOctreeData.inl" -#include "MultiGridOctreeData.SortedTreeNodes.inl" -#include "MultiGridOctreeData.IsoSurface.inl" -#endif // MULTI_GRID_OCTREE_DATA_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.inl b/src/scanner/PoissonRecon/Src/MultiGridOctreeData.inl deleted file mode 100755 index 888c9a2..0000000 --- a/src/scanner/PoissonRecon/Src/MultiGridOctreeData.inl +++ /dev/null @@ -1,2645 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "Octree.h" -#include "MyTime.h" -#include "MemoryUsage.h" -#include "PointStream.h" -#include "MAT.h" - -#define ITERATION_POWER 1.0/3 -#define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 -#define SPLAT_ORDER 2 - -const double MATRIX_ENTRY_EPSILON = 0; -const double EPSILON = 1e-6; -const double ROUND_EPS = 1e-5; - - - -////////////////// -// TreeNodeData // -////////////////// -int TreeNodeData::NodeCount = 0; -TreeNodeData::TreeNodeData( void ){ nodeIndex = NodeCount++; } -TreeNodeData::~TreeNodeData( void ) { } - - -//////////// -// Octree // -//////////// -template< class Real > double Octree< Real >::maxMemoryUsage=0; - -template< class Real > -double Octree< Real >::MemoryUsage(void) -{ - double mem = double( MemoryInfo::Usage() ) / (1<<20); - if( mem>maxMemoryUsage ) maxMemoryUsage=mem; - return mem; -} - -template< class Real > -Octree< Real >::Octree( void ) -{ - threads = 1; - _normalSmooth = 0; - _constrainValues = false; -} - -template< class Real > -bool Octree< Real >::_IsInset( const TreeOctNode* node ) -{ - int d , off[3]; - node->depthAndOffset( d , off ); - int res = 1<=o && off[0]=o && off[1]=o && off[2] -bool Octree< Real >::_IsInsetSupported( const TreeOctNode* node ) -{ - int d , off[3]; - node->depthAndOffset( d , off ); - int res = 1<=o && off[0]=o && off[1]=o && off[2] -int Octree< Real >::SplatOrientedPoint( ConstPointer( Real ) kernelDensityWeights , TreeOctNode* node , const Point3D& position , const Point3D& normal , NormalInfo& normalInfo , typename TreeOctNode::NeighborKey3& neighborKey ) -{ - double x , dxdy , dxdydz , dx[DIMENSION][SPLAT_ORDER+1]; - double width; - int off[3]; - typename TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node ); - Point3D center; - Real w; - node->centerAndWidth( center , w ); - width=w; - for( int i=0 ; i<3 ; i++ ) - { -#if SPLAT_ORDER==2 - off[i] = 0; - x = ( center[i] - position[i] - width ) / width; - dx[i][0] = 1.125+1.500*x+0.500*x*x; - x = ( center[i] - position[i] ) / width; - dx[i][1] = 0.750 - x*x; - - dx[i][2] = 1. - dx[i][1] - dx[i][0]; -#elif SPLAT_ORDER==1 - x = ( position[i] - center[i] ) / width; - if( x<0 ) - { - off[i] = 0; - dx[i][0] = -x; - } - else - { - off[i] = 1; - dx[i][0] = 1. - x; - } - dx[i][1] = 1. - dx[i][0]; -#elif SPLAT_ORDER==0 - off[i] = 1; - dx[i][0] = 1.; -#else -# error Splat order not supported -#endif // SPLAT_ORDER - } - for( int i=off[0] ; i<=off[0]+SPLAT_ORDER ; i++ ) for( int j=off[1] ; j<=off[1]+SPLAT_ORDER ; j++ ) - { - dxdy = dx[0][i] * dx[1][j]; - for( int k=off[2] ; k<=off[2]+SPLAT_ORDER ; k++ ) - if( neighbors.neighbors[i][j][k] ) - { - dxdydz = dxdy * dx[2][k]; - TreeOctNode* _node = neighbors.neighbors[i][j][k]; - if( normalInfo.normalIndices.size() n; - n[0] = n[1] = n[2] = 0; - idx = normalInfo.normalIndices[ _node->nodeData.nodeIndex ] = (int)normalInfo.normals.size(); - normalInfo.normals.push_back( n ); - } - normalInfo.normals[idx] += normal * Real( dxdydz ); - } - } - return 0; -} -template< class Real > -Real Octree< Real >::SplatOrientedPoint( ConstPointer( Real ) kernelDensityWeights , const Point3D& position , const Point3D& normal , NormalInfo& normalInfo , typename TreeOctNode::NeighborKey3& neighborKey , int splatDepth , Real samplesPerNode , int minDepth , int maxDepth ) -{ - double dx; - Point3D n; - TreeOctNode* temp; - int cnt=0; - double width; - Point3D< Real > myCenter; - Real myWidth; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - - temp = &tree; - while( temp->depth()children ) - { - fprintf( stderr , "Octree::SplatOrientedPoint error\n" ); - return -1; - } - int cIndex=TreeOctNode::CornerIndex(myCenter,position); - temp=&temp->children[cIndex]; - myWidth/=2; - if(cIndex&1) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if(cIndex&2) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if(cIndex&4) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - } - Real weight , depth; - GetSampleDepthAndWeight( kernelDensityWeights , temp , position , neighborKey , samplesPerNode , depth , weight ); - - if( depthmaxDepth ) depth=Real(maxDepth); - int topDepth=int(ceil(depth)); - - dx = 1.0-(topDepth-depth); - if( topDepth<=minDepth ) - { - topDepth=minDepth; - dx=1; - } - else if( topDepth>maxDepth ) - { - topDepth=maxDepth; - dx=1; - } - while( temp->depth()>topDepth ) temp=temp->parent; - while( temp->depth()children) temp->initChildren(); - int cIndex=TreeOctNode::CornerIndex(myCenter,position); - temp=&temp->children[cIndex]; - myWidth/=2; - if(cIndex&1) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if(cIndex&2) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if(cIndex&4) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - } - width = 1.0 / ( 1<depth() ); - n = normal * weight / Real( pow( width , 3 ) ) * Real( dx ); - SplatOrientedPoint( kernelDensityWeights , temp , position , n , normalInfo , neighborKey ); - if( fabs(1.0-dx) > EPSILON ) - { - dx = Real(1.0-dx); - temp = temp->parent; - width = 1.0 / ( 1<depth() ); - - n = normal * weight / Real( pow( width , 3 ) ) * Real( dx ); - SplatOrientedPoint( kernelDensityWeights , temp , position , n , normalInfo , neighborKey ); - } - return weight; -} - -template< class Real > -void Octree< Real >::GetSampleDepthAndWeight( ConstPointer( Real ) kernelDensityWeights , const TreeOctNode* node , const Point3D& position , typename TreeOctNode::ConstNeighborKey3& neighborKey , Real samplesPerNode , Real& depth , Real& weight ) -{ - const TreeOctNode* temp=node; - weight = Real(1.0)/GetSampleWeight( kernelDensityWeights , temp , position , neighborKey ); - if( weight>=samplesPerNode ) depth = Real( temp->depth() + log( weight / samplesPerNode ) / log(double(1<<(DIMENSION-1))) ); - else - { - Real oldWeight , newWeight; - oldWeight = newWeight = weight; - while( newWeightparent ) - { - temp=temp->parent; - oldWeight = newWeight; - newWeight = Real(1.0)/GetSampleWeight( kernelDensityWeights , temp , position, neighborKey ); - } - depth = Real( temp->depth() + log( newWeight / samplesPerNode ) / log( newWeight / oldWeight ) ); - } - weight = Real( pow( double(1<<(DIMENSION-1)) , -double(depth) ) ); -} -template< class Real > -void Octree< Real >::GetSampleDepthAndWeight( ConstPointer( Real ) kernelDensityWeights , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , Real samplesPerNode , Real& depth , Real& weight ) -{ - TreeOctNode* temp=node; - weight = Real(1.0)/GetSampleWeight( kernelDensityWeights , temp , position , neighborKey ); - if( weight>=samplesPerNode ) depth = Real( temp->depth() + log( weight / samplesPerNode ) / log(double(1<<(DIMENSION-1))) ); - else - { - Real oldWeight , newWeight; - oldWeight = newWeight = weight; - while( newWeightparent ) - { - temp=temp->parent; - oldWeight = newWeight; - newWeight = Real(1.0)/GetSampleWeight( kernelDensityWeights , temp , position, neighborKey ); - } - depth = Real( temp->depth() + log( newWeight / samplesPerNode ) / log( newWeight / oldWeight ) ); - } - weight = Real( pow( double(1<<(DIMENSION-1)) , -double(depth) ) ); -} -template< class Real > -Real Octree< Real >::GetSampleWeight( ConstPointer( Real ) kernelDensityWeights , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , int splatDepth ) -{ - Point3D< Real > myCenter; - Real myWidth; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - - TreeOctNode* temp = &tree; - int d = 0; - while( dchildren ) - { - fprintf( stderr , "Octree::SplatOrientedPoint error\n" ); - return -1; - } - int cIndex = TreeOctNode::CornerIndex( myCenter , position ); - temp = &temp->children[cIndex]; - myWidth /= 2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - d++; - } - return GetSampleWeight( kernelDensityWeights , temp , position , neighborKey ); -} -template< class Real > -Real Octree< Real >::GetSampleWeight( ConstPointer( Real ) kernelDensityWeights , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey ) -{ - Real weight=0; - double x , dxdy , dx[DIMENSION][3]; - double width; - typename TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node ); - Point3D center; - Real w; - node->centerAndWidth(center,w); - width=w; - - for( int i=0 ; inodeData.nodeIndex ] ); - } - return Real( 1.0 / weight ); -} -template< class Real > -Real Octree< Real >::GetSampleWeight( ConstPointer( Real ) kernelDensityWeights , const TreeOctNode* node , const Point3D& position , typename TreeOctNode::ConstNeighborKey3& neighborKey ) -{ - Real weight=0; - double x,dxdy,dx[DIMENSION][3]; - double width; - typename TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors( node ); - Point3D center; - Real w; - node->centerAndWidth( center , w ); - width=w; - - for( int i=0 ; inodeData.nodeIndex ] ); - } - return Real( 1.0 / weight ); -} -template< class Real > -int Octree< Real >::UpdateWeightContribution( std::vector< Real >& kernelDensityWeights , TreeOctNode* node , const Point3D& position , typename TreeOctNode::NeighborKey3& neighborKey , Real weight ) -{ - typename TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node ); - if( kernelDensityWeights.size() center; - Real w; - node->centerAndWidth( center , w ); - width=w; - const double SAMPLE_SCALE = 1. / ( 0.125 * 0.125 + 0.75 * 0.75 + 0.125 * 0.125 ); - - for( int i=0 ; inodeData.nodeIndex ] += Real( dxdy * dx[2][k] ); - } - return 0; -} -template< class Real > -bool Octree< Real >::_InBounds( Point3D< Real > p ) const -{ - if( _boundaryType==0 ){ if( p[0]Real(0.75) || p[1]Real(0.75) || p[2]Real(0.75) ) return false; } - else { if( p[0]Real(1.00) || p[1]Real(1.00) || p[2]Real(1.00) ) return false; } - return true; -} -template< class Real > -template< class PointReal > -int Octree< Real >::SetTree( PointStream< PointReal >* pointStream , int minDepth , int maxDepth , int fullDepth , - int splatDepth , Real samplesPerNode , Real scaleFactor , - bool useConfidence , bool useNormalWeights , Real constraintWeight , int adaptiveExponent , - PointInfo& pointInfo , NormalInfo& normalInfo , std::vector< Real >& kernelDensityWeights , std::vector< Real >& centerWeights , - int boundaryType , XForm4x4< Real > xForm , bool makeComplete ) -{ - if( splatDepth<0 ) splatDepth = 0; - - _boundaryType = boundaryType; - if ( _boundaryType<0 ) _boundaryType = -1; - else if( _boundaryType>0 ) _boundaryType = 1; - _samplesPerNode = samplesPerNode; - _splatDepth = splatDepth; - _constrainValues = (constraintWeight>0); - - XForm3x3< Real > xFormN; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) xFormN(i,j) = xForm(i,j); - xFormN = xFormN.transpose().inverse(); - minDepth = std::min< int >( minDepth , maxDepth ); // minDepth <= maxDepth - fullDepth = std::max< int >( minDepth , std::min< int >( fullDepth , maxDepth ) ); // minDepth <= fullDepth <= maxDepth - // If _boundaryType==0, points are scaled to be in the [0.25,0.75]^3 cube so all depths have to be offset by - // and the minDepth has to be 2. - if( _boundaryType==0 ) - { - minDepth++ , maxDepth++ , fullDepth++; - if( splatDepth ) splatDepth++; - minDepth = std::max< int >( minDepth , 2 ); - } - // Otherwise the points are in the [0,1]^3 cube. - // However, for Neumann constraints, the function at depth 0 is constant so the system matrix is zero if there - // is no screening. -#if 0 - else if( _boundaryType==1 && !_constrainValues ) minDepth = std::max< int >( minDepth , 1 ); -#endif - - _fData.set( maxDepth , _boundaryType ); - - _minDepth = minDepth; - _fullDepth = fullDepth; - double pointWeightSum = 0; - Point3D< Real > min , max , myCenter; - Real myWidth; - int i , cnt=0; - TreeOctNode* temp; - - typename TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set( maxDepth ); - - tree.setFullDepth( _fullDepth ); - - // Read through once to get the center and scale - { - double t = Time(); - Point3D< Real > p; - Point3D< PointReal > _p , _n; - while( pointStream->nextPoint( _p , _n ) ) - { - p = xForm * Point3D< Real >(_p); - for( i=0 ; imax[i] ) max[i] = p[i]; - } - cnt++; - } - - if( _boundaryType==0 ) _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ) * 2; - else _scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ); - _center = ( max+min ) /2; - } - - _scale *= scaleFactor; - for( i=0 ; i0 ) - { - double t = Time(); - cnt = 0; - pointStream->reset(); - Point3D< Real > p , n; - Point3D< PointReal > _p , _n; - while( pointStream->nextPoint( _p , _n ) ) - { - p = xForm * Point3D< Real >(_p) , n = xFormN * Point3D< Real >(_n); - p = ( p - _center ) / _scale; - if( !_InBounds(p) ) continue; - myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - myWidth = Real(1.0); - Real weight=Real( 1. ); - if( useConfidence ) weight = Real( Length(n) ); - temp = &tree; - int d=0; - while( dchildren ) temp->initChildren(); - int cIndex=TreeOctNode::CornerIndex( myCenter , p ); - temp = temp->children + cIndex; - myWidth/=2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - d++; - } - UpdateWeightContribution( kernelDensityWeights , temp , p , neighborKey , weight ); - cnt++; - } - } - kernelDensityWeights.resize( TreeNodeData::NodeCount , 0 ); - - std::vector< _PointData >& points = pointInfo.points; - - cnt = 0; - pointStream->reset(); - Point3D< Real > p , n; - Point3D< PointReal > _p , _n; - while( pointStream->nextPoint( _p , _n ) ) - { - p = xForm * Point3D< Real >(_p) , n = xFormN * Point3D< Real >(_n); - n *= Real(-1.); - p = ( p - _center ) / _scale; - if( !_InBounds(p) ) continue; - myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - myWidth = Real(1.0); - Real normalLength = Real( Length( n ) ); - if( normalLength!=normalLength || normalLength<=EPSILON ) continue; - if( !useConfidence ) n /= normalLength; - - Real pointWeight = Real(1.f); - if( samplesPerNode>0 && splatDepth ) pointWeight = SplatOrientedPoint( GetPointer( kernelDensityWeights ) , p , n , normalInfo , neighborKey , splatDepth , samplesPerNode , _minDepth , maxDepth ); - else - { - temp = &tree; - int d=0; - if( splatDepth ) - { - while( dchildren[cIndex]; - myWidth /= 2; - if(cIndex&1) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if(cIndex&2) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if(cIndex&4) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - d++; - } - pointWeight = GetSampleWeight( GetPointer( kernelDensityWeights ) , temp , p , neighborKey ); - } - for( i=0 ; ichildren ) temp->initChildren(); - int cIndex=TreeOctNode::CornerIndex(myCenter,p); - temp=&temp->children[cIndex]; - myWidth/=2; - if(cIndex&1) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if(cIndex&2) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if(cIndex&4) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - d++; - } - SplatOrientedPoint( GetPointer( kernelDensityWeights ) , temp , p , n , normalInfo , neighborKey ); - } - pointWeightSum += pointWeight; - if( _constrainValues ) - { - Real pointScreeningWeight = useNormalWeights ? Real( normalLength ) : Real(1.f); - int d = 0; - TreeOctNode* temp = &tree; - myCenter = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - myWidth = Real(1.0); - while( 1 ) - { - if( pointInfo.pointIndices.size()nodeData.nodeIndex ] = idx; - } - else - { - points[idx].weight += pointScreeningWeight; - points[idx].position += p*pointScreeningWeight; - } - - int cIndex = TreeOctNode::CornerIndex( myCenter , p ); - if( !temp->children ) break; - temp = &temp->children[cIndex]; - myWidth /= 2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - d++; - } - } - cnt++; - } - - if( _boundaryType==0 ) pointWeightSum *= Real(4.); - constraintWeight *= Real( pointWeightSum ); - constraintWeight /= cnt; - - MemoryUsage( ); - if( _constrainValues ) - // Set the average position and scale the weights - for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) ) - if( pointInfo.pointIndex( node )!=-1 ) - { - int idx = pointInfo.pointIndex( node ); - points[idx].position /= points[idx].weight; - int e = ( _boundaryType==0 ? node->depth()-1 : node->depth() ) * adaptiveExponent - ( _boundaryType==0 ? maxDepth-1 : maxDepth ) * (adaptiveExponent-1); - if( e<0 ) points[idx].weight /= Real( 1<<(-e) ); - else points[idx].weight *= Real( 1<< e ); - points[idx].weight *= Real( constraintWeight ); - } -#if FORCE_NEUMANN_FIELD - if( _boundaryType==1 ) - for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) ) - { - int d , off[3] , res; - node->depthAndOffset( d , off ); - res = 1<& normal = normalInfo.normals[ idx ]; - for( int d=0 ; d<3 ; d++ ) if( off[d]==0 || off[d]==res-1 ) normal[d] = 0; - } -#endif // FORCE_NEUMANN_FIELD - centerWeights.resize( tree.nodes() , 0 ); - kernelDensityWeights.resize( tree.nodes() , 0 ); - // Set the point weights for evaluating the iso-value - for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode(node) ) - { - int idx = normalInfo.normalIndex( node ); - if( idx<0 ) centerWeights[ node->nodeData.nodeIndex ] = 0; - else centerWeights[ node->nodeData.nodeIndex ] = Real( Length( normalInfo.normals[ idx ] ) ); - } - MemoryUsage(); - { - std::vector< int > indexMap; - if( makeComplete ) MakeComplete( &indexMap ); - else ClipTree( normalInfo ) , Finalize( &indexMap ); - - { - std::vector< int > temp = pointInfo.pointIndices; - pointInfo.pointIndices.resize( indexMap.size() ); - for( int i=0 ; i temp = normalInfo.normalIndices; - normalInfo.normalIndices.resize( indexMap.size() ); - for( int i=0 ; i temp = centerWeights; - centerWeights.resize( indexMap.size() ); - for( int i=0 ; i temp = kernelDensityWeights; - kernelDensityWeights.resize( indexMap.size() ); - for( int i=0 ; i -void Octree< Real >::MakeComplete( std::vector< int >* map ) -{ - tree.setFullDepth( tree.maxDepth() ); - refineBoundary( map ); - MemoryUsage(); -} -template< class Real > -void Octree< Real >::ClipTree( const NormalInfo& normalInfo ) -{ - int maxDepth = tree.maxDepth(); - for( TreeOctNode* temp=tree.nextNode() ; temp ; temp=tree.nextNode(temp) ) - if( temp->children && temp->depth()>=_fullDepth ) - { - int hasNormals=0; - for( int i=0 ; ichildren[i] , normalInfo ); - if( !hasNormals ) temp->children=NULL; - } - MemoryUsage(); -} - -template< class Real > -void Octree< Real >::Finalize( std::vector< int >* map ) -{ - int maxDepth = tree.maxDepth( ); - typename TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set( maxDepth ); - for( int d=maxDepth ; d>1 ; d-- ) - for( TreeOctNode* node=tree.nextNode() ; node ; node=tree.nextNode( node ) ) if( node->depth()==d ) - { - typename TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors( node->parent->parent ); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( neighbors.neighbors[i][j][k] && !neighbors.neighbors[i][j][k]->children ) - neighbors.neighbors[i][j][k]->initChildren(); - } - refineBoundary( map ); -} -template< class Real > -double Octree< Real >::GetLaplacian( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[] , const int off2[] , bool childParent ) const -{ - double vv[] = - { - integrator.dot( d , off1[0] , off2[0] , false , false , childParent ) , - integrator.dot( d , off1[1] , off2[1] , false , false , childParent ) , - integrator.dot( d , off1[2] , off2[2] , false , false , childParent ) - }; - double dd[] = - { - integrator.dot( d , off1[0] , off2[0] , true , true , childParent ) , - integrator.dot( d , off1[1] , off2[1] , true , true , childParent ) , - integrator.dot( d , off1[2] , off2[2] , true , true , childParent ) - }; - return dd[0]*vv[1]*vv[2] + vv[0]*dd[1]*vv[2] + vv[0]*vv[1]*dd[2]; -} -template< class Real > -double Octree< Real >::GetDivergence1( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[] , const int off2[] , bool childParent , const Point3D< Real >& normal1 ) const -{ - return Point3D< double >::Dot( GetDivergence1( integrator , d , off1 , off2 , childParent ) , normal1 ); -} -template< class Real > -double Octree< Real >::GetDivergence2( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[] , const int off2[] , bool childParent , const Point3D< Real >& normal2 ) const -{ - return Point3D< double >::Dot( GetDivergence2( integrator , d , off1 , off2 , childParent ) , normal2 ); -} -template< class Real > -Point3D< double > Octree< Real >::GetDivergence1( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[] , const int off2[] , bool childParent ) const -{ - double vv[] = - { - integrator.dot( d , off1[0] , off2[0] , false , false , childParent ) , - integrator.dot( d , off1[1] , off2[1] , false , false , childParent ) , - integrator.dot( d , off1[2] , off2[2] , false , false , childParent ) - }; -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - double vd[] = - { - integrator.dot( d , off1[0] , off2[0] , false , true , childParent ) , - integrator.dot( d , off1[1] , off2[1] , false , true , childParent ) , - integrator.dot( d , off1[2] , off2[2] , false , true , childParent ) - }; - return Point3D< double >( vd[0]*vv[1]*vv[2] , vv[0]*vd[1]*vv[2] , vv[0]*vv[1]*vd[2] ); -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - double dv[] = - { - integrator.dot( d , off1[0] , off2[0] , true , false , childParent ) , - integrator.dot( d , off1[1] , off2[1] , true , false , childParent ) , - integrator.dot( d , off1[2] , off2[2] , true , false , childParent ) - }; - return -Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ); -#endif // GRADIENT_DOMAIN_SOLUTION -} -template< class Real > -Point3D< double > Octree< Real >::GetDivergence2( const typename BSplineData< 2 >::Integrator& integrator , int d , const int off1[] , const int off2[] , bool childParent ) const -{ - double vv[] = - { - integrator.dot( d , off1[0] , off2[0] , false , false , childParent ) , - integrator.dot( d , off1[1] , off2[1] , false , false , childParent ) , - integrator.dot( d , off1[2] , off2[2] , false , false , childParent ) - }; -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - double dv[] = - { - integrator.dot( d , off1[0] , off2[0] , true , false , childParent ) , - integrator.dot( d , off1[1] , off2[1] , true , false , childParent ) , - integrator.dot( d , off1[2] , off2[2] , true , false , childParent ) - }; - return Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ); -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - double vd[] = - { - integrator.dot( d , off1[0] , off2[0] , false , true , childParent ) , - integrator.dot( d , off1[1] , off2[1] , false , true , childParent ) , - integrator.dot( d , off1[2] , off2[2] , false , true , childParent ) - }; - return -Point3D< double >( vd[0]*vv[1]*vv[2] , vv[0]*vd[1]*vv[2] , vv[0]*vv[1]*vd[2] ); -#endif // GRADIENT_DOMAIN_SOLUTION -} - -template< class Real > -int Octree< Real >::GetMatrixRowSize( const typename TreeOctNode::Neighbors5& neighbors5 , bool symmetric ) const -{ - int count = 0; - int nodeIndex = neighbors5.neighbors[2][2][2]->nodeData.nodeIndex; - const TreeOctNode* const * _nodes = &neighbors5.neighbors[0][0][0]; - if( symmetric ) - { - for( int i=0 ; i<125 ; i++ ) if( _nodes[i] && _nodes[i]->nodeData.nodeIndex>=nodeIndex ) count++; - } - else - { - for( int i=0 ; i<125 ; i++ ) if( _nodes[i] ) count++; - } - return count; -} - -template< class Real > -int Octree< Real >::SetMatrixRow( const PointInfo& pointInfo , const typename TreeOctNode::Neighbors5& neighbors5 , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineData< 2 >::Integrator& integrator , const Stencil< double , 5 >& stencil , bool symmetric ) const -{ - const std::vector< _PointData >& points = pointInfo.points; - bool hasYZPoints[3] , hasZPoints[3][3]; - Real diagonal = 0; - Real splineValues[3*3*3*3*3]; - memset( splineValues , 0 , sizeof( Real ) * 3 * 3 * 3 * 3 * 3 ); - - int count = 0; - const TreeOctNode* node = neighbors5.neighbors[2][2][2]; - - bool isInterior; - int d , off[3]; - node->depthAndOffset( d , off ); - - int o = _boundaryType==0 ? ( 1<<(d-2) ) : 0; - int mn = 2+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]centerIndex( idx ); - for( int j=0 ; j<3 ; j++ ) - { - hasYZPoints[j] = false; - for( int k=0 ; k<3 ; k++ ) - { - hasZPoints[j][k] = false; - for( int l=0 ; l<3 ; l++ ) - { - const TreeOctNode* _node = neighbors5.neighbors[j+1][k+1][l+1]; - if( _node && pointInfo.pointIndex( _node )!=-1 ) - { - const _PointData& pData = points[ pointInfo.pointIndex( _node ) ]; - Real* _splineValues = splineValues + 3*3*(3*(3*j+k)+l); - Real weight = pData.weight; - Point3D< Real > p = pData.position; - for( int s=0 ; s<3 ; s++ ) - { -#if ROBERTO_TOLDO_FIX - if( idx[0]+j-s>=0 && idx[0]+j-s<((2<=0 && idx[1]+k-s<((2<=0 && idx[2]+l-s<((2<nodeData.nodeIndex; - if( isInterior ) // General case, so try to make fast - { - const TreeOctNode* const * _nodes = &neighbors5.neighbors[0][0][0]; - const double* _stencil = &stencil.values[0][0][0]; - Real* _values = &pointValues[0][0][0]; - if( _constrainValues ) for( int i=0 ; i<125 ; i++ ) _values[i] = Real( _stencil[i] + _values[i] ); - else for( int i=0 ; i<125 ; i++ ) _values[i] = Real( _stencil[i] ); - if( symmetric ) pointValues[2][2][2] /= 2; - row[count++] = MatrixEntry< Real >( nodeIndex-offset , _values[5*5*2+5*2+2] ); - if( symmetric ) - { - for( int i=0 ; i<125 ; i++ ) if( i!=(5*5*2+5*2+2) && _nodes[i] && _nodes[i]->nodeData.nodeIndex>=nodeIndex ) - row[count++] = MatrixEntry< Real >( _nodes[i]->nodeData.nodeIndex-offset , _values[i] ); - } - else - { - for( int i=0 ; i<125 ; i++ ) if( i!=(5*5*2+5*2+2) && _nodes[i] ) - row[count++] = MatrixEntry< Real >( _nodes[i]->nodeData.nodeIndex-offset , _values[i] ); - } - } - else - { - int d , off[3]; - node->depthAndOffset( d , off ); - Real temp = Real( GetLaplacian( integrator , d , off , off , false ) ); - if( _constrainValues ) temp += pointValues[2][2][2]; - if( symmetric ) temp /= 2; - row[count++] = MatrixEntry< Real >( nodeIndex-offset , temp ); - for( int x=0 ; x<5 ; x++ ) for( int y=0 ; y<5 ; y++ ) for( int z=0 ; z<5 ; z++ ) - if( (x!=2 || y!=2 || z!=2) && neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=0 && ( !symmetric || neighbors5.neighbors[x][y][z]->nodeData.nodeIndex>=nodeIndex ) ) - { - const TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); - Real temp = Real( GetLaplacian( integrator , d , off , _off , false ) ); - if( _constrainValues ) temp += pointValues[x][y][z]; - if( symmetric && x==2 && y==2 && z==2 ) temp /= 2; - row[count++] = MatrixEntry< Real >( _node->nodeData.nodeIndex-offset , temp ); - } - } - return count; -} -// if( scatter ) normals come from the center ndoe -// else normals come from the neighbors -template< class Real > -void Octree< Real >::SetDivergenceStencil( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< Point3D< double > , 5 >& stencil , bool scatter ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - int offset[] = { center , center , center }; - for( int x=0 ; x<5 ; x++ ) for( int y=0 ; y<5 ; y++ ) for( int z=0 ; z<5 ; z++ ) - { - int _offset[] = { x+center-2 , y+center-2 , z+center-2 }; - if( scatter ) stencil.values[x][y][z] = GetDivergence1( integrator , depth , offset , _offset , false ); - else stencil.values[x][y][z] = GetDivergence2( integrator , depth , offset , _offset , false ); - } -} -template< class Real > -void Octree< Real >::SetDivergenceStencils( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< Point3D< double > , 5 > stencils[2][2][2] , bool scatter ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int offset[] = { center+i , center+j , center+k }; - for( int x=0 ; x<5 ; x++ ) for( int y=0 ; y<5 ; y++ ) for( int z=0 ; z<5 ; z++ ) - { - int _offset[] = { x-2+center/2 , y-2+center/2 , z-2+center/2 }; - if( scatter ) stencils[i][j][k].values[x][y][z] = GetDivergence1( integrator , depth , offset , _offset , true ); - else stencils[i][j][k].values[x][y][z] = GetDivergence2( integrator , depth , offset , _offset , true ); - } - } -} -template< class Real > -void Octree< Real >::SetLaplacianStencil( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< double , 5 >& stencil ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - int offset[] = { center , center , center }; - for( int x=-2 ; x<=2 ; x++ ) for( int y=-2 ; y<=2 ; y++ ) for( int z=-2 ; z<=2 ; z++ ) - { - int _offset[] = { x+center , y+center , z+center }; - stencil.values[x+2][y+2][z+2] = GetLaplacian( integrator , depth , offset , _offset , false ); - } -} -template< class Real > -void Octree< Real >::SetLaplacianStencils( int depth , const typename BSplineData< 2 >::Integrator& integrator , Stencil< double , 5 > stencils[2][2][2] ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int offset[] = { center+i , center+j , center+k }; - for( int x=-2 ; x<=2 ; x++ ) for( int y=-2 ; y<=2 ; y++ ) for( int z=-2 ; z<=2 ; z++ ) - { - int _offset[] = { x+center/2 , y+center/2 , z+center/2 }; - stencils[i][j][k].values[x+2][y+2][z+2] = GetLaplacian( integrator , depth , offset , _offset , true ); - } - } -} -template< class Real > -void Octree< Real >::SetCenterEvaluationStencil( const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , int depth , Stencil< double , 3 >& stencil ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center+x-1 , center+y-1 , center+z-1 }; - stencil.values[x][y][z] = Real( evaluator.value( depth , center , off[0] , false , false ) * evaluator.value( depth , center , off[1] , false , false ) * evaluator.value( depth , center , off[2] , false , false ) ); - } -} -template< class Real > -void Octree< Real >::SetCenterEvaluationStencils( const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , int depth , Stencil< double , 3 > stencils[8] ) const -{ - if( depth<3 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int idx[] = { center+cx , center+cy , center+cz }; - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center/2+x-1 , center/2+y-1 , center/2+z-1 }; - stencils[Cube::CornerIndex( cx , cy , cz ) ].values[x][y][z] = Real( evaluator.value( depth , idx[0] , off[0] , false , true ) * evaluator.value( depth , idx[1] , off[1] , false , true ) * evaluator.value( depth , idx[2] , off[2] , false , true ) ); - } - } -} -template< class Real > -void Octree< Real >::SetCornerEvaluationStencil( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< double , 3 > stencil[8] ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center+x-1 , center+y-1 , center+z-1 }; - stencil[c].values[x][y][z] = evaluator.value( depth , center , cx , off[0] , false , false ) * evaluator.value( depth , center , cy , off[1] , false , false ) * evaluator.value( depth , center , cz , off[2] , false , false ); - } - } -} -template< class Real > -void Octree< Real >::SetCornerEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< double , 3 > stencils[8][8] ) const -{ - if( depth<3 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); - for( int _cx=0 ; _cx<2 ; _cx++ ) for( int _cy=0 ; _cy<2 ; _cy++ ) for( int _cz=0 ; _cz<2 ; _cz++ ) - { - int _c = Cube::CornerIndex( _cx , _cy , _cz ); - int idx[] = { center+_cx , center+_cy , center+_cz }; - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center/2+x-1 , center/2+y-1 , center/2+z-1 }; - stencils[c][_c].values[x][y][z] = evaluator.value( depth , idx[0] , cx , off[0] , false , true ) * evaluator.value( depth , idx[1] , cy , off[1] , false , true ) * evaluator.value( depth , idx[2] , cz , off[2] , false , true ); - } - } - } -} -template< class Real > -void Octree< Real >::SetCornerNormalEvaluationStencil( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 3 > stencil[8] ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center+x-1 , center+y-1 , center+z-1 }; - double v [] = { evaluator.value( depth , center , cx , off[0] , false , false ) , evaluator.value( depth , center , cy , off[1] , false , false ) , evaluator.value( depth , center , cz , off[2] , false , false ) }; - double dv[] = { evaluator.value( depth , center , cx , off[0] , true , false ) , evaluator.value( depth , center , cy , off[1] , true , false ) , evaluator.value( depth , center , cz , off[2] , true , false ) }; - stencil[c].values[x][y][z] = Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ); - } - } -} -template< class Real > -void Octree< Real >::SetCornerNormalEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 3 > stencils[8][8] ) const -{ - if( depth<3 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); // Which corner of the finer cube - for( int _cx=0 ; _cx<2 ; _cx++ ) for( int _cy=0 ; _cy<2 ; _cy++ ) for( int _cz=0 ; _cz<2 ; _cz++ ) - { - int _c = Cube::CornerIndex( _cx , _cy , _cz ); // Which child node - int idx[] = { center+_cx , center+_cy , center+_cz }; - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - { - int off[] = { center/2+x-1 , center/2+y-1 , center/2+z-1 }; - double v [] = { evaluator.value( depth , idx[0] , cx , off[0] , false , true ) , evaluator.value( depth , idx[1] , cy , off[1] , false , true ) , evaluator.value( depth , idx[2] , cz , off[2] , false , true ) }; - double dv[] = { evaluator.value( depth , idx[0] , cx , off[0] , true , true ) , evaluator.value( depth , idx[1] , cy , off[1] , true , true ) , evaluator.value( depth , idx[2] , cz , off[2] , true , true ) }; - stencils[c][_c].values[x][y][z] = Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ); - } - } - } -} -template< class Real > -void Octree< Real >::SetCornerNormalEvaluationStencil( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 5 > stencil[8] ) const -{ - if( depth<2 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); - for( int x=0 ; x<5 ; x++ ) for( int y=0 ; y<5 ; y++ ) for( int z=0 ; z<5 ; z++ ) - { - int off[] = { center+x-2 , center+y-2 , center+z-2 }; - double v [] = { evaluator.value( depth , center , cx , off[0] , false , false ) , evaluator.value( depth , center , cy , off[1] , false , false ) , evaluator.value( depth , center , cz , off[2] , false , false ) }; - double dv[] = { evaluator.value( depth , center , cx , off[0] , true , false ) , evaluator.value( depth , center , cy , off[1] , true , false ) , evaluator.value( depth , center , cz , off[2] , true , false ) }; - stencil[c].values[x][y][z] = Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ); - } - } -} -template< class Real > -void Octree< Real >::SetCornerNormalEvaluationStencils( const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , int depth , Stencil< Point3D< double > , 5 > stencils[8][8] ) const -{ - if( depth<3 ) return; - int center = 1<<(depth-1); - for( int cx=0 ; cx<2 ; cx++ ) for( int cy=0 ; cy<2 ; cy++ ) for( int cz=0 ; cz<2 ; cz++ ) - { - int c = Cube::CornerIndex( cx , cy , cz ); // Which corner of the finer cube - for( int _cx=0 ; _cx<2 ; _cx++ ) for( int _cy=0 ; _cy<2 ; _cy++ ) for( int _cz=0 ; _cz<2 ; _cz++ ) - { - int _c = Cube::CornerIndex( _cx , _cy , _cz ); // Which child node - int idx[] = { center+_cx , center+_cy , center+_cz }; - for( int x=0 ; x<5 ; x++ ) for( int y=0 ; y<5 ; y++ ) for( int z=0 ; z<5 ; z++ ) - { - int off[] = { center/2+x-2 , center/2+y-2 , center/2+z-2 }; - double v [] = { evaluator.value( depth , idx[0] , cx , off[0] , false , true ) , evaluator.value( depth , idx[1] , cy , off[1] , false , true ) , evaluator.value( depth , idx[2] , cz , off[2] , false , true ) }; - double dv[] = { evaluator.value( depth , idx[0] , cx , off[0] , true , true ) , evaluator.value( depth , idx[1] , cy , off[1] , true , true ) , evaluator.value( depth , idx[2] , cz , off[2] , true , true ) }; - stencils[c][_c].values[x][y][z] = Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ); - } - } - } -} - -template< class Real > -void Octree< Real >::UpdateCoarserSupportBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ) -{ - if( node->parent ) - { - int x , y , z , c = int( node - node->parent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - if( x==0 ) endX = 4; - else startX = 1; - if( y==0 ) endY = 4; - else startY = 1; - if( z==0 ) endZ = 4; - else startZ = 1; - } -} -// Given the solution @( depth ) add to the met constraints @( depth-1 ) -template< class Real > -void Octree< Real >::UpdateConstraintsFromFiner( const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) fineSolution , Pointer( Real ) coarseConstraints ) const -{ - if( depth<=_minDepth ) return; - Stencil< double , 5 > stencils[2][2][2]; - // Get the stencil describing the Laplacian relating coefficients @(depth) with coefficients @(depth-1) - SetLaplacianStencils( depth , integrator , stencils ); - size_t start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start; - int lStart = sNodes.nodeCount[depth-1]; - memset( coarseConstraints , 0 , sizeof(Real)*(sNodes.nodeCount[depth]-sNodes.nodeCount[depth-1]) ); - - // Iterate over the nodes @( depth ) - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; iparent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - if( insetSupported ) - { - typename TreeOctNode::Neighbors5 pNeighbors5; - neighborKey.getNeighbors( node->parent , pNeighbors5 ); - const Stencil< double , 5 >& lapStencil = stencils[x][y][z]; - - Pointer( Real ) __coarseConstraints = coarseConstraints-lStart; - bool isInterior; - int d , off[3]; - { - node->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2) ) : 0; - int mn = 4+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]nodeData.nodeIndex-start ]; - for( int x=startX ; xnodeData.nodeIndex>=0 ) - { - const TreeOctNode* _node = pNeighbors5.neighbors[x][y][z]; - if( isInterior ) -#pragma omp atomic - __coarseConstraints[ _node->nodeData.nodeIndex ] += Real( lapStencil.values[x][y][z] * solution ); - else - { - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); -#pragma omp atomic - __coarseConstraints[ _node->nodeData.nodeIndex ] += Real( GetLaplacian( integrator , d , off , _off , true ) * solution ); - } - } - } - } -} - -template< class Real > -void Octree< Real >::UpdateConstraintsFromCoarser( const PointInfo& pointInfo , const typename TreeOctNode::Neighbors5& neighbors5 , const typename TreeOctNode::Neighbors5& pNeighbors5 , TreeOctNode* node , Pointer( Real ) constraints , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::Integrator& integrator , const Stencil< double , 5 >& lapStencil ) const -{ - const std::vector< _PointData >& points = pointInfo.points; - if( node->depth()<=_minDepth ) return; - bool isInterior; - int d , off[3]; - { - node->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2) ) : 0; - int mn = 4+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]nodeData.nodeIndex>=0 ) - { - const TreeOctNode* _node = pNeighbors5.neighbors[x][y][z]; - Real _solution = metSolution[ _node->nodeData.nodeIndex ]; - { - if( isInterior ) constraints[ node->nodeData.nodeIndex ] -= Real( lapStencil.values[x][y][z] * _solution ); - else - { - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); - constraints[ node->nodeData.nodeIndex ] -= Real( GetLaplacian( integrator , d , off , _off , true ) * _solution ); - } - } - } - if( _constrainValues ) - { - double constraint = 0; - int idx[3] ; - node->centerIndex( idx ); - // Evaluate the current node's basis function at adjacent points - for( int x=1 ; x<4 ; x++ ) for( int y=1 ; y<4 ; y++ ) for( int z=1 ; z<4 ; z++ ) - if( neighbors5.neighbors[x][y][z] && pointInfo.pointIndex( neighbors5.neighbors[x][y][z] )!=-1 ) - { - const _PointData& pData = points[ pointInfo.pointIndex( neighbors5.neighbors[x][y][z] ) ]; - Real weightedPointValue = pData.weightedCoarserValue; - Point3D< Real > p = pData.position; - constraint += - _fData.baseBSplines[idx[0]][x-1]( p[0] ) * - _fData.baseBSplines[idx[1]][y-1]( p[1] ) * - _fData.baseBSplines[idx[2]][z-1]( p[2] ) * - weightedPointValue; - } - constraints[ node->nodeData.nodeIndex ] -= Real( constraint ); - } -} -struct UpSampleData -{ - int start; - double v[2]; - UpSampleData( void ) { start = 0 , v[0] = v[1] = 0.; } - UpSampleData( int s , double v1 , double v2 ) { start = s , v[0] = v1 , v[1] = v2; } -}; -template< class Real > -template< class C > -void Octree< Real >::DownSample( int depth , const SortedTreeNodes& sNodes , ConstPointer( C ) fineConstraints , Pointer( C ) coarseConstraints ) const -{ - if( depth==0 ) return; - double cornerValue; - if ( _boundaryType==-1 ) cornerValue = 0.50; - else if( _boundaryType== 1 ) cornerValue = 1.00; - else cornerValue = 0.75; - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepthAndOffset( d , off ); - for( int dd=0 ; dd<3 ; dd++ ) - { - if ( off[dd] ==0 ) usData[dd] = UpSampleData( 1 , cornerValue , 0.00 ); - else if( off[dd]+1==(1<parent ); - C c = fineConstraints[ i-sNodes.nodeCount[depth] ]; - for( int ii=0 ; ii<2 ; ii++ ) - { - int _ii = ii + usData[0].start; - C cx = C( c*usData[0].v[ii] ); - for( int jj=0 ; jj<2 ; jj++ ) - { - int _jj = jj + usData[1].start; - C cxy = C( cx*usData[1].v[jj] ); - for( int kk=0 ; kk<2 ; kk++ ) - { - int _kk = kk + usData[2].start; - TreeOctNode* pNode = neighbors.neighbors[_ii][_jj][_kk]; - if( pNode ) -#pragma omp atomic - coarseConstraints[ pNode->nodeData.nodeIndex-sNodes.nodeCount[depth-1] ] += C( cxy*usData[2].v[kk] ); - } - } - } - } -} -template< class Real > -template< class C > -void Octree< Real >::UpSample( int depth , const SortedTreeNodes& sNodes , ConstPointer( C ) coarseCoefficients , Pointer( C ) fineCoefficients ) const -{ - double cornerValue; - if ( _boundaryType==-1 ) cornerValue = 0.50; - else if( _boundaryType== 1 ) cornerValue = 1.00; - else cornerValue = 0.75; - if( depth<=_minDepth ) return; - - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepthAndOffset( d , off ); - for( int d=0 ; d<3 ; d++ ) - { - if ( off[d] ==0 ) usData[d] = UpSampleData( 1 , cornerValue , 0.00 ) , isInterior = false; - else if( off[d]+1==(1<parent ); - for( int ii=0 ; ii<2 ; ii++ ) - { - int _ii = ii + usData[0].start; - double dx = usData[0].v[ii]; - for( int jj=0 ; jj<2 ; jj++ ) - { - int _jj = jj + usData[1].start; - double dxy = dx * usData[1].v[jj]; - for( int kk=0 ; kk<2 ; kk++ ) - { - int _kk = kk + usData[2].start; - TreeOctNode* node = neighbors.neighbors[_ii][_jj][_kk]; - if( node ) - { - double dxyz = dxy * usData[2].v[kk]; - int _i = node->nodeData.nodeIndex; - fineCoefficients[ i-sNodes.nodeCount[depth] ] += coarseCoefficients[ _i-sNodes.nodeCount[depth-1] ] * Real( dxyz ); - } - } - } - } - } -} -// At each point @( depth ), evaluate the met solution @( depth-1 ) -template< class Real > -void Octree< Real >::SetPointValuesFromCoarser( PointInfo& pointInfo , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) coarseCoefficients ) -{ - std::vector< _PointData >& points = pointInfo.points; - // For every node at the current depth - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; i -Real Octree< Real >::_WeightedCoarserFunctionValue( const _PointData& pointData , const typename TreeOctNode::NeighborKey3& neighborKey , const TreeOctNode* pointNode , ConstPointer( Real ) coarseCoefficients ) const -{ - double pointValue = 0; - int depth = pointNode->depth(); - if( _boundaryType==-1 && depth==0 ) return Real(-0.5) * pointData.weight; - - if( depth<=_minDepth ) return Real(0.); - - Real weight = pointData.weight; - Point3D< Real > p = pointData.position; - - // Iterate over all basis functions that overlap the point at the coarser resolutions - { - int d , _idx[3]; - const typename TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth-1]; - neighbors.neighbors[1][1][1]->depthAndOffset( d , _idx ); - _idx[0] = BinaryNode::CenterIndex( d , _idx[0]-1 ); - _idx[1] = BinaryNode::CenterIndex( d , _idx[1]-1 ); - _idx[2] = BinaryNode::CenterIndex( d , _idx[2]-1 ); - - for( int j=0 ; j<3 ; j++ ) - { -#if ROBERTO_TOLDO_FIX - double xValue = 0; - if( _idx[0]+j>=0 && _idx[0]+j<((1<=0 && _idx[1]+k<((1<nodeData.nodeIndex>=0 && _idx[2]+l>=0 && _idx[2]+l<((1<nodeData.nodeIndex] ); -#else // !ROBERTO_TOLDO_FIX - if( basisNode && basisNode->nodeData.nodeIndex>=0 ) - _pointValue += _fData.baseBSplines[ _idx[2]+l ][2-l]( p[2] ) * double( coarseCoefficients[basisNode->nodeData.nodeIndex] ); -#endif // ROBERTO_TOLDO_FIX - } - pointValue += _pointValue * xyValue; - } - } - } - if( _boundaryType==-1 ) pointValue -= 0.5; - return Real( pointValue * weight ); -} -template< class Real > -void Octree< Real >::SetPointConstraintsFromFiner( const PointInfo& pointInfo , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) finerCoefficients , Pointer( Real ) coarserConstraints ) const -{ - const std::vector< _PointData >& points = pointInfo.points; - // Note: We can't iterate over the finer point nodes as the point weights might be - // scaled incorrectly, due to the adaptive exponent. So instead, we will iterate - // over the coarser nodes and evaluate the finer solution at the associated points. - if( !depth ) return; - size_t start = sNodes.nodeCount[depth-1] , end = sNodes.nodeCount[depth] , range = end-start; - memset( coarserConstraints , 0 , sizeof( Real ) * ( sNodes.nodeCount[depth]-sNodes.nodeCount[depth-1] ) ); - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; i p = points[ pIdx ].position; - // Update constraints for all nodes @( depth-1 ) that overlap the point - int d , idx[3]; - neighbors.neighbors[1][1][1]->depthAndOffset( d, idx ); - // Set the (offset) index to the top-left-front corner of the 3x3x3 block of b-splines - // overlapping the point. - idx[0] = BinaryNode::CenterIndex( d , idx[0]-1 ); - idx[1] = BinaryNode::CenterIndex( d , idx[1]-1 ); - idx[2] = BinaryNode::CenterIndex( d , idx[2]-1 ); - for( int x=0 ; x<3 ; x++ ) for( int y=0 ; y<3 ; y++ ) for( int z=0 ; z<3 ; z++ ) - if( neighbors.neighbors[x][y][z] ) - { -#pragma omp atomic - coarserConstraints[ neighbors.neighbors[x][y][z]->nodeData.nodeIndex - sNodes.nodeCount[depth-1] ] += - Real( - _fData.baseBSplines[idx[0]+x][2-x]( p[0] ) * - _fData.baseBSplines[idx[1]+y][2-y]( p[1] ) * - _fData.baseBSplines[idx[2]+z][2-z]( p[2] ) * - finerPointValue - ); - } - } - } - } -} -template< class Real > -Real Octree< Real >::_WeightedFinerFunctionValue( const _PointData& pointData , const typename TreeOctNode::NeighborKey3& neighborKey , const TreeOctNode* pointNode , ConstPointer( Real ) finerCoefficients ) const -{ - typename TreeOctNode::Neighbors3 childNeighbors; - double pointValue = 0; - int depth = pointNode->depth(); - Real weight = pointData.weight; - Point3D< Real > p = pointData.position; - neighborKey.getChildNeighbors( p , depth , childNeighbors ); - // Iterate over all finer basis functions that overlap the point at the coarser resolutions - int d , idx[3]; - { - Point3D< Real > c; - Real w; - neighborKey.neighbors[depth].neighbors[1][1][1]->depthAndOffset( d , idx ); - neighborKey.neighbors[depth].neighbors[1][1][1]->centerAndWidth( c , w ); - d++; - idx[0] *= 2 , idx[1] *= 2 , idx[2] *= 2; - int cIndex=TreeOctNode::CornerIndex( c , p ); - if( cIndex&1 ) idx[0]++; - if( cIndex&2 ) idx[1]++; - if( cIndex&4 ) idx[2]++; - } - // Center the indexing at the top-left-front corner - idx[0] = BinaryNode::CenterIndex( d , idx[0]-1 ); - idx[1] = BinaryNode::CenterIndex( d , idx[1]-1 ); - idx[2] = BinaryNode::CenterIndex( d , idx[2]-1 ); - - for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) for( int l=0 ; l<3 ; l++ ) - { - const TreeOctNode* basisNode = childNeighbors.neighbors[j][k][l]; - if( basisNode && basisNode->nodeData.nodeIndex>=0 ) - pointValue += - _fData.baseBSplines[ idx[0]+j ][2-j]( p[0] ) * - _fData.baseBSplines[ idx[1]+k ][2-k]( p[1] ) * - _fData.baseBSplines[ idx[2]+l ][2-l]( p[2] ) * - double( finerCoefficients[ basisNode->nodeData.nodeIndex ] ); - } - if( _boundaryType==-1 ) pointValue -= Real(0.5); - return Real( pointValue * weight ); -} -template< class Real > -int Octree< Real >::GetSliceMatrixAndUpdateConstraints( const PointInfo& pointInfo , SparseMatrix< Real >& matrix , Pointer( Real ) constraints , const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) metSolution , bool coarseToFine , int nStart , int nEnd ) -{ - size_t range = nEnd-nStart; - Stencil< double , 5 > stencil , stencils[2][2][2]; - SetLaplacianStencil ( depth , integrator , stencil ); - SetLaplacianStencils( depth , integrator , stencils ); - matrix.Resize( (int)range ); - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; i( i , Real(1) ); - matrix.rowSizes[i] = 1; - } - - if( depth>_minDepth ) - { - // Offset the constraints using the solution from lower resolutions. - int x , y , z , c; - if( node->parent ) - { - c = int( node - node->parent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - } - else x = y = z = 0; - if( insetSupported && coarseToFine ) - { - typename TreeOctNode::Neighbors5 pNeighbors5; - neighborKey.getNeighbors( node->parent , pNeighbors5 ); - UpdateConstraintsFromCoarser( pointInfo , neighbors5 , pNeighbors5 , node , constraints , metSolution , integrator , stencils[x][y][z] ); - } - } - } - return 1; -} -template< class Real > -int Octree< Real >::GetMatrixAndUpdateConstraints( const PointInfo& pointInfo , SparseSymmetricMatrix< Real >& matrix , Pointer( Real ) constraints , const typename BSplineData< 2 >::Integrator& integrator , int depth , const SortedTreeNodes& sNodes , ConstPointer( Real ) metSolution , bool coarseToFine ) -{ - size_t start = sNodes.nodeCount[depth] , end = sNodes.nodeCount[depth+1] , range = end-start; - Stencil< double , 5 > stencil , stencils[2][2][2]; - SetLaplacianStencil ( depth , integrator , stencil ); - SetLaplacianStencils( depth , integrator , stencils ); - matrix.Resize( (int)range ); - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; i( i , Real(1) ); - matrix.rowSizes[i] = 1; - } - if( depth>_minDepth ) - { - // Offset the constraints using the solution from lower resolutions. - int x , y , z , c; - if( node->parent ) - { - c = int( node - node->parent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - } - else x = y = z = 0; - if( insetSupported && coarseToFine ) - { - typename TreeOctNode::Neighbors5 pNeighbors5; - neighborKey.getNeighbors( node->parent , pNeighbors5 ); - UpdateConstraintsFromCoarser( pointInfo , neighbors5 , pNeighbors5 , node , constraints , metSolution , integrator , stencils[x][y][z] ); - } - } - } - return 1; -} - -template< class Real > -Pointer( Real ) Octree< Real >::SolveSystem( PointInfo& pointInfo , Pointer( Real ) constraints , bool showResidual , int iters , int maxSolveDepth , int cgDepth , double accuracy ) -{ - int iter=0; - typename BSplineData< 2 >::Integrator integrator; - _fData.setIntegrator( integrator , _boundaryType==0 ); - iters = std::max< int >( 0 , iters ); - if( _boundaryType==0 ) maxSolveDepth++ , cgDepth++; - - Pointer( Real ) solution = AllocPointer< Real >( _sNodes.nodeCount[_sNodes.maxDepth] ); - memset( solution , 0 , sizeof(Real)*_sNodes.nodeCount[_sNodes.maxDepth] ); - - solution[0] = 0; - - std::vector< Real > metSolution( _sNodes.nodeCount[ _sNodes.maxDepth-1 ] , 0 ); - for( int d=_minDepth ; d<_sNodes.maxDepth ; d++ ) - { - DumpOutput( "Depth[%d/%d]: %d\n" , _boundaryType==0 ? d-1 : d , _boundaryType==0 ? _sNodes.maxDepth-2 : _sNodes.maxDepth-1 , _sNodes.nodeCount[d+1]-_sNodes.nodeCount[d] ); - if( d==_minDepth ) - _SolveSystemCG( pointInfo , d , integrator , _sNodes , solution , constraints , GetPointer( metSolution ) , _sNodes.nodeCount[_minDepth+1]-_sNodes.nodeCount[_minDepth] , true , showResidual, NULL , NULL , NULL ); - else - { - if( d>cgDepth ) iter += _SolveSystemGS( pointInfo , d , integrator , _sNodes , solution , constraints , GetPointer( metSolution ) , d>maxSolveDepth ? 0 : iters , true , showResidual , NULL , NULL , NULL ); - else iter += _SolveSystemCG( pointInfo , d , integrator , _sNodes , solution , constraints , GetPointer( metSolution ) , d>maxSolveDepth ? 0 : iters , true , showResidual , NULL , NULL , NULL , accuracy ); - } - } - - return solution; -} -template< class Real > -void Octree< Real >::_setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const -{ - const int modulus = 3; - indices.resize( modulus*modulus*modulus ); - int count[modulus*modulus*modulus]; - memset( count , 0 , sizeof(int)*modulus*modulus*modulus ); -#pragma omp parallel for num_threads( threads ) - for( int i=start ; idepthAndOffset( d , off ); - int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); -#pragma omp atomic - count[idx]++; - } - - for( int i=0 ; idepthAndOffset( d , off ); - int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); - indices[idx].push_back( _sNodes.treeNodes[i]->nodeData.nodeIndex - start ); - } -} -template< class Real > -int Octree< Real >::_SolveSystemGS( PointInfo& pointInfo , int depth , const typename BSplineData< 2 >::Integrator& integrator , const SortedTreeNodes& sNodes , Pointer( Real ) solution , Pointer( Real ) constraints , Pointer( Real ) metSolutionConstraints , int iters , bool coarseToFine , bool showResidual , double* bNorm2 , double* inRNorm2 , double* outRNorm2 , bool forceSilent ) -{ - Pointer( Real ) metSolution = NullPointer< Real >(); - Pointer( Real ) metConstraints = NullPointer< Real >(); - if( coarseToFine ) metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 - else metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth - - double _maxMemoryUsage = maxMemoryUsage; - maxMemoryUsage = 0; - Vector< Real > X , B; - int slices = 1< offsets( slices+1 , 0 ); - for( int i=sNodes.nodeCount[depth] ; idepthAndOffset( d , off ); - offsets[ off[2] ]++; - } - for( int i=1 ; i=1 ; i-- ) offsets[i] = offsets[i-1]; - offsets[0] = 0; - - X.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] ); - B.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] ); - if( coarseToFine ) - { - if( depth>_minDepth ) - { - // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) - if( depth-2>=_minDepth ) UpSample( depth-1 , sNodes , ( ConstPointer( Real ) )metSolution+_sNodes.nodeCount[depth-2] , metSolution+_sNodes.nodeCount[depth-1] ); - // Add in the change in solution @(depth-1) -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += solution[i]; - // Evaluate the points @(depth) using the cumulative change in solution @(depth-1) - if( _constrainValues ) - { - evaluateTime = Time(); - SetPointValuesFromCoarser( pointInfo , depth , sNodes , metSolution+_sNodes.nodeCount[depth-1] ); - evaluateTime = Time() - evaluateTime; - } - } - } - else if( depth<_sNodes.maxDepth-1 ) - for( int i=_sNodes.nodeCount[depth] ; i<_sNodes.nodeCount[depth+1] ; i++ ) constraints[i] -= metConstraints[i]; - // Initialize with the previously computed solution -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth] ; i<_sNodes.nodeCount[depth+1] ; i++ ) X[ i-_sNodes.nodeCount[depth] ] = solution[i]; - double bNorm=0 , inRNorm=0 , outRNorm=0; - if( depth>=_minDepth ) - { - int frontOffset = ( showResidual || inRNorm2 ) ? 2 : 0; - int backOffset = ( showResidual || outRNorm2 ) ? 2 : 0; - int solveSlices = std::min< int >( 2*iters-1 , slices ) , matrixSlices = std::max< int >( 1 , std::min< int >( solveSlices+frontOffset+backOffset , slices ) ); - std::vector< SparseMatrix< Real > > _M( matrixSlices ); - std::vector< std::vector< std::vector< int > > > __mcIndices( std::max< int >( 0 , solveSlices ) ); - - int dir = coarseToFine ? -1 : 1 , start = coarseToFine ? slices-1 : 0 , end = coarseToFine ? -1 : slices; - for( int frontSlice=start-frontOffset*dir , backSlice = frontSlice-2*(iters-1)*dir ; backSlice!=end+backOffset*dir ; frontSlice+=dir , backSlice+=dir ) - { - double t; - if( frontSlice+frontOffset*dir>=0 && frontSlice+frontOffset*dirnodeData.nodeIndex ]; - else B[i] = Real(0); - } - if( showResidual || inRNorm2 ) -#pragma omp parallel for num_threads( threads ) reduction( + : bNorm , inRNorm ) - for( int j=0 ; j<_M[_s].rows ; j++ ) - { - Real temp = Real(0); - ConstPointer( MatrixEntry< Real > ) start = _M[_s][j]; - ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - Real b = B[ j + offsets[s] ] ; - bNorm += b*b; - inRNorm += (temp-b) * (temp-b); - } - else if( bNorm2 ) -#pragma omp parallel for num_threads( threads ) reduction( + : bNorm ) - for( int j=0 ; j<_M[_s].rows ; j++ ) - { - Real b = B[ j + offsets[s] ] ; - bNorm += b*b; - } - } - t = Time(); - if( iters && frontSlice>=0 && frontSlice=backSlice*dir ; slice-=2*dir ) - if( slice>=0 && slice::SolveGS( __mcIndices[__s] , _M[_s] , B , X , !coarseToFine , threads , offsets[s] ); - } - solveTime += Time() - t; - if( (showResidual || outRNorm2) && backSlice-backOffset*dir>=0 && backSlice-backOffset*dir ) start = _M[_s][j]; - ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - Real b = B[ j + offsets[s] ]; - outRNorm += (temp-b) * (temp-b); - } - } - } - } - - if( bNorm2 ) bNorm2[depth] = bNorm; - if( inRNorm2 ) inRNorm2[depth] = inRNorm; - if( outRNorm2 ) outRNorm2[depth] = outRNorm; - if( showResidual && iters ) - { - for( int i=0 ; i %.4e -> %.4e (%.2e) [%d]\n" , sqrt( bNorm ) , sqrt( inRNorm ) , sqrt( outRNorm ) , sqrt( outRNorm/bNorm ) , iters ); - } - - // Copy the old solution into the buffer, write in the new solution, compute the change, and update the met constraints -#pragma omp parallel for num_threads( threads ) - for( int i=sNodes.nodeCount[depth] ; i_minDepth ) - { - // Explicitly compute the restriction of the met solution onto the coarser nodes - // and down-sample the previous accumulation - { - UpdateConstraintsFromFiner( integrator , depth , sNodes , GetPointer( X ) , metConstraints+sNodes.nodeCount[depth-1] ); - if( _constrainValues ) SetPointConstraintsFromFiner( pointInfo , depth , sNodes , GetPointer( X ) , metConstraints+sNodes.nodeCount[depth-1] ); - if( depth( maxMemoryUsage , _maxMemoryUsage ); - - return iters; -} -template< class Real > -int Octree< Real >::_SolveSystemCG( PointInfo& pointInfo , int depth , const typename BSplineData< 2 >::Integrator& integrator , const SortedTreeNodes& sNodes , Pointer( Real ) solution , Pointer( Real ) constraints , Pointer( Real ) metSolutionConstraints , int iters , bool coarseToFine , bool showResidual , double* bNorm2 , double* inRNorm2 , double* outRNorm2 , double accuracy ) -{ - Pointer( Real ) metSolution = NullPointer< Real >(); - Pointer( Real ) metConstraints = NullPointer< Real >(); - if( coarseToFine ) metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 - else metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth - double _maxMemoryUsage = maxMemoryUsage; - maxMemoryUsage = 0; - int iter = 0; - Vector< Real > X , B; - SparseSymmetricMatrix< Real > M; - double systemTime=0. , solveTime=0. , updateTime=0. , evaluateTime = 0.; - X.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] ); - if( coarseToFine ) - { - if( depth>_minDepth ) - { - // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) - if( depth-2>=_minDepth ) UpSample( depth-1 , sNodes , ( ConstPointer( Real ) )metSolution+_sNodes.nodeCount[depth-2] , metSolution+_sNodes.nodeCount[depth-1] ); - // Add in the change in solution @(depth-1) -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth-1] ; i<_sNodes.nodeCount[depth] ; i++ ) metSolution[i] += solution[i]; - // Evaluate the points @(depth) using the cumulative change in solution @(depth-1) - if( _constrainValues ) - { - evaluateTime = Time(); - SetPointValuesFromCoarser( pointInfo , depth , sNodes , metSolution+_sNodes.nodeCount[depth-1] ); - evaluateTime = Time() - evaluateTime; - } - } - } - else if( depth<_sNodes.maxDepth-1 ) - for( int i=_sNodes.nodeCount[depth] ; i<_sNodes.nodeCount[depth+1] ; i++ ) constraints[i] -= metConstraints[i]; - // Initialize with the previously computed solution -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[depth] ; i<_sNodes.nodeCount[depth+1] ; i++ ) X[ i-_sNodes.nodeCount[depth] ] = solution[i]; - systemTime = Time(); - { - // Get the system matrix (and adjust the right-hand-side based on the coarser solution if prolonging) - if( coarseToFine ) GetMatrixAndUpdateConstraints( pointInfo , M , constraints , integrator , depth , sNodes , metSolution , true ); - else GetMatrixAndUpdateConstraints( pointInfo , M , constraints , integrator , depth , sNodes , NullPointer< Real >() , false ); - // Set the constraint vector - B.Resize( sNodes.nodeCount[depth+1]-sNodes.nodeCount[depth] ); - for( int i=sNodes.nodeCount[depth] ; i mrVector; - mrVector.resize( threads , M.rows ); - bool addDCTerm = (M.rows==res*res*res && !_constrainValues && _boundaryType!=-1); - double bNorm , inRNorm , outRNorm; - if( showResidual || bNorm2 ) bNorm = B.Norm( 2 ); - if( showResidual || inRNorm2 ) inRNorm = ( addDCTerm ? ( B - M * X - X.Average() ) : ( B - M * X ) ).Norm( 2 ); - - if( _boundaryType==0 && depth>3 ) res -= 1<<(depth-2); - if( iters ) iter += SparseSymmetricMatrix< Real >::SolveCG( M , B , iters , X , mrVector , Real( accuracy ) , 0 , addDCTerm ); - solveTime = Time()-solveTime; - if( showResidual || outRNorm2 ) outRNorm = ( addDCTerm ? ( B - M * X - X.Average() ) : ( B - M * X ) ).Norm( 2 ); - if( bNorm2 ) bNorm2[depth] = bNorm * bNorm; - if( inRNorm2 ) inRNorm2[depth] = inRNorm * inRNorm; - if( outRNorm2 ) outRNorm2[depth] = outRNorm * outRNorm; - if( showResidual && iters ) - { - for( int i=0 ; i %.4e -> %.4e (%.2e) [%d]\n" , bNorm , inRNorm , outRNorm , outRNorm/bNorm , iter ); - } - - // Copy the old solution into the buffer, write in the new solution, compute the change, and update the met solution - { -#pragma omp parallel for num_threads( threads ) - for( int i=sNodes.nodeCount[depth] ; i_minDepth ) - { - // Explicitly compute the restriction of the met solution onto the coarser nodes - // and down-sample the previous accumulation - { - UpdateConstraintsFromFiner( integrator , depth , sNodes , GetPointer( X ) , metConstraints + sNodes.nodeCount[depth-1] ); - if( _constrainValues ) SetPointConstraintsFromFiner( pointInfo , depth , sNodes , GetPointer( X ) , metConstraints+sNodes.nodeCount[depth-1] ); - if( depth( maxMemoryUsage , _maxMemoryUsage ); - return iter; -} -template< class Real > -int Octree< Real >::HasNormals( TreeOctNode* node , const NormalInfo& normalInfo ) -{ - int idx = normalInfo.normalIndex( node ); - if( idx>=0 ) - { - const Point3D< Real >& normal = normalInfo.normals[ idx ]; - if( normal[0]!=0 || normal[1]!=0 || normal[2]!=0 ) return 1; - } - if( node->children ) for( int i=0 ; ichildren[i] , normalInfo ) ) return 1; - return 0; -} -template< class Real > -Pointer( Real ) Octree< Real >::SetLaplacianConstraints( const NormalInfo& normalInfo ) -{ - // To set the Laplacian constraints, we iterate over the - // splatted normals and compute the dot-product of the - // divergence of the normal field with all the basis functions. - // Within the same depth: set directly as a gather - // Coarser depths - typename BSplineData< 2 >::Integrator integrator; - _fData.setIntegrator( integrator , _boundaryType==0 ); - int maxDepth = _sNodes.maxDepth-1; - Point3D< Real > zeroPoint; - zeroPoint[0] = zeroPoint[1] = zeroPoint[2] = 0; - Pointer( Real ) constraints = AllocPointer< Real >( _sNodes.nodeCount[_sNodes.maxDepth] ); - if( !constraints ) fprintf( stderr , "[ERROR] Failed to allocate constraints: %d * %zu\n" , _sNodes.nodeCount[_sNodes.maxDepth] , sizeof( Real ) ) , exit( 0 ); - memset( constraints , 0 , sizeof(Real)*_sNodes.nodeCount[_sNodes.maxDepth] ); - Pointer( Real ) _constraints = AllocPointer< Real >( _sNodes.nodeCount[maxDepth] ); - if( !_constraints ) fprintf( stderr , "[ERROR] Failed to allocate _constraints: %d * %zu\n" , _sNodes.nodeCount[maxDepth] , sizeof( Real ) ) , exit( 0 ); - memset( _constraints , 0 , sizeof(Real)*_sNodes.nodeCount[maxDepth] ); - MemoryUsage(); - - for( int d=maxDepth ; d>=(_boundaryType==0?2:0) ; d-- ) - { - int offset = d>0 ? _sNodes.treeNodes[ _sNodes.nodeCount[d-1] ]->nodeData.nodeIndex : 0; - Stencil< Point3D< double > , 5 > stencil , stencils[2][2][2]; - SetDivergenceStencil ( d , integrator , stencil , false ); - SetDivergenceStencils( d , integrator , stencils , true ); - - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepth(); - typename TreeOctNode::Neighbors5 neighbors5; - neighborKey.getNeighbors( node , neighbors5 ); - - bool isInterior , isInterior2; - { - int d , off[3]; - node->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2)) : 0; - int mn = 2+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]=mn && off[0]=mn && off[1]=mn && off[2]parent->children ); - Cube::FactorCornerIndex( c , cx , cy , cz ); - } - else cx = cy = cz = 0; - Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz]; - int d , off[3]; - node->depthAndOffset( d , off ); - // Set constraints from current depth - // Gather the constraints from the vector-field at _node into the constraint stored with node - { - - if( isInterior ) - for( int x=startX ; x=0 ) constraints[ node->nodeData.nodeIndex ] += Point3D< Real >::Dot( stencil.values[x][y][z] , normalInfo.normals[ _idx ] ); - } - } - else - for( int x=startX ; x=0 ) - { - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); - constraints[ node->nodeData.nodeIndex ] += Real( GetDivergence2( integrator , d , off , _off , false , normalInfo.normals[ _idx ] ) ); - } - } - } - UpdateCoarserSupportBounds( neighbors5.neighbors[2][2][2] , startX , endX , startY , endY , startZ , endZ ); - } - int idx = normalInfo.normalIndex( node ); - if( idx<0 ) continue; - const Point3D< Real >& normal = normalInfo.normals[ idx ]; - if( normal[0]==0 && normal[1]==0 && normal[2]==0 ) continue; - - // Set the constraints for the parents - if( depth>_minDepth ) - { - neighborKey.getNeighbors( node->parent , neighbors5 ); - - for( int x=startX ; x& div = _stencil.values[x][y][z]; - c = Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] ); - } - else - { - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); - c = Real( GetDivergence1( integrator , d , off , _off , true , normal ) ); - } -#pragma omp atomic - _constraints[ _node->nodeData.nodeIndex ] += c; - } - } - } - MemoryUsage(); - } - - // Fine-to-coarse down-sampling of constraints - for( int d=maxDepth-1 ; d>=(_boundaryType==0?2:0) ; d-- ) DownSample( d , _sNodes , ( ConstPointer( Real ) )_constraints + _sNodes.nodeCount[d] , _constraints+_sNodes.nodeCount[d-1] ); - - // Add the accumulated constraints from all finer depths -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i<_sNodes.nodeCount[maxDepth] ; i++ ) constraints[i] += _constraints[i]; - - FreePointer( _constraints ); - - - std::vector< Point3D< Real > > coefficients( _sNodes.nodeCount[maxDepth] , zeroPoint ); - for( int d=maxDepth-1 ; d>=0 ; d-- ) - { -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodes.nodeCount[d] ; i<_sNodes.nodeCount[d+1] ; i++ ) - { - int idx = normalInfo.normalIndex( _sNodes.treeNodes[i] ); - if( idx<0 ) continue; - coefficients[i] = normalInfo.normals[ idx ]; - } - } - - // Coarse-to-fine up-sampling of coefficients - for( int d=(_boundaryType==0?2:0) ; d ) ) GetPointer( coefficients ) + _sNodes.nodeCount[d-1] , GetPointer( coefficients ) + _sNodes.nodeCount[d] ); - - // Compute the contribution from all coarser depths - for( int d=0 ; d<=maxDepth ; d++ ) - { - size_t start = _sNodes.nodeCount[d] , end = _sNodes.nodeCount[d+1] , range = end - start; - Stencil< Point3D< double > , 5 > stencils[2][2][2]; - SetDivergenceStencils( d , integrator , stencils , false ); - std::vector< typename TreeOctNode::NeighborKey3 > neighborKeys( std::max< int >( 1 , threads ) ); - for( int i=0 ; idepth(); - if( !depth ) continue; - int startX=0 , endX=5 , startY=0 , endY=5 , startZ=0 , endZ=5; - UpdateCoarserSupportBounds( node , startX , endX , startY , endY , startZ , endZ ); - typename TreeOctNode::Neighbors5 neighbors5; - neighborKey.getNeighbors( node->parent , neighbors5 ); - - bool isInterior; - { - int d , off[3]; - node->depthAndOffset( d , off ); - int o = _boundaryType==0 ? (1<<(d-2)) : 0; - int mn = 4+o , mx = (1<=mn && off[0]=mn && off[1]=mn && off[2]parent->children ); - Cube::FactorCornerIndex( c , cx , cy , cz ); - } - else cx = cy = cz = 0; - Stencil< Point3D< double > , 5 >& _stencil = stencils[cx][cy][cz]; - - Real constraint = Real(0); - int d , off[3]; - node->depthAndOffset( d , off ); - for( int x=startX ; xnodeData.nodeIndex; - if( isInterior ) - { - Point3D< double >& div = _stencil.values[x][y][z]; - Point3D< Real >& normal = coefficients[_i]; - constraint += Real( div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2] ); - } - else - { - int _d , _off[3]; - _node->depthAndOffset( _d , _off ); - constraint += Real( GetDivergence2( integrator , d , off , _off , true , coefficients[_i] ) ); - } - } - constraints[ node->nodeData.nodeIndex ] += constraint; - } - } - MemoryUsage(); - return constraints; -} -template< class Real > -void Octree< Real >::refineBoundary( std::vector< int >* map ){ _sNodes.set( tree , map ); } - - - -template< class Real > -Real Octree< Real >::getCenterValue( const typename TreeOctNode::ConstNeighborKey3& neighborKey , const TreeOctNode* node , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CenterEvaluator< 1 >& evaluator , const Stencil< double , 3 >& stencil , const Stencil< double , 3 >& pStencil , bool isInterior ) const -{ - if( node->children ) fprintf( stderr , "[WARNING] getCenterValue assumes leaf node\n" ); - Real value=0; - - int d , off[3]; - node->depthAndOffset( d , off ); - - if( isInterior ) - { - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - { - const TreeOctNode* n = neighborKey.neighbors[d].neighbors[i][j][k]; - if( n ) value += solution[ n->nodeData.nodeIndex ] * Real( stencil.values[i][j][k] ); - } - if( d>_minDepth ) - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - { - const TreeOctNode* n = neighborKey.neighbors[d-1].neighbors[i][j][k]; - if( n ) value += metSolution[n->nodeData.nodeIndex] * Real( pStencil.values[i][j][k] ); - } - } - else - { - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - { - const TreeOctNode* n = neighborKey.neighbors[d].neighbors[i][j][k]; - if( n ) - { - int _d , _off[3]; - n->depthAndOffset( _d , _off ); - value += - solution[ n->nodeData.nodeIndex ] * Real( - evaluator.value( d , off[0] , _off[0] , false , false ) * evaluator.value( d , off[1] , _off[1] , false , false ) * evaluator.value( d , off[1] , _off[1] , false , false ) ); - } - } - if( d>_minDepth ) - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - { - const TreeOctNode* n = neighborKey.neighbors[d-1].neighbors[i][j][k]; - if( n ) - { - int _d , _off[3]; - n->depthAndOffset( _d , _off ); - value += - solution[ n->nodeData.nodeIndex ] * Real( - evaluator.value( d , off[0] , _off[0] , false , false ) * evaluator.value( d , off[1] , _off[1] , false , false ) * evaluator.value( d , off[1] , _off[1] , false , false ) ); - } - } - } - return value; -} -template< class Real > -Real Octree< Real >::getCornerValue( const typename TreeOctNode::ConstNeighborKey3& neighborKey , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 >& stencil , const Stencil< double , 3 > stencils[8] , bool isInterior ) const -{ - double value = 0; - if( _boundaryType==-1 ) value = -0.5; - int d , off[3]; - node->depthAndOffset( d , off ); - - int cx , cy , cz; - int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3; - Cube::FactorCornerIndex( corner , cx , cy , cz ); - { - typename TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d]; - if( cx==0 ) endX = 2; - else startX = 1; - if( cy==0 ) endY = 2; - else startY = 1; - if( cz==0 ) endZ = 2; - else startZ = 1; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * stencil.values[x][y][z]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - value += solution[ _node->nodeData.nodeIndex ] * evaluator.value( d , off[0] , cx , _off[0] , false , false ) * evaluator.value( d , off[1] , cy , _off[1] , false , false ) * evaluator.value( d , off[2] , cz , _off[2] , false , false ); - } - } - } - if( d>_minDepth ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - if( cx!=_cx ) startX = 0 , endX = 3; - if( cy!=_cy ) startY = 0 , endY = 3; - if( cz!=_cz ) startZ = 0 , endZ = 3; - typename TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d-1]; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * stencils[_corner].values[x][y][z]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - value += metSolution[ _node->nodeData.nodeIndex ] * evaluator.value( d , off[0] , cx , _off[0] , false , true ) * evaluator.value( d , off[1] , cy , _off[1] , false , true ) * evaluator.value( d , off[2] , cz , _off[2] , false , true ); - } - } - } - return Real( value ); -} -template< class Real > -std::pair< Real , Point3D< Real > > Octree< Real >::getCornerValueAndNormal( const typename TreeOctNode::ConstNeighborKey3& neighborKey , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< double , 3 >& vStencil , const Stencil< double , 3 > vStencils[8] , const Stencil< Point3D< double > , 3 >& nStencil , const Stencil< Point3D< double > , 3 > nStencils[8] , bool isInterior ) const -{ - double value = 0; - Point3D< double > normal; - if( _boundaryType==-1 ) value = -0.5; - int d , off[3]; - node->depthAndOffset( d , off ); - - int cx , cy , cz; - int startX = 0 , endX = 3 , startY = 0 , endY = 3 , startZ = 0 , endZ = 3; - Cube::FactorCornerIndex( corner , cx , cy , cz ); - { - typename TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d]; - if( cx==0 ) endX = 2; - else startX = 1; - if( cy==0 ) endY = 2; - else startY = 1; - if( cz==0 ) endZ = 2; - else startZ = 1; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * vStencil.values[x][y][z] , normal += nStencil.values[x][y][z] * solution[ _node->nodeData.nodeIndex ]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - double v [] = { evaluator.value( d , off[0] , cx , _off[0] , false , false ) , evaluator.value( d , off[1] , cy , _off[1] , false , false ) , evaluator.value( d , off[2] , cz , _off[2] , false , false ) }; - double dv[] = { evaluator.value( d , off[0] , cx , _off[0] , true , false ) , evaluator.value( d , off[1] , cy , _off[1] , true , false ) , evaluator.value( d , off[2] , cz , _off[2] , true , false ) }; - value += solution[ _node->nodeData.nodeIndex ] * evaluator.value( d , off[0] , cx , _off[0] , false , false ) * evaluator.value( d , off[1] , cy , _off[1] , false , false ) * evaluator.value( d , off[2] , cz , _off[2] , false , false ); - normal += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; - } - } - } - if( d>_minDepth ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - if( cx!=_cx ) startX = 0 , endX = 3; - if( cy!=_cy ) startY = 0 , endY = 3; - if( cz!=_cz ) startZ = 0 , endZ = 3; - typename TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d-1]; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * vStencils[_corner].values[x][y][z] , normal += nStencils[_corner].values[x][y][z] * metSolution[ _node->nodeData.nodeIndex ]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - double v [] = { evaluator.value( d , off[0] , cx , _off[0] , false , true ) , evaluator.value( d , off[1] , cy , _off[1] , false , true ) , evaluator.value( d , off[2] , cz , _off[2] , false , true ) }; - double dv[] = { evaluator.value( d , off[0] , cx , _off[0] , true , true ) , evaluator.value( d , off[1] , cy , _off[1] , true , true ) , evaluator.value( d , off[2] , cz , _off[2] , true , true ) }; - value += metSolution[ _node->nodeData.nodeIndex ] * evaluator.value( d , off[0] , cx , _off[0] , false , true ) * evaluator.value( d , off[1] , cy , _off[1] , false , true ) * evaluator.value( d , off[2] , cz , _off[2] , false , true ); - normal += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * metSolution[ _node->nodeData.nodeIndex ]; - } - } - } - return std::pair< Real , Point3D< Real > >( Real( value ) , Point3D< Real >( normal ) ); -} -template< class Real > -Point3D< Real > Octree< Real >::getCornerNormal( const typename TreeOctNode::ConstNeighbors5& neighbors5 , const typename TreeOctNode::ConstNeighbors5& pNeighbors5 , const TreeOctNode* node , int corner , ConstPointer( Real ) solution , ConstPointer( Real ) metSolution , const typename BSplineData< 2 >::template CornerEvaluator< 2 >& evaluator , const Stencil< Point3D< double > , 5 >& nStencil , const Stencil< Point3D< double > , 5 > nStencils[8] , bool isInterior ) const -{ - Point3D< double > normal; - normal[0] = normal[1] = normal[2] = 0.; - - int d , off[3]; - node->depthAndOffset( d , off ); - - int cx , cy , cz; - int startX = 0 , endX = 5 , startY = 0 , endY = 5 , startZ = 0 , endZ = 5; - Cube::FactorCornerIndex( corner , cx , cy , cz ); - { - if( cx==0 ) endX = 4; - else startX = 1; - if( cy==0 ) endY = 4; - else startY = 1; - if( cz==0 ) endZ = 4; - else startZ = 1; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - double v [] = { evaluator.value( d , off[0] , cx , _off[0] , false , false ) , evaluator.value( d , off[1] , cy , _off[1] , false , false ) , evaluator.value( d , off[2] , cz , _off[2] , false , false ) }; - double dv[] = { evaluator.value( d , off[0] , cx , _off[0] , true , false ) , evaluator.value( d , off[1] , cy , _off[1] , true , false ) , evaluator.value( d , off[2] , cz , _off[2] , true , false ) }; - normal += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; - } - } - } - if( d>_minDepth ) - { - int _cx , _cy , _cz , _corner = int( node - node->parent->children ); - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - if( cx!=_cx ) startX = 0 , endX = 5; - if( cy!=_cy ) startY = 0 , endY = 5; - if( cz!=_cz ) startZ = 0 , endZ = 5; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ]; - } - else - for( int x=startX ; xdepthAndOffset( _d , _off ); - double v [] = { evaluator.value( d , off[0] , cx , _off[0] , false , true ) , evaluator.value( d , off[1] , cy , _off[1] , false , true ) , evaluator.value( d , off[2] , cz , _off[2] , false , true ) }; - double dv[] = { evaluator.value( d , off[0] , cx , _off[0] , true , true ) , evaluator.value( d , off[1] , cy , _off[1] , true , true ) , evaluator.value( d , off[2] , cz , _off[2] , true , true ) }; - normal += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * metSolution[ _node->nodeData.nodeIndex ]; - } - } - } - return Point3D< Real >( Real(normal[0]) , Real(normal[1]) , Real(normal[2]) ); -} - -template< class Real > -Real Octree< Real >::Evaluate( ConstPointer( Real ) coefficients , Point3D< Real > p , const BSplineData< 2 >* fData ) const -{ - Real value = Real(0); - BSplineData< 2 > _fData; - if( !fData ) _fData.set( tree.maxDepth() , _boundaryType ) , fData = &_fData; - const TreeOctNode* n = tree.nextNode(); - while( n ) - { - Point3D< Real > c; - Real w; - n->centerAndWidth( c , w ); - c -= p , w *= Real(1.5); - if( fabs(c[0])>w || fabs(c[1])>w || fabs(c[2])>w ) - { - n = tree.nextBranch( n ); - continue; - } - int d , off[3]; - n->depthAndOffset( d , off ); - value += (Real) - ( - coefficients[ n->nodeData.nodeIndex ] * - fData->baseFunctions[ BinaryNode::CenterIndex( d , off[0] ) ]( p[0] ) * - fData->baseFunctions[ BinaryNode::CenterIndex( d , off[1] ) ]( p[1] ) * - fData->baseFunctions[ BinaryNode::CenterIndex( d , off[2] ) ]( p[2] ) - ); - n = tree.nextNode( n ); - } - if( _boundaryType==-1 ) value -= Real(0.5); - return value; -} -template< class Real > -Pointer( Real ) Octree< Real >::Evaluate( ConstPointer( Real ) coefficients , int& res , Real isoValue , int depth ) -{ - int maxDepth = _boundaryType==0 ? tree.maxDepth()-1 : tree.maxDepth(); - if( depth<=0 || depth>maxDepth ) depth = maxDepth; - res = 1<::template ValueTables< Real > vTables = _fData.template getValueTables< Real >( _fData.VALUE_FLAG ); - Pointer( Real ) values = NewPointer< Real >( res * res * res ); - memset( values , 0 , sizeof( Real ) * res * res * res ); - - for( TreeOctNode* n=tree.nextNode() ; n ; n=tree.nextNode( n ) ) - { - if( n->depth()>(_boundaryType==0?depth+1:depth) ) continue; - if( n->depth()<_minDepth ) continue; - int d , idx[3] , start[3] , end[3]; - n->depthAndOffset( d , idx ); - bool skip=false; - for( int i=0 ; i<3 ; i++ ) - { - // Get the index of the functions - idx[i] = BinaryNode::CenterIndex( d , idx[i] ); - // Figure out which samples fall into the range - vTables.setSampleSpan( idx[i] , start[i] , end[i] ); - // We only care about the odd indices - if( !(start[i]&1) ) start[i]++; - if( !( end[i]&1) ) end[i]--; - if( _boundaryType==0 ) - { - // (start[i]-1)>>1 >= res/2 - // ( end[i]-1)<<1 < 3*res/2 - start[i] = std::max< int >( start[i] , res+1 ); - end [i] = std::min< int >( end [i] , 3*res-1 ); - } - } - if( skip ) continue; - Real coefficient = coefficients[ n->nodeData.nodeIndex ]; - for( int x=start[0] ; x<=end[0] ; x+=2 ) - for( int y=start[1] ; y<=end[1] ; y+=2 ) - for( int z=start[2] ; z<=end[2] ; z+=2 ) - { - int xx = (x-1)>>1 , yy=(y-1)>>1 , zz = (z-1)>>1; - if( _boundaryType==0 ) xx -= res/2 , yy -= res/2 , zz -= res/2; - values[ zz*res*res + yy*res + xx ] += - coefficient * - vTables.valueTable[ idx[0] + x*vTables.functionCount ] * - vTables.valueTable[ idx[1] + y*vTables.functionCount ] * - vTables.valueTable[ idx[2] + z*vTables.functionCount ]; - } - } - if( _boundaryType==-1 ) for( int i=0 ; idepthAndOffset(d,o); - for(int i=0;idepthAndOffset( d , o ); - for( int i=0 ; idepthAndOffset(d,o); - for(int i=0;idepthAndOffset( d ,off ); - Cube::FactorEdgeIndex( eIndex , o , i1 , i2 ); - for( int i=0 ; i -#include -#ifndef WIN32 -#include -#endif // WIN32 - -inline double Time( void ) -{ -#ifdef WIN32 - struct _timeb t; - _ftime( &t ); - return double( t.time ) + double( t.millitm ) / 1000.0; -#else // WIN32 - struct timeval t; - gettimeofday( &t , NULL ); - return t.tv_sec + double( t.tv_usec ) / 1000000; -#endif // WIN32 -} - -#endif // MY_TIME_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/Octree.h b/src/scanner/PoissonRecon/Src/Octree.h deleted file mode 100755 index dd2b39e..0000000 --- a/src/scanner/PoissonRecon/Src/Octree.h +++ /dev/null @@ -1,292 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef OCT_NODE_INCLUDED -#define OCT_NODE_INCLUDED - -#include "Allocator.h" -#include "BinaryNode.h" -#include "MarchingCubes.h" - -#define DIMENSION 3 - - -template< class NodeData > -class OctNode -{ -private: - static int UseAlloc; - unsigned long long _depthAndOffset; - - class AdjacencyCountFunction - { - public: - int count; - void Function( const OctNode< NodeData >* node1 , const OctNode< NodeData >* node2 ); - }; - template - void __processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2,int cIndex3,int cIndex4); - template< class NodeAdjacencyFunction > - void __processNodeFaces( const OctNode* node , NodeAdjacencyFunction* F , int cIndex1 , int cIndex2 , int cIndex3 , int cIndex4 ) const; - template - void __processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2); - template - void __processNodeNodes(OctNode* node,NodeAdjacencyFunction* F); - template - static void __ProcessNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,NodeAdjacencyFunction* F); - template - static void __ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,TerminatingNodeAdjacencyFunction* F); - template - static void __ProcessPointAdjacentNodes(int dx,int dy,int dz,OctNode* node2,int radius2,int cWidth2,PointAdjacencyFunction* F); - template - static void __ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,int depth,NodeAdjacencyFunction* F); - template - static void __ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,int depth,NodeAdjacencyFunction* F); - - // This is made private because the division by two has been pulled out. - static inline int Overlap(int c1,int c2,int c3,int dWidth); - inline static int ChildOverlap(int dx,int dy,int dz,int d,int cRadius2); - - const OctNode* __faceNeighbor(int dir,int off) const; - const OctNode* __edgeNeighbor(int o,const int i[2],const int idx[2]) const; - OctNode* __faceNeighbor(int dir,int off,int forceChildren); - OctNode* __edgeNeighbor(int o,const int i[2],const int idx[2],int forceChildren); -public: - static const int DepthShift,OffsetShift,OffsetShift1,OffsetShift2,OffsetShift3; - static const int DepthMask,OffsetMask; - - static Allocator< OctNode > NodeAllocator; - static int UseAllocator( void ); - static void SetAllocator( int blockSize ); - - OctNode* parent; - OctNode* children; - NodeData nodeData; - - OctNode(void); - ~OctNode(void); - int initChildren( void ); - - void depthAndOffset( int& depth , int offset[DIMENSION] ) const; - void centerIndex( int index[DIMENSION] ) const; - int depth( void ) const; - static inline void DepthAndOffset( const long long& index , int& depth , int offset[DIMENSION] ); - template< class Real > static inline void CenterAndWidth( const long long& index , Point3D< Real >& center , Real& width ); - static inline int Depth( const long long& index ); - static inline void Index( int depth , const int offset[3] , short& d , short off[DIMENSION] ); - static inline unsigned long long Index( int depth , const int offset[3] ); - template< class Real > void centerAndWidth( Point3D& center , Real& width ) const; - template< class Real > bool isInside( Point3D< Real > p ) const; - - size_t leaves( void ) const; - size_t maxDepthLeaves( int maxDepth ) const; - size_t nodes( void ) const; - int maxDepth( void ) const; - - const OctNode* root( void ) const; - - const OctNode* nextLeaf(const OctNode* currentLeaf=NULL) const; - OctNode* nextLeaf(OctNode* currentLeaf=NULL); - const OctNode* nextNode(const OctNode* currentNode=NULL) const; - OctNode* nextNode(OctNode* currentNode=NULL); - const OctNode* nextBranch(const OctNode* current) const; - OctNode* nextBranch(OctNode* current); - const OctNode* prevBranch(const OctNode* current) const; - OctNode* prevBranch(OctNode* current); - - void setFullDepth(int maxDepth); - - void printLeaves(void) const; - void printRange(void) const; - - template - void processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int fIndex,int processCurrent=1); - template< class NodeAdjacencyFunction > - void processNodeFaces( const OctNode* node , NodeAdjacencyFunction* F , int fIndex , int processCurrent=1 ) const; - template - void processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int eIndex,int processCurrent=1); - template - void processNodeCorners(OctNode* node,NodeAdjacencyFunction* F,int cIndex,int processCurrent=1); - template - void processNodeNodes(OctNode* node,NodeAdjacencyFunction* F,int processCurrent=1); - - template - static void ProcessNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessTerminatingNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessPointAdjacentNodes(int maxDepth,const int center1[3],OctNode* node2,int width2,PointAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessPointAdjacentNodes(int dx,int dy,int dz,OctNode* node2,int radius2,int width2,PointAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessFixedDepthNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessMaxDepthNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - - template< class Real > static int CornerIndex( const Point3D& center , const Point3D &p ); - - OctNode* faceNeighbor(int faceIndex,int forceChildren=0); - const OctNode* faceNeighbor(int faceIndex) const; - OctNode* edgeNeighbor(int edgeIndex,int forceChildren=0); - const OctNode* edgeNeighbor(int edgeIndex) const; - OctNode* cornerNeighbor(int cornerIndex,int forceChildren=0); - const OctNode* cornerNeighbor(int cornerIndex) const; - - template< class Real > OctNode* getNearestLeaf(const Point3D& p); - template< class Real > const OctNode* getNearestLeaf(const Point3D& p) const; - - static int CommonEdge(const OctNode* node1,int eIndex1,const OctNode* node2,int eIndex2); - static int CompareForwardDepths(const void* v1,const void* v2); - static int CompareByDepthAndXYZ( const void* v1 , const void* v2 ); - static int CompareByDepthAndZIndex( const void* v1 , const void* v2 ); - static int CompareForwardPointerDepths(const void* v1,const void* v2); - static int CompareBackwardDepths(const void* v1,const void* v2); - static int CompareBackwardPointerDepths(const void* v1,const void* v2); - - - template - OctNode& operator = ( const OctNode< NodeData2 >& node ); - - template< class Real > - static inline int Overlap2(const int &depth1,const int offSet1[DIMENSION],const Real& multiplier1,const int &depth2,const int offSet2[DIMENSION],const Real& multiplier2); - - - int write(const char* fileName) const; - int write(FILE* fp) const; - int read(const char* fileName); - int read(FILE* fp); - - class Neighbors5 - { - public: - OctNode* neighbors[5][5][5]; - Neighbors5( void ); - void clear( void ); - }; - class ConstNeighbors5 - { - public: - const OctNode* neighbors[5][5][5]; - ConstNeighbors5( void ); - void clear( void ); - }; - - class NeighborKey5 - { - int _depth; - public: - Neighbors5* neighbors; - - NeighborKey5( void ); - ~NeighborKey5( void ); - - void set( int depth ); - Neighbors5& getNeighbors( OctNode* node ); - Neighbors5& setNeighbors( OctNode* node , int xStart=0 , int xEnd=5 , int yStart=0 , int yEnd=5 , int zStart=0 , int zEnd=5 ); - }; - class ConstNeighborKey5 - { - int _depth; - public: - ConstNeighbors5* neighbors; - - ConstNeighborKey5( void ); - ~ConstNeighborKey5( void ); - - void set( int depth ); - ConstNeighbors5& getNeighbors( const OctNode* node ); - }; - - class Neighbors3 - { - public: - OctNode* neighbors[3][3][3]; - Neighbors3( void ); - void clear( void ); - }; - class ConstNeighbors3 - { - public: - const OctNode* neighbors[3][3][3]; - ConstNeighbors3( void ); - void clear( void ); - }; - class NeighborKey3 - { - int _depth; - public: - Neighbors3* neighbors; - - NeighborKey3( void ); - NeighborKey3( const NeighborKey3& key3 ); - ~NeighborKey3( void ); - - void set( int depth ); - template< class Real > Neighbors3& setNeighbors( OctNode* root , Point3D< Real > p , int d ); - template< class Real > Neighbors3& getNeighbors( OctNode* root , Point3D< Real > p , int d ); - Neighbors3& setNeighbors( OctNode* node , bool flags[3][3][3] ); - Neighbors3& setNeighbors( OctNode* node ); - Neighbors3& getNeighbors( OctNode* node ); - void setNeighbors( OctNode* node , typename OctNode< NodeData >::Neighbors5& neighbors ); - void getNeighbors( OctNode* node , typename OctNode< NodeData >::Neighbors5& neighbors ); - - template< class Real > bool setChildNeighbors( Point3D< Real > p , int d , Neighbors3& childNeighbors ) const; - template< class Real > bool getChildNeighbors( Point3D< Real > p , int d , Neighbors3& childNeighbors ) const; - }; - class ConstNeighborKey3 - { - int _depth; - public: - ConstNeighbors3* neighbors; - - ConstNeighborKey3( void ); - ConstNeighborKey3( const ConstNeighborKey3& key3 ); - ~ConstNeighborKey3( void ); - - void set(int depth); - ConstNeighbors3& getNeighbors( const OctNode* node ); - ConstNeighbors3& getNeighbors( const OctNode* node , int minDepth ); - void getNeighbors( const OctNode* node , typename OctNode< NodeData >::ConstNeighbors5& neighbors ); - }; - - void centerIndex(int maxDepth,int index[DIMENSION]) const; - int width(int maxDepth) const; -}; - - -#include "Octree.inl" - -#endif // OCT_NODE diff --git a/src/scanner/PoissonRecon/Src/Octree.inl b/src/scanner/PoissonRecon/Src/Octree.inl deleted file mode 100755 index f5437fa..0000000 --- a/src/scanner/PoissonRecon/Src/Octree.inl +++ /dev/null @@ -1,2349 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#include - -///////////// -// OctNode // -///////////// -template< class NodeData > const int OctNode< NodeData >::DepthShift=5; -template< class NodeData > const int OctNode< NodeData >::OffsetShift = ( sizeof(long long)*8 - DepthShift ) / 3; -template< class NodeData > const int OctNode< NodeData >::DepthMask=(1< const int OctNode< NodeData >::OffsetMask=(1< const int OctNode< NodeData >::OffsetShift1=DepthShift; -template< class NodeData > const int OctNode< NodeData >::OffsetShift2=OffsetShift1+OffsetShift; -template< class NodeData > const int OctNode< NodeData >::OffsetShift3=OffsetShift2+OffsetShift; - -template< class NodeData > int OctNode< NodeData >::UseAlloc=0; -template< class NodeData > Allocator > OctNode< NodeData >::NodeAllocator; - -template< class NodeData > -void OctNode< NodeData >::SetAllocator(int blockSize) -{ - if(blockSize>0) - { - UseAlloc=1; - NodeAllocator.set(blockSize); - } - else{UseAlloc=0;} -} -template< class NodeData > -int OctNode< NodeData >::UseAllocator(void){return UseAlloc;} - -template< class NodeData > -OctNode< NodeData >::OctNode(void){ - parent=children=NULL; - _depthAndOffset = 0; -} - -template< class NodeData > -OctNode< NodeData >::~OctNode(void){ - if(!UseAlloc){if(children){delete[] children;}} - parent=children=NULL; -} -template< class NodeData > -void OctNode< NodeData >::setFullDepth( int maxDepth ) -{ - if( maxDepth ) - { - if( !children ) initChildren(); - for( int i=0 ; i<8 ; i++ ) children[i].setFullDepth( maxDepth-1 ); - } -} - -template< class NodeData > -int OctNode< NodeData >::initChildren( void ) -{ - if( UseAlloc ) children=NodeAllocator.newElements(8); - else - { - if( children ) delete[] children; - children = NULL; - children = new OctNode[Cube::CORNERS]; - } - if( !children ) - { - fprintf(stderr,"Failed to initialize children in OctNode::initChildren\n"); - exit(0); - return 0; - } - int d , off[3]; - depthAndOffset( d , off ); - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int idx=Cube::CornerIndex(i,j,k); - children[idx].parent = this; - children[idx].children = NULL; - int off2[3]; - off2[0] = (off[0]<<1)+i; - off2[1] = (off[1]<<1)+j; - off2[2] = (off[2]<<1)+k; - children[idx]._depthAndOffset = Index( d+1 , off2 ); - } - return 1; -} -template< class NodeData > -inline void OctNode< NodeData >::Index(int depth,const int offset[3],short& d,short off[3]){ - d=short(depth); - off[0]=short((1< -inline void OctNode< NodeData >::depthAndOffset( int& depth , int offset[DIMENSION] ) const -{ - depth = int( _depthAndOffset & DepthMask ); - offset[0] = int( (_depthAndOffset>>OffsetShift1) & OffsetMask ); - offset[1] = int( (_depthAndOffset>>OffsetShift2) & OffsetMask ); - offset[2] = int( (_depthAndOffset>>OffsetShift3) & OffsetMask ); -} -template< class NodeData > -inline void OctNode< NodeData >::centerIndex( int index[DIMENSION] ) const -{ - int d , off[DIMENSION]; - depthAndOffset( d , off ); - for( int i=0 ; i -inline unsigned long long OctNode< NodeData >::Index( int depth , const int offset[3] ) -{ - unsigned long long idx=0; - idx |= ( ( (unsigned long long)(depth ) ) & DepthMask ); - idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1; - idx |= ( ( (unsigned long long)(offset[1]) ) & OffsetMask ) << OffsetShift2; - idx |= ( ( (unsigned long long)(offset[2]) ) & OffsetMask ) << OffsetShift3; - return idx; -} -template< class NodeData > -inline int OctNode< NodeData >::depth( void ) const {return int( _depthAndOffset & DepthMask );} -template< class NodeData > -inline void OctNode< NodeData >::DepthAndOffset(const long long& index,int& depth,int offset[3]){ - depth=int(index&DepthMask); - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< -inline int OctNode< NodeData >::Depth(const long long& index){return int(index&DepthMask);} -template< class NodeData > -template< class Real > -void OctNode< NodeData >::centerAndWidth( Point3D& center , Real& width ) const -{ - int depth , offset[3]; - depthAndOffset( depth , offset ); - width = Real( 1.0 / (1< -template< class Real > -bool OctNode< NodeData >::isInside( Point3D< Real > p ) const -{ - Point3D< Real > c; - Real w; - centerAndWidth( c , w ); - w /= 2; - return (c[0]-w) -template< class Real > -inline void OctNode< NodeData >::CenterAndWidth(const long long& index,Point3D& center,Real& width){ - int depth,offset[3]; - depth=index&DepthMask; - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< -int OctNode< NodeData >::maxDepth(void) const{ - if(!children){return 0;} - else{ - int c,d; - for(int i=0;ic){c=d;} - } - return c+1; - } -} -template< class NodeData > -size_t OctNode< NodeData >::nodes( void ) const -{ - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -size_t OctNode< NodeData >::leaves( void ) const -{ - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -size_t OctNode< NodeData >::maxDepthLeaves( int maxDepth ) const -{ - if( depth()>maxDepth ) return 0; - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -const OctNode< NodeData >* OctNode< NodeData >::root(void) const{ - const OctNode* temp=this; - while(temp->parent){temp=temp->parent;} - return temp; -} - - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextBranch( const OctNode* current ) const -{ - if( !current->parent || current==this ) return NULL; - if(current-current->parent->children==Cube::CORNERS-1) return nextBranch( current->parent ); - else return current+1; -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextBranch(OctNode* current){ - if(!current->parent || current==this){return NULL;} - if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} - else{return current+1;} -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::prevBranch( const OctNode* current ) const -{ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::prevBranch( OctNode* current ) -{ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextLeaf(const OctNode* current) const{ - if(!current){ - const OctNode< NodeData >* temp=this; - while(temp->children){temp=&temp->children[0];} - return temp; - } - if(current->children){return current->nextLeaf();} - const OctNode* temp=nextBranch(current); - if(!temp){return NULL;} - else{return temp->nextLeaf();} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextLeaf(OctNode* current){ - if(!current){ - OctNode< NodeData >* temp=this; - while(temp->children){temp=&temp->children[0];} - return temp; - } - if(current->children){return current->nextLeaf();} - OctNode* temp=nextBranch(current); - if(!temp){return NULL;} - else{return temp->nextLeaf();} -} - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextNode( const OctNode* current ) const -{ - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch(current); -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextNode( OctNode* current ) -{ - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch( current ); -} - -template< class NodeData > -void OctNode< NodeData >::printRange(void) const -{ - Point3D< float > center; - float width; - centerAndWidth(center,width); - for(int dim=0;dim -void OctNode< NodeData >::AdjacencyCountFunction::Function(const OctNode< NodeData >* node1,const OctNode< NodeData >* node2){count++;} - -template< class NodeData > -template -void OctNode< NodeData >::processNodeNodes(OctNode* node,NodeAdjacencyFunction* F,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){__processNodeNodes(node,F);} -} -template< class NodeData > -template -void OctNode< NodeData >::processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int fIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){ - int c1,c2,c3,c4; - Cube::FaceCorners(fIndex,c1,c2,c3,c4); - __processNodeFaces(node,F,c1,c2,c3,c4); - } -} -template< class NodeData > -template< class NodeAdjacencyFunction > -void OctNode< NodeData >::processNodeFaces( const OctNode* node , NodeAdjacencyFunction* F , int fIndex , int processCurrent ) const -{ - if( processCurrent ) F->Function( this , node ); - if(children) - { - int c1 , c2 , c3 , c4; - Cube::FaceCorners( fIndex , c1 , c2 , c3 , c4 ); - __processNodeFaces( node , F , c1 , c2 , c3 , c4 ); - } -} -template< class NodeData > -template -void OctNode< NodeData >::processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int eIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){ - int c1,c2; - Cube::EdgeCorners(eIndex,c1,c2); - __processNodeEdges(node,F,c1,c2); - } -} -template< class NodeData > -template -void OctNode< NodeData >::processNodeCorners(OctNode* node,NodeAdjacencyFunction* F,int cIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - OctNode< NodeData >* temp=this; - while(temp->children){ - temp=&temp->children[cIndex]; - F->Function(temp,node); - } -} -template< class NodeData > -template -void OctNode< NodeData >::__processNodeNodes(OctNode* node,NodeAdjacencyFunction* F){ - F->Function(&children[0],node); - F->Function(&children[1],node); - F->Function(&children[2],node); - F->Function(&children[3],node); - F->Function(&children[4],node); - F->Function(&children[5],node); - F->Function(&children[6],node); - F->Function(&children[7],node); - if(children[0].children){children[0].__processNodeNodes(node,F);} - if(children[1].children){children[1].__processNodeNodes(node,F);} - if(children[2].children){children[2].__processNodeNodes(node,F);} - if(children[3].children){children[3].__processNodeNodes(node,F);} - if(children[4].children){children[4].__processNodeNodes(node,F);} - if(children[5].children){children[5].__processNodeNodes(node,F);} - if(children[6].children){children[6].__processNodeNodes(node,F);} - if(children[7].children){children[7].__processNodeNodes(node,F);} -} -template< class NodeData > -template -void OctNode< NodeData >::__processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2){ - F->Function(&children[cIndex1],node); - F->Function(&children[cIndex2],node); - if(children[cIndex1].children){children[cIndex1].__processNodeEdges(node,F,cIndex1,cIndex2);} - if(children[cIndex2].children){children[cIndex2].__processNodeEdges(node,F,cIndex1,cIndex2);} -} -template< class NodeData > -template -void OctNode< NodeData >::__processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2,int cIndex3,int cIndex4){ - F->Function(&children[cIndex1],node); - F->Function(&children[cIndex2],node); - F->Function(&children[cIndex3],node); - F->Function(&children[cIndex4],node); - if(children[cIndex1].children){children[cIndex1].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex2].children){children[cIndex2].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex3].children){children[cIndex3].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex4].children){children[cIndex4].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} -} -template< class NodeData > -template< class NodeAdjacencyFunction > -void OctNode< NodeData >::__processNodeFaces( const OctNode* node , NodeAdjacencyFunction* F , int cIndex1 , int cIndex2 , int cIndex3 , int cIndex4 ) const -{ - F->Function( &children[cIndex1] , node ); - F->Function( &children[cIndex2] , node ); - F->Function( &children[cIndex3] , node ); - F->Function( &children[cIndex4] , node ); - if( children[cIndex1].children ) children[cIndex1].__processNodeFaces( node , F , cIndex1 , cIndex2 , cIndex3 , cIndex4 ); - if( children[cIndex2].children ) children[cIndex2].__processNodeFaces( node , F , cIndex1 , cIndex2 , cIndex3 , cIndex4 ); - if( children[cIndex3].children ) children[cIndex3].__processNodeFaces( node , F , cIndex1 , cIndex2 , cIndex3 , cIndex4 ); - if( children[cIndex4].children ) children[cIndex4].__processNodeFaces( node , F , cIndex1 , cIndex2 , cIndex3 , cIndex4 ); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,NodeAdjacencyFunction* F,int processCurrent){ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,F,processCurrent); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessNodeAdjacentNodes(int dx,int dy,int dz, - OctNode< NodeData >* node1,int radius1, - OctNode< NodeData >* node2,int radius2,int width2, - NodeAdjacencyFunction* F,int processCurrent){ - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(!node2->children){return;} - __ProcessNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,F); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessTerminatingNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent){ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessTerminatingNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,F,processCurrent); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz, - OctNode< NodeData >* node1,int radius1, - OctNode< NodeData >* node2,int radius2,int width2, - TerminatingNodeAdjacencyFunction* F,int processCurrent) -{ - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(!node2->children){return;} - __ProcessTerminatingNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,F); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessPointAdjacentNodes( int maxDepth , const int c1[3] , OctNode* node2 , int width2 , PointAdjacencyFunction* F , int processCurrent ) -{ - int c2[3] , w2; - node2->centerIndex( maxDepth+1 , c2 ); - w2 = node2->width( maxDepth+1 ); - ProcessPointAdjacentNodes( c1[0]-c2[0] , c1[1]-c2[1] , c1[2]-c2[2] , node2 , (width2*w2)>>1 , w2 , F , processCurrent ); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessPointAdjacentNodes(int dx,int dy,int dz, - OctNode< NodeData >* node2,int radius2,int width2, - PointAdjacencyFunction* F,int processCurrent) -{ - if( !Overlap(dx,dy,dz,radius2) ) return; - if( processCurrent ) F->Function(node2); - if( !node2->children ) return; - __ProcessPointAdjacentNodes( -dx , -dy , -dz , node2 , radius2 , width2>>1 , F ); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessFixedDepthNodeAdjacentNodes(int maxDepth, - OctNode< NodeData >* node1,int width1, - OctNode< NodeData >* node2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) -{ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessFixedDepthNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,depth,F,processCurrent); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode< NodeData >* node1,int radius1, - OctNode< NodeData >* node2,int radius2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) -{ - int d=node2->depth(); - if(d>depth){return;} - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(d==depth){if(processCurrent){F->Function(node2,node1);}} - else{ - if(!node2->children){return;} - __ProcessFixedDepthNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,depth-1,F); - } -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessMaxDepthNodeAdjacentNodes(int maxDepth, - OctNode< NodeData >* node1,int width1, - OctNode< NodeData >* node2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) -{ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - ProcessMaxDepthNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,depth,F,processCurrent); -} -template< class NodeData > -template -void OctNode< NodeData >::ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode< NodeData >* node1,int radius1, - OctNode< NodeData >* node2,int radius2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) -{ - int d=node2->depth(); - if(d>depth){return;} - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(dchildren){__ProcessMaxDepthNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2>>1,depth-1,F);} -} -template< class NodeData > -template -void OctNode< NodeData >::__ProcessNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - NodeAdjacencyFunction* F) -{ - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){F->Function(&node2->children[0],node1);if(node2->children[0].children){__ProcessNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){F->Function(&node2->children[1],node1);if(node2->children[1].children){__ProcessNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){F->Function(&node2->children[2],node1);if(node2->children[2].children){__ProcessNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){F->Function(&node2->children[3],node1);if(node2->children[3].children){__ProcessNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){F->Function(&node2->children[4],node1);if(node2->children[4].children){__ProcessNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,F);}} - if(o& 32){F->Function(&node2->children[5],node1);if(node2->children[5].children){__ProcessNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,F);}} - if(o& 64){F->Function(&node2->children[6],node1);if(node2->children[6].children){__ProcessNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,F);}} - if(o&128){F->Function(&node2->children[7],node1);if(node2->children[7].children){__ProcessNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,F);}} - } -} -template< class NodeData > -template -void OctNode< NodeData >::__ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - TerminatingNodeAdjacencyFunction* F) -{ - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){if(F->Function(&node2->children[0],node1) && node2->children[0].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){if(F->Function(&node2->children[1],node1) && node2->children[1].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){if(F->Function(&node2->children[2],node1) && node2->children[2].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){if(F->Function(&node2->children[3],node1) && node2->children[3].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){if(F->Function(&node2->children[4],node1) && node2->children[4].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,F);}} - if(o& 32){if(F->Function(&node2->children[5],node1) && node2->children[5].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,F);}} - if(o& 64){if(F->Function(&node2->children[6],node1) && node2->children[6].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,F);}} - if(o&128){if(F->Function(&node2->children[7],node1) && node2->children[7].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,F);}} - } -} -template< class NodeData > -template -void OctNode< NodeData >::__ProcessPointAdjacentNodes(int dx,int dy,int dz, - OctNode* node2,int radius2,int cWidth2, - PointAdjacencyFunction* F) -{ - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius,cWidth); - if( o ) - { - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){F->Function(&node2->children[0]);if(node2->children[0].children){__ProcessPointAdjacentNodes(dx1,dy1,dz1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){F->Function(&node2->children[1]);if(node2->children[1].children){__ProcessPointAdjacentNodes(dx2,dy1,dz1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){F->Function(&node2->children[2]);if(node2->children[2].children){__ProcessPointAdjacentNodes(dx1,dy2,dz1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){F->Function(&node2->children[3]);if(node2->children[3].children){__ProcessPointAdjacentNodes(dx2,dy2,dz1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){F->Function(&node2->children[4]);if(node2->children[4].children){__ProcessPointAdjacentNodes(dx1,dy1,dz2,&node2->children[4],radius,cWidth,F);}} - if(o& 32){F->Function(&node2->children[5]);if(node2->children[5].children){__ProcessPointAdjacentNodes(dx2,dy1,dz2,&node2->children[5],radius,cWidth,F);}} - if(o& 64){F->Function(&node2->children[6]);if(node2->children[6].children){__ProcessPointAdjacentNodes(dx1,dy2,dz2,&node2->children[6],radius,cWidth,F);}} - if(o&128){F->Function(&node2->children[7]);if(node2->children[7].children){__ProcessPointAdjacentNodes(dx2,dy2,dz2,&node2->children[7],radius,cWidth,F);}} - } -} -template< class NodeData > -template -void OctNode< NodeData >::__ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - int depth,NodeAdjacencyFunction* F) -{ - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(node2->depth()==depth){ - if(o& 1){F->Function(&node2->children[0],node1);} - if(o& 2){F->Function(&node2->children[1],node1);} - if(o& 4){F->Function(&node2->children[2],node1);} - if(o& 8){F->Function(&node2->children[3],node1);} - if(o& 16){F->Function(&node2->children[4],node1);} - if(o& 32){F->Function(&node2->children[5],node1);} - if(o& 64){F->Function(&node2->children[6],node1);} - if(o&128){F->Function(&node2->children[7],node1);} - } - else{ - if(o& 1){if(node2->children[0].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,depth,F);}} - if(o& 2){if(node2->children[1].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,depth,F);}} - if(o& 4){if(node2->children[2].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,depth,F);}} - if(o& 8){if(node2->children[3].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,depth,F);}} - if(o& 16){if(node2->children[4].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,depth,F);}} - if(o& 32){if(node2->children[5].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,depth,F);}} - if(o& 64){if(node2->children[6].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,depth,F);}} - if(o&128){if(node2->children[7].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,depth,F);}} - } - } -} -template< class NodeData > -template -void OctNode< NodeData >::__ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - int depth,NodeAdjacencyFunction* F) -{ - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(node2->depth()<=depth){ - if(o& 1){F->Function(&node2->children[0],node1);} - if(o& 2){F->Function(&node2->children[1],node1);} - if(o& 4){F->Function(&node2->children[2],node1);} - if(o& 8){F->Function(&node2->children[3],node1);} - if(o& 16){F->Function(&node2->children[4],node1);} - if(o& 32){F->Function(&node2->children[5],node1);} - if(o& 64){F->Function(&node2->children[6],node1);} - if(o&128){F->Function(&node2->children[7],node1);} - } - if(node2->depth()children[0].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,depth,F);}} - if(o& 2){if(node2->children[1].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,depth,F);}} - if(o& 4){if(node2->children[2].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,depth,F);}} - if(o& 8){if(node2->children[3].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,depth,F);}} - if(o& 16){if(node2->children[4].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,depth,F);}} - if(o& 32){if(node2->children[5].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,depth,F);}} - if(o& 64){if(node2->children[6].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,depth,F);}} - if(o&128){if(node2->children[7].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,depth,F);}} - } - } -} -template< class NodeData > -inline int OctNode< NodeData >::ChildOverlap(int dx,int dy,int dz,int d,int cRadius2) -{ - int w1=d-cRadius2; - int w2=d+cRadius2; - int overlap=0; - - int test=0,test1=0; - if(dx-w1){test =1;} - if(dx-w2){test|=2;} - - if(!test){return 0;} - if(dz-w1){test1 =test;} - if(dz-w2){test1|=test<<4;} - - if(!test1){return 0;} - if(dy-w1){overlap =test1;} - if(dy-w2){overlap|=test1<<2;} - return overlap; -} - -template< class NodeData > -template< class Real > -OctNode< NodeData >* OctNode< NodeData >::getNearestLeaf(const Point3D& p){ - Point3D center; - Real width; - OctNode< NodeData >* temp; - int cIndex; - if(!children){return this;} - centerAndWidth(center,width); - temp=this; - while(temp->children){ - cIndex=CornerIndex(center,p); - temp=&temp->children[cIndex]; - width/=2; - if(cIndex&1){center.coords[0]+=width/2;} - else {center.coords[0]-=width/2;} - if(cIndex&2){center.coords[1]+=width/2;} - else {center.coords[1]-=width/2;} - if(cIndex&4){center.coords[2]+=width/2;} - else {center.coords[2]-=width/2;} - } - return temp; -} -template< class NodeData > -template< class Real > -const OctNode< NodeData >* OctNode< NodeData >::getNearestLeaf(const Point3D& p) const{ - int nearest; - Real temp,dist2; - if(!children){return this;} - for(int i=0;i -int OctNode< NodeData >::CommonEdge(const OctNode< NodeData >* node1,int eIndex1,const OctNode< NodeData >* node2,int eIndex2){ - int o1,o2,i1,i2,j1,j2; - - Cube::FactorEdgeIndex(eIndex1,o1,i1,j1); - Cube::FactorEdgeIndex(eIndex2,o2,i2,j2); - if(o1!=o2){return 0;} - - int dir[2]; - int idx1[2]; - int idx2[2]; - switch(o1){ - case 0: dir[0]=1; dir[1]=2; break; - case 1: dir[0]=0; dir[1]=2; break; - case 2: dir[0]=0; dir[1]=1; break; - }; - int d1,d2,off1[3],off2[3]; - node1->depthAndOffset(d1,off1); - node2->depthAndOffset(d2,off2); - idx1[0]=off1[dir[0]]+(1<d2){ - idx2[0]<<=(d1-d2); - idx2[1]<<=(d1-d2); - } - else{ - idx1[0]<<=(d2-d1); - idx1[1]<<=(d2-d1); - } - if(idx1[0]==idx2[0] && idx1[1]==idx2[1]){return 1;} - else {return 0;} -} -template< class NodeData > -template< class Real > -int OctNode< NodeData >::CornerIndex(const Point3D& center,const Point3D& p){ - int cIndex=0; - if(p.coords[0]>center.coords[0]){cIndex|=1;} - if(p.coords[1]>center.coords[1]){cIndex|=2;} - if(p.coords[2]>center.coords[2]){cIndex|=4;} - return cIndex; -} -template< class NodeData > -template< class NodeData2 > -OctNode< NodeData >& OctNode< NodeData >::operator = ( const OctNode< NodeData2 >& node ) -{ - int i; - if(children){delete[] children;} - children=NULL; - - this->depth = node.depth; - for(i=0;ioffset[i] = node.offset[i];} - if(node.children){ - initChildren(); - for(i=0;i -int OctNode< NodeData >::CompareForwardDepths(const void* v1,const void* v2){ - return ((const OctNode< NodeData >*)v1)->depth-((const OctNode< NodeData >*)v2)->depth; -} -template< class NodeData > -int OctNode< NodeData >::CompareByDepthAndXYZ( const void* v1 , const void* v2 ) -{ - const OctNode< NodeData > *n1 = (*(const OctNode< NodeData >**)v1); - const OctNode< NodeData > *n2 = (*(const OctNode< NodeData >**)v2); - if( n1->d!=n2->d ) return int(n1->d)-int(n2->d); - else if( n1->off[0]!=n2->off[0] ) return int(n1->off[0]) - int(n2->off[0]); - else if( n1->off[1]!=n2->off[1] ) return int(n1->off[1]) - int(n2->off[1]); - else if( n1->off[2]!=n2->off[2] ) return int(n1->off[2]) - int(n2->off[2]); - return 0; -} - -long long _InterleaveBits( int p[3] ) -{ - long long key = 0; - for( int i=0 ; i<32 ; i++ ) key |= ( ( p[0] & (1< -int OctNode< NodeData >::CompareByDepthAndZIndex( const void* v1 , const void* v2 ) -{ - const OctNode< NodeData >* n1 = (*(const OctNode< NodeData >**)v1); - const OctNode< NodeData >* n2 = (*(const OctNode< NodeData >**)v2); - int d1 , off1[3] , d2 , off2[3]; - n1->depthAndOffset( d1 , off1 ) , n2->depthAndOffset( d2 , off2 ); - if ( d1>d2 ) return 1; - else if( d1k2 ) return 1; - else if( k1 -int OctNode< NodeData >::CompareForwardPointerDepths( const void* v1 , const void* v2 ) -{ - const OctNode< NodeData >* n1 = (*(const OctNode< NodeData >**)v1); - const OctNode< NodeData >* n2 = (*(const OctNode< NodeData >**)v2); - if(n1->d!=n2->d){return int(n1->d)-int(n2->d);} - while( n1->parent!=n2->parent ) - { - n1=n1->parent; - n2=n2->parent; - } - if(n1->off[0]!=n2->off[0]){return int(n1->off[0])-int(n2->off[0]);} - if(n1->off[1]!=n2->off[1]){return int(n1->off[1])-int(n2->off[1]);} - return int(n1->off[2])-int(n2->off[2]); - return 0; -} -template< class NodeData > -int OctNode< NodeData >::CompareBackwardDepths(const void* v1,const void* v2){ - return ((const OctNode< NodeData >*)v2)->depth-((const OctNode< NodeData >*)v1)->depth; -} -template< class NodeData > -int OctNode< NodeData >::CompareBackwardPointerDepths(const void* v1,const void* v2){ - return (*(const OctNode< NodeData >**)v2)->depth()-(*(const OctNode< NodeData >**)v1)->depth(); -} -template< class NodeData > -template< class Real > -inline int OctNode< NodeData >::Overlap2(const int &depth1,const int offSet1[DIMENSION],const Real& multiplier1,const int &depth2,const int offSet2[DIMENSION],const Real& multiplier2){ - int d=depth2-depth1; - Real w=multiplier2+multiplier1*(1<=w || - fabs(Real(offSet2[1]-(offSet1[1]<=w || - fabs(Real(offSet2[2]-(offSet1[2]<=w - ){return 0;} - return 1; -} -template< class NodeData > -inline int OctNode< NodeData >::Overlap(int c1,int c2,int c3,int dWidth){ - if(c1>=dWidth || c1<=-dWidth || c2>=dWidth || c2<=-dWidth || c3>=dWidth || c3<=-dWidth){return 0;} - else{return 1;} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::faceNeighbor(int faceIndex,int forceChildren){return __faceNeighbor(faceIndex>>1,faceIndex&1,forceChildren);} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::faceNeighbor(int faceIndex) const {return __faceNeighbor(faceIndex>>1,faceIndex&1);} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor(int dir,int off,int forceChildren){ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - OctNode* temp=parent->__faceNeighbor(dir,off,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor(int dir,int off) const { - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - const OctNode* temp=parent->__faceNeighbor(dir,off); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } -} - -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor(int edgeIndex,int forceChildren){ - int idx[2],o,i[2]; - Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor(o,i,idx,forceChildren); -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor(int edgeIndex) const { - int idx[2],o,i[2]; - Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor(o,i,idx); -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor(int o,const int i[2],const int idx[2]) const{ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - const OctNode* temp=parent->__faceNeighbor(idx[1],i[1]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - const OctNode* temp=parent->__edgeNeighbor(o,i,idx); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else{return NULL;} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor(int o,const int i[2],const int idx[2],int forceChildren){ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - OctNode* temp=parent->__faceNeighbor(idx[1],i[1],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - OctNode* temp=parent->__edgeNeighbor(o,i,idx,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } - else{return NULL;} -} - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor(int cornerIndex) const { - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - const OctNode* temp=((const OctNode*)parent)->cornerNeighbor(cornerIndex); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else if(aIndex==6){ // Agree on face 0 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor(int cornerIndex,int forceChildren){ - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - OctNode* temp=((OctNode*)parent)->cornerNeighbor(cornerIndex,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } - else if(aIndex==6){ // Agree on face 0 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} -} -//////////////////////// -// OctNodeNeighborKey // -//////////////////////// -template< class NodeData > -OctNode< NodeData >::Neighbors3::Neighbors3(void){clear();} -template< class NodeData > -void OctNode< NodeData >::Neighbors3::clear(void){ - for(int i=0;i<3;i++){for(int j=0;j<3;j++){for(int k=0;k<3;k++){neighbors[i][j][k]=NULL;}}} -} -template< class NodeData > -OctNode< NodeData >::NeighborKey3::NeighborKey3( void ){ _depth=-1 , neighbors=NULL; } -template< class NodeData > -OctNode< NodeData >::NeighborKey3::NeighborKey3( const NeighborKey3& nKey3 ) -{ - _depth = 0 , neighbors = NULL; - set( nKey3._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &nKey3.neighbors[d] , sizeof(Neighbors3) ); -} -template< class NodeData > -OctNode< NodeData >::NeighborKey3::~NeighborKey3(void) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; -} - -template< class NodeData > -void OctNode< NodeData >::NeighborKey3::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - _depth = d; - if( d<0 ) return; - neighbors = new Neighbors3[d+1]; -} -template< class NodeData > -template< class Real > -bool OctNode< NodeData >::NeighborKey3::setChildNeighbors( Point3D< Real > p , int d , typename OctNode< NodeData >::Neighbors3& childNeighbors ) const -{ - if( !neighbors[d].neighbors[1][1][1] ) return false; - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - neighbors[d].neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - if( !neighbors[d].neighbors[1][1][1]->children ) neighbors[d].neighbors[1][1][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - childNeighbors.neighbors[x2+i][y2+j][z2+k] = &neighbors[d].neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - // Set the neighbors from across the faces - i=x1<<1; - if( neighbors[d].neighbors[i][1][1] ) - { - if( !neighbors[d].neighbors[i][1][1]->children ) neighbors[d].neighbors[i][1][1]->initChildren(); - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][y2+j][z2+k] = &neighbors[d].neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - j=y1<<1; - if( neighbors[d].neighbors[1][j][1] ) - { - if( !neighbors[d].neighbors[1][j][1]->children ) neighbors[d].neighbors[1][j][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[x2+i][j][z2+k] = &neighbors[d].neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - } - k=z1<<1; - if( neighbors[d].neighbors[1][1][k] ) - { - if( !neighbors[d].neighbors[1][1][k]->children ) neighbors[d].neighbors[1][1][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[x2+i][y2+j][k] = &neighbors[d].neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - } - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( neighbors[d].neighbors[i][j][1] ) - { - if( !neighbors[d].neighbors[i][j][1]->children ) neighbors[d].neighbors[i][j][1]->initChildren(); - for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][j][z2+k] = &neighbors[d].neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - } - i=x1<<1 , k=z1<<1; - if( neighbors[d].neighbors[i][1][k] ) - { - if( !neighbors[d].neighbors[i][1][k]->children ) neighbors[d].neighbors[i][1][k]->initChildren(); - for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[i][y2+j][k] = &neighbors[d].neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - } - j=y1<<1 , k=z1<<1; - if( neighbors[d].neighbors[1][j][k] ) - { - if( !neighbors[d].neighbors[1][j][k]->children ) neighbors[d].neighbors[1][j][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) childNeighbors.neighbors[x2+i][j][k] = &neighbors[d].neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - } - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( neighbors[d].neighbors[i][j][k] ) - { - if( !neighbors[d].neighbors[i][j][k]->children ) neighbors[d].neighbors[i][j][k]->initChildren(); - childNeighbors.neighbors[i][j][k] = &neighbors[d].neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - return true; -} -template< class NodeData > -template< class Real > -bool OctNode< NodeData >::NeighborKey3::getChildNeighbors( Point3D< Real > p , int d , typename OctNode< NodeData >::Neighbors3& childNeighbors ) const -{ - if( !neighbors[d].neighbors[1][1][1] ) return false; - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - neighbors[d].neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - // Set the neighbors of the center cell - if( neighbors[d].neighbors[1][1][1] && neighbors[d].neighbors[1][1][1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - childNeighbors.neighbors[x2+i][y2+j][z2+k] = &neighbors[d].neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - // Set the neighbors from across the faces - i=x1<<1; - if( neighbors[d].neighbors[i][1][1] && neighbors[d].neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][y2+j][z2+k] = &neighbors[d].neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - else - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][y2+j][z2+k] = NULL; - j=y1<<1; - if( neighbors[d].neighbors[1][j][1] && neighbors[d].neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[x2+i][j][z2+k] = &neighbors[d].neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - else - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[x2+i][j][z2+k] = NULL; - k=z1<<1; - if( neighbors[d].neighbors[1][1][k] && neighbors[d].neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[x2+i][y2+j][k] = &neighbors[d].neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - else - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[x2+i][y2+j][k] = NULL; - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( neighbors[d].neighbors[i][j][1] && neighbors[d].neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][j][z2+k] = &neighbors[d].neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - else - for( k=0 ; k<2 ; k++ ) childNeighbors.neighbors[i][j][z2+k] = NULL; - i=x1<<1 , k=z1<<1; - if( neighbors[d].neighbors[i][1][k] && neighbors[d].neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[i][y2+j][k] = &neighbors[d].neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - else - for( j=0 ; j<2 ; j++ ) childNeighbors.neighbors[i][y2+j][k] = NULL; - j=y1<<1 , k=z1<<1; - if( neighbors[d].neighbors[1][j][k] && neighbors[d].neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) childNeighbors.neighbors[x2+i][j][k] = &neighbors[d].neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - else - for( i=0 ; i<2 ; i++ ) childNeighbors.neighbors[x2+i][j][k] = NULL; - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( neighbors[d].neighbors[i][j][k] && neighbors[d].neighbors[i][j][k]->children ) - childNeighbors.neighbors[i][j][k] = &neighbors[d].neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - else - childNeighbors.neighbors[i][j][k] = NULL; - - return true; -} -template< class NodeData > -template< class Real > -typename OctNode< NodeData >::Neighbors3& OctNode< NodeData >::NeighborKey3::setNeighbors( OctNode< NodeData >* root , Point3D< Real > p , int d ) -{ - if( !neighbors[d].neighbors[1][1][1] || !neighbors[d].neighbors[1][1][1]->isInside( p ) ) - { - neighbors[d].clear(); - - if( !d ) neighbors[d].neighbors[1][1][1] = root; - else - { - Neighbors3& temp = setNeighbors( root , p , d-1 ); - - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - temp.neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - if( !temp.neighbors[1][1][1]->children ) temp.neighbors[1][1][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = &temp.neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] ) - { - if( !temp.neighbors[i][1][1]->children ) temp.neighbors[i][1][1]->initChildren(); - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - j=y1<<1; - if( temp.neighbors[1][j][1] ) - { - if( !temp.neighbors[1][j][1]->children ) temp.neighbors[1][j][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - } - k=z1<<1; - if( temp.neighbors[1][1][k] ) - { - if( !temp.neighbors[1][1][k]->children ) temp.neighbors[1][1][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - } - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] ) - { - if( !temp.neighbors[i][j][1]->children ) temp.neighbors[i][j][1]->initChildren(); - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - } - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] ) - { - if( !temp.neighbors[i][1][k]->children ) temp.neighbors[i][1][k]->initChildren(); - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - } - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] ) - { - if( !temp.neighbors[1][j][k]->children ) temp.neighbors[1][j][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - } - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] ) - { - if( !temp.neighbors[i][j][k]->children ) temp.neighbors[i][j][k]->initChildren(); - neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[d]; -} -template< class NodeData > -template< class Real > -typename OctNode< NodeData >::Neighbors3& OctNode< NodeData >::NeighborKey3::getNeighbors( OctNode< NodeData >* root , Point3D< Real > p , int d ) -{ - if( !neighbors[d].neighbors[1][1][1] || !neighbors[d].neighbors[1][1][1]->isInside( p ) ) - { - neighbors[d].clear(); - - if( !d ) neighbors[d].neighbors[1][1][1] = root; - else - { - Neighbors3& temp = getNeighbors( root , p , d-1 ); - - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - temp.neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - if( !temp.neighbors[1][1][1] || !temp.neighbors[1][1][1]->children ) - { - fprintf( stderr , "[ERROR] Couldn't find node at appropriate depth\n" ); - exit( 0 ); - } - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = &temp.neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - j=y1<<1; - if( temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - k=z1<<1; - if( temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children ) - neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - return neighbors[d]; -} - -template< class NodeData > -typename OctNode< NodeData >::Neighbors3& OctNode< NodeData >::NeighborKey3::setNeighbors( OctNode< NodeData >* node ) -{ - int d = node->depth(); - if( node==neighbors[d].neighbors[1][1][1] ) - { - bool reset = false; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( !neighbors[d].neighbors[i][j][k] ) reset = true; - if( reset ) neighbors[d].neighbors[1][1][1] = NULL; - } - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[1][1][1] = node; - else - { - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for(i=0;i<2;i++){ - for(j=0;j<2;j++){ - for(k=0;k<2;k++){ - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - } - } - } - Neighbors3& temp=setNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if(temp.neighbors[i][1][1]){ - if(!temp.neighbors[i][1][1]->children) temp.neighbors[i][1][1]->initChildren(); - for(j=0;j<2;j++) for(k=0;k<2;k++) neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - j=y1<<1; - if(temp.neighbors[1][j][1]){ - if(!temp.neighbors[1][j][1]->children){temp.neighbors[1][j][1]->initChildren();} - for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} - } - k=z1<<1; - if(temp.neighbors[1][1][k]){ - if(!temp.neighbors[1][1][k]->children){temp.neighbors[1][1][k]->initChildren();} - for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} - } - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if(temp.neighbors[i][j][1]){ - if(!temp.neighbors[i][j][1]->children){temp.neighbors[i][j][1]->initChildren();} - for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} - } - i=x1<<1; k=z1<<1; - if(temp.neighbors[i][1][k]){ - if(!temp.neighbors[i][1][k]->children){temp.neighbors[i][1][k]->initChildren();} - for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} - } - j=y1<<1; k=z1<<1; - if(temp.neighbors[1][j][k]){ - if(!temp.neighbors[1][j][k]->children){temp.neighbors[1][j][k]->initChildren();} - for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} - } - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if(temp.neighbors[i][j][k]){ - if(!temp.neighbors[i][j][k]->children){temp.neighbors[i][j][k]->initChildren();} - neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[d]; -} -// Note the assumption is that if you enable an edge, you also enable adjacent faces. -// And, if you enable a corner, you enable adjacent edges and faces. -template< class NodeData > -typename OctNode< NodeData >::Neighbors3& OctNode< NodeData >::NeighborKey3::setNeighbors( OctNode< NodeData >* node , bool flags[3][3][3] ) -{ - int d = node->depth(); - if( node==neighbors[d].neighbors[1][1][1] ) - { - bool reset = false; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( flags[i][j][k] && !neighbors[d].neighbors[i][j][k] ) reset = true; - if( reset ) neighbors[d].neighbors[1][1][1] = NULL; - } - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[1][1][1] = node; - else - { - int x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for( int i=0 ; i<2 ; i++ ) - for( int j=0 ; j<2 ; j++ ) - for( int k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - - Neighbors3& temp=setNeighbors( node->parent , flags ); - - // Set the neighbors from across the faces - { - int i=x1<<1; - if( temp.neighbors[i][1][1] ) - { - if( flags[i][1][1] && !temp.neighbors[i][1][1]->children ) temp.neighbors[i][1][1]->initChildren(); - if( temp.neighbors[i][1][1]->children ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - } - { - int j = y1<<1; - if( temp.neighbors[1][j][1] ) - { - if( flags[1][j][1] && !temp.neighbors[1][j][1]->children ) temp.neighbors[1][j][1]->initChildren(); - if( temp.neighbors[1][j][1]->children ) for( int i=0 ; i<2 ; i++ ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - } - } - { - int k = z1<<1; - if( temp.neighbors[1][1][k] ) - { - if( flags[1][1][k] && !temp.neighbors[1][1][k]->children ) temp.neighbors[1][1][k]->initChildren(); - if( temp.neighbors[1][1][k]->children ) for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - } - } - - // Set the neighbors from across the edges - { - int i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] ) - { - if( flags[i][j][1] && !temp.neighbors[i][j][1]->children ) temp.neighbors[i][j][1]->initChildren(); - if( temp.neighbors[i][j][1]->children ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - } - } - { - int i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] ) - { - if( flags[i][1][k] && !temp.neighbors[i][1][k]->children ) temp.neighbors[i][1][k]->initChildren(); - if( temp.neighbors[i][1][k]->children ) for( int j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - } - } - { - int j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] ) - { - if( flags[1][j][k] && !temp.neighbors[1][j][k]->children ) temp.neighbors[1][j][k]->initChildren(); - if( temp.neighbors[1][j][k]->children ) for( int i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - } - } - - // Set the neighbor from across the corner - { - int i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] ) - { - if( flags[i][j][k] && !temp.neighbors[i][j][k]->children ) temp.neighbors[i][j][k]->initChildren(); - if( temp.neighbors[i][j][k]->children ) neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - } - return neighbors[d]; -} - -template< class NodeData > -typename OctNode< NodeData >::Neighbors3& OctNode< NodeData >::NeighborKey3::getNeighbors( OctNode< NodeData >* node ) -{ - int d=node->depth(); - if(node!=neighbors[d].neighbors[1][1][1]) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[1][1][1] = node; - else - { - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = node->parent->children + Cube::CornerIndex(i,j,k); - - Neighbors3& temp=getNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = temp.neighbors[i][1][1]->children + Cube::CornerIndex(x2,j,k); - j=y1<<1; - if( temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = temp.neighbors[1][j][1]->children + Cube::CornerIndex(i,y2,k); - k=z1<<1; - if( temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++) neighbors[d].neighbors[x2+i][y2+j][k] = temp.neighbors[1][1][k]->children + Cube::CornerIndex(i,j,z2); - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if( temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = temp.neighbors[i][j][1]->children + Cube::CornerIndex(x2,y2,k); - i=x1<<1; k=z1<<1; - if( temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = temp.neighbors[i][1][k]->children + Cube::CornerIndex(x2,j,z2); - j=y1<<1; k=z1<<1; - if( temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = temp.neighbors[1][j][k]->children + Cube::CornerIndex(i,y2,z2); - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if( temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children ) - neighbors[d].neighbors[i][j][k] = temp.neighbors[i][j][k]->children + Cube::CornerIndex(x2,y2,z2); - } - } - return neighbors[node->depth()]; -} -template< class NodeData > -void OctNode< NodeData >::NeighborKey3::setNeighbors( OctNode< NodeData >* node , typename OctNode< NodeData >::Neighbors5& neighbors ) -{ - neighbors.clear(); - if( !node ) return; - if( !node->parent ) neighbors.neighbors[2][2][2] = node; - else - { - int c = int( node - node->parent->children ); - const OctNode< NodeData >::Neighbors3& _neighbors = setNeighbors( node->parent ); - switch( c ) - { - case 0: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 1: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 2: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj-1][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 3: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj-1][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 4: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 5: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 6: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj-1][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - case 7: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] ) - { - if( !_neighbors.neighbors[i][j][k]->children ) _neighbors.neighbors[i][j][k]->initChildren(); - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj-1][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - } - break; - } - } -} -template< class NodeData > -void OctNode< NodeData >::NeighborKey3::getNeighbors( OctNode< NodeData >* node , typename OctNode< NodeData >::Neighbors5& neighbors ) -{ - neighbors.clear(); - if( !node ) return; - if( !node->parent ) neighbors.neighbors[2][2][2] = node; - else - { - int c = int( node - node->parent->children ); - const OctNode< NodeData >::Neighbors3& _neighbors = getNeighbors( node->parent ); - OctNode< NodeData >* const * _nodes = &_neighbors.neighbors[0][0][0]; - const OctNode< NodeData >* const * _node; - const OctNode< NodeData >* __node; - int iS , iE , jS , jE , kS , kE; -#define _S( i ) ( (i==0) ? 1 : 0 ) -#define _E( i ) ( (i==2) ? 1 : 2 ) - switch( c ) - { - case 0: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iE=_E(i) ; for( int j=0 ; j<3 ; j++ ){ jE=_E(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kE=_E(k) , __node = *_node; - if( __node && __node->children ) for( int ii=0 , iii=2*i ; iichildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 1: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iS=_S(i) ; for( int j=0 ; j<3 ; j++ ){ jE=_E(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kE=_E(k) , __node = *_node; - if( __node && __node->children ) for( int ii=iS , iii=2*i+iS-1 ; ii<2 ; ii++ , iii++ ) for( int jj=0 , jjj=2*j ; jjchildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 2: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iE=_E(i) ; for( int j=0 ; j<3 ; j++ ){ jS=_S(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kE=_E(k) , __node = *_node; - if( __node && __node->children ) for( int ii=0 , iii=2*i ; iichildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 3: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iS=_S(i) ; for( int j=0 ; j<3 ; j++ ){ jS=_S(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kE=_E(k) , __node = *_node; - if( __node && __node->children ) for( int ii=iS , iii=2*i+iS-1 ; ii<2 ; ii++ , iii++ ) for( int jj=jS , jjj=2*j+jS-1 ; jj<2 ; jj++ , jjj++ ) for( int kk=0 , kkk=2*k ; kkchildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 4: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iE=_E(i) ; for( int j=0 ; j<3 ; j++ ){ jE=_E(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kS=_S(k) , __node = *_node; - if( __node && __node->children ) for( int ii=0 , iii=2*i ; iichildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 5: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iS=_S(i) ; for( int j=0 ; j<3 ; j++ ){ jE=_E(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kS=_S(k) , __node = *_node; - if( __node && __node->children ) for( int ii=iS , iii=2*i+iS-1 ; ii<2 ; ii++ , iii++ ) for( int jj=0 , jjj=2*j ; jjchildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 6: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iE=_E(i) ; for( int j=0 ; j<3 ; j++ ){ jS=_S(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kS=_S(k) , __node = *_node; - if( __node && __node->children ) for( int ii=0 , iii=2*i ; iichildren + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - case 7: - _node = _nodes; - for( int i=0 ; i<3 ; i++ ){ iS=_S(i) ; for( int j=0 ; j<3 ; j++ ){ jS=_S(j) ; for( int k=0 ; k<3 ; k++ , _node++ ){ kS=_S(k) , __node = *_node; - if( __node && __node->children ) for( int ii=iS , iii=2*i+iS-1 ; ii<2 ; ii++ , iii++ ) for( int jj=jS , jjj=2*j+jS-1 ; jj<2 ; jj++ , jjj++ ) for( int kk=kS , kkk=2*k+kS-1 ; kk<2 ; kk++ , kkk++ ) - neighbors.neighbors[iii][jjj][kkk] = __node->children + Cube::CornerIndex( ii , jj , kk ); - } } } - break; - } -#undef _S -#undef _E - } -} -template< class NodeData > -void OctNode< NodeData >::ConstNeighborKey3::getNeighbors( const OctNode< NodeData >* node , typename OctNode< NodeData >::ConstNeighbors5& neighbors ) -{ - neighbors.clear(); - if( !node ) return; - if( !node->parent ) neighbors.neighbors[2][2][2] = node; - else - { - int c = int( node - node->parent->children ); - const OctNode< NodeData >::ConstNeighbors3& _neighbors = getNeighbors( node->parent ); - switch( c ) - { - case 0: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 1: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 2: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj-1][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 3: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=0 ; kk<( (k==2) ? 1 : 2 ) ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj-1][2*k+kk] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 4: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 5: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=0 ; jj<( (j==2) ? 1 : 2 ) ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 6: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=0 ; ii<( (i==2) ? 1 : 2 ) ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii][2*j+jj-1][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - case 7: - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) - if( _neighbors.neighbors[i][j][k] && _neighbors.neighbors[i][j][k]->children ) - for( int ii=( (i==0) ? 1 : 0 ) ; ii<2 ; ii++ ) - for( int jj=( (j==0) ? 1 : 0 ) ; jj<2 ; jj++ ) - for( int kk=( (k==0) ? 1 : 0 ) ; kk<2 ; kk++ ) - neighbors.neighbors[2*i+ii-1][2*j+jj-1][2*k+kk-1] = _neighbors.neighbors[i][j][k]->children + Cube::CornerIndex( ii , jj , kk ); - break; - } - } -} - -/////////////////////// -// ConstNeighborKey3 // -/////////////////////// -template< class NodeData > -OctNode< NodeData >::ConstNeighbors3::ConstNeighbors3(void){clear();} -template< class NodeData > -void OctNode< NodeData >::ConstNeighbors3::clear(void){ - for(int i=0;i<3;i++){for(int j=0;j<3;j++){for(int k=0;k<3;k++){neighbors[i][j][k]=NULL;}}} -} -template< class NodeData > -OctNode< NodeData >::ConstNeighborKey3::ConstNeighborKey3( void ){ _depth=-1 , neighbors=NULL; } -template< class NodeData > -OctNode< NodeData >::ConstNeighborKey3::ConstNeighborKey3( const ConstNeighborKey3& key3 ) -{ - _depth = 0 , neighbors = NULL; - set( key3._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key3.neighbors[d] , sizeof(ConstNeighbors3) ); -} -template< class NodeData > -OctNode< NodeData >::ConstNeighborKey3::~ConstNeighborKey3(void){ - if( neighbors ) delete[] neighbors; - neighbors=NULL; -} - -template< class NodeData > -void OctNode< NodeData >::ConstNeighborKey3::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - _depth = d; - if( d<0 ) return; - neighbors = new ConstNeighbors3[d+1]; -} -template< class NodeData > -typename OctNode< NodeData >::ConstNeighbors3& OctNode< NodeData >::ConstNeighborKey3::getNeighbors(const OctNode< NodeData >* node) -{ - int d=node->depth(); - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if(!node->parent) neighbors[d].neighbors[1][1][1]=node; - else - { - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = node->parent->children + Cube::CornerIndex(i,j,k); - - ConstNeighbors3& temp=getNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = temp.neighbors[i][1][1]->children + Cube::CornerIndex(x2,j,k); - j=y1<<1; - if( temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = temp.neighbors[1][j][1]->children + Cube::CornerIndex(i,y2,k); - k=z1<<1; - if( temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = temp.neighbors[1][1][k]->children + Cube::CornerIndex(i,j,z2); - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if( temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = temp.neighbors[i][j][1]->children + Cube::CornerIndex(x2,y2,k); - i=x1<<1; k=z1<<1; - if( temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = temp.neighbors[i][1][k]->children + Cube::CornerIndex(x2,j,z2); - j=y1<<1; k=z1<<1; - if( temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = temp.neighbors[1][j][k]->children + Cube::CornerIndex(i,y2,z2); - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if( temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children ) - neighbors[d].neighbors[i][j][k] = temp.neighbors[i][j][k]->children + Cube::CornerIndex(x2,y2,z2); - } - } - return neighbors[node->depth()]; -} -template< class NodeData > -typename OctNode< NodeData >::ConstNeighbors3& OctNode< NodeData >::ConstNeighborKey3::getNeighbors( const OctNode< NodeData >* node , int minDepth ) -{ - int d=node->depth(); - if( dparent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - - ConstNeighbors3& temp=getNeighbors( node->parent , minDepth ); - - // Set the syblings - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = node->parent->children + Cube::CornerIndex(i,j,k); - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = temp.neighbors[i][1][1]->children + Cube::CornerIndex(x2,j,k); - - j=y1<<1; - if( temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = temp.neighbors[1][j][1]->children + Cube::CornerIndex(i,y2,k); - - k=z1<<1; - if( temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = temp.neighbors[1][1][k]->children + Cube::CornerIndex(i,j,z2); - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = temp.neighbors[i][j][1]->children + Cube::CornerIndex(x2,y2,k); - - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = temp.neighbors[i][1][k]->children + Cube::CornerIndex(x2,j,z2); - - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = temp.neighbors[1][j][k]->children + Cube::CornerIndex(i,y2,z2); - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children ) - neighbors[d].neighbors[i][j][k] = temp.neighbors[i][j][k]->children + Cube::CornerIndex(x2,y2,z2); - } - } - return neighbors[node->depth()]; -} - -template< class NodeData > OctNode< NodeData >::Neighbors5::Neighbors5( void ){ clear(); } -template< class NodeData > OctNode< NodeData >::ConstNeighbors5::ConstNeighbors5( void ){ clear(); } -template< class NodeData > -void OctNode< NodeData >::Neighbors5::clear( void ) -{ - for( int i=0 ; i<5 ; i++ ) for( int j=0 ; j<5 ; j++ ) for( int k=0 ; k<5 ; k++ ) neighbors[i][j][k] = NULL; -} -template< class NodeData > -void OctNode< NodeData >::ConstNeighbors5::clear( void ) -{ - for( int i=0 ; i<5 ; i++ ) for( int j=0 ; j<5 ; j++ ) for( int k=0 ; k<5 ; k++ ) neighbors[i][j][k] = NULL; -} -template< class NodeData > -OctNode< NodeData >::NeighborKey5::NeighborKey5( void ) -{ - _depth = -1; - neighbors = NULL; -} -template< class NodeData > -OctNode< NodeData >::ConstNeighborKey5::ConstNeighborKey5( void ) -{ - _depth = -1; - neighbors = NULL; -} -template< class NodeData > -OctNode< NodeData >::NeighborKey5::~NeighborKey5( void ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; -} -template< class NodeData > -OctNode< NodeData >::ConstNeighborKey5::~ConstNeighborKey5( void ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; -} -template< class NodeData > -void OctNode< NodeData >::NeighborKey5::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - if(d<0) return; - _depth = d; - neighbors=new Neighbors5[d+1]; -} -template< class NodeData > -void OctNode< NodeData >::ConstNeighborKey5::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - if(d<0) return; - _depth = d; - neighbors=new ConstNeighbors5[d+1]; -} -template< class NodeData > -typename OctNode< NodeData >::Neighbors5& OctNode< NodeData >::NeighborKey5::getNeighbors( OctNode* node ) -{ - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[2][2][2]=node; - else - { - getNeighbors( node->parent ); - Neighbors5& temp = neighbors[d-1]; - int x1 , y1 , z1 , x2 , y2 , z2; - int idx = int( node - node->parent->children ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - - Neighbors5& n = neighbors[d]; - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - int i , j , k; - int fx0 = x2+1 , fy0 = y2+1 , fz0 = z2+1; // Indices of the bottom left corner of the parent within the 5x5x5 - int cx1 = x1*2+1 , cy1 = y1*2+1 , cz1 = z1*2+1; - int cx2 = x2*2+1 , cy2 = y2*2+1 , cz2 = z2*2+1; - int fx1 = x1*3 , fy1 = y1*3 , fz1 = z1*3; - int fx2 = x2*4 , fy2 = y2*4 , fz2 = z2*4; - - // Set the syblings - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy0+j][fz0+k] = node->parent->children + Cube::CornerIndex( i , j , k ); - - // Set the neighbors from across the faces - if( temp.neighbors[cx1][2][2] && temp.neighbors[cx1][2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy0+j][fz0+k] = temp.neighbors[cx1][2][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][cy1][2] && temp.neighbors[2][cy1][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy1+j][fz0+k] = temp.neighbors[2][cy1][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][2][cz1] && temp.neighbors[2][2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy0+j][fz1+k] = temp.neighbors[2][2][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx2][2][2] && temp.neighbors[cx2][2][2]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy0+j][fz0+k] = temp.neighbors[cx2][2][2]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy2][2] && temp.neighbors[2][cy2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy2 ][fz0+k] = temp.neighbors[2][cy2][2]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[2][2][cz2] && temp.neighbors[2][2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx0+i][fy0+j][fz2 ] = temp.neighbors[2][2][cz2]->children + Cube::CornerIndex( i , j , z1 ); - - // Set the neighbors from across the edges - if( temp.neighbors[cx1][cy1][2] && temp.neighbors[cx1][cy1][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy1+j][fz0+k] = temp.neighbors[cx1][cy1][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][2][cz1] && temp.neighbors[cx1][2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy0+j][fz1+k] = temp.neighbors[cx1][2][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][cy1][cz1] && temp.neighbors[2][cy1][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy1+j][fz1+k] = temp.neighbors[2][cy1][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][cy2][2] && temp.neighbors[cx1][cy2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy2 ][fz0+k] = temp.neighbors[cx1][cy2][2]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx1][2][cz2] && temp.neighbors[cx1][2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx1+i][fy0+j][fz2 ] = temp.neighbors[cx1][2][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx2][cy1][2] && temp.neighbors[cx2][cy1][2]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy1+j][fz0+k] = temp.neighbors[cx2][cy1][2]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy1][cz2] && temp.neighbors[2][cy1][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx0+i][fy1+j][fz2 ] = temp.neighbors[2][cy1][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx2][2][cz1] && temp.neighbors[cx2][2][cz1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy0+j][fz1+k] = temp.neighbors[cx2][2][cz1]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy2][cz1] && temp.neighbors[2][cy2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy2 ][fz1+k] = temp.neighbors[2][cy2][cz1]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx2][cy2][2] && temp.neighbors[cx2][cy2][2]->children ) - for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy2 ][fz0+k] = temp.neighbors[cx2][cy2][2]->children + Cube::CornerIndex( x1 , y1 , k ); - if( temp.neighbors[cx2][2][cz2] && temp.neighbors[cx2][2][cz2]->children ) - for( j=0 ; j<2 ; j++ ) - n.neighbors[fx2 ][fy0+j][fz2 ] = temp.neighbors[cx2][2][cz2]->children + Cube::CornerIndex( x1 , j , z1 ); - if( temp.neighbors[2][cy2][cz2] && temp.neighbors[2][cy2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) - n.neighbors[fx0+i][fy2 ][fz2 ] = temp.neighbors[2][cy2][cz2]->children + Cube::CornerIndex( i , y1 , z1 ); - - // Set the neighbor from across the corners - if( temp.neighbors[cx1][cy1][cz1] && temp.neighbors[cx1][cy1][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy1+j][fz1+k] = temp.neighbors[cx1][cy1][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][cy1][cz2] && temp.neighbors[cx1][cy1][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx1+i][fy1+j][fz2 ] = temp.neighbors[cx1][cy1][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx1][cy2][cz1] && temp.neighbors[cx1][cy2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy2 ][fz1+k] = temp.neighbors[cx1][cy2][cz1]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx2][cy1][cz1] && temp.neighbors[cx2][cy1][cz1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy1+j][fz1+k] = temp.neighbors[cx2][cy1][cz1]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[cx1][cy2][cz2] && temp.neighbors[cx1][cy2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) - n.neighbors[fx1+i][fy2 ][fz2 ] = temp.neighbors[cx1][cy2][cz2]->children + Cube::CornerIndex( i , y1 , z1 ); - if( temp.neighbors[cx2][cy1][cz2] && temp.neighbors[cx2][cy1][cz2]->children ) - for( j=0 ; j<2 ; j++ ) - n.neighbors[fx2 ][fy1+j][fz2 ] = temp.neighbors[cx2][cy1][cz2]->children + Cube::CornerIndex( x1 , j , z1 ); - if( temp.neighbors[cx2][cy2][cz1] && temp.neighbors[cx2][cy2][cz1]->children ) - for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy2 ][fz1+k] = temp.neighbors[cx2][cy2][cz1]->children + Cube::CornerIndex( x1 , y1 , k ); - if( temp.neighbors[cx2][cy2][cz2] && temp.neighbors[cx2][cy2][cz2]->children ) - n.neighbors[fx2 ][fy2 ][fz2 ] = temp.neighbors[cx2][cy2][cz2]->children + Cube::CornerIndex( x1 , y1 , z1 ); - } - } - return neighbors[d]; -} -template< class NodeData > -typename OctNode< NodeData >::Neighbors5& OctNode< NodeData >::NeighborKey5::setNeighbors( OctNode* node , int xStart , int xEnd , int yStart , int yEnd , int zStart , int zEnd ) -{ - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[2][2][2] = node; - else - { - setNeighbors( node->parent , xStart , xEnd , yStart , yEnd , zStart , zEnd ); - Neighbors5& temp = neighbors[d-1]; - int x1 , y1 , z1 , x2 , y2 , z2 , ii , jj , kk; - int idx = int( node-node->parent->children ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - - for( int i=xStart ; i>1); - for( int j=yStart ; j>1); - for( int k=zStart ; k>1); - if(temp.neighbors[x2][y2][z2] ) - { - if( !temp.neighbors[x2][y2][z2]->children ) temp.neighbors[x2][y2][z2]->initChildren(); - neighbors[d].neighbors[i][j][k] = temp.neighbors[x2][y2][z2]->children + Cube::CornerIndex(ii,jj,kk); - } - } - } - } - } - } - return neighbors[d]; -} -template< class NodeData > -typename OctNode< NodeData >::ConstNeighbors5& OctNode< NodeData >::ConstNeighborKey5::getNeighbors( const OctNode* node ) -{ - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if(!node->parent) neighbors[d].neighbors[2][2][2]=node; - else - { - getNeighbors( node->parent ); - ConstNeighbors5& temp = neighbors[d-1]; - int x1,y1,z1,x2,y2,z2,ii,jj,kk; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex(idx,x1,y1,z1); - - for(int i=0;i<5;i++) - { - x2=i+x1; - ii=x2&1; - x2=1+(x2>>1); - for(int j=0;j<5;j++) - { - y2=j+y1; - jj=y2&1; - y2=1+(y2>>1); - for(int k=0;k<5;k++) - { - z2=k+z1; - kk=z2&1; - z2=1+(z2>>1); - if(temp.neighbors[x2][y2][z2] && temp.neighbors[x2][y2][z2]->children) - neighbors[d].neighbors[i][j][k] = temp.neighbors[x2][y2][z2]->children + Cube::CornerIndex(ii,jj,kk); - } - } - } - } - } - return neighbors[d]; -} - - -template< class NodeData > -int OctNode< NodeData >::write(const char* fileName) const{ - FILE* fp=fopen(fileName,"wb"); - if(!fp){return 0;} - int ret=write(fp); - fclose(fp); - return ret; -} -template< class NodeData > -int OctNode< NodeData >::write(FILE* fp) const{ - fwrite(this,sizeof(OctNode< NodeData >),1,fp); - if(children){for(int i=0;i -int OctNode< NodeData >::read(const char* fileName){ - FILE* fp=fopen(fileName,"rb"); - if(!fp){return 0;} - int ret=read(fp); - fclose(fp); - return ret; -} -template< class NodeData > -int OctNode< NodeData >::read(FILE* fp){ - fread(this,sizeof(OctNode< NodeData >),1,fp); - parent=NULL; - if(children){ - children=NULL; - initChildren(); - for(int i=0;i -int OctNode< NodeData >::width(int maxDepth) const { - int d=depth(); - return 1<<(maxDepth-d); -} -template< class NodeData > -void OctNode< NodeData >::centerIndex(int maxDepth,int index[DIMENSION]) const -{ - int d,o[3]; - depthAndOffset(d,o); - for(int i=0;i -#include "Polynomial.h" - -template -class StartingPolynomial{ -public: - Polynomial p; - double start; - - template - StartingPolynomial operator * (const StartingPolynomial& p) const; - StartingPolynomial scale(double s) const; - StartingPolynomial shift(double t) const; - int operator < (const StartingPolynomial& sp) const; - static int Compare(const void* v1,const void* v2); -}; - -template -class PPolynomial -{ -public: - size_t polyCount; - StartingPolynomial* polys; - - PPolynomial(void); - PPolynomial(const PPolynomial& p); - ~PPolynomial(void); - - PPolynomial& operator = (const PPolynomial& p); - - int size(void) const; - - void set( size_t size ); - // Note: this method will sort the elements in sps - void set( StartingPolynomial* sps , int count ); - void reset( size_t newSize ); - - - double operator()( double t ) const; - double integral( double tMin , double tMax ) const; - double Integral( void ) const; - - template - PPolynomial& operator = (const PPolynomial& p); - - PPolynomial operator + (const PPolynomial& p) const; - PPolynomial operator - (const PPolynomial& p) const; - - template - PPolynomial operator * (const Polynomial& p) const; - - template - PPolynomial operator * (const PPolynomial& p) const; - - - PPolynomial& operator += ( double s ); - PPolynomial& operator -= ( double s ); - PPolynomial& operator *= ( double s ); - PPolynomial& operator /= ( double s ); - PPolynomial operator + ( double s ) const; - PPolynomial operator - ( double s ) const; - PPolynomial operator * ( double s ) const; - PPolynomial operator / ( double s ) const; - - PPolynomial& addScaled(const PPolynomial& poly,double scale); - - PPolynomial scale( double s ) const; - PPolynomial shift( double t ) const; - - PPolynomial< Degree-1 > derivative(void) const; - PPolynomial< Degree+1 > integral(void) const; - - void getSolutions(double c,std::vector& roots,double EPS,double min=-DBL_MAX,double max=DBL_MAX) const; - - void printnl( void ) const; - - PPolynomial< Degree+1 > MovingAverage( double radius ) const; - static PPolynomial BSpline( double radius=0.5 ); - - void write( FILE* fp , int samples , double min , double max ) const; -}; -#include "PPolynomial.inl" -#endif // P_POLYNOMIAL_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/PPolynomial.inl b/src/scanner/PoissonRecon/Src/PPolynomial.inl deleted file mode 100755 index 7db3954..0000000 --- a/src/scanner/PoissonRecon/Src/PPolynomial.inl +++ /dev/null @@ -1,431 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "Factor.h" - -//////////////////////// -// StartingPolynomial // -//////////////////////// -template -template -StartingPolynomial StartingPolynomial::operator * (const StartingPolynomial& p) const{ - StartingPolynomial sp; - if(start>p.start){sp.start=start;} - else{sp.start=p.start;} - sp.p=this->p*p.p; - return sp; -} -template -StartingPolynomial StartingPolynomial::scale(double s) const{ - StartingPolynomial q; - q.start=start*s; - q.p=p.scale(s); - return q; -} -template -StartingPolynomial StartingPolynomial::shift(double s) const{ - StartingPolynomial q; - q.start=start+s; - q.p=p.shift(s); - return q; -} - - -template -int StartingPolynomial::operator < (const StartingPolynomial& sp) const{ - if(start -int StartingPolynomial::Compare(const void* v1,const void* v2){ - double d=((StartingPolynomial*)(v1))->start-((StartingPolynomial*)(v2))->start; - if (d<0) {return -1;} - else if (d>0) {return 1;} - else {return 0;} -} - -///////////////// -// PPolynomial // -///////////////// -template -PPolynomial::PPolynomial(void){ - polyCount=0; - polys=NULL; -} -template -PPolynomial::PPolynomial(const PPolynomial& p){ - polyCount=0; - polys=NULL; - set(p.polyCount); - memcpy(polys,p.polys,sizeof(StartingPolynomial)*p.polyCount); -} - -template -PPolynomial::~PPolynomial(void){ - if(polyCount){free(polys);} - polyCount=0; - polys=NULL; -} -template -void PPolynomial::set(StartingPolynomial* sps,int count){ - int i,c=0; - set(count); - qsort(sps,count,sizeof(StartingPolynomial),StartingPolynomial::Compare); - for( i=0 ; i -int PPolynomial::size(void) const{return int(sizeof(StartingPolynomial)*polyCount);} - -template -void PPolynomial::set( size_t size ) -{ - if(polyCount){free(polys);} - polyCount=0; - polys=NULL; - polyCount=size; - if(size){ - polys=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*size); - memset(polys,0,sizeof(StartingPolynomial)*size); - } -} -template -void PPolynomial::reset( size_t newSize ) -{ - polyCount=newSize; - polys=(StartingPolynomial*)realloc(polys,sizeof(StartingPolynomial)*newSize); -} - -template -PPolynomial& PPolynomial::operator = (const PPolynomial& p){ - set(p.polyCount); - memcpy(polys,p.polys,sizeof(StartingPolynomial)*p.polyCount); - return *this; -} - -template -template -PPolynomial& PPolynomial::operator = (const PPolynomial& p){ - set(p.polyCount); - for(int i=0;i -double PPolynomial::operator ()( double t ) const -{ - double v=0; - for( int i=0 ; ipolys[i].start ; i++ ) v+=polys[i].p(t); - return v; -} - -template -double PPolynomial::integral( double tMin , double tMax ) const -{ - int m=1; - double start,end,s,v=0; - start=tMin; - end=tMax; - if(tMin>tMax){ - m=-1; - start=tMax; - end=tMin; - } - for(int i=0;i -double PPolynomial::Integral(void) const{return integral(polys[0].start,polys[polyCount-1].start);} -template -PPolynomial PPolynomial::operator + (const PPolynomial& p) const{ - PPolynomial q; - int i,j; - size_t idx=0; - q.set(polyCount+p.polyCount); - i=j=-1; - - while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} - else if (i>=int( polyCount)-1) {q.polys[idx]=p.polys[++j];} - else if(polys[i+1].start -PPolynomial PPolynomial::operator - (const PPolynomial& p) const{ - PPolynomial q; - int i,j; - size_t idx=0; - q.set(polyCount+p.polyCount); - i=j=-1; - - while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} - else if (i>=int( polyCount)-1) {q.polys[idx].start=p.polys[++j].start;q.polys[idx].p=p.polys[j].p*(-1.0);} - else if(polys[i+1].start -PPolynomial& PPolynomial::addScaled(const PPolynomial& p,double scale){ - int i,j; - StartingPolynomial* oldPolys=polys; - size_t idx=0,cnt=0,oldPolyCount=polyCount; - polyCount=0; - polys=NULL; - set(oldPolyCount+p.polyCount); - i=j=-1; - while(cnt=int( p.polyCount)-1) {polys[idx]=oldPolys[++i];} - else if (i>=int(oldPolyCount)-1) {polys[idx].start= p.polys[++j].start;polys[idx].p=p.polys[j].p*scale;} - else if (oldPolys[i+1].start -template -PPolynomial PPolynomial::operator * (const PPolynomial& p) const{ - PPolynomial q; - StartingPolynomial *sp; - int i,j,spCount=int(polyCount*p.polyCount); - - sp=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*spCount); - for(i=0;i -template -PPolynomial PPolynomial::operator * (const Polynomial& p) const{ - PPolynomial q; - q.set(polyCount); - for(int i=0;i -PPolynomial PPolynomial::scale( double s ) const -{ - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i -PPolynomial PPolynomial::shift( double s ) const -{ - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i -PPolynomial PPolynomial::derivative(void) const{ - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i -PPolynomial PPolynomial::integral(void) const{ - int i; - PPolynomial q; - q.set(polyCount); - for(i=0;i -PPolynomial& PPolynomial::operator += ( double s ) {polys[0].p+=s;} -template -PPolynomial& PPolynomial::operator -= ( double s ) {polys[0].p-=s;} -template -PPolynomial& PPolynomial::operator *= ( double s ) -{ - for(int i=0;i -PPolynomial& PPolynomial::operator /= ( double s ) -{ - for(size_t i=0;i -PPolynomial PPolynomial::operator + ( double s ) const -{ - PPolynomial q=*this; - q+=s; - return q; -} -template -PPolynomial PPolynomial::operator - ( double s ) const -{ - PPolynomial q=*this; - q-=s; - return q; -} -template -PPolynomial PPolynomial::operator * ( double s ) const -{ - PPolynomial q=*this; - q*=s; - return q; -} -template -PPolynomial PPolynomial::operator / ( double s ) const -{ - PPolynomial q=*this; - q/=s; - return q; -} - -template -void PPolynomial::printnl(void) const{ - Polynomial p; - - if(!polyCount){ - Polynomial p; - printf("[-Infinity,Infinity]\n"); - } - else{ - for(size_t i=0;i -PPolynomial< 0 > PPolynomial< 0 >::BSpline( double radius ) -{ - PPolynomial q; - q.set(2); - - q.polys[0].start=-radius; - q.polys[1].start= radius; - - q.polys[0].p.coefficients[0]= 1.0; - q.polys[1].p.coefficients[0]=-1.0; - return q; -} -template< int Degree > -PPolynomial< Degree > PPolynomial::BSpline( double radius ) -{ - return PPolynomial< Degree-1 >::BSpline().MovingAverage( radius ); -} -template -PPolynomial PPolynomial::MovingAverage( double radius ) const -{ - PPolynomial A; - Polynomial p; - StartingPolynomial* sps; - - sps=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*polyCount*2); - - for(int i=0;i -void PPolynomial::getSolutions(double c,std::vector& roots,double EPS,double min,double max) const{ - Polynomial p; - std::vector tempRoots; - - p.setZero(); - for(size_t i=0;imax){break;} - if(ipolys[i].start && (i+1==polyCount || tempRoots[j]<=polys[i+1].start)){ - if(tempRoots[j]>min && tempRoots[j] -void PPolynomial::write(FILE* fp,int samples,double min,double max) const{ - fwrite(&samples,sizeof(int),1,fp); - for(int i=0;i -#include -#include -#include - -#define PLY_ASCII 1 /* ascii PLY file */ -#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ -#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ -#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ - -#define PLY_OKAY 0 /* ply routine worked okay */ -#define PLY_ERROR -1 /* error in ply routine */ - - /* scalar data types supported by PLY format */ - -#define PLY_START_TYPE 0 -#define PLY_CHAR 1 -#define PLY_SHORT 2 -#define PLY_INT 3 -#define PLY_UCHAR 4 -#define PLY_USHORT 5 -#define PLY_UINT 6 -#define PLY_FLOAT 7 -#define PLY_DOUBLE 8 -#define PLY_INT_8 9 -#define PLY_UINT_8 10 -#define PLY_INT_16 11 -#define PLY_UINT_16 12 -#define PLY_INT_32 13 -#define PLY_UINT_32 14 -#define PLY_FLOAT_32 15 -#define PLY_FLOAT_64 16 - -#define PLY_END_TYPE 17 - -#define PLY_SCALAR 0 -#define PLY_LIST 1 - -#define PLY_STRIP_COMMENT_HEADER 0 - -typedef struct PlyProperty { /* description of a property */ - - char *name; /* property name */ - int external_type; /* file's data type */ - int internal_type; /* program's data type */ - int offset; /* offset bytes of prop in a struct */ - - int is_list; /* 1 = list, 0 = scalar */ - int count_external; /* file's count type */ - int count_internal; /* program's count type */ - int count_offset; /* offset byte for list count */ - -} PlyProperty; - -typedef struct PlyElement { /* description of an element */ - char *name; /* element name */ - int num; /* number of elements in this object */ - int size; /* size of element (bytes) or -1 if variable */ - int nprops; /* number of properties for this element */ - PlyProperty **props; /* list of properties in the file */ - char *store_prop; /* flags: property wanted by user? */ - int other_offset; /* offset to un-asked-for props, or -1 if none*/ - int other_size; /* size of other_props structure */ -} PlyElement; - -typedef struct PlyOtherProp { /* describes other properties in an element */ - char *name; /* element name */ - int size; /* size of other_props */ - int nprops; /* number of properties in other_props */ - PlyProperty **props; /* list of properties in other_props */ -} PlyOtherProp; - -typedef struct OtherData { /* for storing other_props for an other element */ - void *other_props; -} OtherData; - -typedef struct OtherElem { /* data for one "other" element */ - char *elem_name; /* names of other elements */ - int elem_count; /* count of instances of each element */ - OtherData **other_data; /* actual property data for the elements */ - PlyOtherProp *other_props; /* description of the property data */ -} OtherElem; - -typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ - int num_elems; /* number of other elements */ - OtherElem *other_list; /* list of data for other elements */ -} PlyOtherElems; - -typedef struct PlyFile { /* description of PLY file */ - FILE *fp; /* file pointer */ - int file_type; /* ascii or binary */ - float version; /* version number of file */ - int nelems; /* number of elements of object */ - PlyElement **elems; /* list of elements */ - int num_comments; /* number of comments */ - char **comments; /* list of comments */ - int num_obj_info; /* number of items of object information */ - char **obj_info; /* list of object info items */ - PlyElement *which_elem; /* which element we're currently writing */ - PlyOtherElems *other_elems; /* "other" elements from a PLY file */ -} PlyFile; - - /* memory allocation */ -extern char *my_alloc(); -#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) - -#ifndef ALLOCN -#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \ -{ \ - if ((OLD_N) == 0) \ -{ ALLOCN((PTR),TYPE,(NEW_N));} \ - else \ -{ \ - (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \ - if (((PTR) == NULL) && ((NEW_N) != 0)) \ -{ \ - fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - fprintf(stderr, " tried to reallocate %d->%d\n", \ - (OLD_N), (NEW_N)); \ - exit(-1); \ -} \ - if ((NEW_N)>(OLD_N)) \ - memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \ - ((NEW_N)-(OLD_N))*sizeof(TYPE)); \ -} \ -} - -#define ALLOCN(PTR,TYPE,N) \ -{ (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\ - if ((PTR) == NULL) { \ - fprintf(stderr, "Memory allocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - exit(-1); \ - } \ -} - - -#define FREE(PTR) { free((PTR)); (PTR) = NULL; } -#endif - - -/*** delcaration of routines ***/ - -extern PlyFile *ply_write(FILE *, int, const char **, int); -extern PlyFile *ply_open_for_writing(char *, int, const char **, int, float *); -extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); -extern void ply_describe_property(PlyFile *, const char *, PlyProperty *); -extern void ply_element_count(PlyFile *, const char *, int); -extern void ply_header_complete(PlyFile *); -extern void ply_put_element_setup(PlyFile *, const char *); -extern void ply_put_element(PlyFile *, void *); -extern void ply_put_comment(PlyFile *, char *); -extern void ply_put_obj_info(PlyFile *, char *); -extern PlyFile *ply_read(FILE *, int *, char ***); -extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); -extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); -extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); -extern int ply_get_property(PlyFile *, char *, PlyProperty *); -extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); -extern void ply_get_element(PlyFile *, void *); -extern char **ply_get_comments(PlyFile *, int *); -extern char **ply_get_obj_info(PlyFile *, int *); -extern void ply_close(PlyFile *); -extern void ply_get_info(PlyFile *, float *, int *); -extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); -extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); -extern void ply_put_other_elements (PlyFile *); -extern void ply_free_other_elements (PlyOtherElems *); -extern void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int); - -extern int equal_strings(const char *, const char *); - -#ifdef __cplusplus -} -#endif -#include "Geometry.h" -#include - -template< class Real > int PLYType( void ); -template<> inline int PLYType< int >( void ){ return PLY_INT ; } -template<> inline int PLYType< char >( void ){ return PLY_CHAR ; } -template<> inline int PLYType< unsigned char >( void ){ return PLY_UCHAR ; } -template<> inline int PLYType< float >( void ){ return PLY_FLOAT ; } -template<> inline int PLYType< double >( void ){ return PLY_DOUBLE; } -template< class Real > inline int PLYType( void ){ fprintf( stderr , "[ERROR] Unrecognized type\n" ) , exit( 0 ); } - -typedef struct PlyFace -{ - unsigned char nr_vertices; - int *vertices; - int segment; -} PlyFace; -static PlyProperty face_props[] = -{ - { _strdup( "vertex_indices" ) , PLY_INT , PLY_INT , offsetof( PlyFace , vertices ) , 1 , PLY_UCHAR, PLY_UCHAR , offsetof(PlyFace,nr_vertices) }, -}; - -template< class Real > -class PlyVertex -{ -public: - const static int Components=3; - static PlyProperty Properties[]; - - Point3D< Real > point; - - PlyVertex( void ) { ; } - PlyVertex( Point3D< Real > p ) { point=p; } - PlyVertex operator + ( PlyVertex p ) const { return PlyVertex( point+p.point ); } - PlyVertex operator - ( PlyVertex p ) const { return PlyVertex( point-p.point ); } - template< class _Real > PlyVertex operator * ( _Real s ) const { return PlyVertex( point*s ); } - template< class _Real > PlyVertex operator / ( _Real s ) const { return PlyVertex( point/s ); } - PlyVertex& operator += ( PlyVertex p ) { point += p.point ; return *this; } - PlyVertex& operator -= ( PlyVertex p ) { point -= p.point ; return *this; } - template< class _Real > PlyVertex& operator *= ( _Real s ) { point *= s ; return *this; } - template< class _Real > PlyVertex& operator /= ( _Real s ) { point /= s ; return *this; } -}; -template< class Real , class _Real > PlyVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyVertex< Real > v ) { return PlyVertex< Real >( xForm * v.point ); } -template< class Real > PlyProperty PlyVertex< Real >::Properties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyValueVertex -{ -public: - const static int Components=4; - static PlyProperty Properties[]; - - Point3D point; - Real value; - - PlyValueVertex( void ) : value( Real(0) ) { ; } - PlyValueVertex( Point3D< Real > p , Real v ) : point(p) , value(v) { ; } - PlyValueVertex operator + ( PlyValueVertex p ) const { return PlyValueVertex( point+p.point , value+p.value ); } - PlyValueVertex operator - ( PlyValueVertex p ) const { return PlyValueVertex( point-p.value , value-p.value ); } - template< class _Real > PlyValueVertex operator * ( _Real s ) const { return PlyValueVertex( point*s , Real(value*s) ); } - template< class _Real > PlyValueVertex operator / ( _Real s ) const { return PlyValueVertex( point/s , Real(value/s) ); } - PlyValueVertex& operator += ( PlyValueVertex p ) { point += p.point , value += p.value ; return *this; } - PlyValueVertex& operator -= ( PlyValueVertex p ) { point -= p.point , value -= p.value ; return *this; } - template< class _Real > PlyValueVertex& operator *= ( _Real s ) { point *= s , value *= Real(s) ; return *this; } - template< class _Real > PlyValueVertex& operator /= ( _Real s ) { point /= s , value /= Real(s) ; return *this; } -}; -template< class Real , class _Real > PlyValueVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyValueVertex< Real > v ) { return PlyValueVertex< Real >( xForm * v.point , v.value ); } -template< class Real > -PlyProperty PlyValueVertex< Real >::Properties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "value" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , value ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyOrientedVertex -{ -public: - const static int Components=6; - static PlyProperty Properties[]; - - Point3D point , normal; - - PlyOrientedVertex( void ) { ; } - PlyOrientedVertex( Point3D< Real > p , Point3D< Real > n ) : point(p) , normal(n) { ; } - PlyOrientedVertex operator + ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point+p.point , normal+p.normal ); } - PlyOrientedVertex operator - ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point-p.value , normal-p.normal ); } - template< class _Real > PlyOrientedVertex operator * ( _Real s ) const { return PlyOrientedVertex( point*s , normal*s ); } - template< class _Real > PlyOrientedVertex operator / ( _Real s ) const { return PlyOrientedVertex( point/s , normal/s ); } - PlyOrientedVertex& operator += ( PlyOrientedVertex p ) { point += p.point , normal += p.normal ; return *this; } - PlyOrientedVertex& operator -= ( PlyOrientedVertex p ) { point -= p.point , normal -= p.normal ; return *this; } - template< class _Real > PlyOrientedVertex& operator *= ( _Real s ) { point *= s , normal *= s ; return *this; } - template< class _Real > PlyOrientedVertex& operator /= ( _Real s ) { point /= s , normal /= s ; return *this; } -}; -template< class Real , class _Real > PlyOrientedVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyOrientedVertex< Real > v ) { return PlyOrientedVertex< Real >( xForm * v.point , xForm.inverse().transpose() * v.normal ); } -template< class Real > -PlyProperty PlyOrientedVertex< Real >::Properties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nx" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "ny" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nz" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyColorVertex -{ -public: - const static int Components=6; - static PlyProperty Properties[]; - - Point3D point; - unsigned char color[3]; - - operator Point3D& () {return point;} - operator const Point3D& () const {return point;} - PlyColorVertex(void) {point.coords[0]=point.coords[1]=point.coords[2]=0,color[0]=color[1]=color[2]=0;} - PlyColorVertex(const Point3D& p) {point=p;} -}; -template< class Real > -PlyProperty PlyColorVertex< Real >::Properties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "red" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "green" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "blue" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[2] ) ) , 0 , 0 , 0 , 0 } -}; - -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point3D< float >& translate , float scale , char** comments=NULL , int commentNum=0 , XForm4x4< Real > xForm=XForm4x4< Real >::Identity() ); - -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , char** comments=NULL , int commentNum=0 , XForm4x4< Real > xForm=XForm4x4< Real >::Identity() ); - -template -int PlyReadPolygons(char* fileName, - std::vector& vertices,std::vector >& polygons, - PlyProperty* properties,int propertyNum, - int& file_type, - char*** comments=NULL,int* commentNum=NULL , bool* readFlags=NULL ); - -template -int PlyWritePolygons(char* fileName, - const std::vector& vertices,const std::vector >& polygons, - PlyProperty* properties,int propertyNum, - int file_type, - char** comments=NULL,const int& commentNum=0); - -template -int PlyWritePolygons(char* fileName, - const std::vector& vertices , const std::vector< std::vector< int > >& polygons, - PlyProperty* properties,int propertyNum, - int file_type, - char** comments,const int& commentNum) -{ - int nr_vertices=int(vertices.size()); - int nr_faces=int(polygons.size()); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if (!ply){return 0;} - - // - // describe vertex and face properties - // - ply_element_count(ply, "vertex", nr_vertices); - for(int i=0;imaxFaceVerts) - { - delete[] ply_face.vertices; - maxFaceVerts=int(polygons[i].size()); - ply_face.vertices=new int[maxFaceVerts]; - } - ply_face.nr_vertices=int(polygons[i].size()); - for(int j=0;j -int PlyReadPolygons(char* fileName, - std::vector& vertices , std::vector >& polygons , - PlyProperty* properties , int propertyNum , - int& file_type , - char*** comments , int* commentNum , bool* readFlags ) -{ - int nr_elems; - char **elist; - float version; - int i,j,k; - PlyFile* ply; - char* elem_name; - int num_elems; - int nr_props; - PlyProperty** plist; - PlyFace ply_face; - - ply = ply_open_for_reading(fileName, &nr_elems, &elist, &file_type, &version); - if(!ply) return 0; - - if(comments) - { - (*comments)=new char*[*commentNum+ply->num_comments]; - for(int i=0;inum_comments;i++) - (*comments)[i]=_strdup(ply->comments[i]); - *commentNum=ply->num_comments; - } - - for (i=0; i < nr_elems; i++) { - elem_name = elist[i]; - plist = ply_get_element_description(ply, elem_name, &num_elems, &nr_props); - if(!plist) - { - for(i=0;ielems[i]->name); - free(ply->elems[i]->store_prop); - for(j=0;jelems[i]->nprops;j++){ - free(ply->elems[i]->props[j]->name); - free(ply->elems[i]->props[j]); - } - free(ply->elems[i]->props); - } - for(i=0;ielems[i]);} - free(ply->elems); - for(i=0;inum_comments;i++){free(ply->comments[i]);} - free(ply->comments); - for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} - free(ply->obj_info); - ply_free_other_elements (ply->other_elems); - - for(i=0;iname); - free(plist[j]); - } - free(plist); - } // for each type of element - - for(i=0;ielems[i]->name); - free(ply->elems[i]->store_prop); - for(j=0;jelems[i]->nprops;j++){ - free(ply->elems[i]->props[j]->name); - free(ply->elems[i]->props[j]); - } - if(ply->elems[i]->props && ply->elems[i]->nprops){free(ply->elems[i]->props);} - } - for(i=0;ielems[i]);} - free(ply->elems); - for(i=0;inum_comments;i++){free(ply->comments[i]);} - free(ply->comments); - for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} - free(ply->obj_info); - ply_free_other_elements (ply->other_elems); - - - for(i=0;i -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point3D& translate , float scale , char** comments , int commentNum , XForm4x4< Real > xForm ) -{ - int i; - int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size()); - int nr_faces=mesh->polygonCount(); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if( !ply ) return 0; - - mesh->resetIterator(); - - // - // describe vertex and face properties - // - ply_element_count( ply , "vertex" , nr_vertices ); - for( int i=0 ; iinCorePoints.size() ) ; i++ ) - { - Vertex vertex = xForm * ( mesh->inCorePoints[i] * scale + translate ); - ply_put_element(ply, (void *) &vertex); - } - for( i=0; ioutOfCorePointCount() ; i++ ) - { - Vertex vertex; - mesh->nextOutOfCorePoint( vertex ); - vertex = xForm * ( vertex * scale +translate ); - ply_put_element(ply, (void *) &vertex); - } // for, write vertices - - // write faces - std::vector< CoredVertexIndex > polygon; - ply_put_element_setup( ply , "face" ); - for( i=0 ; inextPolygon( polygon ); - ply_face.nr_vertices = int( polygon.size() ); - ply_face.vertices = new int[ polygon.size() ]; - for( int i=0 ; iinCorePoints.size() ); - ply_put_element( ply, (void *) &ply_face ); - delete[] ply_face.vertices; - } // for, write faces - - ply_close( ply ); - return 1; -} -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , char** comments , int commentNum , XForm4x4< Real > xForm ) -{ - int i; - int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size()); - int nr_faces=mesh->polygonCount(); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if( !ply ) return 0; - - mesh->resetIterator(); - - // - // describe vertex and face properties - // - ply_element_count( ply , "vertex" , nr_vertices ); - for( int i=0 ; iinCorePoints.size() ) ; i++ ) - { - Vertex vertex = xForm * mesh->inCorePoints[i]; - ply_put_element(ply, (void *) &vertex); - } - for( i=0; ioutOfCorePointCount() ; i++ ) - { - Vertex vertex; - mesh->nextOutOfCorePoint( vertex ); - vertex = xForm * ( vertex ); - ply_put_element(ply, (void *) &vertex); - } // for, write vertices - - // write faces - std::vector< CoredVertexIndex > polygon; - ply_put_element_setup( ply , "face" ); - for( i=0 ; inextPolygon( polygon ); - ply_face.nr_vertices = int( polygon.size() ); - ply_face.vertices = new int[ polygon.size() ]; - for( int i=0 ; iinCorePoints.size() ); - ply_put_element( ply, (void *) &ply_face ); - delete[] ply_face.vertices; - } // for, write faces - - ply_close( ply ); - return 1; -} -inline int PlyDefaultFileType(void){return PLY_ASCII;} - -#endif /* !__PLY_H__ */ diff --git a/src/scanner/PoissonRecon/Src/PlyFile.cpp b/src/scanner/PoissonRecon/Src/PlyFile.cpp deleted file mode 100755 index bb84486..0000000 --- a/src/scanner/PoissonRecon/Src/PlyFile.cpp +++ /dev/null @@ -1,2727 +0,0 @@ -/* - - The interface routines for reading and writing PLY polygon files. - - Greg Turk, February 1994 - - --------------------------------------------------------------- - - A PLY file contains a single polygonal _object_. - - An object is composed of lists of _elements_. Typical elements are - vertices, faces, edges and materials. - - Each type of element for a given object has one or more _properties_ - associated with the element type. For instance, a vertex element may - have as properties the floating-point values x,y,z and the three unsigned - chars representing red, green and blue. - - --------------------------------------------------------------- - - Copyright (c) 1994 The Board of Trustees of The Leland Stanford - Junior University. All rights reserved. - - Permission to use, copy, modify and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that the above copyright notice and this permission notice appear in - all copies of this software and that you do not sell the software. - - THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, - EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -*/ - -#include -#include -#include -#include -#include "Ply.h" - -const char *type_names[] = { - "invalid", - "char", - "short", - "int", - "uchar", - "ushort", - "uint", - "float", - "double", - - "int8", // character 1 - "uint8", // unsigned character 1 - "int16", // short integer 2 - "uint16", // unsigned short integer 2 - "int32", // integer 4 - "uint32", // unsigned integer 4 - "float32", // single-precision float 4 - "float64", // double-precision float 8 - -}; - -int ply_type_size[] = { - 0, - 1, - 2, - 4, - 1, - 2, - 4, - 4, - 8, - 1, - 1, - 2, - 2, - 4, - 4, - 8 -}; - -typedef union -{ - int int_value; - char byte_values[sizeof(int)]; -} endian_test_type; - - -static int native_binary_type = -1; -static int types_checked = 0; - -#define NO_OTHER_PROPS -1 - -#define DONT_STORE_PROP 0 -#define STORE_PROP 1 - -#define OTHER_PROP 0 -#define NAMED_PROP 1 - - -/* returns 1 if strings are equal, 0 if not */ -int equal_strings(const char *, const char *); - -/* find an element in a plyfile's list */ -PlyElement *find_element(PlyFile *, const char *); - -/* find a property in an element's list */ -PlyProperty *find_property(PlyElement *, const char *, int *); - -/* write to a file the word describing a PLY file data type */ -void write_scalar_type (FILE *, int); - -/* read a line from a file and break it up into separate words */ -char **get_words(FILE *, int *, char **); -char **old_get_words(FILE *, int *); - -/* write an item to a file */ -void write_binary_item(FILE *, int, int, unsigned int, double, int); -void write_ascii_item(FILE *, int, unsigned int, double, int); -double old_write_ascii_item(FILE *, char *, int); - -/* add information to a PLY file descriptor */ -void add_element(PlyFile *, char **); -void add_property(PlyFile *, char **); -void add_comment(PlyFile *, char *); -void add_obj_info(PlyFile *, char *); - -/* copy a property */ -void copy_property(PlyProperty *, PlyProperty *); - -/* store a value into where a pointer and a type specify */ -void store_item(char *, int, int, unsigned int, double); - -/* return the value of a stored item */ -void get_stored_item( void *, int, int *, unsigned int *, double *); - -/* return the value stored in an item, given ptr to it and its type */ -double get_item_value(char *, int); - -/* get binary or ascii item and store it according to ptr and type */ -void get_ascii_item(char *, int, int *, unsigned int *, double *); -void get_binary_item(FILE *, int, int, int *, unsigned int *, double *); - -/* get a bunch of elements from a file */ -void ascii_get_element(PlyFile *, char *); -void binary_get_element(PlyFile *, char *); - -/* memory allocation */ -char *my_alloc(int, int, const char *); - -/* byte ordering */ -void get_native_binary_type(); -void swap_bytes(char *, int); - -void check_types(); - -/*************/ -/* Writing */ -/*************/ - - -/****************************************************************************** -Given a file pointer, get ready to write PLY data to the file. - - Entry: - fp - the given file pointer - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - - Exit: - returns a pointer to a PlyFile, used to refer to this file, or NULL if error -******************************************************************************/ - -PlyFile *ply_write( - FILE *fp, - int nelems, - const char **elem_names, - int file_type - ) -{ - int i; - PlyFile *plyfile; - PlyElement *elem; - - /* check for NULL file pointer */ - if (fp == NULL) - return (NULL); - - if (native_binary_type == -1) - get_native_binary_type(); - if (!types_checked) - check_types(); - - /* create a record for this object */ - - plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); - if (file_type == PLY_BINARY_NATIVE) - plyfile->file_type = native_binary_type; - else - plyfile->file_type = file_type; - plyfile->num_comments = 0; - plyfile->num_obj_info = 0; - plyfile->nelems = nelems; - plyfile->version = 1.0; - plyfile->fp = fp; - plyfile->other_elems = NULL; - - /* tuck aside the names of the elements */ - - plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); - for (i = 0; i < nelems; i++) { - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - plyfile->elems[i] = elem; - elem->name = _strdup (elem_names[i]); - elem->num = 0; - elem->nprops = 0; - } - - /* return pointer to the file descriptor */ - return (plyfile); -} - - -/****************************************************************************** -Open a polygon file for writing. - - Entry: - filename - name of file to read from - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - - Exit: - version - version number of PLY file - returns a file identifier, used to refer to this file, or NULL if error -******************************************************************************/ - -PlyFile *ply_open_for_writing( - char *filename, - int nelems, - const char **elem_names, - int file_type, - float *version - ) -{ - PlyFile *plyfile; - char *name; - FILE *fp; - - /* tack on the extension .ply, if necessary */ - - name = (char *) myalloc (int(sizeof (char) * (strlen (filename)) + 5)); - strcpy (name, filename); - if (strlen (name) < 4 || - strcmp (name + strlen (name) - 4, ".ply") != 0) - strcat (name, ".ply"); - - /* open the file for writing */ - - fp = fopen (name, "wb"); - if (fp == NULL) { - return (NULL); - } - - /* create the actual PlyFile structure */ - - plyfile = ply_write (fp, nelems, elem_names, file_type); - if (plyfile == NULL) - return (NULL); - - /* say what PLY file version number we're writing */ - *version = plyfile->version; - - /* return pointer to the file descriptor */ - return (plyfile); -} - - -/****************************************************************************** -Describe an element, including its properties and how many will be written -to the file. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - nelems - number of elements of this type to be written - nprops - number of properties contained in the element - prop_list - list of properties -******************************************************************************/ - -void ply_describe_element( - PlyFile *plyfile, - char *elem_name, - int nelems, - int nprops, - PlyProperty *prop_list - ) -{ - int i; - PlyElement *elem; - PlyProperty *prop; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); - exit (-1); - } - - elem->num = nelems; - - /* copy the list of properties */ - - elem->nprops = nprops; - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); - elem->store_prop = (char *) myalloc (sizeof (char) * nprops); - - for (i = 0; i < nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - elem->props[i] = prop; - elem->store_prop[i] = NAMED_PROP; - copy_property (prop, &prop_list[i]); - } -} - - -/****************************************************************************** -Describe a property of an element. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - prop - the new property -******************************************************************************/ - -void ply_describe_property( - PlyFile *plyfile, - const char *elem_name, - PlyProperty *prop - ) -{ - PlyElement *elem; - PlyProperty *elem_prop; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr, "ply_describe_property: can't find element '%s'\n", - elem_name); - return; - } - - /* create room for new property */ - - if (elem->nprops == 0) { - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); - elem->store_prop = (char *) myalloc (sizeof (char)); - elem->nprops = 1; - } - else { - elem->nprops++; - elem->props = (PlyProperty **) - realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); - elem->store_prop = (char *) - realloc (elem->store_prop, sizeof (char) * elem->nprops); - } - - /* copy the new property */ - - elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - elem->props[elem->nprops - 1] = elem_prop; - elem->store_prop[elem->nprops - 1] = NAMED_PROP; - copy_property (elem_prop, prop); -} - - -/****************************************************************************** -Describe what the "other" properties are that are to be stored, and where -they are in an element. -******************************************************************************/ - -void ply_describe_other_properties( - PlyFile *plyfile, - PlyOtherProp *other, - int offset - ) -{ - int i; - PlyElement *elem; - PlyProperty *prop; - - /* look for appropriate element */ - elem = find_element (plyfile, other->name); - if (elem == NULL) { - fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", - other->name); - return; - } - - /* create room for other properties */ - - if (elem->nprops == 0) { - elem->props = (PlyProperty **) - myalloc (sizeof (PlyProperty *) * other->nprops); - elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); - elem->nprops = 0; - } - else { - int newsize; - newsize = elem->nprops + other->nprops; - elem->props = (PlyProperty **) - realloc (elem->props, sizeof (PlyProperty *) * newsize); - elem->store_prop = (char *) - realloc (elem->store_prop, sizeof (char) * newsize); - } - - /* copy the other properties */ - - for (i = 0; i < other->nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, other->props[i]); - elem->props[elem->nprops] = prop; - elem->store_prop[elem->nprops] = OTHER_PROP; - elem->nprops++; - } - - /* save other info about other properties */ - elem->other_size = other->size; - elem->other_offset = offset; -} - - -/****************************************************************************** -State how many of a given element will be written. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - nelems - number of elements of this type to be written -******************************************************************************/ - -void ply_element_count( - PlyFile *plyfile, - const char *elem_name, - int nelems - ) -{ - PlyElement *elem; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); - exit (-1); - } - - elem->num = nelems; -} - - -/****************************************************************************** -Signal that we've described everything a PLY file's header and that the -header should be written to the file. - - Entry: - plyfile - file identifier -******************************************************************************/ - -void ply_header_complete(PlyFile *plyfile) -{ - int i,j; - FILE *fp = plyfile->fp; - PlyElement *elem; - PlyProperty *prop; - - fprintf (fp, "ply\n"); - - switch (plyfile->file_type) { - case PLY_ASCII: - fprintf (fp, "format ascii 1.0\n"); - break; - case PLY_BINARY_BE: - fprintf (fp, "format binary_big_endian 1.0\n"); - break; - case PLY_BINARY_LE: - fprintf (fp, "format binary_little_endian 1.0\n"); - break; - default: - fprintf (stderr, "ply_header_complete: bad file type = %d\n", - plyfile->file_type); - exit (-1); - } - - /* write out the comments */ - - for (i = 0; i < plyfile->num_comments; i++) - fprintf (fp, "comment %s\n", plyfile->comments[i]); - - /* write out object information */ - - for (i = 0; i < plyfile->num_obj_info; i++) - fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); - - /* write out information about each element */ - - for (i = 0; i < plyfile->nelems; i++) { - - elem = plyfile->elems[i]; - fprintf (fp, "element %s %d\n", elem->name, elem->num); - - /* write out each property */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (prop->is_list) { - fprintf (fp, "property list "); - write_scalar_type (fp, prop->count_external); - fprintf (fp, " "); - write_scalar_type (fp, prop->external_type); - fprintf (fp, " %s\n", prop->name); - } - else { - fprintf (fp, "property "); - write_scalar_type (fp, prop->external_type); - fprintf (fp, " %s\n", prop->name); - } - } - } - - fprintf (fp, "end_header\n"); -} - - -/****************************************************************************** -Specify which elements are going to be written. This should be called -before a call to the routine ply_put_element(). - - Entry: - plyfile - file identifier - elem_name - name of element we're talking about -******************************************************************************/ - -void ply_put_element_setup(PlyFile *plyfile, const char *elem_name) -{ - PlyElement *elem; - - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); - exit (-1); - } - - plyfile->which_elem = elem; -} - - -/****************************************************************************** -Write an element to the file. This routine assumes that we're -writing the type of element specified in the last call to the routine -ply_put_element_setup(). - - Entry: - plyfile - file identifier - elem_ptr - pointer to the element -******************************************************************************/ - -void ply_put_element(PlyFile *plyfile, void *elem_ptr) -{ - int j,k; - FILE *fp = plyfile->fp; - PlyElement *elem; - PlyProperty *prop; - char *elem_data,*item; - char **item_ptr; - int list_count; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - char **other_ptr; - - elem = plyfile->which_elem; - elem_data = (char *)elem_ptr; - other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); - - /* write out either to an ascii or binary file */ - - if (plyfile->file_type == PLY_ASCII) { - - /* write an ascii file */ - - /* write out each property of the element */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (elem->store_prop[j] == OTHER_PROP) - elem_data = *other_ptr; - else - elem_data = (char *)elem_ptr; - if (prop->is_list) { - item = elem_data + prop->count_offset; - get_stored_item ((void *) item, prop->count_internal, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->count_external); - list_count = uint_val; - item_ptr = (char **) (elem_data + prop->offset); - item = item_ptr[0]; - item_size = ply_type_size[prop->internal_type]; - for (k = 0; k < list_count; k++) { - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->external_type); - item += item_size; - } - } - else { - item = elem_data + prop->offset; - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->external_type); - } - } - - fprintf (fp, "\n"); - } - else { - - /* write a binary file */ - - /* write out each property of the element */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (elem->store_prop[j] == OTHER_PROP) - elem_data = *other_ptr; - else - elem_data = (char *)elem_ptr; - if (prop->is_list) { - item = elem_data + prop->count_offset; - item_size = ply_type_size[prop->count_internal]; - get_stored_item ((void *) item, prop->count_internal, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->count_external); - list_count = uint_val; - item_ptr = (char **) (elem_data + prop->offset); - item = item_ptr[0]; - item_size = ply_type_size[prop->internal_type]; - for (k = 0; k < list_count; k++) { - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->external_type); - item += item_size; - } - } - else { - item = elem_data + prop->offset; - item_size = ply_type_size[prop->internal_type]; - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->external_type); - } - } - - } -} - - -/****************************************************************************** -Specify a comment that will be written in the header. - - Entry: - plyfile - file identifier - comment - the comment to be written - ******************************************************************************/ - - void ply_put_comment(PlyFile *plyfile, char *comment) - { - /* (re)allocate space for new comment */ - if (plyfile->num_comments == 0) - plyfile->comments = (char **) myalloc (sizeof (char *)); - else - plyfile->comments = (char **) realloc (plyfile->comments, - sizeof (char *) * (plyfile->num_comments + 1)); - - /* add comment to list */ - plyfile->comments[plyfile->num_comments] = _strdup (comment); - plyfile->num_comments++; - } - - - /****************************************************************************** - Specify a piece of object information (arbitrary text) that will be written - in the header. - - Entry: - plyfile - file identifier - obj_info - the text information to be written - ******************************************************************************/ - - void ply_put_obj_info(PlyFile *plyfile, char *obj_info) - { - /* (re)allocate space for new info */ - if (plyfile->num_obj_info == 0) - plyfile->obj_info = (char **) myalloc (sizeof (char *)); - else - plyfile->obj_info = (char **) realloc (plyfile->obj_info, - sizeof (char *) * (plyfile->num_obj_info + 1)); - - /* add info to list */ - plyfile->obj_info[plyfile->num_obj_info] = _strdup (obj_info); - plyfile->num_obj_info++; - } - - - - - - - - /*************/ - /* Reading */ - /*************/ - - - - /****************************************************************************** - Given a file pointer, get ready to read PLY data from the file. - - Entry: - fp - the given file pointer - - Exit: - nelems - number of elements in object - elem_names - list of element names - returns a pointer to a PlyFile, used to refer to this file, or NULL if error - ******************************************************************************/ - - PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) - { - int i,j; - PlyFile *plyfile; - int nwords; - char **words; - char **elist; - PlyElement *elem; - char *orig_line; - /* check for NULL file pointer */ - if (fp == NULL) - return (NULL); - - if (native_binary_type == -1) - get_native_binary_type(); - if (!types_checked) - check_types(); - /* create record for this object */ - - plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); - plyfile->nelems = 0; - plyfile->comments = NULL; - plyfile->num_comments = 0; - plyfile->obj_info = NULL; - plyfile->num_obj_info = 0; - plyfile->fp = fp; - plyfile->other_elems = NULL; - - /* read and parse the file's header */ - - words = get_words (plyfile->fp, &nwords, &orig_line); - if (!words || !equal_strings (words[0], "ply")) - { - if (words) - free(words); - return (NULL); - } - while (words) { - /* parse words */ - - if (equal_strings (words[0], "format")) { - if (nwords != 3) { - free(words); - return (NULL); - } - if (equal_strings (words[1], "ascii")) - plyfile->file_type = PLY_ASCII; - else if (equal_strings (words[1], "binary_big_endian")) - plyfile->file_type = PLY_BINARY_BE; - else if (equal_strings (words[1], "binary_little_endian")) - plyfile->file_type = PLY_BINARY_LE; - else { - free(words); - return (NULL); - } - plyfile->version = (float)atof (words[2]); - } - else if (equal_strings (words[0], "element")) - add_element (plyfile, words); - else if (equal_strings (words[0], "property")) - add_property (plyfile, words); - else if (equal_strings (words[0], "comment")) - add_comment (plyfile, orig_line); - else if (equal_strings (words[0], "obj_info")) - add_obj_info (plyfile, orig_line); - else if (equal_strings (words[0], "end_header")) { - free(words); - break; - } - - /* free up words space */ - free (words); - - words = get_words (plyfile->fp, &nwords, &orig_line); - } - - /* create tags for each property of each element, to be used */ - /* later to say whether or not to store each property for the user */ - - for (i = 0; i < plyfile->nelems; i++) { - elem = plyfile->elems[i]; - elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); - for (j = 0; j < elem->nprops; j++) - elem->store_prop[j] = DONT_STORE_PROP; - elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ - } - - /* set return values about the elements */ - - elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); - for (i = 0; i < plyfile->nelems; i++) - elist[i] = _strdup (plyfile->elems[i]->name); - - *elem_names = elist; - *nelems = plyfile->nelems; - - /* return a pointer to the file's information */ - - return (plyfile); -} - - -/****************************************************************************** -Open a polygon file for reading. - - Entry: - filename - name of file to read from - - Exit: - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - version - version number of PLY file - returns a file identifier, used to refer to this file, or NULL if error - ******************************************************************************/ - - PlyFile *ply_open_for_reading( - char *filename, - int *nelems, - char ***elem_names, - int *file_type, - float *version - ) - { - FILE *fp; - PlyFile *plyfile; - char *name; - - /* tack on the extension .ply, if necessary */ - - name = (char *) myalloc (int(sizeof (char) * (strlen (filename) + 5))); - strcpy (name, filename); - if (strlen (name) < 4 || - strcmp (name + strlen (name) - 4, ".ply") != 0) - strcat (name, ".ply"); - - /* open the file for reading */ - - fp = fopen (name, "rb"); - if (fp == NULL) - return (NULL); - - /* create the PlyFile data structure */ - - plyfile = ply_read (fp, nelems, elem_names); - - /* determine the file type and version */ - - *file_type = plyfile->file_type; - *version = plyfile->version; - - /* return a pointer to the file's information */ - - free(name); - return (plyfile); - } - - - /****************************************************************************** - Get information about a particular element. - - Entry: - plyfile - file identifier - elem_name - name of element to get information about - - Exit: - nelems - number of elements of this type in the file - nprops - number of properties - returns a list of properties, or NULL if the file doesn't contain that elem - ******************************************************************************/ - - PlyProperty **ply_get_element_description( - PlyFile *plyfile, - char *elem_name, - int *nelems, - int *nprops - ) - { - int i; - PlyElement *elem; - PlyProperty *prop; - PlyProperty **prop_list; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) - return (NULL); - - *nelems = elem->num; - *nprops = elem->nprops; - - /* make a copy of the element's property list */ - prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); - for (i = 0; i < elem->nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, elem->props[i]); - prop_list[i] = prop; - } - - /* return this duplicate property list */ - return (prop_list); - } - - - /****************************************************************************** - Specify which properties of an element are to be returned. This should be - called before a call to the routine ply_get_element(). - - Entry: - plyfile - file identifier - elem_name - which element we're talking about - nprops - number of properties - prop_list - list of properties - ******************************************************************************/ - - void ply_get_element_setup( - PlyFile *plyfile, - char *elem_name, - int nprops, - PlyProperty *prop_list - ) - { - int i; - PlyElement *elem; - PlyProperty *prop; - int index; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - plyfile->which_elem = elem; - - /* deposit the property information into the element's description */ - for (i = 0; i < nprops; i++) { - - /* look for actual property */ - prop = find_property (elem, prop_list[i].name, &index); - if (prop == NULL) { - fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", - prop_list[i].name, elem_name); - continue; - } - - /* store its description */ - prop->internal_type = prop_list[i].internal_type; - prop->offset = prop_list[i].offset; - prop->count_internal = prop_list[i].count_internal; - prop->count_offset = prop_list[i].count_offset; - - /* specify that the user wants this property */ - elem->store_prop[index] = STORE_PROP; - } - } - - - /****************************************************************************** - Specify a property of an element that is to be returned. This should be - called (usually multiple times) before a call to the routine ply_get_element(). - This routine should be used in preference to the less flexible old routine - called ply_get_element_setup(). - - Entry: - plyfile - file identifier - elem_name - which element we're talking about - prop - property to add to those that will be returned - ******************************************************************************/ - - int ply_get_property( - PlyFile *plyfile, - char *elem_name, - PlyProperty *prop - ) - { - PlyElement *elem; - PlyProperty *prop_ptr; - int index; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - plyfile->which_elem = elem; - - /* deposit the property information into the element's description */ - - prop_ptr = find_property (elem, prop->name, &index); - if (prop_ptr == NULL) { -// fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", -// prop->name, elem_name); -// return; - return 0; - } - prop_ptr->internal_type = prop->internal_type; - prop_ptr->offset = prop->offset; - prop_ptr->count_internal = prop->count_internal; - prop_ptr->count_offset = prop->count_offset; - - /* specify that the user wants this property */ - elem->store_prop[index] = STORE_PROP; - return 1; - } - - - /****************************************************************************** - Read one element from the file. This routine assumes that we're reading - the type of element specified in the last call to the routine - ply_get_element_setup(). - - Entry: - plyfile - file identifier - elem_ptr - pointer to location where the element information should be put - ******************************************************************************/ - - void ply_get_element(PlyFile *plyfile, void *elem_ptr) - { - if (plyfile->file_type == PLY_ASCII) - ascii_get_element (plyfile, (char *) elem_ptr); - else - binary_get_element (plyfile, (char *) elem_ptr); - } - - - /****************************************************************************** - Extract the comments from the header information of a PLY file. - - Entry: - plyfile - file identifier - - Exit: - num_comments - number of comments returned - returns a pointer to a list of comments - ******************************************************************************/ - - char **ply_get_comments(PlyFile *plyfile, int *num_comments) - { - *num_comments = plyfile->num_comments; - return (plyfile->comments); - } - - - /****************************************************************************** - Extract the object information (arbitrary text) from the header information - of a PLY file. - - Entry: - plyfile - file identifier - - Exit: - num_obj_info - number of lines of text information returned - returns a pointer to a list of object info lines - ******************************************************************************/ - - char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) - { - *num_obj_info = plyfile->num_obj_info; - return (plyfile->obj_info); - } - - - /****************************************************************************** - Make ready for "other" properties of an element-- those properties that - the user has not explicitly asked for, but that are to be stashed away - in a special structure to be carried along with the element's other - information. - - Entry: - plyfile - file identifier - elem - element for which we want to save away other properties - ******************************************************************************/ - - void setup_other_props(PlyElement *elem) - { - int i; - PlyProperty *prop; - int size = 0; - int type_size; - - /* Examine each property in decreasing order of size. */ - /* We do this so that all data types will be aligned by */ - /* word, half-word, or whatever within the structure. */ - - for (type_size = 8; type_size > 0; type_size /= 2) { - - /* add up the space taken by each property, and save this information */ - /* away in the property descriptor */ - - for (i = 0; i < elem->nprops; i++) { - - /* don't bother with properties we've been asked to store explicitly */ - if (elem->store_prop[i]) - continue; - - prop = elem->props[i]; - - /* internal types will be same as external */ - prop->internal_type = prop->external_type; - prop->count_internal = prop->count_external; - - /* check list case */ - if (prop->is_list) { - - /* pointer to list */ - if (type_size == sizeof (void *)) { - prop->offset = size; - size += sizeof (void *); /* always use size of a pointer here */ - } - - /* count of number of list elements */ - if (type_size == ply_type_size[prop->count_external]) { - prop->count_offset = size; - size += ply_type_size[prop->count_external]; - } - } - /* not list */ - else if (type_size == ply_type_size[prop->external_type]) { - prop->offset = size; - size += ply_type_size[prop->external_type]; - } - } - - } - - /* save the size for the other_props structure */ - elem->other_size = size; - } - - - /****************************************************************************** - Specify that we want the "other" properties of an element to be tucked - away within the user's structure. The user needn't be concerned for how - these properties are stored. - - Entry: - plyfile - file identifier - elem_name - name of element that we want to store other_props in - offset - offset to where other_props will be stored inside user's structure - - Exit: - returns pointer to structure containing description of other_props - ******************************************************************************/ - - PlyOtherProp *ply_get_other_properties( - PlyFile *plyfile, - char *elem_name, - int offset - ) - { - int i; - PlyElement *elem; - PlyOtherProp *other; - PlyProperty *prop; - int nprops; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", - elem_name); - return (NULL); - } - - /* remember that this is the "current" element */ - plyfile->which_elem = elem; - - /* save the offset to where to store the other_props */ - elem->other_offset = offset; - - /* place the appropriate pointers, etc. in the element's property list */ - setup_other_props (elem); - - /* create structure for describing other_props */ - other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); - other->name = _strdup (elem_name); - other->size = elem->other_size; - other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); - - /* save descriptions of each "other" property */ - nprops = 0; - for (i = 0; i < elem->nprops; i++) { - if (elem->store_prop[i]) - continue; - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, elem->props[i]); - other->props[nprops] = prop; - nprops++; - } - other->nprops = nprops; - - /* set other_offset pointer appropriately if there are NO other properties */ - if (other->nprops == 0) { - elem->other_offset = NO_OTHER_PROPS; - } - - /* return structure */ - return (other); - } - - - - - /*************************/ - /* Other Element Stuff */ - /*************************/ - - - - - /****************************************************************************** - Grab all the data for an element that a user does not want to explicitly - read in. - - Entry: - plyfile - pointer to file - elem_name - name of element whose data is to be read in - elem_count - number of instances of this element stored in the file - - Exit: - returns pointer to ALL the "other" element data for this PLY file - ******************************************************************************/ - - PlyOtherElems *ply_get_other_element ( - PlyFile *plyfile, - char *elem_name, - int elem_count - ) - { - int i; - PlyElement *elem; - PlyOtherElems *other_elems; - OtherElem *other; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf (stderr, - "ply_get_other_element: can't find element '%s'\n", elem_name); - exit (-1); - } - - /* create room for the new "other" element, initializing the */ - /* other data structure if necessary */ - - if (plyfile->other_elems == NULL) { - plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); - other_elems = plyfile->other_elems; - other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); - other = &(other_elems->other_list[0]); - other_elems->num_elems = 1; - } - else { - other_elems = plyfile->other_elems; - other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, - sizeof (OtherElem) * other_elems->num_elems + 1); - other = &(other_elems->other_list[other_elems->num_elems]); - other_elems->num_elems++; - } - - /* count of element instances in file */ - other->elem_count = elem_count; - - /* save name of element */ - other->elem_name = _strdup (elem_name); - - /* create a list to hold all the current elements */ - other->other_data = (OtherData **) - malloc (sizeof (OtherData *) * other->elem_count); - - /* set up for getting elements */ - other->other_props = ply_get_other_properties (plyfile, elem_name, - offsetof(OtherData,other_props)); - - /* grab all these elements */ - for (i = 0; i < other->elem_count; i++) { - /* grab and element from the file */ - other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); - ply_get_element (plyfile, (void *) other->other_data[i]); - } - - /* return pointer to the other elements data */ - return (other_elems); - } - - - /****************************************************************************** - Pass along a pointer to "other" elements that we want to save in a given - PLY file. These other elements were presumably read from another PLY file. - - Entry: - plyfile - file pointer in which to store this other element info - other_elems - info about other elements that we want to store - ******************************************************************************/ - - void ply_describe_other_elements ( - PlyFile *plyfile, - PlyOtherElems *other_elems - ) - { - int i; - OtherElem *other; - PlyElement *elem; - - /* ignore this call if there is no other element */ - if (other_elems == NULL) - return; - - /* save pointer to this information */ - plyfile->other_elems = other_elems; - - /* describe the other properties of this element */ - /* store them in the main element list as elements with - only other properties */ - - REALLOCN(plyfile->elems, PlyElement *, - plyfile->nelems, plyfile->nelems + other_elems->num_elems); - for (i = 0; i < other_elems->num_elems; i++) { - other = &(other_elems->other_list[i]); - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - plyfile->elems[plyfile->nelems++] = elem; - elem->name = _strdup (other->elem_name); - elem->num = other->elem_count; - elem->nprops = 0; - ply_describe_other_properties (plyfile, other->other_props, - offsetof(OtherData,other_props)); - } - } - - - /****************************************************************************** - Write out the "other" elements specified for this PLY file. - - Entry: - plyfile - pointer to PLY file to write out other elements for - ******************************************************************************/ - - void ply_put_other_elements (PlyFile *plyfile) - { - int i,j; - OtherElem *other; - - /* make sure we have other elements to write */ - if (plyfile->other_elems == NULL) - return; - - /* write out the data for each "other" element */ - - for (i = 0; i < plyfile->other_elems->num_elems; i++) { - - other = &(plyfile->other_elems->other_list[i]); - ply_put_element_setup (plyfile, other->elem_name); - - /* write out each instance of the current element */ - for (j = 0; j < other->elem_count; j++) - ply_put_element (plyfile, (void *) other->other_data[j]); - } - } - - - /****************************************************************************** - Free up storage used by an "other" elements data structure. - - Entry: - other_elems - data structure to free up - ******************************************************************************/ - - void ply_free_other_elements (PlyOtherElems *other_elems) - { - other_elems = other_elems; - } - - - - /*******************/ - /* Miscellaneous */ - /*******************/ - - - - /****************************************************************************** - Close a PLY file. - - Entry: - plyfile - identifier of file to close - ******************************************************************************/ - - void ply_close(PlyFile *plyfile) - { - fclose (plyfile->fp); - - /* free up memory associated with the PLY file */ - free (plyfile); - } - - - /****************************************************************************** - Get version number and file type of a PlyFile. - - Entry: - ply - pointer to PLY file - - Exit: - version - version of the file - file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE - ******************************************************************************/ - - void ply_get_info(PlyFile *ply, float *version, int *file_type) - { - if (ply == NULL) - return; - - *version = ply->version; - *file_type = ply->file_type; - } - - - /****************************************************************************** - Compare two strings. Returns 1 if they are the same, 0 if not. - ******************************************************************************/ - - int equal_strings(const char *s1, const char *s2) - { - - while (*s1 && *s2) - if (*s1++ != *s2++) - return (0); - - if (*s1 != *s2) - return (0); - else - return (1); - } - - - /****************************************************************************** - Find an element from the element list of a given PLY object. - - Entry: - plyfile - file id for PLY file - element - name of element we're looking for - - Exit: - returns the element, or NULL if not found - ******************************************************************************/ - - PlyElement *find_element(PlyFile *plyfile, const char *element) - { - int i; - - for (i = 0; i < plyfile->nelems; i++) - if (equal_strings (element, plyfile->elems[i]->name)) - return (plyfile->elems[i]); - - return (NULL); - } - - - /****************************************************************************** - Find a property in the list of properties of a given element. - - Entry: - elem - pointer to element in which we want to find the property - prop_name - name of property to find - - Exit: - index - index to position in list - returns a pointer to the property, or NULL if not found - ******************************************************************************/ - - PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index) - { - int i; - - for (i = 0; i < elem->nprops; i++) - if (equal_strings (prop_name, elem->props[i]->name)) { - *index = i; - return (elem->props[i]); - } - - *index = -1; - return (NULL); - } - - - /****************************************************************************** - Read an element from an ascii file. - - Entry: - plyfile - file identifier - elem_ptr - pointer to element - ******************************************************************************/ - - void ascii_get_element(PlyFile *plyfile, char *elem_ptr) - { - int j,k; - PlyElement *elem; - PlyProperty *prop; - char **words; - int nwords; - int which_word; - char *elem_data,*item=NULL; - char *item_ptr; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - int list_count; - int store_it; - char **store_array; - char *orig_line; - char *other_data=NULL; - int other_flag; - - /* the kind of element we're reading currently */ - elem = plyfile->which_elem; - - /* do we need to setup for other_props? */ - - if (elem->other_offset != NO_OTHER_PROPS) { - char **ptr; - other_flag = 1; - /* make room for other_props */ - other_data = (char *) myalloc (elem->other_size); - /* store pointer in user's structure to the other_props */ - ptr = (char **) (elem_ptr + elem->other_offset); - *ptr = other_data; - } - else - other_flag = 0; - - /* read in the element */ - - words = get_words (plyfile->fp, &nwords, &orig_line); - if (words == NULL) { - fprintf (stderr, "ply_get_element: unexpected end of file\n"); - exit (-1); - } - - which_word = 0; - - for (j = 0; j < elem->nprops; j++) { - - prop = elem->props[j]; - store_it = (elem->store_prop[j] | other_flag); - - /* store either in the user's structure or in other_props */ - if (elem->store_prop[j]) - elem_data = elem_ptr; - else - elem_data = other_data; - - if (prop->is_list) { /* a list */ - - /* get and store the number of items in the list */ - get_ascii_item (words[which_word++], prop->count_external, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->count_offset; - store_item(item, prop->count_internal, int_val, uint_val, double_val); - } - - /* allocate space for an array of items and store a ptr to the array */ - list_count = int_val; - item_size = ply_type_size[prop->internal_type]; - store_array = (char **) (elem_data + prop->offset); - - if (list_count == 0) { - if (store_it) - *store_array = NULL; - } - else { - if (store_it) { - item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); - item = item_ptr; - *store_array = item_ptr; - } - - /* read items and store them into the array */ - for (k = 0; k < list_count; k++) { - get_ascii_item (words[which_word++], prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - store_item (item, prop->internal_type, - int_val, uint_val, double_val); - item += item_size; - } - } - } - - } - else { /* not a list */ - get_ascii_item (words[which_word++], prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->offset; - store_item (item, prop->internal_type, int_val, uint_val, double_val); - } - } - - } - - free (words); -} - - -/****************************************************************************** -Read an element from a binary file. - - Entry: - plyfile - file identifier - elem_ptr - pointer to an element - ******************************************************************************/ - - void binary_get_element(PlyFile *plyfile, char *elem_ptr) - { - int j,k; - PlyElement *elem; - PlyProperty *prop; - FILE *fp = plyfile->fp; - char *elem_data,*item=NULL; - char *item_ptr; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - int list_count; - int store_it; - char **store_array; - char *other_data=NULL; - int other_flag; - - /* the kind of element we're reading currently */ - elem = plyfile->which_elem; - - /* do we need to setup for other_props? */ - - if (elem->other_offset != NO_OTHER_PROPS) { - char **ptr; - other_flag = 1; - /* make room for other_props */ - other_data = (char *) myalloc (elem->other_size); - /* store pointer in user's structure to the other_props */ - ptr = (char **) (elem_ptr + elem->other_offset); - *ptr = other_data; - } - else - other_flag = 0; - - /* read in a number of elements */ - - for (j = 0; j < elem->nprops; j++) { - - prop = elem->props[j]; - store_it = (elem->store_prop[j] | other_flag); - - /* store either in the user's structure or in other_props */ - if (elem->store_prop[j]) - elem_data = elem_ptr; - else - elem_data = other_data; - - if (prop->is_list) { /* a list */ - - /* get and store the number of items in the list */ - get_binary_item (fp, plyfile->file_type, prop->count_external, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->count_offset; - store_item(item, prop->count_internal, int_val, uint_val, double_val); - } - - /* allocate space for an array of items and store a ptr to the array */ - list_count = int_val; - item_size = ply_type_size[prop->internal_type]; - store_array = (char **) (elem_data + prop->offset); - if (list_count == 0) { - if (store_it) - *store_array = NULL; - } - else { - if (store_it) { - item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); - item = item_ptr; - *store_array = item_ptr; - } - - /* read items and store them into the array */ - for (k = 0; k < list_count; k++) { - get_binary_item (fp, plyfile->file_type, prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - store_item (item, prop->internal_type, - int_val, uint_val, double_val); - item += item_size; - } - } - } - - } - else { /* not a list */ - get_binary_item (fp, plyfile->file_type, prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->offset; - store_item (item, prop->internal_type, int_val, uint_val, double_val); - } - } - - } - } - - - /****************************************************************************** - Write to a file the word that represents a PLY data type. - - Entry: - fp - file pointer - code - code for type - ******************************************************************************/ - - void write_scalar_type (FILE *fp, int code) - { - /* make sure this is a valid code */ - - if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) { - fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); - exit (-1); - } - - /* write the code to a file */ - - fprintf (fp, "%s", type_names[code]); - } - - /****************************************************************************** - Reverse the order in an array of bytes. This is the conversion from big - endian to little endian and vice versa - - Entry: - bytes - array of bytes to reverse (in place) - num_bytes - number of bytes in array - ******************************************************************************/ - - void swap_bytes(char *bytes, int num_bytes) - { - int i; - char temp; - - for (i=0; i < num_bytes/2; i++) - { - temp = bytes[i]; - bytes[i] = bytes[(num_bytes-1)-i]; - bytes[(num_bytes-1)-i] = temp; - } - } - - /****************************************************************************** - Find out if this machine is big endian or little endian - - Exit: - set global variable, native_binary_type = - either PLY_BINARY_BE or PLY_BINARY_LE - - ******************************************************************************/ - - void get_native_binary_type() - { - endian_test_type test; - - test.int_value = 0; - test.int_value = 1; - if (test.byte_values[0] == 1) - native_binary_type = PLY_BINARY_LE; - else if (test.byte_values[sizeof(int)-1] == 1) - native_binary_type = PLY_BINARY_BE; - else - { - fprintf(stderr, "ply: Couldn't determine machine endianness.\n"); - fprintf(stderr, "ply: Exiting...\n"); - exit(1); - } - } - - /****************************************************************************** - Verify that all the native types are the sizes we need - - - ******************************************************************************/ - - void check_types() - { - if ((ply_type_size[PLY_CHAR] != sizeof(char)) || - (ply_type_size[PLY_SHORT] != sizeof(short)) || - (ply_type_size[PLY_INT] != sizeof(int)) || - (ply_type_size[PLY_UCHAR] != sizeof(unsigned char)) || - (ply_type_size[PLY_USHORT] != sizeof(unsigned short)) || - (ply_type_size[PLY_UINT] != sizeof(unsigned int)) || - (ply_type_size[PLY_FLOAT] != sizeof(float)) || - (ply_type_size[PLY_DOUBLE] != sizeof(double))) - { - fprintf(stderr, "ply: Type sizes do not match built-in types\n"); - fprintf(stderr, "ply: Exiting...\n"); - exit(1); - } - - types_checked = 1; - } - - /****************************************************************************** - Get a text line from a file and break it up into words. - - IMPORTANT: The calling routine call "free" on the returned pointer once - finished with it. - - Entry: - fp - file to read from - - Exit: - nwords - number of words returned - orig_line - the original line of characters - returns a list of words from the line, or NULL if end-of-file - ******************************************************************************/ - - char **get_words(FILE *fp, int *nwords, char **orig_line) - { -#define BIG_STRING 4096 - static char str[BIG_STRING]; - static char str_copy[BIG_STRING]; - char **words; - int max_words = 10; - int num_words = 0; - char *ptr,*ptr2; - char *result; - - words = (char **) myalloc (sizeof (char *) * max_words); - - /* read in a line */ - result = fgets (str, BIG_STRING, fp); - if (result == NULL) { - *nwords = 0; - *orig_line = NULL; - return (NULL); - } - /* convert line-feed and tabs into spaces */ - /* (this guarentees that there will be a space before the */ - /* null character at the end of the string) */ - - str[BIG_STRING-2] = ' '; - str[BIG_STRING-1] = '\0'; - - for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { - *ptr2 = *ptr; - // Added line here to manage carriage returns - if (*ptr == '\t' || *ptr == '\r') { - *ptr = ' '; - *ptr2 = ' '; - } - else if (*ptr == '\n') { - *ptr = ' '; - *ptr2 = '\0'; - break; - } - } - - /* find the words in the line */ - - ptr = str; - while (*ptr != '\0') { - - /* jump over leading spaces */ - while (*ptr == ' ') - ptr++; - - /* break if we reach the end */ - if (*ptr == '\0') - break; - - /* save pointer to beginning of word */ - if (num_words >= max_words) { - max_words += 10; - words = (char **) realloc (words, sizeof (char *) * max_words); - } - words[num_words++] = ptr; - - /* jump over non-spaces */ - while (*ptr != ' ') - ptr++; - - /* place a null character here to mark the end of the word */ - *ptr++ = '\0'; - } - - /* return the list of words */ - *nwords = num_words; - *orig_line = str_copy; - return (words); - } - - - /****************************************************************************** - Return the value of an item, given a pointer to it and its type. - - Entry: - item - pointer to item - type - data type that "item" points to - - Exit: - returns a double-precision float that contains the value of the item - ******************************************************************************/ - - double get_item_value(char *item, int type) - { - unsigned char *puchar; - char *pchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - int int_value; - unsigned int uint_value; - double double_value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - pchar = (char *) item; - int_value = *pchar; - return ((double) int_value); - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - int_value = *puchar; - return ((double) int_value); - case PLY_SHORT: - case PLY_INT_16: - pshort = (short int *) item; - int_value = *pshort; - return ((double) int_value); - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short int *) item; - int_value = *pushort; - return ((double) int_value); - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - int_value = *pint; - return ((double) int_value); - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - uint_value = *puint; - return ((double) uint_value); - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - double_value = *pfloat; - return (double_value); - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - double_value = *pdouble; - return (double_value); - default: - fprintf (stderr, "get_item_value: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Write out an item to a file as raw binary bytes. - - Entry: - fp - file to write to - int_val - integer version of item - uint_val - unsigned integer version of item - double_val - double-precision float version of item - type - data type to write out - ******************************************************************************/ - - void write_binary_item( - FILE *fp, - int file_type, - int int_val, - unsigned int uint_val, - double double_val, - int type - ) - { - unsigned char uchar_val; - char char_val; - unsigned short ushort_val; - short short_val; - float float_val; - void *value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - char_val = char(int_val); - value = &char_val; - break; - case PLY_SHORT: - case PLY_INT_16: - short_val = short(int_val); - value = &short_val; - break; - case PLY_INT: - case PLY_INT_32: - value = &int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - uchar_val = (unsigned char)(uint_val); - value = &uchar_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - ushort_val = (unsigned short)(uint_val); - value = &ushort_val; - break; - case PLY_UINT: - case PLY_UINT_32: - value = &uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - float_val = (float)double_val; - value = &float_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - value = &double_val; - break; - default: - fprintf (stderr, "write_binary_item: bad type = %d\n", type); - exit (-1); - } - - - if ((file_type != native_binary_type) && (ply_type_size[type] > 1)) - swap_bytes((char *)value, ply_type_size[type]); - - if (fwrite (value, ply_type_size[type], 1, fp) != 1) - { - fprintf(stderr, "PLY ERROR: fwrite() failed -- aborting.\n"); - exit(1); - } - } - - - /****************************************************************************** - Write out an item to a file as ascii characters. - - Entry: - fp - file to write to - int_val - integer version of item - uint_val - unsigned integer version of item - double_val - double-precision float version of item - type - data type to write out - ******************************************************************************/ - - void write_ascii_item( - FILE *fp, - int int_val, - unsigned int uint_val, - double double_val, - int type - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - case PLY_SHORT: - case PLY_INT_16: - case PLY_INT: - case PLY_INT_32: - if (fprintf (fp, "%d ", int_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - case PLY_UCHAR: - case PLY_UINT_8: - case PLY_USHORT: - case PLY_UINT_16: - case PLY_UINT: - case PLY_UINT_32: - - if (fprintf (fp, "%u ", uint_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - case PLY_DOUBLE: - case PLY_FLOAT_64: - if (fprintf (fp, "%g ", double_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - default: - fprintf (stderr, "write_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Write out an item to a file as ascii characters. - - Entry: - fp - file to write to - item - pointer to item to write - type - data type that "item" points to - - Exit: - returns a double-precision float that contains the value of the written item - ******************************************************************************/ - - double old_write_ascii_item(FILE *fp, char *item, int type) - { - unsigned char *puchar; - char *pchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - int int_value; - unsigned int uint_value; - double double_value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - pchar = (char *) item; - int_value = *pchar; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - int_value = *puchar; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_SHORT: - case PLY_INT_16: - pshort = (short int *) item; - int_value = *pshort; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short int *) item; - int_value = *pushort; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - int_value = *pint; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - uint_value = *puint; - fprintf (fp, "%u ", uint_value); - return ((double) uint_value); - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - double_value = *pfloat; - fprintf (fp, "%g ", double_value); - return (double_value); - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - double_value = *pdouble; - fprintf (fp, "%g ", double_value); - return (double_value); - default: - fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Get the value of an item that is in memory, and place the result - into an integer, an unsigned integer and a double. - - Entry: - ptr - pointer to the item - type - data type supposedly in the item - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_stored_item( - void *ptr, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *int_val = *((char *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - *uint_val = *((unsigned char *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_SHORT: - case PLY_INT_16: - *int_val = *((short int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - *uint_val = *((unsigned short int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_INT: - case PLY_INT_32: - *int_val = *((int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - *uint_val = *((unsigned int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - *double_val = *((float *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = *((double *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - default: - fprintf (stderr, "get_stored_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Get the value of an item from a binary file, and place the result - into an integer, an unsigned integer and a double. - - Entry: - fp - file to get item from - type - data type supposedly in the word - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_binary_item( - FILE *fp, - int file_type, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - char c[8]; - void *ptr; - - ptr = (void *) c; - - if (fread (ptr, ply_type_size[type], 1, fp) != 1) - { - fprintf(stderr, "PLY ERROR: fread() failed -- aborting.\n"); - exit(1); - } - - - if ((file_type != native_binary_type) && (ply_type_size[type] > 1)) - swap_bytes((char *)ptr, ply_type_size[type]); - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *int_val = *((char *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - *uint_val = *((unsigned char *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_SHORT: - case PLY_INT_16: - *int_val = *((short int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - *uint_val = *((unsigned short int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_INT: - case PLY_INT_32: - *int_val = *((int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - *uint_val = *((unsigned int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - *double_val = *((float *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = *((double *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - default: - fprintf (stderr, "get_binary_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Extract the value of an item from an ascii word, and place the result - into an integer, an unsigned integer and a double. - - Entry: - word - word to extract value from - type - data type supposedly in the word - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_ascii_item( - char *word, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - case PLY_UCHAR: - case PLY_UINT_8: - case PLY_SHORT: - case PLY_INT_16: - case PLY_USHORT: - case PLY_UINT_16: - case PLY_INT: - case PLY_INT_32: - *int_val = atoi (word); - *uint_val = (unsigned int) *int_val; - *double_val = (double) *int_val; - break; - - case PLY_UINT: - case PLY_UINT_32: - *uint_val = strtol (word, (char **) NULL, 10); - *int_val = (int) *uint_val; - *double_val = (double) *uint_val; - break; - - case PLY_FLOAT: - case PLY_FLOAT_32: - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = atof (word); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - - default: - fprintf (stderr, "get_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Store a value into a place being pointed to, guided by a data type. - - Entry: - item - place to store value - type - data type - int_val - integer version of value - uint_val - unsigned integer version of value - double_val - double version of value - - Exit: - item - pointer to stored value - ******************************************************************************/ - - void store_item ( - char *item, - int type, - int int_val, - unsigned int uint_val, - double double_val - ) - { - unsigned char *puchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *item = char(int_val); - break; - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - *puchar = (unsigned char)(uint_val); - break; - case PLY_SHORT: - case PLY_INT_16: - pshort = (short *) item; - *pshort = short(int_val); - break; - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short *) item; - *pushort = (unsigned short)(uint_val); - break; - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - *pint = int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - *puint = uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - *pfloat = (float)double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - *pdouble = double_val; - break; - default: - fprintf (stderr, "store_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Add an element to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - words - list of words describing the element - nwords - number of words in the list - ******************************************************************************/ - - void add_element (PlyFile *plyfile, char **words) - { - PlyElement *elem; - - /* create the new element */ - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - elem->name = _strdup (words[1]); - elem->num = atoi (words[2]); - elem->nprops = 0; - - /* make room for new element in the object's list of elements */ - if (plyfile->nelems == 0) - plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); - else - plyfile->elems = (PlyElement **) realloc (plyfile->elems, - sizeof (PlyElement *) * (plyfile->nelems + 1)); - - /* add the new element to the object's list */ - plyfile->elems[plyfile->nelems] = elem; - plyfile->nelems++; - } - - - /****************************************************************************** - Return the type of a property, given the name of the property. - - Entry: - name - name of property type - - Exit: - returns integer code for property, or 0 if not found - ******************************************************************************/ - - int get_prop_type(char *type_name) - { - int i; - - for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) - if (equal_strings (type_name, type_names[i])) - return (i); - - /* if we get here, we didn't find the type */ - return (0); - } - - - /****************************************************************************** - Add a property to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - words - list of words describing the property - nwords - number of words in the list - ******************************************************************************/ - - void add_property (PlyFile *plyfile, char **words) - { - PlyProperty *prop; - PlyElement *elem; - - /* create the new property */ - - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - - if (equal_strings (words[1], "list")) { /* is a list */ - prop->count_external = get_prop_type (words[2]); - prop->external_type = get_prop_type (words[3]); - prop->name = _strdup (words[4]); - prop->is_list = 1; - } - else { /* not a list */ - prop->external_type = get_prop_type (words[1]); - prop->name = _strdup (words[2]); - prop->is_list = 0; - } - - /* add this property to the list of properties of the current element */ - - elem = plyfile->elems[plyfile->nelems - 1]; - - if (elem->nprops == 0) - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); - else - elem->props = (PlyProperty **) realloc (elem->props, - sizeof (PlyProperty *) * (elem->nprops + 1)); - - elem->props[elem->nprops] = prop; - elem->nprops++; - } - - - /****************************************************************************** - Add a comment to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - line - line containing comment - ******************************************************************************/ - - void add_comment (PlyFile *plyfile, char *line) - { - int i; - - /* skip over "comment" and leading spaces and tabs */ - i = 7; - while (line[i] == ' ' || line[i] == '\t') - i++; - - ply_put_comment (plyfile, &line[i]); - } - - - /****************************************************************************** - Add a some object information to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - line - line containing text info - ******************************************************************************/ - - void add_obj_info (PlyFile *plyfile, char *line) - { - int i; - - /* skip over "obj_info" and leading spaces and tabs */ - i = 8; - while (line[i] == ' ' || line[i] == '\t') - i++; - - ply_put_obj_info (plyfile, &line[i]); - } - - - /****************************************************************************** - Copy a property. - ******************************************************************************/ - - void copy_property(PlyProperty *dest, PlyProperty *src) - { - dest->name = _strdup (src->name); - dest->external_type = src->external_type; - dest->internal_type = src->internal_type; - dest->offset = src->offset; - - dest->is_list = src->is_list; - dest->count_external = src->count_external; - dest->count_internal = src->count_internal; - dest->count_offset = src->count_offset; - } - - - /****************************************************************************** - Allocate some memory. - - Entry: - size - amount of memory requested (in bytes) - lnum - line number from which memory was requested - fname - file name from which memory was requested - ******************************************************************************/ - - char *my_alloc(int size, int lnum, const char *fname) - { - char *ptr; - - ptr = (char *) malloc (size); - - if (ptr == 0) { - fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); - } - - return (ptr); - } - diff --git a/src/scanner/PoissonRecon/Src/PointStream.h b/src/scanner/PoissonRecon/Src/PointStream.h deleted file mode 100755 index 739b22d..0000000 --- a/src/scanner/PoissonRecon/Src/PointStream.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior writften permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef POINT_STREAM_INCLUDED -#define POINT_STREAM_INCLUDED -#include "Ply.h" - -#include -#include - - -template< class Real > -class PointStream -{ -public: - virtual ~PointStream( void ){} - virtual void reset( void ) = 0; - virtual bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ) = 0; -}; - -template< class Real > -class MemoryPointStream : public PointStream< Real > -{ - const std::pair< Point3D< Real > , Point3D< Real > >* _points; - size_t _pointCount; - size_t _current; -public: - MemoryPointStream( size_t pointCount , std::pair< Point3D< Real > , Point3D< Real > >* points ); - ~MemoryPointStream( void ); - void reset( void ); - bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ); -}; - -template< class Real > -class ASCIIPointStream : public PointStream< Real > -{ - FILE* _fp; -public: - ASCIIPointStream( const char* fileName ); - ~ASCIIPointStream( void ); - void reset( void ); - bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ); -}; - -template< class Real > -class BinaryPointStream : public PointStream< Real > -{ - FILE* _fp; - static const int POINT_BUFFER_SIZE=1024; - Real _pointBuffer[ POINT_BUFFER_SIZE * 2 * 3 ]; - int _pointsInBuffer , _currentPointIndex; -public: - BinaryPointStream( const char* filename ); - ~BinaryPointStream( void ); - void reset( void ); - bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ); -}; - -template< class Real > -class PLYPointStream : public PointStream< Real > -{ - char* _fileName; - PlyFile* _ply; - int _nr_elems; - char **_elist; - - int _pCount , _pIdx; - void _free( void ); -public: - PLYPointStream( const char* fileName ); - ~PLYPointStream( void ); - void reset( void ); - bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ); -}; - - - -template< class Real > -class PCDPointStream : public PointStream< Real > -{ - char* _fileName; - // PlyFile* _ply; - // int _nr_elems; - // char **_elist; - - int _pCount , _pIdx; - - pcl::PointCloud::Ptr _cloud; - - // void _free( void ); -public: - PCDPointStream( const char* fileName ); - ~PCDPointStream( void ); - void reset( void ); - void reset( pcl::PointCloud::Ptr cloud_in); - bool nextPoint( Point3D< Real >& p , Point3D< Real >& n ); -}; - -#include "PointStream.inl" -#endif // POINT_STREAM_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/PointStream.inl b/src/scanner/PoissonRecon/Src/PointStream.inl deleted file mode 100755 index d73cd41..0000000 --- a/src/scanner/PoissonRecon/Src/PointStream.inl +++ /dev/null @@ -1,271 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - - -template< class Real > -MemoryPointStream< Real >::MemoryPointStream( size_t pointCount , std::pair< Point3D< Real > , Point3D< Real > >* points ){ _points = points , _pointCount = pointCount , _current = 0; } -template< class Real > -MemoryPointStream< Real >::~MemoryPointStream( void ){ ; } -template< class Real > -void MemoryPointStream< Real >::reset( void ) { _current=0; } -template< class Real > -bool MemoryPointStream< Real >::nextPoint( Point3D< Real >& p , Point3D< Real >& n ) -{ - if( _current>=_pointCount ) return false; - p = _points[_current].first , n = _points[_current].second; - _current++; - return true; -} - -template< class Real > -ASCIIPointStream< Real >::ASCIIPointStream( const char* fileName ) -{ - _fp = fopen( fileName , "r" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real > -ASCIIPointStream< Real >::~ASCIIPointStream( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real > -void ASCIIPointStream< Real >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } -template< class Real > -bool ASCIIPointStream< Real >::nextPoint( Point3D< Real >& p , Point3D< Real >& n ) -{ - float c[2*DIMENSION]; - if( fscanf( _fp , " %f %f %f %f %f %f " , &c[0] , &c[1] , &c[2] , &c[3] , &c[4] , &c[5] )!=2*DIMENSION ) return false; - p[0] = c[0] , p[1] = c[1] , p[2] = c[2]; - n[0] = c[3] , n[1] = c[4] , n[2] = c[5]; - return true; -} -template< class Real > -BinaryPointStream< Real >::BinaryPointStream( const char* fileName ) -{ - _pointsInBuffer = _currentPointIndex = 0; - _fp = fopen( fileName , "rb" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real > -BinaryPointStream< Real >::~BinaryPointStream( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real > -void BinaryPointStream< Real >::reset( void ) -{ - fseek( _fp , SEEK_SET , 0 ); - _pointsInBuffer = _currentPointIndex = 0; -} -template< class Real > -bool BinaryPointStream< Real >::nextPoint( Point3D< Real >& p , Point3D< Real >& n ) -{ - if( _currentPointIndex<_pointsInBuffer ) - { - p[0] = _pointBuffer[ _currentPointIndex*6+0 ]; - p[1] = _pointBuffer[ _currentPointIndex*6+1 ]; - p[2] = _pointBuffer[ _currentPointIndex*6+2 ]; - n[0] = _pointBuffer[ _currentPointIndex*6+3 ]; - n[1] = _pointBuffer[ _currentPointIndex*6+4 ]; - n[2] = _pointBuffer[ _currentPointIndex*6+5 ]; - _currentPointIndex++; - return true; - } - else - { - _currentPointIndex = 0; - _pointsInBuffer = int( fread( _pointBuffer , sizeof( Real ) * 6 , POINT_BUFFER_SIZE , _fp ) ); - if( !_pointsInBuffer ) return false; - else return nextPoint( p , n ); - } -} - -// PLY -template< class Real > -PLYPointStream< Real >::PLYPointStream( const char* fileName ) -{ - _fileName = new char[ strlen( fileName )+1 ]; - strcpy( _fileName , fileName ); - _ply = NULL; - reset(); -} -template< class Real > -void PLYPointStream< Real >::reset( void ) -{ - int fileType; - float version; - PlyProperty** plist; - if( _ply ) _free(); - _ply = ply_open_for_reading( _fileName, &_nr_elems, &_elist, &fileType, &version ); - if( !_ply ) - { - fprintf( stderr, "[ERROR] Failed to open ply file for reading: %s\n" , _fileName ); - exit( 0 ); - } - bool foundVertices = false; - for( int i=0 ; i<_nr_elems ; i++ ) - { - int num_elems; - int nr_props; - char* elem_name = _elist[i]; - plist = ply_get_element_description( _ply , elem_name , &num_elems , &nr_props ); - if( !plist ) - { - fprintf( stderr , "[ERROR] Failed to get element description: %s\n" , elem_name ); - exit( 0 ); - } - - if( equal_strings( "vertex" , elem_name ) ) - { - foundVertices = true; - _pCount = num_elems , _pIdx = 0; - for( int i=0 ; i::Components ; i++ ) - if( !ply_get_property( _ply , elem_name , &(PlyOrientedVertex< Real >::Properties[i]) ) ) - { - fprintf( stderr , "[ERROR] Failed to find property in ply file: %s\n" , PlyOrientedVertex< Real >::Properties[i].name ); - exit( 0 ); - } - } - for( int j=0 ; jname ); - free( plist[j] ); - } - free( plist ); - if( foundVertices ) break; - } - if( !foundVertices ) - { - fprintf( stderr , "[ERROR] Could not find vertices in ply file\n" ); - exit( 0 ); - } -} -template< class Real > -void PLYPointStream< Real >::_free( void ) -{ - if( _ply ) ply_close( _ply ) , _ply = NULL; - if( _elist ) - { - for( int i=0 ; i<_nr_elems ; i++ ) free( _elist[i] ); - free( _elist ); - } -} -template< class Real > -PLYPointStream< Real >::~PLYPointStream( void ) -{ - _free(); - if( _fileName ) delete[] _fileName , _fileName = NULL; -} -template< class Real > -bool PLYPointStream< Real >::nextPoint( Point3D< Real >& p , Point3D< Real >& n ) -{ - if( _pIdx<_pCount ) - { - PlyOrientedVertex< Real > op; - ply_get_element( _ply, (void *)&op ); - p = op.point; - n = op.normal; - _pIdx++; - return true; - } - else return false; -} - -// PCD -template< class Real > -PCDPointStream< Real >::PCDPointStream( const char* fileName ) -{ - _cloud.reset(); - - _fileName = new char[ strlen( fileName )+1 ]; - strcpy( _fileName , fileName ); - reset(); - -} -template< class Real > -void PCDPointStream< Real >::reset( void ) -{ - _cloud.reset(); - - _cloud.reset(new pcl::PointCloud) ; - if (pcl::io::loadPCDFile (_fileName, *_cloud) < 0) - { - PCL_ERROR ("Error loading cloud %s.\n", _fileName); - } - _pIdx = 0; - -} - -template< class Real > -void PCDPointStream< Real >::reset( pcl::PointCloud::Ptr cloud_in) -{ - _cloud.reset(); - _cloud = cloud_in; - _pIdx = 0; -} - -// template< class Real > -// void PCDPointStream< Real >::_free( void ) -// { -// // if( _ply ) ply_close( _ply ) , _ply = NULL; -// // if( _elist ) -// // { -// // for( int i=0 ; i<_nr_elems ; i++ ) free( _elist[i] ); -// // free( _elist ); -// // } -// } -template< class Real > -PCDPointStream< Real >::~PCDPointStream( void ) -{ - _cloud.reset(); - // _free(); - if( _fileName ) delete[] _fileName , _fileName = NULL; -} -template< class Real > -bool PCDPointStream< Real >::nextPoint( Point3D< Real >& p , Point3D< Real >& n ) -{ - if( _pIdx < _cloud->width ){ - - p.coords[0] = _cloud->points[_pIdx].x; - p.coords[1] = _cloud->points[_pIdx].y; - p.coords[2] = _cloud->points[_pIdx].z; - - n.coords[0] = _cloud->points[_pIdx].normal_x; - n.coords[1] = _cloud->points[_pIdx].normal_y; - n.coords[2] = _cloud->points[_pIdx].normal_z; - - _pIdx += 1; - return true; - } - - else { - return false; - } -} diff --git a/src/scanner/PoissonRecon/Src/PoissonRecon.cpp b/src/scanner/PoissonRecon/Src/PoissonRecon.cpp deleted file mode 100755 index 68a9610..0000000 --- a/src/scanner/PoissonRecon/Src/PoissonRecon.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#include -#include -#ifdef _WIN32 -#include -#include -#endif // _WIN32 -#include "MyTime.h" -#include "MarchingCubes.h" -#include "Octree.h" -#include "SparseMatrix.h" -#include "CmdLineParser.h" -#include "PPolynomial.h" -#include "Ply.h" -#include "MemoryUsage.h" -#ifdef _OPENMP -#include "omp.h" -#endif // _OPENMP -void DumpOutput( const char* format , ... ); -void DumpOutput2( char* str , const char* format , ... ); -#include "MultiGridOctreeData.h" - -#define DEFAULT_FULL_DEPTH 5 - -#define XSTR(x) STR(x) -#define STR(x) #x -#if DEFAULT_FULL_DEPTH -#pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) ) -#endif // DEFAULT_FULL_DEPTH - -#include -char* outputFile=NULL; -int echoStdout=0; -void DumpOutput( const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } -} -void DumpOutput2( char* str , const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } - va_list args; - va_start( args , format ); - vsprintf( str , format , args ); - va_end( args ); - if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; -} - - -cmdLineString - In( "in" ) , - Out( "out" ) , - VoxelGrid( "voxel" ) , - XForm( "xForm" ); - -cmdLineReadable -#ifdef _WIN32 - Performance( "performance" ) , -#endif // _WIN32 - Complete( "complete" ) , - ShowResidual( "showResidual" ) , - NoComments( "noComments" ) , - PolygonMesh( "polygonMesh" ) , - Confidence( "confidence" ) , - NormalWeights( "nWeights" ) , - NonManifold( "nonManifold" ) , - ASCII( "ascii" ) , - Density( "density" ) , - Verbose( "verbose" ) , - Double( "double" ); - -cmdLineInt - Depth( "depth" , 8 ) , - CGDepth( "cgDepth" , 0 ) , - KernelDepth( "kernelDepth" ) , - AdaptiveExponent( "adaptiveExp" , 1 ) , - Iters( "iters" , 8 ) , - VoxelDepth( "voxelDepth" , -1 ) , - FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , - MinDepth( "minDepth" , 0 ) , - MaxSolveDepth( "maxSolveDepth" ) , - BoundaryType( "boundary" , 1 ) , - Threads( "threads" , omp_get_num_procs() ); - -cmdLineFloat - SamplesPerNode( "samplesPerNode" , 1.f ) , - Scale( "scale" , 1.1f ) , - CSSolverAccuracy( "cgAccuracy" , float(1e-3) ) , - PointWeight( "pointWeight" , 4.f ); - - -cmdLineReadable* params[] = -{ - &In , &Depth , &Out , &XForm , - &Scale , &Verbose , &CSSolverAccuracy , &NoComments , &Double , - &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , - &PointWeight , &VoxelGrid , &Threads , &MaxSolveDepth , - &AdaptiveExponent , &BoundaryType , - &Density , - &FullDepth , - &MinDepth , - &CGDepth , &Iters , - &Complete , -#ifdef _WIN32 - &Performance , -#endif // _WIN32 -}; - - -void ShowUsage(char* ex) -{ - printf( "Usage: %s\n" , ex ); - printf( "\t --%s \n" , In.name ); - - printf( "\t[--%s ]\n" , Out.name ); - printf( "\t[--%s ]\n" , VoxelGrid.name ); - - printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); - printf( "\t\t Running at depth d corresponds to solving on a 2^d x 2^d x 2^d\n" ); - printf( "\t\t voxel grid.\n" ); - - printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); - printf( "\t\t This flag specifies the depth up to which the octree should be complete.\n" ); - - printf( "\t[--%s =<%s>]\n" , VoxelDepth.name , Depth.name ); - - printf( "\t[--%s =%d]\n" , CGDepth.name , CGDepth.value ); - printf( "\t\t The depth up to which a conjugate-gradients solver should be used.\n"); - - printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); - printf( "\t\t Specifies the factor of the bounding cube that the input\n" ); - printf( "\t\t samples should fit into.\n" ); - - printf( "\t[--%s =%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); - printf( "\t\t This parameter specifies the minimum number of points that\n" ); - printf( "\t\t should fall within an octree node.\n" ); - - printf( "\t[--%s =%f]\n" , PointWeight.name , PointWeight.value ); - printf( "\t\t This value specifies the weight that point interpolation constraints are\n" ); - printf( "\t\t given when defining the (screened) Poisson system.\n" ); - - printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); - printf( "\t\t This flag specifies the (maximum if CG) number of solver iterations.\n" ); - -#ifdef _OPENMP - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); - printf( "\t\t This parameter specifies the number of threads across which\n" ); - printf( "\t\t the solver should be parallelized.\n" ); -#endif // _OPENMP - - printf( "\t[--%s]\n" , Confidence.name ); - printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" ); - printf( "\t\t used as a confidence value, affecting the sample's\n" ); - printf( "\t\t constribution to the reconstruction process.\n" ); - - printf( "\t[--%s]\n" , NormalWeights.name ); - printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" ); - printf( "\t\t used as to modulate the interpolation weight.\n" ); - -#if 0 - printf( "\t[--%s]\n" , NonManifold.name ); - printf( "\t\t If this flag is enabled, the isosurface extraction does not add\n" ); - printf( "\t\t a planar polygon's barycenter in order to ensure that the output\n" ); - printf( "\t\t mesh is manifold.\n" ); -#endif - - printf( "\t[--%s]\n" , PolygonMesh.name); - printf( "\t\t If this flag is enabled, the isosurface extraction returns polygons\n" ); - printf( "\t\t rather than triangles.\n" ); - -#if 0 - printf( "\t[--%s =%d]\n" , MinDepth.name , MinDepth.value ); - printf( "\t\t This flag specifies the coarsest depth at which the system is to be solved.\n" ); - - printf( "\t[--%s =%g]\n" , CSSolverAccuracy.name , CSSolverAccuracy.value ); - printf( "\t\t This flag specifies the accuracy cut-off to be used for CG.\n" ); - - printf( "\t[--%s =%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); - printf( "\t\t This flag specifies the exponent scale for the adaptive weighting.\n" ); - -#ifdef _WIN32 - printf( "\t[--%s]\n" , Performance.name ); - printf( "\t\t If this flag is enabled, the running time and peak memory usage\n" ); - printf( "\t\t is output after the reconstruction.\n" ); -#endif // _WIN32 -#endif - - printf( "\t[--%s]\n" , Density.name ); - printf( "\t\t If this flag is enabled, the sampling density is written out with the vertices.\n" ); - -#if 0 - printf( "\t[--%s]\n" , ASCII.name ); - printf( "\t\t If this flag is enabled, the output file is written out in ASCII format.\n" ); - - printf( "\t[--%s]\n" , NoComments.name ); - printf( "\t\t If this flag is enabled, the output file will not include comments.\n" ); -#endif - - printf( "\t[--%s]\n" , Double.name ); - printf( "\t\t If this flag is enabled, the reconstruction will be performed with double-precision floats.\n" ); - - printf( "\t[--%s]\n" , Verbose.name ); - printf( "\t\t If this flag is enabled, the progress of the reconstructor will be output to STDOUT.\n" ); -} -template< class Real , class Vertex > -int Execute( int argc , char* argv[] ) -{ - Reset< Real >(); - int i; - int paramNum = sizeof(params)/sizeof(cmdLineReadable*); - int commentNum=0; - char **comments; - - comments = new char*[paramNum+7]; - for( i=0 ; i xForm , iXForm; - if( XForm.set ) - { - FILE* fp = fopen( XForm.value , "r" ); - if( !fp ) - { - fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); - xForm = XForm4x4< Real >::Identity(); - } - else - { - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) - { - float f; - fscanf( fp , " %f " , &f ); - xForm(i,j) = (Real)f; - } - fclose( fp ); - } - } - else xForm = XForm4x4< Real >::Identity(); - iXForm = xForm.inverse(); - - DumpOutput2( comments[commentNum++] , "Running Screened Poisson Reconstruction (Version 6.13)\n" ); - char str[1024]; - for( int i=0 ; iset ) - { - params[i]->writeValue( str ); - if( strlen( str ) ) DumpOutput2( comments[commentNum++] , "\t--%s %s\n" , params[i]->name , str ); - else DumpOutput2( comments[commentNum++] , "\t--%s\n" , params[i]->name ); - } - - double t; - double tt=Time(); - Real isoValue = 0; - - Octree< Real > tree; - tree.threads = Threads.value; - - if( !In.set ) - { - ShowUsage(argv[0]); - return 0; - } - if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; - - OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); - - t=Time(); - int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; - if( kernelDepth>Depth.value ) - { - fprintf( stderr,"[ERROR] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); - return EXIT_FAILURE; - } - - double maxMemoryUsage; - t=Time() , tree.maxMemoryUsage=0; - typename Octree< Real >::PointInfo* pointInfo = new typename Octree< Real >::PointInfo(); - typename Octree< Real >::NormalInfo* normalInfo = new typename Octree< Real >::NormalInfo(); - std::vector< Real >* kernelDensityWeights = new std::vector< Real >(); - std::vector< Real >* centerWeights = new std::vector< Real >(); - PointStream< float >* pointStream; - char* ext = GetFileExtension( In.value ); - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryPointStream< float >( In.value ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYPointStream< float >( In.value ); - else if( !strcasecmp( ext , "pcd" ) ) pointStream = new PCDPointStream< float >( In.value ); - else pointStream = new ASCIIPointStream< float >( In.value ); - delete[] ext; - - int pointCount = tree.template SetTree< float >( pointStream , MinDepth.value , Depth.value , FullDepth.value , kernelDepth , Real(SamplesPerNode.value) , Scale.value , Confidence.set , NormalWeights.set , PointWeight.value , AdaptiveExponent.value , *pointInfo , *normalInfo , *kernelDensityWeights , *centerWeights , BoundaryType.value , xForm , Complete.set ); - if( !Density.set ) delete kernelDensityWeights , kernelDensityWeights = NULL; - - DumpOutput2( comments[commentNum++] , "# Tree set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); - DumpOutput( "Input Points: %d\n" , pointCount ); - DumpOutput( "Leaves/Nodes: %d/%d\n" , tree.tree.leaves() , tree.tree.nodes() ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); - - maxMemoryUsage = tree.maxMemoryUsage; - t=Time() , tree.maxMemoryUsage=0; - Pointer( Real ) constraints = tree.SetLaplacianConstraints( *normalInfo ); - delete normalInfo; - DumpOutput2( comments[commentNum++] , "# Constraints set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); - maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); - - t=Time() , tree.maxMemoryUsage=0; - Pointer( Real ) solution = tree.SolveSystem( *pointInfo , constraints , ShowResidual.set , Iters.value , MaxSolveDepth.value , CGDepth.value , CSSolverAccuracy.value ); - delete pointInfo; - FreePointer( constraints ); - DumpOutput2( comments[commentNum++] , "# Linear system solved in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); - maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); - - CoredFileMeshData< Vertex > mesh; - - if( Verbose.set ) tree.maxMemoryUsage=0; - t=Time(); - isoValue = tree.GetIsoValue( solution , *centerWeights ); - delete centerWeights; - DumpOutput( "Got average in: %f\n" , Time()-t ); - DumpOutput( "Iso-Value: %e\n" , isoValue ); - - if( VoxelGrid.set ) - { - double t = Time(); - FILE* fp = fopen( VoxelGrid.value , "wb" ); - if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); - else - { - int res; - Pointer( Real ) values = tree.Evaluate( solution , res , isoValue , VoxelDepth.value ); - fwrite( &res , sizeof(int) , 1 , fp ); - if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); - else - { - float *fValues = new float[res*res*res]; - for( int i=0 ; i() , solution , isoValue , mesh , true , !NonManifold.set , PolygonMesh.set ); - if( PolygonMesh.set ) DumpOutput2( comments[commentNum++] , "# Got polygons in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); - else DumpOutput2( comments[commentNum++] , "# Got triangles in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); - maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); - DumpOutput2( comments[commentNum++],"# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-tt , maxMemoryUsage ); - - if( NoComments.set ) - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); - } - else - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , comments , commentNum , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , comments , commentNum , iXForm ); - } - DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - } - FreePointer( solution ); - return 1; -} - -#ifdef _WIN32 -inline double to_seconds( const FILETIME& ft ) -{ - const double low_to_sec=100e-9; // 100 nanoseconds - const double high_to_sec=low_to_sec*4294967296.0; - return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; -} -#endif // _WIN32 - -int main( int argc , char* argv[] ) -{ -#if defined(WIN32) && defined(MAX_MEMORY_GB) - if( MAX_MEMORY_GB>0 ) - { - SIZE_T peakMemory = 1; - peakMemory <<= 30; - peakMemory *= MAX_MEMORY_GB; - printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); - HANDLE h = CreateJobObject( NULL , NULL ); - AssignProcessToJobObject( h , GetCurrentProcess() ); - - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; - jeli.JobMemoryLimit = peakMemory; - if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) - fprintf( stderr , "Failed to set memory limit\n" ); - } -#endif // defined(WIN32) && defined(MAX_MEMORY_GB) - double t = Time(); - - cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); - if( Density.set ) - if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); - else Execute< float , PlyValueVertex< float > >( argc , argv ); - else - if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); - else Execute< float , PlyVertex< float > >( argc , argv ); -#ifdef _WIN32 - if( Performance.set ) - { - HANDLE cur_thread=GetCurrentThread(); - FILETIME tcreat, texit, tkernel, tuser; - if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) - printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); - else printf( "Time: %.2f\n" , Time()-t ); - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , pmc.PeakWorkingSetSize>>20 ); - } -#endif // _WIN32 - return EXIT_SUCCESS; -} diff --git a/src/scanner/PoissonRecon/Src/Polynomial.h b/src/scanner/PoissonRecon/Src/Polynomial.h deleted file mode 100755 index 80e15d3..0000000 --- a/src/scanner/PoissonRecon/Src/Polynomial.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef POLYNOMIAL_INCLUDED -#define POLYNOMIAL_INCLUDED - -#include - -template< int Degree > -class Polynomial{ -public: - double coefficients[Degree+1]; - - Polynomial(void); - template - Polynomial(const Polynomial& P); - double operator()( double t ) const; - double integral( double tMin , double tMax ) const; - - int operator == (const Polynomial& p) const; - int operator != (const Polynomial& p) const; - int isZero(void) const; - void setZero(void); - - template - Polynomial& operator = (const Polynomial &p); - Polynomial& operator += (const Polynomial& p); - Polynomial& operator -= (const Polynomial& p); - Polynomial operator - (void) const; - Polynomial operator + (const Polynomial& p) const; - Polynomial operator - (const Polynomial& p) const; - template - Polynomial operator * (const Polynomial& p) const; - - Polynomial& operator += ( double s ); - Polynomial& operator -= ( double s ); - Polynomial& operator *= ( double s ); - Polynomial& operator /= ( double s ); - Polynomial operator + ( double s ) const; - Polynomial operator - ( double s ) const; - Polynomial operator * ( double s ) const; - Polynomial operator / ( double s ) const; - - Polynomial scale( double s ) const; - Polynomial shift( double t ) const; - - Polynomial derivative(void) const; - Polynomial integral(void) const; - - void printnl(void) const; - - Polynomial& addScaled(const Polynomial& p,double scale); - - static void Negate(const Polynomial& in,Polynomial& out); - static void Subtract(const Polynomial& p1,const Polynomial& p2,Polynomial& q); - static void Scale(const Polynomial& p,double w,Polynomial& q); - static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q); - static void AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q); - static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q); - - void getSolutions(double c,std::vector& roots,double EPS) const; - int getSolutions( double c , double* roots , double EPS ) const; - - static Polynomial BSplineComponent( int i ); -}; - -#include "Polynomial.inl" -#endif // POLYNOMIAL_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/Polynomial.inl b/src/scanner/PoissonRecon/Src/Polynomial.inl deleted file mode 100755 index a41b501..0000000 --- a/src/scanner/PoissonRecon/Src/Polynomial.inl +++ /dev/null @@ -1,332 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#include -#include "Factor.h" - -//////////////// -// Polynomial // -//////////////// -template -Polynomial::Polynomial(void){memset(coefficients,0,sizeof(double)*(Degree+1));} -template -template -Polynomial::Polynomial(const Polynomial& P){ - memset(coefficients,0,sizeof(double)*(Degree+1)); - for(int i=0;i<=Degree && i<=Degree2;i++){coefficients[i]=P.coefficients[i];} -} - - -template -template -Polynomial& Polynomial::operator = (const Polynomial &p){ - int d=Degree -Polynomial Polynomial::derivative(void) const{ - Polynomial p; - for(int i=0;i -Polynomial Polynomial::integral(void) const{ - Polynomial p; - p.coefficients[0]=0; - for(int i=0;i<=Degree;i++){p.coefficients[i+1]=coefficients[i]/(i+1);} - return p; -} -template<> double Polynomial< 0 >::operator() ( double t ) const { return coefficients[0]; } -template<> double Polynomial< 1 >::operator() ( double t ) const { return coefficients[0]+coefficients[1]*t; } -template<> double Polynomial< 2 >::operator() ( double t ) const { return coefficients[0]+(coefficients[1]+coefficients[2]*t)*t; } -template -double Polynomial::operator() ( double t ) const{ - double v=coefficients[Degree]; - for( int d=Degree-1 ; d>=0 ; d-- ) v = v*t + coefficients[d]; - return v; -} -template -double Polynomial::integral( double tMin , double tMax ) const -{ - double v=0; - double t1,t2; - t1=tMin; - t2=tMax; - for(int i=0;i<=Degree;i++){ - v+=coefficients[i]*(t2-t1)/(i+1); - if(t1!=-DBL_MAX && t1!=DBL_MAX){t1*=tMin;} - if(t2!=-DBL_MAX && t2!=DBL_MAX){t2*=tMax;} - } - return v; -} -template -int Polynomial::operator == (const Polynomial& p) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]!=p.coefficients[i]){return 0;}} - return 1; -} -template -int Polynomial::operator != (const Polynomial& p) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]==p.coefficients[i]){return 0;}} - return 1; -} -template -int Polynomial::isZero(void) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]!=0){return 0;}} - return 1; -} -template -void Polynomial::setZero(void){memset(coefficients,0,sizeof(double)*(Degree+1));} - -template -Polynomial& Polynomial::addScaled(const Polynomial& p,double s){ - for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i]*s;} - return *this; -} -template -Polynomial& Polynomial::operator += (const Polynomial& p){ - for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i];} - return *this; -} -template -Polynomial& Polynomial::operator -= (const Polynomial& p){ - for(int i=0;i<=Degree;i++){coefficients[i]-=p.coefficients[i];} - return *this; -} -template -Polynomial Polynomial::operator + (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++){q.coefficients[i]=(coefficients[i]+p.coefficients[i]);} - return q; -} -template -Polynomial Polynomial::operator - (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++) {q.coefficients[i]=coefficients[i]-p.coefficients[i];} - return q; -} -template -void Polynomial::Scale(const Polynomial& p,double w,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p.coefficients[i]*w;} -} -template -void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i]*w2;} -} -template -void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i];} -} -template -void Polynomial::AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]+p2.coefficients[i]*w2;} -} - -template -void Polynomial::Subtract(const Polynomial &p1,const Polynomial& p2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]-p2.coefficients[i];} -} -template -void Polynomial::Negate(const Polynomial& in,Polynomial& out){ - out=in; - for(int i=0;i<=Degree;i++){out.coefficients[i]=-out.coefficients[i];} -} - -template -Polynomial Polynomial::operator - (void) const{ - Polynomial q=*this; - for(int i=0;i<=Degree;i++){q.coefficients[i]=-q.coefficients[i];} - return q; -} -template -template -Polynomial Polynomial::operator * (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++){for(int j=0;j<=Degree2;j++){q.coefficients[i+j]+=coefficients[i]*p.coefficients[j];}} - return q; -} - -template -Polynomial& Polynomial::operator += ( double s ) -{ - coefficients[0]+=s; - return *this; -} -template -Polynomial& Polynomial::operator -= ( double s ) -{ - coefficients[0]-=s; - return *this; -} -template -Polynomial& Polynomial::operator *= ( double s ) -{ - for(int i=0;i<=Degree;i++){coefficients[i]*=s;} - return *this; -} -template -Polynomial& Polynomial::operator /= ( double s ) -{ - for(int i=0;i<=Degree;i++){coefficients[i]/=s;} - return *this; -} -template -Polynomial Polynomial::operator + ( double s ) const -{ - Polynomial q=*this; - q.coefficients[0]+=s; - return q; -} -template -Polynomial Polynomial::operator - ( double s ) const -{ - Polynomial q=*this; - q.coefficients[0]-=s; - return q; -} -template -Polynomial Polynomial::operator * ( double s ) const -{ - Polynomial q; - for(int i=0;i<=Degree;i++){q.coefficients[i]=coefficients[i]*s;} - return q; -} -template -Polynomial Polynomial::operator / ( double s ) const -{ - Polynomial q; - for( int i=0 ; i<=Degree ; i++ ) q.coefficients[i] = coefficients[i]/s; - return q; -} -template -Polynomial Polynomial::scale( double s ) const -{ - Polynomial q=*this; - double s2=1.0; - for(int i=0;i<=Degree;i++){ - q.coefficients[i]*=s2; - s2/=s; - } - return q; -} -template -Polynomial Polynomial::shift( double t ) const -{ - Polynomial q; - for(int i=0;i<=Degree;i++){ - double temp=1; - for(int j=i;j>=0;j--){ - q.coefficients[j]+=coefficients[i]*temp; - temp*=-t*j; - temp/=(i-j+1); - } - } - return q; -} -template -void Polynomial::printnl(void) const{ - for(int j=0;j<=Degree;j++){ - printf("%6.4f x^%d ",coefficients[j],j); - if(j=0){printf("+");} - } - printf("\n"); -} -template -void Polynomial::getSolutions(double c,std::vector& roots,double EPS) const -{ - double r[4][2]; - int rCount=0; - roots.clear(); - switch(Degree){ - case 1: - rCount=Factor(coefficients[1],coefficients[0]-c,r,EPS); - break; - case 2: - rCount=Factor(coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; - case 3: - rCount=Factor(coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; -// case 4: -// rCount=Factor(coefficients[4],coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); -// break; - default: - printf("Can't solve polynomial of degree: %d\n",Degree); - } - for(int i=0;i -int Polynomial::getSolutions( double c , double* roots , double EPS ) const -{ - double _roots[4][2]; - int _rCount=0; - switch( Degree ) - { - case 1: _rCount = Factor( coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; - case 2: _rCount = Factor( coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; - case 3: _rCount = Factor( coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; -// case 4: _rCount = Factor( coefficients[4] , coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; - default: printf( "Can't solve polynomial of degree: %d\n" , Degree ); - } - int rCount = 0; - for( int i=0 ; i<_rCount ; i++ ) if( fabs(_roots[i][1])<=EPS ) roots[rCount++] = _roots[i][0]; - return rCount; -} -template< > -Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int i ) -{ - Polynomial p; - p.coefficients[0] = 1.; - return p; -} -template< int Degree > -Polynomial< Degree > Polynomial< Degree >::BSplineComponent( int i ) -{ - Polynomial p; - if( i>0 ) - { - Polynomial< Degree > _p = Polynomial< Degree-1 >::BSplineComponent( i-1 ).integral(); - p -= _p; - p.coefficients[0] += _p(1); - } - if( i _p = Polynomial< Degree-1 >::BSplineComponent( i ).integral(); - p += _p; - } - return p; -} \ No newline at end of file diff --git a/src/scanner/PoissonRecon/Src/SparseMatrix.h b/src/scanner/PoissonRecon/Src/SparseMatrix.h deleted file mode 100755 index 086558d..0000000 --- a/src/scanner/PoissonRecon/Src/SparseMatrix.h +++ /dev/null @@ -1,210 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __SPARSEMATRIX_HPP -#define __SPARSEMATRIX_HPP - -#define ZERO_TESTING_JACOBI 1 - - -#include "Vector.h" -#include "Array.h" - -template -struct MatrixEntry -{ - MatrixEntry( void ) { N =-1; Value = 0; } - MatrixEntry( int i ) { N = i; Value = 0; } - MatrixEntry( int i , T v ) { N = i; Value = v; } - int N; - T Value; -}; - -template class SparseMatrix -{ -private: - bool _contiguous; - int _maxEntriesPerRow; - void _init( void ); -public: - int rows; - Pointer( int ) rowSizes; - Pointer( Pointer( MatrixEntry< T > ) ) m_ppElements; - Pointer( MatrixEntry< T > ) operator[] ( int idx ) { return m_ppElements[idx]; } - ConstPointer( MatrixEntry< T > ) operator[] ( int idx ) const { return m_ppElements[idx]; } - - SparseMatrix( void ); - SparseMatrix( int rows ); - SparseMatrix( int rows , int maxEntriesPerRow ); - void Resize( int rows ); - void Resize( int rows , int maxEntriesPerRow ); - void SetRowSize( int row , int count ); - int Entries( void ) const; - - SparseMatrix( const SparseMatrix& M ); - ~SparseMatrix(); - - void SetZero(); - - SparseMatrix& operator = (const SparseMatrix& M); - - SparseMatrix operator * (const T& V) const; - SparseMatrix& operator *= (const T& V); - - - template - Vector operator * (const Vector& V) const; - template - Vector Multiply( const Vector& V ) const; - template - void Multiply( const Vector& In , Vector& Out , int threads=1 ) const; - - static int Solve (const SparseMatrix& M,const Vector& b, int iters,Vector& solution,const T eps=1e-8); - - template - static int SolveSymmetric( const SparseMatrix& M , const Vector& b , int iters , Vector& solution , const T2 eps=1e-8 , int reset=1 , int threads=1 ); - - bool write( FILE* fp ) const; - bool write( const char* fileName ) const; - bool read( FILE* fp ); - bool read( const char* fileName ); - - template< class T2 > - static int SolveJacobi( const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int threads=1 , int offset=0 ); - template< class T2 > - static int SolveGS( const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , bool forward , int offset=0 ); - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , bool forward , int threads=1 , int offset=0 ); - - template< class T2 > - static int SolveJacobi( const SparseMatrix& M , const Vector& b , Vector& x , Vector& Mx , T2 sor , int threads=1 , int offset=0 ); - template< class T2 > - static int SolveGS( const SparseMatrix& M , const Vector& b , Vector& x , bool forward , int offset=0 ); - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , const Vector& b , Vector& x , bool forward , int threads=1 , int offset=0 ); - - template< class T2 > - void getDiagonal( Vector< T2 >& diagonal , int threads=1 , int offset=0 ) const; -}; - - -template< class T2 > -struct MapReduceVector -{ -private: - int _dim; -public: - std::vector< T2* > out; - MapReduceVector( void ) { _dim = 0; } - ~MapReduceVector( void ) - { - if( _dim ) for( int t=0 ; t -class SparseSymmetricMatrix : public SparseMatrix< T > -{ -public: - - template< class T2 > - Vector< T2 > operator * ( const Vector& V ) const; - - template< class T2 > - Vector< T2 > Multiply( const Vector& V ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const; - - template< class T2 > - static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool addDCTerm=false , bool solveNormal=false ); - - template< class T2 > - static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false ); -#ifdef WIN32 - template< class T2 > - static int SolveCGAtomic( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool solveNormal=false ); -#endif // WIN32 - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , T2 sor , int reset ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 sor=T2(1.) , int reset=1 ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int reset ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 sor=T2(1.) , int reset=1 ); - - enum - { - ORDERING_UPPER_TRIANGULAR , - ORDERING_LOWER_TRIANGULAR , - ORDERING_NONE - }; - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset ); - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 ); - - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 , int ordering=ORDERING_NONE ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , bool forward , int reset=1 , int ordering=ORDERING_NONE ); - - template< class T2 > - void getDiagonal( Vector< T2 >& diagonal , int threads=1 ) const; -}; - -#include "SparseMatrix.inl" - -#endif - diff --git a/src/scanner/PoissonRecon/Src/SparseMatrix.inl b/src/scanner/PoissonRecon/Src/SparseMatrix.inl deleted file mode 100755 index f43e2f3..0000000 --- a/src/scanner/PoissonRecon/Src/SparseMatrix.inl +++ /dev/null @@ -1,1343 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include - - -/////////////////// -// SparseMatrix // -/////////////////// -/////////////////////////////////////// -// SparseMatrix Methods and Memebers // -/////////////////////////////////////// - -template< class T > -void SparseMatrix< T >::_init( void ) -{ - _contiguous = false; - _maxEntriesPerRow = 0; - rows = 0; - rowSizes = NullPointer< int >( ); - m_ppElements = NullPointer< Pointer( MatrixEntry< T > ) >( ); -} - -template< class T > SparseMatrix< T >::SparseMatrix( void ){ _init(); } - -template< class T > SparseMatrix< T >::SparseMatrix( int rows ){ _init() , Resize( rows ); } -template< class T > SparseMatrix< T >::SparseMatrix( int rows , int maxEntriesPerRow ){ _init() , Resize( rows , maxEntriesPerRow ); } - -template< class T > -SparseMatrix< T >::SparseMatrix( const SparseMatrix& M ) -{ - _init(); - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } -} -template -int SparseMatrix::Entries( void ) const -{ - int e = 0; - for( int i=0 ; i -SparseMatrix& SparseMatrix::operator = (const SparseMatrix& M) -{ - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } - return *this; -} - -template -SparseMatrix::~SparseMatrix( void ){ Resize( 0 ); } - -template< class T > -bool SparseMatrix< T >::write( const char* fileName ) const -{ - FILE* fp = fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool SparseMatrix< T >::read( const char* fileName ) -{ - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool SparseMatrix< T >::write( FILE* fp ) const -{ - if( fwrite( &rows , sizeof( int ) , 1 , fp )!=1 ) return false; - if( fwrite( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - return true; -} -template< class T > -bool SparseMatrix< T >::read( FILE* fp ) -{ - int r; - if( fread( &r , sizeof( int ) , 1 , fp )!=1 ) return false; - Resize( r ); - if( fread( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - } - return true; -} - - -template< class T > -void SparseMatrix< T >::Resize( int r ) -{ - if( rows>0 ) - { - if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } - else for( int i=0 ; i( r ); - m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); - memset( rowSizes , 0 , sizeof( int ) * r ); - } - _contiguous = false; - _maxEntriesPerRow = 0; -} -template< class T > -void SparseMatrix< T >::Resize( int r , int e ) -{ - if( rows>0 ) - { - if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } - else for( int i=0 ; i( r ); - m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); - m_ppElements[0] = AllocPointer< MatrixEntry< T > >( r * e ); - memset( rowSizes , 0 , sizeof( int ) * r ); - for( int i=1 ; i -void SparseMatrix< T >::SetRowSize( int row , int count ) -{ - if( _contiguous ) - { - if( count>_maxEntriesPerRow ) fprintf( stderr , "[ERROR] Cannot set row size on contiguous matrix: %d<=%d\n" , count , _maxEntriesPerRow ) , exit( 0 ); - rowSizes[row] = count; - } - else if( row>=0 && row0 ) m_ppElements[row] = AllocPointer< MatrixEntry< T > >( count ); - // [WARNING] Why wasn't this line here before??? - rowSizes[row] = count; - } -} - - -template -void SparseMatrix::SetZero() -{ - Resize(this->m_N, this->m_M); -} - -template -SparseMatrix SparseMatrix::operator * (const T& V) const -{ - SparseMatrix M(*this); - M *= V; - return M; -} - -template -SparseMatrix& SparseMatrix::operator *= (const T& V) -{ - for( int i=0 ; i -template -Vector SparseMatrix::Multiply( const Vector& V ) const -{ - Vector R( rows ); - Multiply( V , R ); - return R; -} - -template -template -void SparseMatrix::Multiply( const Vector& In , Vector& Out , int threads ) const -{ -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i ) start = m_ppElements[i]; - ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; - ConstPointer( MatrixEntry< T > ) e; - for( e=start ; e!=end ; e++ ) temp += In[ e->N ] * e->Value; - Out[i] = temp; -#else - for( int j=0 ; j -template -Vector SparseMatrix::operator * (const Vector& V) const -{ - return Multiply(V); -} - -template -template -int SparseMatrix::SolveSymmetric( const SparseMatrix& M , const Vector& b , int iters , Vector& solution , const T2 eps , int reset , int threads ) -{ - if( reset ) - { - solution.Resize( b.Dimensions() ); - solution.SetZero(); - } - Vector< T2 > r; - r.Resize( solution.Dimensions() ); - M.Multiply( solution , r ); - r = b - r; - Vector< T2 > d = r; - double delta_new , delta_0; - for( int i=0 ; i q; - q.Resize( d.Dimensions() ); - for( ii=0; iieps*delta_0 ; ii++ ) - { - M.Multiply( d , q , threads ); - double dDotQ = 0 , alpha = 0; - for( int i=0 ; i -int SparseMatrix::Solve(const SparseMatrix& M,const Vector& b,int iters,Vector& solution,const T eps){ - SparseMatrix mTranspose=M.Transpose(); - Vector bb=mTranspose*b; - Vector d,r,Md; - T alpha,beta,rDotR; - int i; - - solution.Resize(M.Columns()); - solution.SetZero(); - - d=r=bb; - rDotR=r.Dot(r); - for(i=0;ieps;i++){ - T temp; - Md=mTranspose*(M*d); - alpha=rDotR/d.Dot(Md); - solution+=d*alpha; - r-=Md*alpha; - temp=r.Dot(r); - beta=temp/rDotR; - rDotR=temp; - d=r+d*beta; - } - return i; -} - - - - -/////////////////////////// -// SparseSymmetricMatrix // -/////////////////////////// -template -template -Vector SparseSymmetricMatrix::operator * (const Vector& V) const {return Multiply(V);} -template -template -Vector SparseSymmetricMatrix::Multiply( const Vector& V ) const -{ - Vector R( SparseMatrix< T >::rows ); - - for(int i=0; i::rows; i++){ - for(int ii=0;ii::rowSizes[i];ii++) - { - int j=SparseMatrix< T >::m_ppElements[i][ii].N; - R(i) += SparseMatrix< T >::m_ppElements[i][ii].Value * V.m_pV[j]; - R(j) += SparseMatrix< T >::m_ppElements[i][ii].Value * V.m_pV[i]; - } - } - return R; -} - -template -template -void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , bool addDCTerm ) const -{ - Out.SetZero(); - const T2* in = &In[0]; - T2* out = &Out[0]; - T2 dcTerm = T2( 0 ); - if( addDCTerm ) - { - for( int i=0 ; i::rows ; i++ ) dcTerm += in[i]; - dcTerm /= SparseMatrix< T >::rows; - } - for( int i=0 ; i::rows ; i++ ) - { - const MatrixEntry* temp = SparseMatrix< T >::m_ppElements[i]; - const MatrixEntry* end = temp + SparseMatrix< T >::rowSizes[i]; - const T2& in_i_ = in[i]; - T2 out_i = T2(0); - for( ; temp!=end ; temp++ ) - { - int j=temp->N; - T2 v=temp->Value; - out_i += v * in[j]; - out[j] += v * in_i_; - } - out[i] += out_i; - } - if( addDCTerm ) for( int i=0 ; i::rows ; i++ ) out[i] += dcTerm; -} -template -template -void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm ) const -{ - int dim = int( In.Dimensions() ); - const T2* in = &In[0]; - int threads = OutScratch.threads(); - if( addDCTerm ) - { - T2 dcTerm = 0; -#pragma omp parallel for num_threads( threads ) reduction ( + : dcTerm ) - for( int t=0 ; t::rows*t)/threads ; i<(SparseMatrix< T >::rows*(t+1))/threads ; i++ ) - { - const T2& in_i_ = in[i]; - T2& out_i_ = out[i]; - ConstPointer( MatrixEntry< T > ) temp; - ConstPointer( MatrixEntry< T > ) end; - for( temp = SparseMatrix< T >::m_ppElements[i] , end = temp+SparseMatrix< T >::rowSizes[i] ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - dcTerm += in_i_; - } - } - dcTerm /= dim; - dim = int( Out.Dimensions() ); - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i::rows*t)/threads ; i<(SparseMatrix< T >::rows*(t+1))/threads ; i++ ) - { - T2 in_i_ = in[i]; - T2 out_i_ = T2(); - ConstPointer( MatrixEntry< T > ) temp; - ConstPointer( MatrixEntry< T > ) end; - for( temp = SparseMatrix< T >::m_ppElements[i] , end = temp+SparseMatrix< T >::rowSizes[i] ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - out[i] += out_i_; - } - } - dim = int( Out.Dimensions() ); - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i -template -void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const -{ - int dim = In.Dimensions(); - const T2* in = &In[0]; - int threads = OutScratch.size(); -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = SparseMatrix< T >::m_ppElements[i]; - const MatrixEntry* end = temp + SparseMatrix< T >::rowSizes[i]; - const T2& in_i_ = in[i]; - T2& out_i_ = out[i]; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - } - } - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i -inline void AtomicIncrement( volatile float* ptr , float addend ) -{ - float newValue = *ptr; - LONG& _newValue = *( (LONG*)&newValue ); - LONG _oldValue; - for( ;; ) - { - _oldValue = _newValue; - newValue += addend; - _newValue = InterlockedCompareExchange( (LONG*) ptr , _newValue , _oldValue ); - if( _newValue==_oldValue ) break; - } -} -inline void AtomicIncrement( volatile double* ptr , double addend ) -//inline void AtomicIncrement( double* ptr , double addend ) -{ - double newValue = *ptr; - LONGLONG& _newValue = *( (LONGLONG*)&newValue ); - LONGLONG _oldValue; - do - { - _oldValue = _newValue; - newValue += addend; - _newValue = InterlockedCompareExchange64( (LONGLONG*) ptr , _newValue , _oldValue ); - } - while( _newValue!=_oldValue ); -} -#endif // _AtomicIncrement_ -template< class T > -void MultiplyAtomic( const SparseSymmetricMatrix< T >& A , const Vector< float >& In , Vector< float >& Out , int threads , const int* partition=NULL ) -{ - Out.SetZero(); - const float* in = &In[0]; - float* out = &Out[0]; - if( partition ) -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const float& in_i = in[i]; - float out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - float v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - else -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const float& in_i = in[i]; - float out_i = 0.f; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - float v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } -} -template< class T > -void MultiplyAtomic( const SparseSymmetricMatrix< T >& A , const Vector< double >& In , Vector< double >& Out , int threads , const int* partition=NULL ) -{ - Out.SetZero(); - const double* in = &In[0]; - double* out = &Out[0]; - - if( partition ) -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const double& in_i = in[i]; - double out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - else -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const double& in_i = in[i]; - double out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } -} - -template< class T > -template< class T2 > -int SparseSymmetricMatrix< T >::SolveCGAtomic( const SparseSymmetricMatrix< T >& A , const Vector< T2 >& b , int iters , Vector< T2 >& x , T2 eps , int reset , int threads , bool solveNormal ) -{ - eps *= eps; - int dim = b.Dimensions(); - if( reset ) - { - x.Resize( dim ); - x.SetZero(); - } - Vector< T2 > r( dim ) , d( dim ) , q( dim ); - Vector< T2 > temp; - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - std::vector< int > partition( threads+1 ); - { - int eCount = 0; - for( int i=0 ; i=eCount*(t+1) ) - { - partition[t+1] = i; - break; - } - } - } - partition[threads] = A.rows; - } - if( solveNormal ) - { - MultiplyAtomic( A , x , temp , threads , &partition[0] ); - MultiplyAtomic( A , temp , r , threads , &partition[0] ); - MultiplyAtomic( A , b , temp , threads , &partition[0] ); -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) MultiplyAtomic( A , d , temp , threads , &partition[0] ) , MultiplyAtomic( A , temp , q , threads , &partition[0] ); - else MultiplyAtomic( A , d , q , threads , &partition[0] ); - double dDotQ = 0; - for( int i=0 ; i -template< class T2 > -int SparseSymmetricMatrix< T >::SolveCG( const SparseSymmetricMatrix& A , const Vector& b , int iters , Vector& x , MapReduceVector< T2 >& scratch , T2 eps , int reset , bool addDCTerm , bool solveNormal ) -{ - int threads = scratch.threads(); -#if 0 - int dim = b.Dimensions(); -#if 1 - Vector< T2 > r( dim ) , d( dim ) , Ad( dim ) , temp( dim ); - if( reset ) x.Resize( dim ); -#else - Vector< T2 > r ,d , Ad , temp; -#endif - - double delta_new = 0 , delta_0; - - //////////////////////// - // d = r = b - M * x - // \delta_new = ||r||^2 -#if 1 - A.Multiply( x , temp , scratch , addDCTerm ); - d = r = b - temp; -#else - d = r = b - Multiply< AddAverage >( A , x ); -#endif - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - //////////////////////////////////// - // \alpha = ||r||^2 / (d^t * M * d) -#if 1 - A.Multiply( d , Ad , scratch , addDCTerm ); -#else - Ad = Multiply< AddAverage >( A , d ); -#endif - double dDotMd = 0; - for( int i=0 ; i( A , x ); -#endif - for( int i=0 ; i r( dim ) , d( dim ) , q( dim ) , temp; - if( reset ) x.Resize( dim ); - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - double delta_new = 0 , delta_0; - if( solveNormal ) - { - A.Multiply( x , temp , scratch , addDCTerm ) , A.Multiply( temp , r , scratch , addDCTerm ) , A.Multiply( b , temp , scratch , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) A.Multiply( d , temp , scratch , addDCTerm ) , A.Multiply( temp , q , scratch , addDCTerm ); - else A.Multiply( d , q , scratch , addDCTerm ); - double dDotQ = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) - for( int i=0 ; i -template< class T2 > -int SparseSymmetricMatrix::SolveCG( const SparseSymmetricMatrix& A , const Vector& b , int iters , Vector& x , T2 eps , int reset , int threads , bool addDCTerm , bool solveNormal ) -{ - eps *= eps; - int dim = int( b.Dimensions() ); - MapReduceVector< T2 > outScratch; - if( threads<1 ) threads = 1; - if( threads>1 ) outScratch.resize( threads , dim ); - if( reset ) x.Resize( dim ); - Vector< T2 > r( dim ) , d( dim ) , q( dim ); - Vector< T2 > temp; - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - double delta_new = 0 , delta_0; - - if( solveNormal ) - { - if( threads>1 ) A.Multiply( x , temp , outScratch , addDCTerm ) , A.Multiply( temp , r , outScratch , addDCTerm ) , A.Multiply( b , temp , outScratch , addDCTerm ); - else A.Multiply( x , temp , addDCTerm ) , A.Multiply( temp , r , addDCTerm ) , A.Multiply( b , temp , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; i1 ) A.Multiply( x , r , outScratch , addDCTerm ); - else A.Multiply( x , r , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) - { - if( threads>1 ) A.Multiply( d , temp , outScratch , addDCTerm ) , A.Multiply( temp , q , outScratch , addDCTerm ); - else A.Multiply( d , temp , addDCTerm ) , A.Multiply( temp , q , addDCTerm ); - } - else - { - if( threads>1 ) A.Multiply( d , q , outScratch , addDCTerm ); - else A.Multiply( d , q , addDCTerm ); - } - double dDotQ = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) - for( int i=0 ; i1 ) A.Multiply( x , temp , outScratch , addDCTerm ) , A.Multiply( temp , r , outScratch , addDCTerm ); - else A.Multiply( x , temp , addDCTerm ) , A.Multiply( temp , r , addDCTerm ); - } - else - { - if( threads>1 ) A.Multiply( x , r , outScratch , addDCTerm ); - else A.Multiply( x , r , addDCTerm ); - } -#pragma omp parallel for num_threads( threads ) reduction ( + : delta_new ) - for( int i=0 ; i -template< class T2 > -int SparseMatrix::SolveJacobi( const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int threads , int offset ) -{ - M.Multiply( x , Mx , threads ); -#if ZERO_TESTING_JACOBI - for( int j=0 ; j -template< class T2 > -int SparseMatrix::SolveJacobi( const SparseMatrix& M , const Vector& b , Vector& x , Vector& Mx , T2 sor , int threads , int offset ) -{ - M.Multiply( x , Mx , threads ); -#if ZERO_TESTING_JACOBI - for( int j=0 ; j -template< class T2 > -int SparseSymmetricMatrix::SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int reset ) -{ - if( reset ) x.Resize( b.Dimensions() ) , x.SetZero(); - M.Multiply( x , Mx ); - // solution_new[j] * diagonal[j] + ( Md[j] - solution_old[j] * diagonal[j] ) = b[j] - // solution_new[j] = ( b[j] - ( Md[j] - solution_old[j] * diagonal[j] ) ) / diagonal[j] - // solution_new[j] = ( b[j] - Md[j] ) / diagonal[j] + solution_old[j] - // for( int j=0 ; j -template< class T2 > -int SparseSymmetricMatrix::SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , T2 sor , int reset ) -{ - if( reset ) x.Resize( b.Dimensions() ) , x.SetZero(); - M.Multiply( x , Mx , scratch ); - // solution_new[j] * diagonal[j] + ( Md[j] - solution_old[j] * diagonal[j] ) = b[j] - // solution_new[j] = ( b[j] - ( Md[j] - solution_old[j] * diagonal[j] ) ) / diagonal[j] - // solution_new[j] = ( b[j] - Md[j] ) / diagonal[j] + solution_old[j] - // for( int j=0 ; j -template< class T2 > -int SparseSymmetricMatrix::SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 sor , int reset ) -{ - Vector< T2 > diagonal , Mx; - M.getDiagonal( diagonal ); - Mx.Resize( M.rows ); - for( int i=0 ; i -template< class T2 > -int SparseSymmetricMatrix::SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 sor , int reset ) -{ - Vector< T2 > diagonal , Mx; - M.getDiagonal( diagonal , scratch.threads() ); - Mx.Resize( M.rows ); - for( int i=0 ; i -template -int SparseMatrix::SolveGS( const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , bool forward , int offset ) -{ -#define ITERATE \ - { \ - ConstPointer( MatrixEntry< T > ) start = M[j]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[j+offset]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[j+offset] += _b / diagonal[j]; \ - } - -#if ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } -#else // !ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ ITERATE; } -#endif // ZERO_TESTING_JACOBI -#undef ITERATE - return M.rows; -} -template -template -int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , bool forward , int threads , int offset ) -{ - int sum=0; -#ifdef _WIN32 -#define SetOMPParallel __pragma( omp parallel for num_threads( threads ) ) -#else // !_WIN32 -#define SetOMPParallel _Pragma( "omp parallel for num_threads( threads )" ) -#endif // _WIN32 -#if ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[jj+offset]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[jj+offset] += _b / diagonal[jj]; \ - } \ - } -#else // !ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[jj+offset]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[jj+offset] += _b / diagonal[jj]; \ - } \ - } -#endif // ZERO_TESTING_JACOBI - - if( forward ) for( int j=0 ; j=0 ; j-- ){ sum += int( mcIndices[j].size() ) ; ITERATE( mcIndices[j] ); } -#undef ITERATE -#undef SetOMPParallel - return sum; -} -template -template -int SparseMatrix::SolveGS( const SparseMatrix& M , const Vector& b , Vector& x , bool forward , int offset ) -{ - int start = forward ? 0 : M.rows-1 , end = forward ? M.rows : -1 , dir = forward ? 1 : -1; - for( int j=start ; j!=end ; j+=dir ) - { - T diagonal = M[j][0].Value; -#if ZERO_TESTING_JACOBI - if( diagonal ) -#endif // ZERO_TESTING_JACOBI - { - ConstPointer( MatrixEntry< T > ) start = M[j]; - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; - ConstPointer( MatrixEntry< T > ) e; - start++; - T2 _b = b[j+offset]; - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; - x[j+offset] = _b / diagonal; - } - } - return M.rows; -} -template -template -int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , const Vector& b , Vector& x , bool forward , int threads , int offset ) -{ - int sum=0 , start = forward ? 0 : int( mcIndices.size() )-1 , end = forward ? int( mcIndices.size() ) : -1 , dir = forward ? 1 : -1; - for( int j=start ; j!=end ; j+=dir ) - { - const std::vector< int >& _mcIndices = mcIndices[j]; - sum += int( _mcIndices.size() ); - { -#pragma omp parallel for num_threads( threads ) - for( int k=0 ; k ) start = M[jj]; - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; - ConstPointer( MatrixEntry< T > ) e; - start++; - T2 _b = b[jj+offset]; - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; - x[jj+offset] = _b / diagonal; - } - } - } - } - return sum; -} - - -template -template -int SparseSymmetricMatrix::SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ) -{ - if( reset ) x.Resize( b.Dimensions() ) , x.SetZero(); - dx.SetZero(); - M.Multiply( x , Mx ); -#define ITERATE \ - { \ - ConstPointer( MatrixEntry< T > ) start = M[j]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _Mx = Mx[j]; \ - if( ordering!=ORDERING_UPPER_TRIANGULAR ) \ - for( e=start ; e!=end ; e++ ) _Mx += dx[ e->N ] * e->Value; \ - dx[j] = ( b[j]-_Mx ) / diagonal[j]; \ - x[j] += dx[j]; \ - if( ordering!=ORDERING_LOWER_TRIANGULAR ) \ - for( e=start ; e!=end ; e++ ) Mx[ e->N ] += dx[j] * e->Value; \ - } - -#if ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } -#else // !ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ ITERATE; } -#endif // ZERO_TESTING_JACOBI -#undef ITERATE - return M.rows; -} -template -template -int SparseSymmetricMatrix::SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ) -{ - if( reset ) x.Resize( b.Dimensions() ) , x.SetZero(); - dx.SetZero(); - M.Multiply( x , Mx , scratch ); -#define ITERATE \ - { \ - ConstPointer( MatrixEntry< T > ) start = M[j]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _Mx = Mx[j]; \ - if( ordering!=ORDERING_UPPER_TRIANGULAR ) \ - for( e=start ; e!=end ; e++ ) _Mx += dx[ e->N ] * e->Value; \ - dx[j] = ( b[j]-_Mx ) / diagonal[j]; \ - x[j] += dx[j]; \ - if( ordering!=ORDERING_LOWER_TRIANGULAR ) \ - for( e=start ; e!=end ; e++ ) Mx[ e->N ] += dx[j] * e->Value; \ - } - -#if ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } -#else // !ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ ITERATE; } -#endif // ZERO_TESTING_JACOBI -#undef ITERATE - return M.rows; -} -template -template -int SparseSymmetricMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset ) -{ - int sum = 0; - if( reset ) x.Resize( b.Dimensions() ) , x.SetZero(); - M.Multiply( x , Mx , scratch ); - dx.SetZero(); -#ifdef _WIN32 -#define SetOMPParallel __pragma( omp parallel for num_threads( scratch.threads() ) ) -#else // !_WIN32 -#define SetOMPParallel _Pragma( "omp parallel for num_threads( scratch.threads() )" ) -#endif // _WIN32 -#if ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _Mx = Mx[jj]; \ - for( e=start ; e!=end ; e++ ) _Mx += dx[ e->N ] * e->Value; \ - Mx[jj] = _Mx; \ - dx[jj] = ( b[jj]-_Mx ) / diagonal[jj]; \ - x[jj] += dx[jj]; \ - for( e=start ; e!=end ; e++ ) Mx[ e->N ] += dx[jj] * e->Value; \ - } \ - } -#else // !ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _Mx = Mx[jj]; \ - for( e=start ; e!=end ; e++ ) _Mx += dx[ e->N ] * e->Value; \ - Mx[jj] = _Mx; \ - dx[jj] = ( b[jj]-_Mx ) / diagonal[jj]; \ - x[jj] += dx[jj]; \ - for( e=start ; e!=end ; e++ ) Mx[ e->N ] += dx[jj] * e->Value; \ - } \ - } -#endif // ZERO_TESTING_JACOBI - - if( forward ) for( int j=0 ; j=0 ; j-- ){ sum += int(mcIndices[j].size()) ; ITERATE( mcIndices[j] ); } -#undef ITERATE -#undef SetOMPParallel - return sum; -} -template -template -int SparseSymmetricMatrix::SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , bool forward , int reset , int ordering ) -{ - Vector< T2 > diagonal , Mx , dx; - M.getDiagonal( diagonal ); - Mx.Resize( M.rows ) , dx.Resize( M.rows ); - for( int i=0 ; i -template -int SparseSymmetricMatrix::SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , MapReduceVector& scratch , bool forward , int reset , int ordering ) -{ - Vector< T2 > diagonal , Mx , dx; - M.getDiagonal( diagonal , scratch.threads() ); - Mx.Resize( M.rows ) , dx.Resize( M.rows ); - for( int i=0 ; i -template -int SparseSymmetricMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , MapReduceVector& scratch , bool forward , int reset ) -{ - Vector< T2 > diagonal , Mx , dx; - M.getDiagonal( diagonal , scratch.threads() ); - Mx.Resize( M.rows ) , dx.Resize( M.rows ); - for( int i=0 ; i -template< class T2 > -void SparseMatrix< T >::getDiagonal( Vector< T2 >& diagonal , int threads , int offset ) const -{ - diagonal.Resize( SparseMatrix< T >::rows ); -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i ) start = m_ppElements[i]; - ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; - ConstPointer( MatrixEntry< T > ) e; - for( e=start ; e!=end ; e++ ) if( e->N==ii ) d += e->Value; - diagonal[i] = d; - } -} -template< class T > -template< class T2 > -void SparseSymmetricMatrix< T >::getDiagonal( Vector< T2 >& diagonal , int threads ) const -{ - diagonal.Resize( SparseMatrix< T >::rows ); -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i::rows ; i++ ) - { - T2 d = 0.; - ConstPointer( MatrixEntry< T > ) start = SparseMatrix< T >::m_ppElements[i]; - ConstPointer( MatrixEntry< T > ) end = start + SparseMatrix< T >::rowSizes[i]; - ConstPointer( MatrixEntry< T > ) e; - for( e=start ; e!=end ; e++ ) if( e->N==i ) d += e->Value; - diagonal[i] = d * T2(2); - } -} \ No newline at end of file diff --git a/src/scanner/PoissonRecon/Src/SurfaceTrimmer.cpp b/src/scanner/PoissonRecon/Src/SurfaceTrimmer.cpp deleted file mode 100755 index 19dfc69..0000000 --- a/src/scanner/PoissonRecon/Src/SurfaceTrimmer.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* -Copyright (c) 2013, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#include -#ifdef _OPENMP -#include -#endif // _OPENMP -#include -#include "CmdLineParser.h" -#include "Geometry.h" -#include "Ply.h" -#include "MAT.h" -#include "MyTime.h" - -#define FOR_RELEASE 1 - -cmdLineString In( "in" ) , Out( "out" ); -cmdLineInt Smooth( "smooth" , 5 ); -cmdLineFloat Trim( "trim" ) , IslandAreaRatio( "aRatio" , 0.001f ); -cmdLineFloatArray< 2 > ColorRange( "color" ); -cmdLineReadable PolygonMesh( "polygonMesh" ); - -cmdLineReadable* params[] = -{ - &In , &Out , &Trim , &PolygonMesh , &ColorRange , &Smooth , &IslandAreaRatio -}; - -void ShowUsage( char* ex ) -{ - printf( "Usage: %s\n" , ex ); - printf( "\t --%s \n" , In.name ); - printf( "\t[--%s ]\n" , Out.name ); - printf( "\t[--%s =%d]\n" , Smooth.name , Smooth.value ); - printf( "\t[--%s ]\n" , Trim.name ); - printf( "\t[--%s =%f]\n" , IslandAreaRatio.name , IslandAreaRatio.value ); - printf( "\t[--%s]\n" , PolygonMesh.name ); -#if !FOR_RELEASE - printf( "\t[--%s ]\n" , ColorRange.name ); -#endif // !FOR_RELEASE -} - -long long EdgeKey( int key1 , int key2 ) -{ - if( key1 -PlyValueVertex< Real > InterpolateVertices( const PlyValueVertex< Real >& v1 , const PlyValueVertex< Real >& v2 , const float& value ) -{ - if( v1.value==v2.value ) return (v1+v2)/Real(2.); - PlyValueVertex< Real > v; - - Real dx = (v1.value-value)/(v1.value-v2.value); - for( int i=0 ; i<3 ; i++ ) v.point.coords[i]=v1.point.coords[i]*(1.f-dx)+v2.point.coords[i]*dx; - v.value=v1.value*(1.f-dx)+v2.value*dx; - return v; -} - -template< class Real > -void ColorVertices( const std::vector< PlyValueVertex< Real > >& inVertices , std::vector< PlyColorVertex< Real > >& outVertices , float min , float max ) -{ - outVertices.resize( inVertices.size() ); - for( size_t i=0 ; i( 0.f , std::min< float >( 1.f , temp ) ); - temp *= 255; - outVertices[i].color[0] = outVertices[i].color[1] = outVertices[i].color[2] = (int)temp; - } -} -template< class Real > -void SmoothValues( std::vector< PlyValueVertex< Real > >& vertices , const std::vector< std::vector< int > >& polygons ) -{ - std::vector< int > count( vertices.size() ); - std::vector< Real > sums( vertices.size() , 0 ); - for( size_t i=0 ; i -void SmoothValues( std::vector< PlyValueVertex< Real > >& vertices , const std::vector< std::vector< int > >& polygons , Real min , Real max ) -{ - std::vector< int > count( vertices.size() ); - std::vector< Real > sums( vertices.size() , 0 ); - for( int i=0 ; imin && vertices[v1].valuemin && vertices[v2].value -void SplitPolygon - ( - const std::vector< int >& polygon , - std::vector< PlyValueVertex< Real > >& vertices , - std::vector< std::vector< int > >* ltPolygons , std::vector< std::vector< int > >* gtPolygons , - std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , - hash_map< long long , int >& vertexTable , - Real trimValue - ) -{ - int sz = int( polygon.size() ); - std::vector< bool > gt( sz ); - int gtCount = 0; - for( int j=0 ; jtrimValue ); - if( gt[j] ) gtCount++; - } - if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } - else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } - else - { - int start; - for( start=0 ; start poly; - - // Add the initial vertex - { - int j1 = (start+int(sz)-1)%sz , j2 = start; - int v1 = polygon[j1] , v2 = polygon[j2]; - int vIdx; - hash_map< long long , int >::iterator iter = vertexTable.find( EdgeKey( v1 , v2 ) ); - if( iter==vertexTable.end() ) - { - vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); - vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); - } - else vIdx = iter->second; - poly.push_back( vIdx ); - } - - for( int _j=0 ; _j<=sz ; _j++ ) - { - int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; - int v1 = polygon[j1] , v2 = polygon[j2]; - if( gt[j2]==gtFlag ) poly.push_back( v2 ); - else - { - int vIdx; - hash_map< long long , int >::iterator iter = vertexTable.find( EdgeKey( v1 , v2 ) ); - if( iter==vertexTable.end() ) - { - vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); - vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); - } - else vIdx = iter->second; - poly.push_back( vIdx ); - if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } - else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } - poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); - gtFlag = !gtFlag; - } - } - } -} -template< class Real > -void Triangulate( const std::vector< PlyValueVertex< Real > >& vertices , const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& triangles ) -{ - triangles.clear(); - for( size_t i=0 ; i3 ) - { - MinimalAreaTriangulation< Real > mat; - std::vector< Point3D< Real > > _vertices( polygons[i].size() ); - std::vector< TriangleIndex > _triangles; - for( int j=0 ; j -void RemoveHangingVertices( std::vector< Vertex >& vertices , std::vector< std::vector< int > >& polygons ) -{ - hash_map< int , int > vMap; - std::vector< bool > vertexFlags( vertices.size() , false ); - for( size_t i=0 ; i _vertices( vCount ); - for( int i=0 ; i >& polygons , std::vector< std::vector< int > >& components ) -{ - std::vector< int > polygonRoots( polygons.size() ); - for( size_t i=0 ; i edgeTable; - for( size_t i=0 ; i::iterator iter = edgeTable.find( eKey ); - if( iter==edgeTable.end() ) edgeTable[ eKey ] = int(i); - else - { - int p = iter->second; - while( polygonRoots[p]!=p ) - { - int temp = polygonRoots[p]; - polygonRoots[p] = int(i); - p = temp; - } - polygonRoots[p] = int(i); - } - } - } - for( size_t i=0 ; i vMap; - for( int i= 0 ; i -inline Point3D< Real > CrossProduct( Point3D< Real > p1 , Point3D< Real > p2 ){ return Point3D< Real >( p1[1]*p2[2]-p1[2]*p2[1] , p1[2]*p2[0]-p1[0]*p2[2] , p1[0]*p1[1]-p1[1]*p2[0] ); } -template< class Real > -double TriangleArea( Point3D< Real > v1 , Point3D< Real > v2 , Point3D< Real > v3 ) -{ - Point3D< Real > n = CrossProduct( v2-v1 , v3-v1 ); - return sqrt( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] ) / 2.; -} -template< class Real > -double PolygonArea( const std::vector< PlyValueVertex< Real > >& vertices , const std::vector< int >& polygon ) -{ - if( polygon.size()<3 ) return 0.; - else if( polygon.size()==3 ) return TriangleArea( vertices[polygon[0]].point , vertices[polygon[1]].point , vertices[polygon[2]].point ); - else - { - Point3D< Real > center; - for( size_t i=0 ; i > vertices; - std::vector< std::vector< int > > polygons; - - int ft , commentNum = paramNum+2; - char** comments; - bool readFlags[ PlyValueVertex< float >::Components ]; - PlyReadPolygons( In.value , vertices , polygons , PlyValueVertex< float >::Properties , PlyValueVertex< float >::Components , ft , &comments , &commentNum , readFlags ); - if( !readFlags[3] ){ fprintf( stderr , "[ERROR] vertices do not have value flag\n" ) ; return EXIT_FAILURE; } -#if 0 - if( Trim.set ) for( int i=0 ; i( min , vertices[i].value ) , max = std::max< float >( max , vertices[i].value ); - printf( "Value Range: [%f,%f]\n" , min , max ); - - - if( Trim.set ) - { - hash_map< long long , int > vertexTable; - std::vector< std::vector< int > > ltPolygons , gtPolygons; - std::vector< bool > ltFlags , gtFlags; - - for( int i=0 ; i0 ) - { - std::vector< std::vector< int > > _ltPolygons , _gtPolygons; - std::vector< std::vector< int > > ltComponents , gtComponents; - SetConnectedComponents( ltPolygons , ltComponents ); - SetConnectedComponents( gtPolygons , gtComponents ); - std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. ); - std::vector< bool > ltComponentFlags( ltComponents.size() , false ) , gtComponentFlags( gtComponents.size() , false ); - double area = 0.; - for( size_t i=0 ; i > polys = ltPolygons; - Triangulate( vertices , ltPolygons , polys ) , ltPolygons = polys; - } - { - std::vector< std::vector< int > > polys = gtPolygons; - Triangulate( vertices , gtPolygons , polys ) , gtPolygons = polys; - } - } - - RemoveHangingVertices( vertices , gtPolygons ); - sprintf( comments[commentNum++] , "#Trimmed In: %9.1f (s)" , Time()-t ); - if( Out.set ) PlyWritePolygons( Out.value , vertices , gtPolygons , PlyValueVertex< float >::Properties , PlyValueVertex< float >::Components , ft , comments , commentNum ); - } - else - { - if( ColorRange.set ) min = ColorRange.values[0] , max = ColorRange.values[1]; - std::vector< PlyColorVertex< float > > outVertices; - ColorVertices( vertices , outVertices , min , max ); - if( Out.set ) PlyWritePolygons( Out.value , outVertices , polygons , PlyColorVertex< float >::Properties , PlyColorVertex< float >::Components , ft , comments , commentNum ); - } - - return EXIT_SUCCESS; -} - diff --git a/src/scanner/PoissonRecon/Src/Time.cpp b/src/scanner/PoissonRecon/Src/Time.cpp deleted file mode 100755 index 08f2aec..0000000 --- a/src/scanner/PoissonRecon/Src/Time.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#ifndef WIN32 -#include -#endif // WIN32 - -double Time( void ) -{ -#ifdef WIN32 - struct _timeb t; - _ftime( &t ); - return double( t.time ) + double( t.millitm ) / 1000.0; -#else // WIN32 - struct timeval t; - gettimeofday( &t , NULL ); - return t.tv_sec + double( t.tv_usec ) / 1000000; -#endif // WIN32 -} diff --git a/src/scanner/PoissonRecon/Src/Time.h b/src/scanner/PoissonRecon/Src/Time.h deleted file mode 100755 index 1858e47..0000000 --- a/src/scanner/PoissonRecon/Src/Time.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef TIME_INCLUDED -#define TIME_INCLUDED -double Time(void); -#endif // TIME_INCLUDED diff --git a/src/scanner/PoissonRecon/Src/Vector.h b/src/scanner/PoissonRecon/Src/Vector.h deleted file mode 100755 index 69899d6..0000000 --- a/src/scanner/PoissonRecon/Src/Vector.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __VECTOR_HPP -#define __VECTOR_HPP - - -#define Assert assert -#include -#include "Array.h" - -template< class T > -class Vector -{ -public: - Vector( void ); - Vector( const Vector& V ); - Vector( size_t N ); - Vector( size_t N, ConstPointer( T ) pV ); - ~Vector( void ); - - const T& operator () (size_t i) const; - T& operator () (size_t i); - const T& operator [] (size_t i) const; - T& operator [] (size_t i); - - void SetZero(); - - size_t Dimensions() const; - void Resize( size_t N ); - - Vector operator * (const T& A) const; - Vector operator / (const T& A) const; - Vector operator - (const T& A) const; - Vector operator + (const T& A) const; - Vector operator - (const Vector& V) const; - Vector operator + (const Vector& V) const; - - Vector& operator *= ( const T& A ); - Vector& operator /= ( const T& A ); - Vector& operator += ( const T& A ); - Vector& operator -= ( const T& A ); - Vector& operator += ( const Vector& V ); - Vector& operator -= ( const Vector& V ); - - Vector& Add( const Vector* V , int count ); - Vector& AddScaled( const Vector& V , const T& scale ); - Vector& SubtractScaled( const Vector& V , const T& scale ); - static void Add( const Vector& V1 , const T& scale1 , const Vector& V2 , const T& scale2 , Vector& Out ); - static void Add( const Vector& V1 , const T& scale1 , const Vector& V2 , Vector& Out ); - - Vector operator - () const; - - Vector& operator = (const Vector& V); - - T Dot( const Vector& V ) const; - - T Length() const; - - T Average() const; - - T Norm( size_t Ln ) const; - void Normalize(); - - bool write( FILE* fp ) const; - bool write( const char* fileName ) const; - bool read( FILE* fp ); - bool read( const char* fileName ); - - Pointer( T ) m_pV; -protected: - size_t m_N; - -}; - -#if ARRAY_DEBUG -template< class C > Array< C > GetPointer( Vector< C >& v ){ return Array< C >::FromPointer( &v[0] , v.Dimensions() ); } -template< class C > ConstArray< C > GetPointer( const Vector< C >& v ){ return ConstArray< C >::FromPointer( &v[0] , v.Dimensions() ); } -#else // !ARRAY_DEBUG -template< class C > C* GetPointer( Vector< C >& v ){ return &v[0]; } -template< class C > const C* GetPointer( const Vector< C >& v ){ return &v[0]; } -#endif // ARRAY_DEBUG - -#include "Vector.inl" - -#endif diff --git a/src/scanner/PoissonRecon/Src/Vector.inl b/src/scanner/PoissonRecon/Src/Vector.inl deleted file mode 100755 index 27f9d10..0000000 --- a/src/scanner/PoissonRecon/Src/Vector.inl +++ /dev/null @@ -1,304 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __VECTORIMPL_HPP -#define __VECTORIMPL_HPP - -#include - -//////////// -// Vector // -//////////// -template -Vector::Vector( void ) -{ - m_N = 0; - m_pV = NullPointer< T >(); -} -template< class T > -Vector< T >::Vector( const Vector& V ) -{ - m_N = 0; - m_pV = NullPointer< T >(); - Resize( V.m_N ); - memcpy( m_pV , V.m_pV , m_N*sizeof(T) ); -} -template -Vector::Vector( size_t N ) -{ - m_N=0; - m_pV = NullPointer< T >(); - Resize(N); -} -template -void Vector::Resize( size_t N ) -{ - if( m_N!=N ) - { - if( m_N ) DeletePointer( m_pV ); - m_N = N; - m_pV = NewPointer< T >( N ); - } - if( N ) memset( m_pV , 0 , N*sizeof(T) ); -} - -template -Vector::Vector( size_t N, ConstPointer( T ) pV ) -{ - Resize(N); - memcpy( m_pV, pV, N*sizeof(T) ); -} -template -Vector::~Vector(){Resize(0);} -template -Vector& Vector::operator = (const Vector& V) -{ - Resize(V.m_N); - memcpy( m_pV, V.m_pV, m_N*sizeof(T) ); - return *this; -} -template -size_t Vector::Dimensions() const{return m_N;} -template -void Vector::SetZero(void){for (size_t i=0; i -const T& Vector::operator () (size_t i) const -{ - return m_pV[i]; -} -template -T& Vector::operator () (size_t i) -{ - return m_pV[i]; -} -template -const T& Vector::operator [] (size_t i) const -{ - return m_pV[i]; -} -template -T& Vector::operator [] (size_t i) -{ - return m_pV[i]; -} -template -Vector Vector::operator * (const T& A) const -{ - Vector V(*this); - for (size_t i=0; i -Vector& Vector::operator *= (const T& A) -{ - for (size_t i=0; i -Vector Vector::operator / (const T& A) const -{ - Vector V(*this); - for (size_t i=0; i -Vector& Vector::operator /= (const T& A) -{ - for (size_t i=0; i -Vector Vector::operator + (const T& A) const -{ - Vector V(*this); - for (size_t i=0; i -Vector& Vector::operator += (const T& A) -{ - for (size_t i=0; i -Vector Vector::operator - (const T& A) const -{ - Vector V(*this); - for (size_t i=0; i -Vector& Vector::operator -= (const T& A) -{ - for (size_t i=0; i -Vector Vector::operator + (const Vector& V0) const -{ - Vector V(m_N); - for (size_t i=0; i -Vector& Vector::operator += (const Vector& V) -{ - for ( size_t i=0 ; i -Vector Vector::operator - (const Vector& V0) const -{ - Vector V(m_N); - for (size_t i=0; i -Vector& Vector::operator -= (const Vector& V) -{ - for (size_t i=0; i -Vector Vector::operator - (void) const -{ - Vector V(m_N); - for (size_t i=0; i -Vector< T >& Vector< T >::Add( const Vector< T >* V , int count ) -{ - for( int c=0 ; c -Vector< T >& Vector< T >::AddScaled( const Vector& V , const T& scale ) -{ - for (size_t i=0; i -Vector& Vector::SubtractScaled(const Vector& V,const T& scale) -{ - for (size_t i=0; i -void Vector::Add( const Vector& V1 , const T& scale1 , const Vector& V2 , const T& scale2 , Vector& Out ) -{ - for( size_t i=0 ; i -void Vector::Add(const Vector& V1,const T& scale1,const Vector& V2,Vector& Out) -{ - for( size_t i=0 ; i -T Vector::Norm( size_t Ln ) const -{ - T N = T(); - for (size_t i = 0; i -void Vector::Normalize() -{ - T N = 1.0f/Norm(2); - for (size_t i = 0; i -T Vector< T >::Average( void ) const -{ - T N = T(); - for( size_t i=0 ; i -T Vector::Length() const -{ - T N = T(); - for (size_t i = 0; i -T Vector::Dot( const Vector& V ) const -{ - T V0 = T(); - for( size_t i=0 ; i -bool Vector< T >::read( const char* fileName ) -{ - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool Vector< T >::write( const char* fileName ) const -{ - FILE* fp = fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool Vector< T >::read( FILE* fp ) -{ - int d; - if( fread( &d , sizeof(int) , 1 , fp )!=1 ) return false; - Resize( d ); - if( fread( &(*this)[0] , sizeof( T ) , d , fp )!=d ) return false; - return true; -} -template< class T > -bool Vector< T >::write( FILE* fp ) const -{ - if( fwrite( &m_N , sizeof( int ) , 1 , fp )!=1 ) return false; - if( fwrite( &(*this)[0] , sizeof( T ) , m_N , fp )!=m_N ) return false; - return true; -} - - - -#endif From 093a534835d774b358b17a0d5bafaa08346c73e3 Mon Sep 17 00:00:00 2001 From: Yen Date: Thu, 24 Dec 2015 16:21:01 +0800 Subject: [PATCH 02/53] update readme for newly added package --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index acd2fa9..1dc5c4e 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,9 @@ fluxclient contains all toolsets to control FLUX 3D Printer * Pillow `pip install Pillow` + +* Numpy +`pip install numpy` + +* Scipy +`pip install scipy` From e1f769d2e6901e1bc2e9987d61458d396b4260f7 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Thu, 24 Dec 2015 16:42:49 +0800 Subject: [PATCH 03/53] Support get/det/del settings in robot --- fluxclient/robot/v0002.py | 19 +++++++++++++++++++ fluxclient/robot_console.py | 26 ++++++++++++++++++-------- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index f464a04..6d70c45 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -450,6 +450,25 @@ def quit_raw_mode(self): sync += 1 return self.get_resp() + @ok_or_error + def config_set(self, key, value): + return self._make_cmd(b"config set " + key.encode() + b" " +\ + value.encode()) + + def config_get(self, key): + ret = self._make_cmd(b"config get " + key.encode()).decode("utf8", + "ignore") + if ret.startswith("ok VAL "): + return ret[7:] + elif ret.startswith("ok EMPTY"): + return None + else: + raise_error(ret) + + @ok_or_error + def config_del(self, key): + return self._make_cmd(b"config del " + key.encode()) + @ok_or_error def set_setting(self, key, value): cmd = "set %s %s" % (key, value) diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index d16df72..a43ebf1 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -50,7 +50,11 @@ def __init__(self, robot_obj): "oneshot": self.oneshot, "scanimages": self.scanimages, "raw": self.raw_mode, - "set": self.set_setting, + "config": { + "set": self.config_set, + "get": self.config_get, + "del": self.config_del + }, "eadj": self.maintain_eadj, "cor_h": self.maintain_hadj, @@ -228,14 +232,20 @@ def scanimages(self, filename=None): os.system("open " + " ".join([n.name for n in tempfiles])) - def set_setting(self, line): - params = line.split(" ") - if len(params) == 2: - logger.info( - self.robot_obj.set_setting(key=params[0], value=params[1]) - ) + def config_set(self, key, value): + self.robot_obj.config_set(key, value) + logger.info("ok") + + def config_get(self, key): + value = self.robot_obj.config_get(key) + if value: + logger.info("%s=%s\nok" % (key, value)) else: - logger.info("BAD_PARAMS") + logger.info("%s not set\nok" % key) + + def config_del(self, key): + self.robot_obj.config_del(key) + logger.info("ok") def maintain_eadj(self, ext=None): def callback(nav): From b4b4b146a6c376e32960a05ad940e518afcd0581 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Thu, 24 Dec 2015 17:44:48 +0800 Subject: [PATCH 04/53] Robot: Change protocol command to fit fluxmonitor 0.13b1 --- fluxclient/robot/v0002.py | 118 +++++++++++++++++++----------------- fluxclient/robot_console.py | 14 ++--- 2 files changed, 65 insertions(+), 67 deletions(-) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 6d70c45..1849f66 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -125,8 +125,9 @@ def position(self): else: return ret + # file commands def list_files(self, entry, path=""): - self._send_cmd(b"ls " + entry.encode() + b" " + path.encode()) + self._send_cmd(b"file ls " + entry.encode() + b" " + path.encode()) resp = self.get_resp().decode("ascii", "ignore") if resp == "continue": files = self.get_resp().decode("utf8", "ignore") @@ -145,14 +146,9 @@ def list_files(self, entry, path=""): else: raise_error(resp) - @ok_or_error - def select_file(self, entry, path): - self._send_cmd(b"select " + entry.encode() + b" " + path.encode()) - return self.get_resp() - def fileinfo(self, entry, path): info = [None, None] - self._send_cmd(b"fileinfo " + entry.encode() + b" " + path.encode()) + self._send_cmd(b"file info " + entry.encode() + b" " + path.encode()) resp = self.get_resp().decode("utf8", "ignore") if resp.startswith("binary "): @@ -171,29 +167,75 @@ def fileinfo(self, entry, path): @ok_or_error def mkdir(self, entry, path): return self._make_cmd( - b"mkdir " + entry.encode() + b" " + path.encode()) + b"file mkdir " + entry.encode() + b" " + path.encode()) @ok_or_error def rmdir(self, entry, path): return self._make_cmd( - b"rmdir " + entry.encode() + b" " + path.encode()) + b"file rmdir " + entry.encode() + b" " + path.encode()) @ok_or_error def cpfile(self, source_entry, source, target_entry, target): return self._make_cmd( - b"cp " + source_entry.encode() + b" " + source.encode() + b" " + b"file cp " + source_entry.encode() + b" " + source.encode() + b" " + target_entry.encode() + b" " + target.encode()) @ok_or_error def rmfile(self, entry, path): return self._make_cmd(b"rm " + entry.encode() + b" " + path.encode()) + def md5(self, filename): + bresp = self._make_cmd(b"file md5 " + filename.encode()) + resp = bresp.decode("ascii", "ignore") + if resp.startswith("md5 "): + return resp[4:] + else: + raise_error(resp) + + def upload_file(self, filename, upload_to="#", cmd="file upload", + progress_callback=None): + mimetype, _ = mimetypes.guess_type(filename) + if not mimetype: + mimetype = "binary" + with open(filename, "rb") as f: + logger.debug("File opened") + size = os.fstat(f.fileno()).st_size + return self.upload_stream(f, size, mimetype, upload_to, cmd, + progress_callback) + + # player commands + @ok_or_error + def select_file(self, entry, path): + self._send_cmd(b"player select " + entry.encode() + b" " +\ + path.encode()) + return self.get_resp() + @ok_or_error def start_play(self): - return self._make_cmd(b"start") + return self._make_cmd(b"player start") + + @ok_or_error + def pause_play(self): + return self._make_cmd(b"player pause") + + @ok_or_error + def abort_play(self): + return self._make_cmd(b"player abort") + + @ok_or_error + def resume_play(self): + return self._make_cmd(b"player resume") + + def report_play(self): + # TODO + msg = self._make_cmd(b"player report").decode("utf8", "ignore") + if msg.startswith("{"): + return json.loads(msg, "ignore") + else: + raise_error(msg) def play_info(self): - self._send_cmd(b"play_info") + self._send_cmd(b"player info") metadata = imgbuf = None resp = self.get_resp().decode("ascii", "ignore") @@ -213,12 +255,13 @@ def play_info(self): else: raise RuntimeError(resp) - def upload_stream(self, stream, length, mimetype, upload_to, cmd="upload", - progress_callback=None): - # cmd = [cmd] [mimetype] [length] [upload_to] - cmd = ("%s %s %i %s" % (cmd, mimetype, length, upload_to)).encode() + def upload_stream(self, stream, length, mimetype, upload_to, + cmd="file upload", progress_callback=None): + entry, path = upload_to.split("/", 1) + # cmd = [cmd] [mimetype] [length] [entry] [path] + cmd = "%s %s %i %s %s" % (cmd, mimetype, length, entry, path) - upload_ret = self._make_cmd(cmd).decode("ascii", "ignore") + upload_ret = self._make_cmd(cmd.encode()).decode("ascii", "ignore") if upload_ret == "continue": logger.info(upload_ret) if upload_ret != "continue": @@ -247,17 +290,7 @@ def upload_stream(self, stream, length, mimetype, upload_to, cmd="upload", if final_ret != b"ok": raise_error(final_ret.decode("ascii", "ignore")) - def upload_file(self, filename, upload_to="#", cmd="upload", - progress_callback=None): - mimetype, _ = mimetypes.guess_type(filename) - if not mimetype: - mimetype = "binary" - with open(filename, "rb") as f: - logger.debug("File opened") - size = os.fstat(f.fileno()).st_size - return self.upload_stream(f, size, mimetype, upload_to, cmd, - progress_callback) - + # Others def begin_upload(self, mimetype, length, cmd="upload", uploadto="#"): cmd = ("%s %s %i %s" % (cmd, mimetype, length, uploadto)).encode() upload_ret = self._make_cmd(cmd).decode("ascii", "ignore") @@ -266,14 +299,6 @@ def begin_upload(self, mimetype, length, cmd="upload", uploadto="#"): else: raise RuntimeError(upload_ret) - def md5(self, filename): - bresp = self._make_cmd(b"md5 " + filename.encode()) - resp = bresp.decode("ascii", "ignore") - if resp.startswith("md5 "): - return resp[4:] - else: - raise_error(resp) - @ok_or_error def begin_scan(self): return self._make_cmd(b"scan") @@ -286,27 +311,6 @@ def quit_task(self): def kick(self): return self._make_cmd(b"kick") - # Play Tasks - @ok_or_error - def pause_play(self): - return self._make_cmd(b"pause") - - @ok_or_error - def abort_play(self): - return self._make_cmd(b"abort") - - @ok_or_error - def resume_play(self): - return self._make_cmd(b"resume") - - def report_play(self): - # TODO - msg = self._make_cmd(b"report").decode("utf8", "ignore") - if msg.startswith("{"): - return json.loads(msg, "ignore") - else: - raise_error(msg) - @ok_or_error def scan_laser(self, left, right): bcmd = b"scanlaser " diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index a43ebf1..832c005 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -38,15 +38,16 @@ def __init__(self, robot_obj): self.cmd_mapping = { "ls": self.list_file, - "select": self.select_file, "fileinfo": self.fileinfo, "mkdir": self.mkdir, "rmdir": self.rmdir, "rmfile": self.rmfile, "cp": self.cpfile, "upload": self.upload_file, - "update_fw": self.update_fw, "md5": self.md5, + + "select": self.select_file, + "update_fw": self.update_fw, "oneshot": self.oneshot, "scanimages": self.scanimages, "raw": self.raw_mode, @@ -173,14 +174,7 @@ def cpfile(self, args): except ValueError: raise RuntimeError("BAD_PARAMS") - def upload_file(self, args): - options = shlex.split(args) - source = options[0] - if len(options) >= 2: - upload_to = " ".join(options[1].split("/", 1)) - else: - upload_to = "#" - + def upload_file(self, source, upload_to="#"): self.robot_obj.upload_file( source, upload_to, progress_callback=self.log_progress_callback) From 32633b72a3c4663854808338bc4d2b60130389dc Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Fri, 25 Dec 2015 11:43:50 +0800 Subject: [PATCH 05/53] Robot: add firmware update API --- fluxclient/robot/v0002.py | 20 +++++++++++++++++--- fluxclient/utils/mimetypes.py | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 1849f66..6640082 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -255,11 +255,25 @@ def play_info(self): else: raise RuntimeError(resp) + def update_fw(self, filename, progress_callback=None): + mimetype, _ = mimetypes.guess_type(filename) + if not mimetype: + mimetype = "binary" + with open(filename, "rb") as f: + logger.debug("File opened") + size = os.fstat(f.fileno()).st_size + self.upload_stream(f, size, mimetype, upload_to, cmd, + progress_callback) + def upload_stream(self, stream, length, mimetype, upload_to, cmd="file upload", progress_callback=None): - entry, path = upload_to.split("/", 1) - # cmd = [cmd] [mimetype] [length] [entry] [path] - cmd = "%s %s %i %s %s" % (cmd, mimetype, length, entry, path) + if upload_to == "#": + # cmd = [cmd] [mimetype] [length] # + cmd = "%s %s %i #" % (cmd, mimetype, length) + else: + entry, path = upload_to.split("/", 1) + # cmd = [cmd] [mimetype] [length] [entry] [path] + cmd = "%s %s %i %s %s" % (cmd, mimetype, length, entry, path) upload_ret = self._make_cmd(cmd.encode()).decode("ascii", "ignore") if upload_ret == "continue": diff --git a/fluxclient/utils/mimetypes.py b/fluxclient/utils/mimetypes.py index db67356..b02580a 100644 --- a/fluxclient/utils/mimetypes.py +++ b/fluxclient/utils/mimetypes.py @@ -5,6 +5,7 @@ add_type("text/gcode", ".gcode") add_type("application/fcode", ".fc") +add_type("binary/flux-firmware", ".fxfw") def validate_ext(filename, match_mimetype): From f2a4292ba768b74dcfcdd905f810b5c58ea01d64 Mon Sep 17 00:00:00 2001 From: Yen Date: Fri, 25 Dec 2015 17:19:23 +0800 Subject: [PATCH 06/53] #978 first draft --- fluxclient/fcode/g_to_f.py | 5 +- fluxclient/printer/stl_slicer.py | 191 ++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 7 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 8815176..7faa98b 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -298,9 +298,10 @@ def process(self, input_stream, output_stream): output_stream.write(struct.pack(' 0 and self.empty_layer[0] == 0: self.empty_layer.pop(0) + + # warning: fileformat didn't consider multi-extruder, use first extruder instead self.md['FILAMENT_USED'] = ','.join(map(str, self.filament)) self.md['TRAVEL_DIST'] = str(self.distance) diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index ce6131d..cc11802 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -7,6 +7,7 @@ import os import sys import copy +from multiprocessing import Process, Pipe from PIL import Image @@ -16,6 +17,76 @@ from fluxclient.printer import ini_string, ini_constraint +def slicing_worker(command, config, image, ext_metadata, output_type, child_pipe): + tmp_gcode_file = command[3] + fail_flag = False + subp = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) + progress = 0.2 + slic3r_error = False + while subp.poll() is None: + line = subp.stdout.readline() + print(line, file=sys.stderr, end='') + sys.stderr.flush() + if line: + if line.startswith('=> ') and not line.startswith('=> Exporting'): + progress += 0.12 + child_pipe.send('{"status": "computing", "message": "%s", "percentage": %.2f}' % ((line.rstrip())[3:], progress)) + elif "Unable to close this loop" in line: + slic3r_error = True + slic3r_out = line + if subp.poll() != 0: + fail_flag = True + # analying gcode(even transform) + child_pipe.send('{"status": "computing", "message": "analyzing metadata", "percentage": 0.99}') + + fcode_output = io.BytesIO() + with open(tmp_gcode_file, 'r') as f: + m_GcodeToFcode = GcodeToFcode(ext_metadata=ext_metadata) + m_GcodeToFcode.config = config + m_GcodeToFcode.image = image + m_GcodeToFcode.process(f, fcode_output) + path = m_GcodeToFcode.path + metadata = m_GcodeToFcode.md + metadata = [float(metadata['TIME_COST']), float(metadata['FILAMENT_USED'].split(',')[0])] + if slic3r_error or len(m_GcodeToFcode.empty_layer) > 0: + child_pipe.send('{"status": "warning", "message" : "%s"}' % ("{} empty layers, might be error when slicing {}".format(len(m_GcodeToFcode.empty_layer), repr(m_GcodeToFcode.empty_layer)))) + + del m_GcodeToFcode + + if output_type == '-g': + with open(tmp_gcode_file, 'rb') as f: + output = f.read() + elif output_type == '-f': + output = fcode_output.getvalue() + else: + raise('wrong output type, only support gcode and fcode') + + ##################### fake code ########################### + with open('output.gcode', 'wb') as f: + with open(tmp_gcode_file, 'rb') as f2: + f.write(f2.read()) + tmp_stl_file = command[1] + with open(tmp_stl_file, 'rb') as f: + with open('merged.stl', 'wb') as f2: + f2.write(f.read()) + + with open('output.fc', 'wb') as f: + f.write(fcode_output.getvalue()) + + StlSlicer.my_ini_writer("output.ini", config) + ########################################################### + + # # clean up tmp files + fcode_output.close() + # os.remove(tmp_stl_file) + # os.remove(tmp_gcode_file) + # os.remove(tmp_slic3r_setting_file) + if fail_flag: + child_pipe.send([False, slic3r_out, []]) + else: + child_pipe.send([output, metadata, path]) + + class StlSlicer(object): """slicing objects""" def __init__(self, slic3r): @@ -23,8 +94,7 @@ def __init__(self, slic3r): self.reset(slic3r) def __del__(self): - if self.working_p: - self.working_p.terminate() + self.end_slicing() def reset(self, slic3r): self.models = {} # models data @@ -42,7 +112,7 @@ def reset(self, slic3r): self.path = None self.image = b'' self.ext_metadata = {'CORRECTION': 'A'} - self.working_p = None + self.working_p = [] def upload(self, name, buf): """ @@ -225,7 +295,6 @@ def gcode_generate(self, names, ws, output_type): p = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) progress = 0.2 - self.working_p = p slic3r_error = False while p.poll() is None: line = p.stdout.readline() @@ -241,7 +310,6 @@ def gcode_generate(self, names, ws, output_type): if p.poll() != 0: fail_flag = True - self.working_p = None # analying gcode(even transform) ws.send_progress('analyzing metadata', 0.99) @@ -293,6 +361,119 @@ def gcode_generate(self, names, ws, output_type): else: return output, metadata + def begin_slicing(self, names, ws, output_type): + """ + input: names of stl that need to be sliced + output: + if success: + gcode (binary in bytes), metadata([TIME_COST, FILAMENT_USED]) + else: + False, [error message] + """ + # TODO: maybe put theese code in multiprocess someday? + # check if names are all seted + for n in names: + if not (n in self.models and n in self.parameter): + return False, '%s not set yet' % (n) + # tmp files + tmp = tempfile.NamedTemporaryFile(suffix='.stl', delete=False) + tmp_stl_file = tmp.name # store merged stl + + tmp = tempfile.NamedTemporaryFile(suffix='.gcode', delete=False) + tmp_gcode_file = tmp.name # store gcode + + tmp = tempfile.NamedTemporaryFile(suffix='.ini', delete=False) + tmp_slic3r_setting_file = tmp.name # store gcode + + ws.send_progress('merging', 0.2) + m_mesh_merge = _printer.MeshObj([], []) + for n in names: + points, faces = self.read_stl(self.models[n]) + m_mesh = _printer.MeshObj(points, faces) + m_mesh.apply_transform(self.parameter[n]) + m_mesh_merge.add_on(m_mesh) + + bounding_box = m_mesh_merge.bounding_box() + cx, cy = (bounding_box[0][0] + bounding_box[1][0]) / 2., (bounding_box[0][1] + bounding_box[1][1]) / 2. + m_mesh_merge.write_stl(tmp_stl_file) + + for key in self.user_setting: + if self.user_setting[key] != "default": + if key == 'print_speed': + pass # TODO + elif key == 'material': + pass # TODO + elif key == 'raft': + if self.user_setting[key] == '0': + self.config['raft_layers'] = '0' + elif self.user_setting[key] == '1': + self.config['raft_layers'] = '4' # TODO? + elif key == 'support': + self.config['support_material'] = self.user_setting[key] + elif key == 'layer_height': + self.config['first_layer_height'] = self.user_setting[key] + self.config['layer_height'] = self.user_setting[key] + elif key == 'infill': + fill_density = float(self.user_setting[key]) * 100 + fill_density = max(min(fill_density, 99), 0) + self.config['fill_density'] = str(fill_density) + '%' + elif key == 'traveling_speed': + self.config['travel_speed'] = self.user_setting[key] + elif key == 'extruding_speed': + self.config['perimeter_speed'] = self.user_setting[key] + self.config['infill_speed'] = self.user_setting[key] + elif key == 'temperature': + self.config['temperature'] = self.user_setting[key] + self.config['first_layer_temperature'] = self.user_setting[key] + 5 + + self.my_ini_writer(tmp_slic3r_setting_file, self.config) + + command = [self.slic3r, tmp_stl_file] + command += ['--output', tmp_gcode_file] + command += ['--print-center', '%f,%f' % (cx, cy)] + command += ['--load', tmp_slic3r_setting_file] + # command += ['--load', '/Users/yen/Documents/config.ini'] + + print('command:', ' '.join(command), file=sys.stderr) + self.end_slicing() + parent_pipe, child_pipe = Pipe() + p = Process(target=slicing_worker, args=(command[:], dict(self.config), self.image, dict(self.ext_metadata), output_type, child_pipe)) + self.working_p.append((p, [tmp_stl_file, tmp_gcode_file, tmp_slic3r_setting_file], parent_pipe)) + p.start() + + def end_slicing(self): + for p in self.working_p: + if p[0].is_alive(): + p[0].terminate() + for filename in p[1]: + try: + os.remove(filename) + except: + pass + self.working_p = [] + + def report_slicing(self): + ret = [] + if self.working_p: + while self.working_p[-1][2].poll(): + message = self.working_p[-1][2].recv() + if type(message) == str: + ret.append(message) + else: + if message[0]: + self.output = message[0] + self.metadata = message[1] + self.path = message[2] + m = '{"status": "complete", "length": %d, "time": %.3f, "filament_length": %.2f}' % (len(self.output), self.metadata[0], self.metadata[1]) + + else: + self.output = None + self.metadata = None + self.path = None + m = '{"status": "error", "error": "{}"}' % message[1] + ret.append(m) + return ret + @classmethod def my_ini_parser(cls, data): """ From fd5f1acd17a21fe3b72293b9586889a88def9d6e Mon Sep 17 00:00:00 2001 From: Yen Date: Fri, 25 Dec 2015 17:59:54 +0800 Subject: [PATCH 07/53] #1004 --- fluxclient/printer/stl_slicer.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index cc11802..8defa17 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -353,9 +353,11 @@ def gcode_generate(self, names, ws, output_type): # clean up tmp files fcode_output.close() - os.remove(tmp_stl_file) - os.remove(tmp_gcode_file) - os.remove(tmp_slic3r_setting_file) + for f in [tmp_stl_file, tmp_gcode_file, tmp_slic3r_setting_file]: + try: + os.remove(f) + except: + pass if fail_flag: return False, slic3r_out else: From 9c06f484ff2f9b438c1bbaad9de1f20438219d43 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Fri, 25 Dec 2015 18:27:50 +0800 Subject: [PATCH 08/53] Update to work with fluxmonitor 1.0b --- fluxclient/__init__.py | 2 +- fluxclient/robot_console.py | 6 ++++++ fluxclient/upnp/base.py | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fluxclient/__init__.py b/fluxclient/__init__.py index 5c06ffe..99d86f6 100644 --- a/fluxclient/__init__.py +++ b/fluxclient/__init__.py @@ -7,5 +7,5 @@ def check_pcl(): return False -__version__ = "0.7a5" +__version__ = "0.8b1" SUPPORT_PCL = check_pcl() diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index 832c005..66428c8 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -48,6 +48,7 @@ def __init__(self, robot_obj): "select": self.select_file, "update_fw": self.update_fw, + "update_mbfw": self.update_mbfw, "oneshot": self.oneshot, "scanimages": self.scanimages, "raw": self.raw_mode, @@ -183,6 +184,11 @@ def update_fw(self, filename): filename.rstrip(), cmd="update_fw", progress_callback=self.log_progress_callback) + def update_mbfw(self, filename): + self.robot_obj.upload_file( + filename.rstrip(), cmd="update_mbfw", + progress_callback=self.log_progress_callback) + def md5(self, filename): md5 = self.robot_obj.md5(" ".join(filename.split("/", 1))) logger.info("MD5 %s %s", filename, md5) diff --git a/fluxclient/upnp/base.py b/fluxclient/upnp/base.py index f97d98d..cc58c1a 100644 --- a/fluxclient/upnp/base.py +++ b/fluxclient/upnp/base.py @@ -26,9 +26,9 @@ def __init__(self, uuid, remote_profile=None, lookup_callback=None, else: self.reload_remote_profile(lookup_callback, lookup_timeout) - if self.remote_version < StrictVersion("0.12a1"): + if self.remote_version < StrictVersion("1.0a0"): raise RuntimeError("fluxmonitor version is too old") - elif self.remote_version >= StrictVersion("0.14a1"): + elif self.remote_version >= StrictVersion("2.0a0"): raise RuntimeError("fluxmonitor version is too new") self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, From a4d40ca653fa6ee531ebe269f5cdd8cae0b7a228 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Sat, 26 Dec 2015 14:12:13 +0800 Subject: [PATCH 09/53] Control: bugfix --- fluxclient/robot/v0002.py | 4 ++++ fluxclient/robot_console.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 6640082..59721d1 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -255,6 +255,10 @@ def play_info(self): else: raise RuntimeError(resp) + @ok_or_error + def play_quit(self): + return self._make_cmd(b"player quit") + def update_fw(self, filename, progress_callback=None): mimetype, _ = mimetypes.guess_type(filename) if not mimetype: diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index 66428c8..3f2c25a 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -34,6 +34,9 @@ def __init__(self, robot_obj): "home": robot_obj.maintain_home, "reset_mb": robot_obj.maintain_reset_mb, + "play": { + "quit": robot_obj.play_quit + } } self.cmd_mapping = { From 86038dbac40b6fd862a3a7e6e64c0cd1dba13160 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Sat, 26 Dec 2015 14:14:54 +0800 Subject: [PATCH 10/53] Contol: fix naming --- fluxclient/robot/v0002.py | 2 +- fluxclient/robot_console.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 59721d1..3f1d050 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -256,7 +256,7 @@ def play_info(self): raise RuntimeError(resp) @ok_or_error - def play_quit(self): + def quit_play(self): return self._make_cmd(b"player quit") def update_fw(self, filename, progress_callback=None): diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index 3f2c25a..3ee96ea 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -35,7 +35,7 @@ def __init__(self, robot_obj): "home": robot_obj.maintain_home, "reset_mb": robot_obj.maintain_reset_mb, "play": { - "quit": robot_obj.play_quit + "quit": robot_obj.quit_play } } From 8b1657bb1abc9015170b244c71140589f6d245bc Mon Sep 17 00:00:00 2001 From: Yen Date: Sat, 26 Dec 2015 17:25:05 +0800 Subject: [PATCH 11/53] change default value, add ignored parameter in setting --- fluxclient/printer/__init__.py | 30 +++++++++++++++++------------- fluxclient/printer/stl_slicer.py | 3 ++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index 966f318..982931e 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -13,6 +13,10 @@ def free(key, value): return 'ok' +def ignore(key, value): + return 'ignore' + + def percentage(key, value, start=0, end=100): tmp_value = value.rstrip('%') return int_range(key, tmp_value, start, end) @@ -72,7 +76,7 @@ def hex_color(key, value): bridge_acceleration = 0 bridge_fan_speed = 100 bridge_flow_ratio = 1 -bridge_speed = 40 +bridge_speed = 20 brim_width = 0 complete_objects = 0 cooling = 1 @@ -124,13 +128,13 @@ def hex_color(key, value): max_print_speed = 50 max_volumetric_speed = 0 min_fan_speed = 80 -min_print_speed = 10 +min_print_speed = 3 min_skirt_length = 0 notes = nozzle_diameter = 0.4 octoprint_apikey = octoprint_host = -only_retract_when_crossing_perimeters = 0 +only_retract_when_crossing_perimeters = 1 ooze_prevention = 0 output_filename_format = [input_filename_base].gcode overhangs = 0 @@ -147,7 +151,7 @@ def hex_color(key, value): retract_layer_change = 0 retract_length = 5.5 retract_length_toolchange = 10 -retract_lift = 0.3 +retract_lift = 0.1 retract_restart_extra = 0 retract_restart_extra_toolchange = 0 retract_speed = 60 @@ -179,13 +183,13 @@ def hex_color(key, value): support_material_spacing = 2 support_material_speed = 40 support_material_threshold = 55 -temperature = 220 +temperature = 210 thin_walls = 0 threads = 2 toolchange_gcode = top_infill_extrusion_width = 0.4 top_solid_infill_speed = 15 -top_solid_layers = 3 +top_solid_layers = 4 travel_speed = 80 use_firmware_retraction = 0 use_relative_e_distances = 0 @@ -226,20 +230,20 @@ def hex_color(key, value): 'extrusion_width': False, 'fan_always_on': [binary], 'fan_below_layer_time': [int_range, 0], - 'filament_colour': [hex_color], + 'filament_colour': [ignore], 'filament_diameter': False, 'fill_angle': False, 'fill_density': [percentage], 'fill_pattern': [finite_choice, ['rectilinear-grid', 'line', 'rectilinear', 'honeycomb']], 'first_layer_acceleration': [binary], - 'first_layer_bed_temperature': [constant], + 'first_layer_bed_temperature': [ignore], 'first_layer_extrusion_width': [percentage, 0, 1666], 'first_layer_height': [float_range, 0.02, 0.4], 'first_layer_speed': [int_range, 1, 150], 'first_layer_temperature': [int_range, 10, 230], 'gap_fill_speed': [int_range, 1, 150], 'gcode_arcs': False, - 'gcode_comments': [constant], + 'gcode_comments': [ignore], 'gcode_flavor': [free], 'infill_acceleration': [binary], 'infill_every_layers': [int_range, 0], @@ -260,8 +264,8 @@ def hex_color(key, value): 'min_skirt_length': False, 'notes': False, 'nozzle_diameter': [float_range], - 'octoprint_apikey': [constant], - 'octoprint_host': [constant], + 'octoprint_apikey': [ignore], + 'octoprint_host': [ignore], 'only_retract_when_crossing_perimeters': [binary], 'ooze_prevention': [binary], 'output_filename_format': [free], @@ -286,7 +290,7 @@ def hex_color(key, value): 'seam_position': False, 'skirt_distance': [float_range, 0], 'skirt_height': [int_range, 0], - 'skirts': [binary], + 'skirts': [int_range, 0, 4], 'slowdown_below_layer_time': [int_range, 0], 'small_perimeter_speed': False, 'solid_infill_below_area': False, @@ -299,7 +303,7 @@ def hex_color(key, value): 'start_gcode': False, 'support_material': [binary], 'support_material_angle': False, - 'support_material_contact_distance': [float_range, 0.05, 20], + 'support_material_contact_distance': [float_range, 0.0, 10], 'support_material_enforce_layers': False, 'support_material_extruder': False, 'support_material_extrusion_width': False, diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 8defa17..16168c3 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -193,7 +193,8 @@ def advanced_setting(self, lines): self.config[key] = value if key == 'temperature': self.config['first_layer_temperature'] = str(min(230, float(value) + 5)) - + elif result == 'ignore': + pass else: bad_lines.append((counter, result)) elif line != '' and line != 'default': From f567159655717e2299d0460ae073860f2a01d7de Mon Sep 17 00:00:00 2001 From: Yen Date: Sun, 27 Dec 2015 14:24:22 +0800 Subject: [PATCH 12/53] more parameter setting --- fluxclient/printer/__init__.py | 4 ++-- fluxclient/printer/stl_slicer.py | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index 982931e..d75d200 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -269,7 +269,7 @@ def hex_color(key, value): 'only_retract_when_crossing_perimeters': [binary], 'ooze_prevention': [binary], 'output_filename_format': [free], - 'overhangs': False, + 'overhangs': [binary], 'perimeter_acceleration': False, 'perimeter_extruder': False, 'perimeter_extrusion_width': False, @@ -298,7 +298,7 @@ def hex_color(key, value): 'solid_infill_extruder': False, 'solid_infill_extrusion_width': False, 'solid_infill_speed': [int_range, 1, 150], - 'spiral_vase': [binary], # TODO: 1 perimeter, no top solid layers, 0% fill density, no support + 'spiral_vase': [binary], 'standby_temperature_delta': [int_range, -400, 400], 'start_gcode': False, 'support_material': [binary], diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 16168c3..c98cbcf 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -14,7 +14,7 @@ from fluxclient.printer import _printer from fluxclient.fcode.g_to_f import GcodeToFcode from fluxclient.scanner.tools import dot, normal -from fluxclient.printer import ini_string, ini_constraint +from fluxclient.printer import ini_string, ini_constraint, ignore def slicing_worker(command, config, image, ext_metadata, output_type, child_pipe): @@ -193,6 +193,18 @@ def advanced_setting(self, lines): self.config[key] = value if key == 'temperature': self.config['first_layer_temperature'] = str(min(230, float(value) + 5)) + if key == 'overhangs' and value == '0': + self.config['support_material'] = '0' + ini_constraint['support_material'] = [ignore] + if key == 'spiral_vase' and value == '1': + self.config['support_material'] = '0' + ini_constraint['support_material'] = [ignore] + self.config['fill_density'] = '0%' + ini_constraint['fill_density'] = [ignore] + self.config['perimeters'] = '1' + ini_constraint['perimeters'] = [ignore] + self.config['top_solid_layers'] = '0' + ini_constraint['top_solid_layers'] = [ignore] elif result == 'ignore': pass else: From cdefc226edb628286ae2cd52b55da67eacd108e1 Mon Sep 17 00:00:00 2001 From: Yen Date: Sun, 27 Dec 2015 14:34:24 +0800 Subject: [PATCH 13/53] fix overhang degree range check --- fluxclient/printer/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index d75d200..b52555c 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -314,7 +314,7 @@ def hex_color(key, value): 'support_material_pattern': [finite_choice, ['rectilinear-grid', 'line', 'rectilinear', 'honeycomb']], 'support_material_spacing': False, 'support_material_speed': [int_range, 1, 150], - 'support_material_threshold': False, + 'support_material_threshold': [int_range, 0, 90], 'temperature': [int_range, 10, 230], 'thin_walls': [binary], 'threads': False, From 743c20725264896d324b39973bfce7d87556bf6f Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Mon, 28 Dec 2015 00:35:13 +0800 Subject: [PATCH 14/53] Robot: Add load/unload filament at maintain task --- fluxclient/__init__.py | 2 +- fluxclient/robot/v0002.py | 62 ++++++++++++++++++++++++++++++++----- fluxclient/robot_console.py | 25 ++++++++++++++- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/fluxclient/__init__.py b/fluxclient/__init__.py index 99d86f6..148ce1d 100644 --- a/fluxclient/__init__.py +++ b/fluxclient/__init__.py @@ -7,5 +7,5 @@ def check_pcl(): return False -__version__ = "0.8b1" +__version__ = "0.8b2" SUPPORT_PCL = check_pcl() diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 3f1d050..8028b3a 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -405,19 +405,26 @@ def scan_backward(self): def begin_maintain(self): return self._make_cmd(b"maintain") - @ok_or_error def maintain_home(self): - return self._make_cmd(b"home") + self._send_cmd(b"home") + while True: + ret = self.get_resp(6.0).decode("ascii", "ignore") + if ret.startswith("DEBUG:"): + logger.info(ret) + elif ret == "ok": + return + else: + raise_error(ret) @ok_or_error def maintain_reset_mb(self): return self._make_cmd(b"reset_mb") - def maintain_eadj(self, navigate_callback, clean=False): + def maintain_calibration(self, navigate_callback, clean=False): if clean: - ret = self._make_cmd(b"eadj clean") + ret = self._make_cmd(b"calibration clean") else: - ret = self._make_cmd(b"eadj") + ret = self._make_cmd(b"calibration") if ret == b"continue": nav = "continue" @@ -432,11 +439,13 @@ def maintain_eadj(self, navigate_callback, clean=False): else: raise_error(ret.decode("ascii", "ignore")) - def maintain_hadj(self, navigate_callback, manual_h=None): + maintain_eadj = maintain_calibration + + def maintain_zprobe(self, navigate_callback, manual_h=None): if manual_h: - ret = self._make_cmd(("cor_h %.4f" % manual_h).encode()) + ret = self._make_cmd(("zprobe %.4f" % manual_h).encode()) else: - ret = self._make_cmd(b"cor_h") + ret = self._make_cmd(b"zprobe") if ret == b"continue": nav = "continue" @@ -451,6 +460,43 @@ def maintain_hadj(self, navigate_callback, manual_h=None): else: raise_error(ret.decode("ascii", "ignore")) + maintain_hadj = maintain_zprobe + + def maintain_headinfo(self): + ret = self._make_cmd(b"headinfo").decode("ascii", "ignore") + if ret.startswith("ok "): + return json.loads(ret[3:]) + else: + raise_error(ret) + + def maintain_load_filament(self, index, temp, navigate_callback): + ret = self._make_cmd( + ("load_filament %i %.1f" % (index, temp)).encode()) + + if ret == b"continue": + while True: + ret = self.get_resp().decode("ascii", "ignore") + if ret.startswith("CTRL "): + navigate_callback(ret[5:]) + elif ret == "ok": + return + else: + raise_error(ret) + + def maintain_unload_filament(self, index, temp, navigate_callback): + ret = self._make_cmd( + ("unload_filament %i %.1f" % (index, temp)).encode()) + + if ret == b"continue": + while True: + ret = self.get_resp().decode("ascii", "ignore") + if ret.startswith("CTRL "): + navigate_callback(ret[5:]) + elif ret == "ok": + return + else: + raise_error(ret) + def raw_mode(self): ret = self._make_cmd(b"raw") if ret == b"continue": diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index 3ee96ea..e3a9856 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -34,6 +34,7 @@ def __init__(self, robot_obj): "home": robot_obj.maintain_home, "reset_mb": robot_obj.maintain_reset_mb, + "headinfo": robot_obj.maintain_headinfo, "play": { "quit": robot_obj.quit_play } @@ -63,6 +64,8 @@ def __init__(self, robot_obj): "eadj": self.maintain_eadj, "cor_h": self.maintain_hadj, + "load_filament": self.maintain_load_filament, + "unload_filament": self.maintain_unload_filament, "play": { "info": self.play_info }, @@ -106,7 +109,11 @@ def on_cmd(self, arguments): logger.error("RuntimeError%s" % repr(e.args)) def simple_cmd(self, func_ptr, *args): - logger.info(func_ptr(*args)) + ret = func_ptr(*args) + if ret: + logger.info(ret) + else: + logger.info("ok") def list_file(self, args): path = shlex.split(args)[0] @@ -277,6 +284,22 @@ def callback(nav): logger.info("Data: %s", ret) logger.info("ok") + def maintain_load_filament(self, index, temp): + def callback(nav): + logger.info("NAV: %s", nav) + + self.robot_obj.maintain_load_filament(int(index), float(temp), + callback) + logger.info("ok") + + def maintain_unload_filament(self, index, temp): + def callback(nav): + logger.info("NAV: %s", nav) + + self.robot_obj.maintain_unload_filament(int(index), float(temp), + callback) + logger.info("ok") + def raw_mode(self): import threading self._raw_sock = self.robot_obj.raw_mode() From 74611487c593aa01a284203bb585f8d8efcf4f1e Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Mon, 28 Dec 2015 00:54:23 +0800 Subject: [PATCH 15/53] Robot: bugfix --- fluxclient/robot/v0002.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 8028b3a..606c27e 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -482,6 +482,8 @@ def maintain_load_filament(self, index, temp, navigate_callback): return else: raise_error(ret) + else: + raise_error(ret.decode("ascii", "utf8")) def maintain_unload_filament(self, index, temp, navigate_callback): ret = self._make_cmd( @@ -496,6 +498,8 @@ def maintain_unload_filament(self, index, temp, navigate_callback): return else: raise_error(ret) + else: + raise_error(ret.decode("ascii", "utf8")) def raw_mode(self): ret = self._make_cmd(b"raw") From b45e285929f9fada5dd60ea480a57de10a6f46b2 Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 28 Dec 2015 18:30:33 +0800 Subject: [PATCH 16/53] update parameter --- fluxclient/printer/__init__.py | 18 +++++++++++++++++- fluxclient/printer/stl_slicer.py | 1 + setup_utils.py | 6 +++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index b52555c..4cef326 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -67,6 +67,22 @@ def hex_color(key, value): return "Invalid value: '%s' for %s, must be a hex color" % (value, key) +def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float('inf'), float_start=float('-inf'), float_end=float('inf')): + m = "Invalid value: '%s' for '%s', must be float or percentage" % (value, key) + try: + if value.endswith('%'): + v = float(value[:-1]) + if v >= percent_start and v <= percent_end: + m = 'ok' + else: + if float(value[:-1]) >= float_start and float(value[:-1]) <= float_end: + m = 'ok' + except: + pass + finally: + return m + + ini_string = '''# generated by Slic3r 1.2.9 on Tue Nov 10 23:28:47 2015 avoid_crossing_perimeters = 0 bed_shape = 84.5344x8.88492,83.1425x17.6725,80.8398x26.2664,77.6514x34.5726,73.6122x42.5,68.7664x49.9617,63.1673x56.8761,56.8761x63.1673,49.9617x68.7664,42.5x73.6122,34.5726x77.6514,26.2664x80.8398,17.6725x83.1425,8.88492x84.5344,0x85,-8.88492x84.5344,-17.6725x83.1425,-26.2664x80.8398,-34.5726x77.6514,-42.5x73.6122,-49.9617x68.7664,-56.8761x63.1673,-63.1673x56.8761,-68.7664x49.9617,-73.6122x42.5,-77.6514x34.5726,-80.8398x26.2664,-83.1425x17.6725,-84.5344x8.88492,-85x0,-84.5344x-8.88492,-83.1425x-17.6725,-80.8398x-26.2664,-77.6514x-34.5726,-73.6122x-42.5,-68.7664x-49.9617,-63.1673x-56.8761,-56.8761x-63.1673,-49.9617x-68.7664,-42.5x-73.6122,-34.5726x-77.6514,-26.2664x-80.8398,-17.6725x-83.1425,-8.88492x-84.5344,0x-85,8.88492x-84.5344,17.6725x-83.1425,26.2664x-80.8398,34.5726x-77.6514,42.5x-73.6122,49.9617x-68.7664,56.8761x-63.1673,63.1673x-56.8761,68.7664x-49.9617,73.6122x-42.5,77.6514x-34.5726,80.8398x-26.2664,83.1425x-17.6725,84.5344x-8.88492,85x0 @@ -219,7 +235,7 @@ def hex_color(key, value): 'end_gcode': [free], 'external_fill_pattern': [finite_choice, ['rectilinear-grid', 'line', 'rectilinear', 'honeycomb']], 'external_perimeter_extrusion_width': False, - 'external_perimeter_speed': [int_range, 1, 150], + 'external_perimeter_speed': [float_or_percent], 'external_perimeters_first': False, 'extra_perimeters': [binary], 'extruder_clearance_height': False, diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index c98cbcf..8aa9b24 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -206,6 +206,7 @@ def advanced_setting(self, lines): self.config['top_solid_layers'] = '0' ini_constraint['top_solid_layers'] = [ignore] elif result == 'ignore': + # ignore this config key anyway pass else: bad_lines.append((counter, result)) diff --git a/setup_utils.py b/setup_utils.py index 2a1c317..88927e5 100644 --- a/setup_utils.py +++ b/setup_utils.py @@ -151,10 +151,14 @@ def create_scanner_extentions(): "pcl_outofcore_release", "pcl_people_release"] include_dirs += ["C:/Program Files (x86)/Eigen/include", "C:/Program Files (x86)/flann/include", + "C:/Program Files/Eigen/include", + "C:/Program Files/flann/include", "C:/Program Files/PCL 1.7.2/include/pcl-1.7", "C:/Program Files/PCL 1.7.2/lib", "C:/local/boost_1_59_0"] - library_dirs += ["C:/Program Files/PCL 1.7.2/lib"] + library_dirs += ["C:/Program Files/PCL 1.7.2/lib", + "C:/local/boost_1_59_0/lib64-msvc-14.0"] + else: raise RuntimeError("Unknow platform!!") From dedb7a3fc41105ea05815ca85a8d6f5a6088ab73 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 29 Dec 2015 18:24:30 +0800 Subject: [PATCH 17/53] # 1002: refill empty path --- fluxclient/fcode/g_to_f.py | 45 ++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 7faa98b..11d7fa6 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -41,6 +41,7 @@ def __init__(self, version=1, head_type="EXTRUDER", ext_metadata={}): self.distance = 0. # recording distance go through self.max_range = [0., 0., 0., 0.] # recording max coordinate, [x, y, z, r] self.filament = [0., 0., 0.] # recording the filament needed, in mm + self.previous = [0., 0., 0.] # recording previous filament/path self.md = {'HEAD_TYPE': head_type} # basic metadata, use extruder as default self.md.update(ext_metadata) @@ -48,6 +49,7 @@ def __init__(self, version=1, head_type="EXTRUDER", ext_metadata={}): self.record_z = 0.0 self.layer_now = 0 self.path = [[[0.0, 0.0, HW_PROFILE['model-1']['height'], 3]]] # recording the path extruder go through + # self.path = [layers], layer = [points], point = [X, Y, Z, path type] self.config = None @@ -112,17 +114,6 @@ def analyze_metadata(self, input_list, comment): if input_list[0] is not None: self.current_speed = input_list[0] - extrudeflag = False - for i in range(4, 7): # extruder - if input_list[i] is not None: - extrudeflag = True - if self.absolute: - self.filament[i - 4] += input_list[i] - self.current_pos[i - 1] - self.current_pos[i - 1] = input_list[i] - else: - self.filament[i - 4] += input_list[i] - self.current_pos[i - 1] += input_list[i] - tmp_path = 0. moveflag = False # record if position change in this command for i in range(1, 4): # position @@ -135,16 +126,41 @@ def analyze_metadata(self, input_list, comment): tmp_path += (input_list[i] ** 2) self.current_pos[i - 1] += input_list[i] if abs(self.current_pos[i - 1]) > self.max_range[i - 1]: - # self.max_range[i - 1] = abs(self.current_pos[i - 1]) self.max_range[i - 1] = self.current_pos[i - 1] - if self.current_pos[0] ** 2 + self.current_pos[1] ** 2: # computer MAX_R + if self.current_pos[0] ** 2 + self.current_pos[1] ** 2 > self.max_range[3]: # computer MAX_R self.max_range[3] = self.current_pos[0] ** 2 + self.current_pos[1] ** 2 tmp_path = sqrt(tmp_path) + + extrudeflag = False + for i in range(4, 7): # extruder + if input_list[i] is not None: + extrudeflag = True + if self.absolute: + if tmp_path != 0: + if input_list[i] - self.current_pos[i - 1] == 0: + input_list[i] = self.previous[i - 4] * tmp_path + self.current_pos[i - 1] + self.G92_delta += self.previous[i - 4] * tmp_path + else: + self.previous[i - 4] = (input_list[i] - self.current_pos[i - 1]) / tmp_path + + self.filament[i - 4] += input_list[i] - self.current_pos[i - 1] + self.current_pos[i - 1] = input_list[i] + else: + if tmp_path != 0: + if input_list[i] == 0: + input_list[i] = self.previous[i - 4] * tmp_path + else: + self.previous[i - 4] = input_list[i] / tmp_path + + self.filament[i - 4] += input_list[i] + self.current_pos[i - 1] += input_list[i] + self.distance += tmp_path self.time_need += tmp_path / self.current_speed * 60 # from minute to sec # fill in self.path if self.record_path: self.process_path(comment, moveflag, extrudeflag) + return input_list def writer(self, buf, stream): """ @@ -189,7 +205,7 @@ def process(self, input_stream, output_stream): # data[0] = float(self.config['first_layer_speed']) * 60 # subcommand |= (1 << 6) - self.analyze_metadata(data, comment) + data = self.analyze_metadata(data, comment) command |= subcommand self.writer(packer(command), output_stream) @@ -300,6 +316,7 @@ def process(self, input_stream, output_stream): if len(self.empty_layer) > 0 and self.empty_layer[0] == 0: self.empty_layer.pop(0) + print('tmppty', self.empty_layer) # warning: fileformat didn't consider multi-extruder, use first extruder instead self.md['FILAMENT_USED'] = ','.join(map(str, self.filament)) From d03b2432eb863e1b47134979690b95278fe41d9e Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 29 Dec 2015 19:31:52 +0800 Subject: [PATCH 18/53] #977: advanced scan parameter --- fluxclient/commands/experiment_tool.py | 3 +- fluxclient/scanner/freeless.py | 47 ++++++------ fluxclient/scanner/image_to_pc.py | 20 ++--- fluxclient/scanner/pc_process.py | 51 ++++++++----- fluxclient/scanner/scan_settings.py | 102 +++++++++++-------------- src/scanner/scanner.pyx | 12 ++- 6 files changed, 117 insertions(+), 118 deletions(-) diff --git a/fluxclient/commands/experiment_tool.py b/fluxclient/commands/experiment_tool.py index bfc57c1..4f76d8d 100755 --- a/fluxclient/commands/experiment_tool.py +++ b/fluxclient/commands/experiment_tool.py @@ -8,6 +8,7 @@ import numpy as np from fluxclient.scanner.pc_process import PcProcess +from fluxclient.scanner.scan_settings import ScanSetting from fluxclient.scanner.tools import read_pcd, write_stl, write_pcd from fluxclient.scanner.pc_process import PcProcess @@ -17,7 +18,7 @@ def show_pc(name, pc_in): def main(in_file, out_file, command=''): - _PcProcess = PcProcess() + _PcProcess = PcProcess(ScanSetting()) tmp = out_file.rfind('.') prefix, suffix = out_file[:tmp], out_file[tmp + 1:] print('out_file', prefix, suffix) diff --git a/fluxclient/scanner/freeless.py b/fluxclient/scanner/freeless.py index 05a2b81..8c59713 100644 --- a/fluxclient/scanner/freeless.py +++ b/fluxclient/scanner/freeless.py @@ -7,10 +7,8 @@ from PIL import Image try: - from . import scan_settings from .tools import write_stl, dot, normal, normalize, point_dis_sq except: - import scan_settings from tools import write_stl, dot, normal, normalize, point_dis_sq NUM_LASER_RANGE_THRESHOLD = 3 @@ -27,19 +25,20 @@ class freeless(): freeless algorithm base on: http://www.freelss.org/ ''' - def __init__(self, laserX, laserZ): + def __init__(self, laserX, laserZ, scan_settings): ''' m_maxLaserWidth, m_minLaserWidth: red dots width within this range will be considered valid laser points firstRowLaserCol : red dot location of previous scanning step, reference for next step RANGE_DISTANCE_THRESHOLD : two range will be merged if their distance is small than this variable ''' + self.settings = scan_settings self.m_laserRanges = [] - self.m_maxLaserWidth = 50 - self.m_minLaserWidth = 3 + self.m_maxLaserWidth = scan_settings.MAXLaserRange + self.m_minLaserWidth = scan_settings.MINLaserRange self.MAX_MAGNITUDE_SQ = (255 * 3.0) # doesn't really matter(just for scaling) - self.m_laserMagnitudeThreshold = 1.25 # main threshold, diff value from 0.0 to 255? - self.firstRowLaserCol = 0.5 * scan_settings.img_width - self.RANGE_DISTANCE_THRESHOLD = 2 + self.m_laserMagnitudeThreshold = scan_settings.MagnitudeThreshold # main threshold, diff value from 0.0 to 255? + self.firstRowLaserCol = 0.5 * self.settings.img_width + self.RANGE_DISTANCE_THRESHOLD = scan_settings.LaserRangeMergeDistance self.numSuspectedBadLaserLocations = 0 self.results = [] self.laser_plane = [[0, 0, 0], normalize([laserZ, 0, -1 * laserX])] @@ -87,7 +86,7 @@ def img_to_points(self, img_o, img_red, indices, step, side, cab_offset, clock=F if clock: step = - step - theta = math.pi * 2 * step / scan_settings.scan_step + theta = math.pi * 2 * step / self.settings.scan_step c = math.cos(theta) s = math.sin(theta) @@ -127,7 +126,7 @@ def intersectLaserPlane(self, ray): return False, None point = [[ray[0][0] + (ray[1][0] * d), ray[0][1] + (ray[1][1] * d), ray[0][2] + (ray[1][2] * d)]] - point.append([scan_settings.laserX_L - point[0][0], scan_settings.laserY_L - point[0][1], scan_settings.laserZ_L - point[0][2]]) + point.append([self.settings.laserX_L - point[0][0], self.settings.laserY_L - point[0][1], self.settings.laserZ_L - point[0][2]]) # print point return True, point @@ -143,16 +142,16 @@ def calculateCameraRay(self, x, y): # return self.place[(x, y)] # portion, We subtract by one because the image is 0 indexed - x = float(x) / (scan_settings.img_width - 1) - y = float(scan_settings.img_height - 1 - y) / (scan_settings.img_height - 1) + x = float(x) / (self.settings.img_width - 1) + y = float(self.settings.img_height - 1 - y) / (self.settings.img_height - 1) - # x = (x * scan_settings.sensorWidth) + scan_settings.cameraX - (scan_settings.sensorWidth * 0.5) + 0.125 # rule of thumb number - # y = (y * scan_settings.sensorHeight) + scan_settings.cameraY - (scan_settings.sensorHeight * 0.5) + 0.31 # rule of thumb number - x = (x * scan_settings.sensorWidth) + scan_settings.cameraX - (scan_settings.sensorWidth * 0.5) # rule of thumb number - y = (y * scan_settings.sensorHeight) + scan_settings.cameraY - (scan_settings.sensorHeight * 0.5) # rule of thumb number - z = scan_settings.cameraZ + scan_settings.focalLength + # x = (x * self.settings.sensorWidth) + self.settings.cameraX - (self.settings.sensorWidth * 0.5) + 0.125 # rule of thumb number + # y = (y * self.settings.sensorHeight) + self.settings.cameraY - (self.settings.sensorHeight * 0.5) + 0.31 # rule of thumb number + x = (x * self.settings.sensorWidth) + self.settings.cameraX - (self.settings.sensorWidth * 0.5) # rule of thumb number + y = (y * self.settings.sensorHeight) + self.settings.cameraY - (self.settings.sensorHeight * 0.5) # rule of thumb number + z = self.settings.cameraZ + self.settings.focalLength - ray = [[x, y, z], normalize([x - scan_settings.cameraX, y - scan_settings.cameraY, z - scan_settings.cameraZ])] + ray = [[x, y, z], normalize([x - self.settings.cameraX, y - self.settings.cameraY, z - self.settings.cameraZ])] # self.place[(x, y)] = ray return ray @@ -215,7 +214,7 @@ def stl_writer(self, results, file_name): print ('tri:', len(tri), 'triangels') write_stl(tri, file_name) - def subProcess(self, img1, img2, maxNumLocations=scan_settings.img_height): + def subProcess(self, img1, img2, maxNumLocations): ''' find out the location of the laser dots return a list of indices [[x,y], [x,y], [x,y]] @@ -249,12 +248,12 @@ def subProcess(self, img1, img2, maxNumLocations=scan_settings.img_height): # print(mag, np.amax(mag), file=sys.stderr) # self.m_laserMagnitudeThreshold = .3 - for row in range(scan_settings.img_height): + for row in range(self.settings.img_height): m_laserRanges = [] # candidates, [ [starting index, ending index, middle point], ... ] m_laserRanges.append([-1, -1, None]) - for col in range(scan_settings.img_width): + for col in range(self.settings.img_width): # diff value is bigger than threshold if mag[row][col] > self.m_laserMagnitudeThreshold: # new candidate appear: first time > threshold, record as starting index @@ -289,7 +288,7 @@ def subProcess(self, img1, img2, maxNumLocations=scan_settings.img_height): else: m_laserRanges[-1][0] = -1 - # if m_laserRanges[-1][0] != -1 and m_laserRanges[-1][0] != scan_settings.img_width - 1: + # if m_laserRanges[-1][0] != -1 and m_laserRanges[-1][0] != self.settings.img_width - 1: # print m_laserRanges # input() @@ -351,7 +350,7 @@ def detectLaserRangeCenter(self, bestRange, img1, img2, row): import subprocess from tools import write_pcd - tmp = freeless(scan_settings.laserX_L, scan_settings.laserZ_L) + tmp = freeless(self.settings.laserX_L, self.settings.laserZ_L) im = np.array(Image.open('../../../rule.jpg')) print(im.shape) # self, img_o, img_red, indices, step, side, cab_offset, clock=False @@ -367,6 +366,6 @@ def detectLaserRangeCenter(self, bestRange, img1, img2, row): subprocess.call(['python', '../../../3ds/3ds/PCDViewer/pcd_to_js.py', output], stdout=open('../../../3ds/3ds/PCDViewer/model.js', 'w')) # p = tmp.img_to_points(sys.argv[1]) - # scan_settings.write_pcd(p, sys.argv[2]) + # self.settings.write_pcd(p, sys.argv[2]) # print >>sys.stderr, "\nError: python ./img_to_points.py [img location] [output file name]\n" diff --git a/fluxclient/scanner/image_to_pc.py b/fluxclient/scanner/image_to_pc.py index ba7bdd0..e2e43f7 100644 --- a/fluxclient/scanner/image_to_pc.py +++ b/fluxclient/scanner/image_to_pc.py @@ -8,11 +8,10 @@ try: from . import freeless - from . import scan_settings from .tools import write_pcd except: + raise import freeless - import scan_settings from tools import write_pcd from fluxclient.hw_profile import HW_PROFILE @@ -24,15 +23,16 @@ class image_to_pc(): """docstring for image_to_pc""" - def __init__(self, steps): - self.reset(steps) + def __init__(self, steps, scan_settings): + self.reset(steps, scan_settings) - def reset(self, steps): + def reset(self, steps, scan_settings): + self.settings = scan_settings self.points_L = [] - self.fs_L = freeless.freeless(scan_settings.laserX_L, scan_settings.laserZ_L) + self.fs_L = freeless.freeless(self.settings.laserX_L, self.settings.laserZ_L, self.settings) self.points_R = [] - self.fs_R = freeless.freeless(scan_settings.laserX_R, scan_settings.laserZ_R) + self.fs_R = freeless.freeless(self.settings.laserX_R, self.settings.laserZ_R, self.settings) self.step_counter = 0 self.steps = steps @@ -60,14 +60,14 @@ def feed(self, buffer_O, buffer_L, buffer_R, step, l_cab, r_cab): img_L = self.to_image(buffer_L) img_R = self.to_image(buffer_R) - indices_L = self.fs_L.subProcess(img_O, img_L, scan_settings.img_height) + indices_L = self.fs_L.subProcess(img_O, img_L, self.settings.img_height) indices_L = [[p[0], p[1] + l_cab]for p in indices_L] - # indices_L = [[i, step] for i in range(scan_settings.img_height)] + # indices_L = [[i, step] for i in range(self.settings.img_height)] point_L_this = self.fs_L.img_to_points(img_O, img_L, indices_L, step, 'L', l_cab, clock=True) self.points_L.extend(point_L_this) # return [self.points_to_bytes(point_L_this), []] - indices_R = self.fs_R.subProcess(img_O, img_R, scan_settings.img_height) + indices_R = self.fs_R.subProcess(img_O, img_R, self.settings.img_height) indices_R = [[p[0], p[1] + r_cab]for p in indices_R] point_R_this = self.fs_R.img_to_points(img_O, img_R, indices_R, step, 'R', r_cab, clock=True) self.points_R.extend(point_R_this) diff --git a/fluxclient/scanner/pc_process.py b/fluxclient/scanner/pc_process.py index 985535e..4b79aee 100644 --- a/fluxclient/scanner/pc_process.py +++ b/fluxclient/scanner/pc_process.py @@ -11,7 +11,6 @@ from scipy.interpolate import Rbf import numpy as np -from . import scan_settings from .tools import write_stl, write_pcd, read_pcd, cross from . import _scanner @@ -21,9 +20,10 @@ class PcProcess(): """process point cloud""" - def __init__(self): + def __init__(self, scan_settings): self.clouds = {} # clouds that hold all the point cloud data, key:name, value:point cloud self.meshs = {} + self.settings = scan_settings def upload(self, name, buffer_pc_L, buffer_pc_R, L_len, R_len): """ @@ -103,15 +103,15 @@ def delete_noise(self, name_in, name_out, stddev): pc = pc[0].add(pc[1]) logger.debug('start with %d point' % len(pc)) - pc.SOR(scan_settings.SOR_neighbors, stddev) + pc.SOR(int(self.settings.NoiseNeighbors), stddev) logger.debug('finished with %d point' % len(pc)) pc_both = [pc, _scanner.PointCloudXYZRGBObj()] self.clouds[name_out] = pc_both - # self.cluster(name_out, name_out, thres=5) - # self.closure(name_out, name_out, -1000, True) - # self.closure(name_out, name_out, 1000, False) - # self.cluster(name_out, name_out, thres=2) + + self.cluster(name_out, name_out, self.settings.SegmentationDistance) + self.closure(name_out, name_out, self.settings.CloseBottom, True) + self.closure(name_out, name_out, self.settings.CloseTop, False) def cluster(self, name_in, name_out, thres=2): pc = self.clouds[name_in] @@ -139,7 +139,7 @@ def to_mesh(self, name_in): # WARNING: merge L and R here! # pc = pc_both[0].clone() pc = pc_both[0].add(pc_both[1]) - pc.ne_viewpoint() + pc.ne_viewpoint(self.settings.NeighborhoodDistance) # pc.ne() pc.to_mesh() # compute mesh return pc @@ -256,11 +256,11 @@ def closure(self, name_in, name_out, z_value, floor): # TODO: use a better way to find ring rec = [float('-inf'), float('inf')] - interval = 2 * pi / scan_settings.scan_step * 0.8 - after = [] # find out the boarder points - for p in points: + interval = 2 * pi / self.settings.scan_step * 0.8 + after = [points[0]] # find out the boarder points + for p in points[1:]: tmp_index = bisect.bisect(rec, p[1]) # binary search where to insert - if p[1] - rec[tmp_index - 1] > interval and rec[tmp_index] - p[1] > interval: + if p[1] - rec[tmp_index - 1] > interval and rec[tmp_index] - p[1] > interval and abs(after[0][0][2] - p[0][2]) < 10: rec.insert(tmp_index, p[1]) after.append(p) if len(rec) > 400 + 2: @@ -293,14 +293,19 @@ def closure(self, name_in, name_out, z_value, floor): # compute the plane using RBF model tmp = [] grid_leaf = 100 - X = np.linspace(min(p[0] for p in plane), max(p[0] for p in plane), grid_leaf) - Y = np.linspace(min(p[1] for p in plane), max(p[1] for p in plane), grid_leaf) + # X = np.linspace(min(p[0] for p in plane), max(p[0] for p in plane), grid_leaf) + # Y = np.linspace(min(p[1] for p in plane), max(p[1] for p in plane), grid_leaf) + X = np.linspace(-100, 100, grid_leaf) + Y = np.linspace(-100, 100, grid_leaf) XI, YI = np.meshgrid(X, Y) x = [p[0] for p in plane] y = [p[1] for p in plane] z = [p[2] for p in plane] + for p in plane: + tmp.append([p[0], p[1], p[2], 255, 0, 0]) + if floor: color = [255, 0, 0] else: @@ -311,17 +316,23 @@ def closure(self, name_in, name_out, z_value, floor): for j in range(3): color[j] += i[j + 3] color = [i / len(after) for i in color] + color = [255., 0., 0.] + rbf = Rbf(x, y, z, function='linear', epsilon=0.1) + # rbf = Rbf(x, y, z) + # rbf = Rbf(x, y, z, function='thin_plate', epsilon=1) + print(rbf([x[0]], [y[0]])) + print(z[0]) - rbf = Rbf(x, y, z, function='linear') ZI = rbf(XI, YI) for xx in range(grid_leaf): for yy in range(grid_leaf): p = [XI[xx][yy], YI[xx][yy], ZI[xx][yy]] + color[:] flag = True - for b in range(len(boarder)): - if (cross(boarder[b], boarder[(b + 1) % len(boarder)], p)) < 0: - flag = False - break + # flag = False + # for b in range(len(boarder)): + # if (cross(boarder[b], boarder[(b + 1) % len(boarder)], p)) < 0: + # flag = False + # break if flag: tmp.append(p) del rbf @@ -347,7 +358,7 @@ def auto_alignment(self, name_base, name_2, name_out): # if either pointcloud with zero point, return name_2 without transform pc_both = pc_2 else: - reg = _scanner.RegCloud(pc_base, pc_2) + reg = _scanner.RegCloud(pc_base, pc_2, self.settings) result, pc_both = reg.SCP() # TODO:result??? diff --git a/fluxclient/scanner/scan_settings.py b/fluxclient/scanner/scan_settings.py index 66d6c6b..7fe1b79 100644 --- a/fluxclient/scanner/scan_settings.py +++ b/fluxclient/scanner/scan_settings.py @@ -1,57 +1,47 @@ #!/usr/bin/env python3 -import math - -scan_step = 400 # steps -theta_a = math.pi / 6 # radius between center and laser - -img_width = 640 -img_height = 480 - -sensorWidth = 3.67 -sensorHeight = 2.74 + 0.08 -focalLength = 3.6 - -# ######### mockup 2, measure by solidwork### -cameraX = 0.0 -cameraY = 22.28 + 8 -cameraZ = -174.70 - -laserX_L = -53.61 -laserY_L = 31.62 -laserZ_L = -76.47 - -laserX_R = 53.61 -laserY_R = 31.62 -laserZ_R = -76.47 - -theta_a = math.atan(laserX_L / laserZ_L) -# ######### mockup 1, hand measured ######### -# cameraX = 0.0 -# cameraY = 90 -# cameraZ = 170.0 - -# laserX_L = -52.0 -# laserY_L = 133. -# laserZ_L = 77.0 - -# laserX_R = 52.0 -# laserY_R = 133. -# laserZ_R = 77.0 -############################################## - -# ######### prototype, hand measured ######### -# cameraX = 0.0 -# cameraY = 120.0 -# cameraZ = 150.0 - -# laserX_L = -80.0 -# laserY_L = 120.0 -# laserZ_L = 120 - -# laserX_R = 80.0 -# laserY_R = 120.0 -# laserZ_R = 120 -############################################## - -SOR_neighbors = 50 -NE_radius = 10 +from math import pi, atan + + +class ScanSetting(object): + """docstring for ScanSetting""" + def __init__(self): + super(ScanSetting, self).__init__() + # for scan + self.scan_step = 400 # steps + self.theta_a = pi / 6 # radius between center and laser + + self.img_width = 640 + self.img_height = 480 + + self.sensorWidth = 3.67 + self.sensorHeight = 2.74 + 0.08 + self.focalLength = 3.6 + + # ######### mockup 2, measure by solidwork### + self.cameraX = 0.0 + self.cameraY = 22.28 + 8 + self.cameraZ = -174.70 + + self.laserX_L = -53.61 + self.laserY_L = 31.62 + self.laserZ_L = -76.47 + + self.laserX_R = 53.61 + self.laserY_R = 31.62 + self.laserZ_R = -76.47 + + self.theta_a = atan(self.laserX_L / self.laserZ_L) + + self.MAXLaserRange = 50 + self.LaserRangeMergeDistance = 2 + self.MINLaserRange = 3 + self.MagnitudeThreshold = 1.25 + self.LLaserAdjustment = 0 + self.RLaserAdjustment = 0 + + # for modeling + self.NoiseNeighbors = 50 + self.NeighborhoodDistance = 10 + self.SegmentationDistance = 2 + self.CloseBottom = -1000 + self.CloseTop = 1000 diff --git a/src/scanner/scanner.pyx b/src/scanner/scanner.pyx index 8ca70f7..840840c 100644 --- a/src/scanner/scanner.pyx +++ b/src/scanner/scanner.pyx @@ -2,8 +2,6 @@ import cython import sys from libcpp.vector cimport vector -import fluxclient.scanner.scan_settings as scan_settings - cdef extern from "scan_module.h": cdef cppclass PointCloudXYZRGBPtr: @@ -129,10 +127,10 @@ cdef class PointCloudXYZRGBObj: # self.obj, pc.obj) # return pc - cpdef int ne(self, float radius=scan_settings.NE_radius): + cpdef int ne(self, radius): return ne(self.obj, self.normalObj, radius) - cpdef int ne_viewpoint(self, float radius=scan_settings.NE_radius): + cpdef int ne_viewpoint(self, radius): return ne_viewpoint(self.obj, self.normalObj, radius) cpdef int concatenatePointsNormal(self): @@ -185,13 +183,13 @@ cdef class RegCloud: cdef M4f transformation - def __init__(self, PointCloudXYZRGBObj obj, PointCloudXYZRGBObj scene): - obj.ne_viewpoint() + def __init__(self, PointCloudXYZRGBObj obj, PointCloudXYZRGBObj scene, setting): + obj.ne_viewpoint(setting.NeighborhoodDistance) obj.concatenatePointsNormal() self.obj = createPointXYZRGBNormalPtr() clone(obj.bothobj, self.obj) - scene.ne_viewpoint() + scene.ne_viewpoint(setting.NeighborhoodDistance) scene.concatenatePointsNormal() self.scene = createPointXYZRGBNormalPtr() clone(scene.bothobj, self.scene) From 78da7656d588b0f42c8391fa5d360dadc2949c38 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 29 Dec 2015 23:35:32 +0800 Subject: [PATCH 19/53] fix for closure --- fluxclient/scanner/pc_process.py | 43 +++++++++++++------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/fluxclient/scanner/pc_process.py b/fluxclient/scanner/pc_process.py index 4b79aee..635e71a 100644 --- a/fluxclient/scanner/pc_process.py +++ b/fluxclient/scanner/pc_process.py @@ -110,8 +110,8 @@ def delete_noise(self, name_in, name_out, stddev): self.clouds[name_out] = pc_both self.cluster(name_out, name_out, self.settings.SegmentationDistance) - self.closure(name_out, name_out, self.settings.CloseBottom, True) - self.closure(name_out, name_out, self.settings.CloseTop, False) + self.closure(name_out, name_out, self.settings.CloseTop, False, 1000) + self.closure(name_out, name_out, self.settings.CloseBottom, True, 1000) def cluster(self, name_in, name_out, thres=2): pc = self.clouds[name_in] @@ -236,7 +236,7 @@ def merge(self, name_base, name_2, name_out): self.clouds[name_out] = both_pc - def closure(self, name_in, name_out, z_value, floor): + def closure(self, name_in, name_out, z_value, floor, thick=5): if floor: logger.debug('adding floor at {}'.format(floor)) else: @@ -258,12 +258,13 @@ def closure(self, name_in, name_out, z_value, floor): rec = [float('-inf'), float('inf')] interval = 2 * pi / self.settings.scan_step * 0.8 after = [points[0]] # find out the boarder points + for p in points[1:]: tmp_index = bisect.bisect(rec, p[1]) # binary search where to insert - if p[1] - rec[tmp_index - 1] > interval and rec[tmp_index] - p[1] > interval and abs(after[0][0][2] - p[0][2]) < 10: + if p[1] - rec[tmp_index - 1] > interval and rec[tmp_index] - p[1] > interval and abs(after[0][0][2] - p[0][2]) < thick: rec.insert(tmp_index, p[1]) after.append(p) - if len(rec) > 400 + 2: + if len(rec) > self.settings.scan_step + 2: break after = sorted(after, key=lambda x: x[1]) @@ -293,18 +294,16 @@ def closure(self, name_in, name_out, z_value, floor): # compute the plane using RBF model tmp = [] grid_leaf = 100 - # X = np.linspace(min(p[0] for p in plane), max(p[0] for p in plane), grid_leaf) - # Y = np.linspace(min(p[1] for p in plane), max(p[1] for p in plane), grid_leaf) - X = np.linspace(-100, 100, grid_leaf) - Y = np.linspace(-100, 100, grid_leaf) + X = np.linspace(min(p[0] for p in plane), max(p[0] for p in plane), grid_leaf) + Y = np.linspace(min(p[1] for p in plane), max(p[1] for p in plane), grid_leaf) XI, YI = np.meshgrid(X, Y) - x = [p[0] for p in plane] - y = [p[1] for p in plane] - z = [p[2] for p in plane] + x = np.array([p[0] for p in plane]) + y = np.array([p[1] for p in plane]) + z = np.array([p[2] for p in plane]) - for p in plane: - tmp.append([p[0], p[1], p[2], 255, 0, 0]) + # for p in plane: + # tmp.append([p[0], p[1], p[2], 255, 0, 0]) if floor: color = [255, 0, 0] @@ -316,23 +315,17 @@ def closure(self, name_in, name_out, z_value, floor): for j in range(3): color[j] += i[j + 3] color = [i / len(after) for i in color] - color = [255., 0., 0.] - rbf = Rbf(x, y, z, function='linear', epsilon=0.1) - # rbf = Rbf(x, y, z) - # rbf = Rbf(x, y, z, function='thin_plate', epsilon=1) - print(rbf([x[0]], [y[0]])) - print(z[0]) + rbf = Rbf(x, y, z, function='linear', smooth=1) ZI = rbf(XI, YI) for xx in range(grid_leaf): for yy in range(grid_leaf): p = [XI[xx][yy], YI[xx][yy], ZI[xx][yy]] + color[:] flag = True - # flag = False - # for b in range(len(boarder)): - # if (cross(boarder[b], boarder[(b + 1) % len(boarder)], p)) < 0: - # flag = False - # break + for b in range(len(boarder)): + if (cross(boarder[b], boarder[(b + 1) % len(boarder)], p)) < 0: + flag = False + break if flag: tmp.append(p) del rbf From b9a5af382d229312c6d4a3c1baf15f60a0841a58 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 29 Dec 2015 23:43:49 +0800 Subject: [PATCH 20/53] fix for windows (ref: simon) --- fluxclient/usb/task.py | 44 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/fluxclient/usb/task.py b/fluxclient/usb/task.py index eb2ef46..57968d6 100644 --- a/fluxclient/usb/task.py +++ b/fluxclient/usb/task.py @@ -1,13 +1,16 @@ - from select import select from time import time from uuid import UUID import logging import struct import json - from serial import Serial +# for windows +import platform +from time import sleep +from serial import serialutil as SerialUtil + from fluxclient import encryptor as E logger = logging.getLogger(__name__) @@ -23,17 +26,31 @@ CODE_SET_PASSWORD = 0x06 +def is_windows(): + return platform.platform().startswith("Windows") + + class UsbTask(object): def __init__(self, port, baudrate=115200): - self.s = Serial(port=port, baudrate=115200, timeout=0) + self.s = 0 + # Select does not work with windows.. + if is_windows(): + self.s = Serial(port=port, baudrate=115200, timeout=0.1) + else: + self.s = Serial(port=port, baudrate=115200, timeout=0) self.s.write(b"\x00" * 16) - - while True: - rl = select((self.s, ), (), (), 0.1)[0] - if rl: - self.s.readall() - else: - break + if is_windows(): + try: + str_read = self.s.readall() # Normally returns with empty string + except SerialUtil.SerialTimeoutException: + logger.error("Serial timeout") + else: + while True: + rl = select((self.s, ), (), (), 0.1)[0] + if rl: + self.s.readall() + else: + break self.keyobj = E.get_or_create_keyobj() self._discover() @@ -67,7 +84,11 @@ def _make_request(self, code, buf=b"", timeout=6.0): ttl = time() + timeout resp = b"" while time() < ttl: - rl = select((self.s, ), (), (), max(time() - ttl, 0))[0] + rl = False + if is_windows(): # In windows, the timeout=0.1 works like select + rl = True + else: + rl = select((self.s, ), (), (), max(time() - ttl, 0))[0] if rl: resp += self.s.readall() if self._try_parse_response(code, resp): @@ -77,6 +98,7 @@ def _make_request(self, code, buf=b"", timeout=6.0): else: raise UsbTaskError(resp[8:].decode("ascii", "ignore"), "status: %i" % status) + raise UsbTaskError("TIMEOUT") def _try_parse_response(self, code, buf): From 258ed6dc99be893751c8319e958cb3065c0e55e3 Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 11:44:13 +0800 Subject: [PATCH 21/53] typo --- fluxclient/fcode/g_to_f.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 11d7fa6..7b03e52 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -322,7 +322,7 @@ def process(self, input_stream, output_stream): self.md['FILAMENT_USED'] = ','.join(map(str, self.filament)) self.md['TRAVEL_DIST'] = str(self.distance) - for v, k in enumerate(['Z', 'Y', 'Z', 'R']): + for v, k in enumerate(['X', 'Y', 'Z', 'R']): self.md['MAX_' + k] = str(self.max_range[v]) self.md['TIME_COST'] = str(self.time_need) From 5fe6f48894074f4c111dbca2cf4392c916873dbc Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 11:59:51 +0800 Subject: [PATCH 22/53] fix typo bug --- fluxclient/fcode/g_to_f.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 7b03e52..53e118a 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -139,7 +139,7 @@ def analyze_metadata(self, input_list, comment): if tmp_path != 0: if input_list[i] - self.current_pos[i - 1] == 0: input_list[i] = self.previous[i - 4] * tmp_path + self.current_pos[i - 1] - self.G92_delta += self.previous[i - 4] * tmp_path + self.G92_delta[i - 1] += self.previous[i - 4] * tmp_path else: self.previous[i - 4] = (input_list[i] - self.current_pos[i - 1]) / tmp_path @@ -322,6 +322,7 @@ def process(self, input_stream, output_stream): self.md['FILAMENT_USED'] = ','.join(map(str, self.filament)) self.md['TRAVEL_DIST'] = str(self.distance) + self.max_range[3] = sqrt(self.max_range[3]) for v, k in enumerate(['X', 'Y', 'Z', 'R']): self.md['MAX_' + k] = str(self.max_range[v]) From 00d189577be625a9310a6c63e792b74132c167d6 Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 17:53:05 +0800 Subject: [PATCH 23/53] first layer setting --- fluxclient/fcode/g_to_f.py | 7 ++++--- fluxclient/printer/__init__.py | 4 +++- fluxclient/printer/stl_slicer.py | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 53e118a..c7a428b 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -201,9 +201,10 @@ def process(self, input_stream, output_stream): data[i] += self.G92_delta[i - 1] # # fix on slic3r bug slowing down in raft but not in real printing - # if self.config is not None and self.layer_now == int(self.config['raft_layers']): - # data[0] = float(self.config['first_layer_speed']) * 60 - # subcommand |= (1 << 6) + if self.config is not None and self.config['flux_first_layer'] == '1' and self.layer_now == int(self.config['raft_layers']): + print('hi') + data[0] = float(self.config['first_layer_speed']) * 60 + subcommand |= (1 << 6) data = self.analyze_metadata(data, comment) command |= subcommand diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index 4cef326..1b9eaf9 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -213,7 +213,8 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( vibration_limit = 0 wipe = 0 xy_size_compensation = 0 -z_offset = 0''' +z_offset = 0 +flux_first_layer = 0''' ini_constraint = { 'avoid_crossing_perimeters': [binary], @@ -346,4 +347,5 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'wipe': False, 'xy_size_compensation': False, 'z_offset': [float_range, 0, 23.5], + 'flux_first_layer': [binary], } diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 8aa9b24..1249caa 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -326,7 +326,6 @@ def gcode_generate(self, names, ws, output_type): # analying gcode(even transform) ws.send_progress('analyzing metadata', 0.99) - fcode_output = io.BytesIO() with open(tmp_gcode_file, 'r') as f: m_GcodeToFcode = GcodeToFcode(ext_metadata=self.ext_metadata) @@ -351,6 +350,7 @@ def gcode_generate(self, names, ws, output_type): raise('wrong output type, only support gcode and fcode') ##################### fake code ########################### + with open('output.gcode', 'wb') as f: with open(tmp_gcode_file, 'rb') as f2: f.write(f2.read()) @@ -503,12 +503,13 @@ def my_ini_parser(cls, data): lines = f.readlines() else: lines = data + for i in lines: if i[0] == '#': pass elif '=' in i: tmp = i.rstrip().split('=') - result[tmp[0].rstrip()] = tmp[1].rstrip() + result[tmp[0].strip()] = tmp[1].strip() else: print(i, file=sys.stderr) raise ValueError('not ini file?') From 225af00d21a2ccff9a988f01473e514bc7190b1c Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 17:53:23 +0800 Subject: [PATCH 24/53] some setting modify --- fluxclient/scanner/scan_settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxclient/scanner/scan_settings.py b/fluxclient/scanner/scan_settings.py index 7fe1b79..e7ac4bf 100644 --- a/fluxclient/scanner/scan_settings.py +++ b/fluxclient/scanner/scan_settings.py @@ -32,10 +32,10 @@ def __init__(self): self.theta_a = atan(self.laserX_L / self.laserZ_L) - self.MAXLaserRange = 50 - self.LaserRangeMergeDistance = 2 + self.MAXLaserRange = 65 + self.LaserRangeMergeDistance = 65 self.MINLaserRange = 3 - self.MagnitudeThreshold = 1.25 + self.MagnitudeThreshold = 3 self.LLaserAdjustment = 0 self.RLaserAdjustment = 0 From 718ac59e76c2a19bc23eb5293e9347aa92ea4f9a Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 17:55:09 +0800 Subject: [PATCH 25/53] come more setting --- fluxclient/scanner/pc_process.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fluxclient/scanner/pc_process.py b/fluxclient/scanner/pc_process.py index 635e71a..d9c79be 100644 --- a/fluxclient/scanner/pc_process.py +++ b/fluxclient/scanner/pc_process.py @@ -110,8 +110,8 @@ def delete_noise(self, name_in, name_out, stddev): self.clouds[name_out] = pc_both self.cluster(name_out, name_out, self.settings.SegmentationDistance) - self.closure(name_out, name_out, self.settings.CloseTop, False, 1000) - self.closure(name_out, name_out, self.settings.CloseBottom, True, 1000) + self.closure(name_out, name_out, self.settings.CloseTop, False, 10) + self.closure(name_out, name_out, self.settings.CloseBottom, True, 10) def cluster(self, name_in, name_out, thres=2): pc = self.clouds[name_in] @@ -119,8 +119,8 @@ def cluster(self, name_in, name_out, thres=2): pc0_size = len(pc[0]) output = (pc[0].add(pc[1])).Euclidean_Cluster(thres) output = sorted(output, key=lambda x: len(x)) - for i in output: - print(len(i)) + # for i in output: + # print(len(i)) tmp_pc = self.to_cpp([[], []]) for j in output[-1:]: for i in j: @@ -141,7 +141,7 @@ def to_mesh(self, name_in): pc = pc_both[0].add(pc_both[1]) pc.ne_viewpoint(self.settings.NeighborhoodDistance) # pc.ne() - pc.to_mesh() # compute mesh + pc.to_mesh(method='POS') # compute mesh return pc def dump(self, name): @@ -316,6 +316,7 @@ def closure(self, name_in, name_out, z_value, floor, thick=5): color[j] += i[j + 3] color = [i / len(after) for i in color] rbf = Rbf(x, y, z, function='linear', smooth=1) + # color = [255, 0, 0] ZI = rbf(XI, YI) for xx in range(grid_leaf): From 33eb33ab738b5bcbf9ac9fb94933d6f9a6e42daf Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 18:16:43 +0800 Subject: [PATCH 26/53] put fake code into if statement base on environ --- fluxclient/laser/laser_bitmap.py | 4 ++- fluxclient/laser/laser_svg.py | 4 ++- fluxclient/printer/stl_slicer.py | 61 +++++++++++++++----------------- fluxclient/utils/svg_parser.py | 3 +- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/fluxclient/laser/laser_bitmap.py b/fluxclient/laser/laser_bitmap.py index dcc9244..357b532 100755 --- a/fluxclient/laser/laser_bitmap.py +++ b/fluxclient/laser/laser_bitmap.py @@ -2,6 +2,7 @@ from math import pi, sin, cos, degrees import logging +from os import environ import numpy as np from PIL import Image @@ -94,7 +95,8 @@ def gcode_generate(self, res=1): gcode = "\n".join(gcode) + "\n" logger.debug("generate gcode done:%d bytes" % len(gcode)) ######################## fake code #################################### - self.dump('./preview.png') + if environ.get("flux_debug") == '1': + self.dump('./preview.png') ####################################################################### return gcode diff --git a/fluxclient/laser/laser_svg.py b/fluxclient/laser/laser_svg.py index fd9948c..74d57c2 100644 --- a/fluxclient/laser/laser_svg.py +++ b/fluxclient/laser/laser_svg.py @@ -3,6 +3,7 @@ import sys from math import sin, cos, pi, sqrt import logging +from os import environ # cElementTree is the c implement of ElementTree, much faster and memory friendly, but no need to specify in py3 import xml.etree.ElementTree as ET @@ -83,7 +84,8 @@ def gcode_generate(self, names, ws=None): gcode += self.turnOff() gcode += ["G28"] ################ fake code ############## - self.dump('./preview.png') + if environ.get("flux_debug") == '1': + self.dump('./preview.png') # output only moving # tmp = [] diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 1249caa..2bad4e8 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -4,7 +4,7 @@ import io import subprocess import tempfile -import os +from os import remove, environ import sys import copy from multiprocessing import Process, Pipe @@ -62,25 +62,23 @@ def slicing_worker(command, config, image, ext_metadata, output_type, child_pipe raise('wrong output type, only support gcode and fcode') ##################### fake code ########################### - with open('output.gcode', 'wb') as f: - with open(tmp_gcode_file, 'rb') as f2: - f.write(f2.read()) - tmp_stl_file = command[1] - with open(tmp_stl_file, 'rb') as f: - with open('merged.stl', 'wb') as f2: - f2.write(f.read()) - - with open('output.fc', 'wb') as f: - f.write(fcode_output.getvalue()) - - StlSlicer.my_ini_writer("output.ini", config) + if environ.get("flux_debug") == '1': + with open('output.gcode', 'wb') as f: + with open(tmp_gcode_file, 'rb') as f2: + f.write(f2.read()) + tmp_stl_file = command[1] + with open(tmp_stl_file, 'rb') as f: + with open('merged.stl', 'wb') as f2: + f2.write(f.read()) + + with open('output.fc', 'wb') as f: + f.write(fcode_output.getvalue()) + + StlSlicer.my_ini_writer("output.ini", config) ########################################################### # # clean up tmp files fcode_output.close() - # os.remove(tmp_stl_file) - # os.remove(tmp_gcode_file) - # os.remove(tmp_slic3r_setting_file) if fail_flag: child_pipe.send([False, slic3r_out, []]) else: @@ -138,8 +136,9 @@ def upload_image(self, buf): image_bytes = b.getvalue() self.image = image_bytes ######################### fake code ################################### - with open('_preview.png', 'wb') as f: - f.write(image_bytes) + if environ.get("flux_debug") == '1': + with open('_preview.png', 'wb') as f: + f.write(image_bytes) ############################################################ def delete(self, name): @@ -301,7 +300,6 @@ def gcode_generate(self, names, ws, output_type): self.my_ini_writer(tmp_slic3r_setting_file, self.config) command += ['--load', tmp_slic3r_setting_file] - # command += ['--load', '/Users/yen/Documents/config.ini'] print('command:', ' '.join(command), file=sys.stderr) @@ -350,26 +348,26 @@ def gcode_generate(self, names, ws, output_type): raise('wrong output type, only support gcode and fcode') ##################### fake code ########################### + if environ.get("flux_debug") == '1': + with open('output.gcode', 'wb') as f: + with open(tmp_gcode_file, 'rb') as f2: + f.write(f2.read()) - with open('output.gcode', 'wb') as f: - with open(tmp_gcode_file, 'rb') as f2: - f.write(f2.read()) + with open(tmp_stl_file, 'rb') as f: + with open('merged.stl', 'wb') as f2: + f2.write(f.read()) - with open(tmp_stl_file, 'rb') as f: - with open('merged.stl', 'wb') as f2: - f2.write(f.read()) - - with open('output.fc', 'wb') as f: - f.write(fcode_output.getvalue()) + with open('output.fc', 'wb') as f: + f.write(fcode_output.getvalue()) - self.my_ini_writer("output.ini", self.config) + self.my_ini_writer("output.ini", self.config) ########################################################### # clean up tmp files fcode_output.close() for f in [tmp_stl_file, tmp_gcode_file, tmp_slic3r_setting_file]: try: - os.remove(f) + remove(f) except: pass if fail_flag: @@ -448,7 +446,6 @@ def begin_slicing(self, names, ws, output_type): command += ['--output', tmp_gcode_file] command += ['--print-center', '%f,%f' % (cx, cy)] command += ['--load', tmp_slic3r_setting_file] - # command += ['--load', '/Users/yen/Documents/config.ini'] print('command:', ' '.join(command), file=sys.stderr) self.end_slicing() @@ -463,7 +460,7 @@ def end_slicing(self): p[0].terminate() for filename in p[1]: try: - os.remove(filename) + remove(filename) except: pass self.working_p = [] diff --git a/fluxclient/utils/svg_parser.py b/fluxclient/utils/svg_parser.py index 92c04cf..71eb927 100644 --- a/fluxclient/utils/svg_parser.py +++ b/fluxclient/utils/svg_parser.py @@ -471,7 +471,8 @@ def preprocess(buf, name): # root.attrib['style'] = "border: solid #ff0000;" # TODO: delete this, this is only for debug ################ fake code ############## - tree.write('preprocess.svg') + if environ.get("flux_debug") == '1': + tree.write('preprocess.svg') ######################################## return [ET.tostring(root), viewBox[2], viewBox[3]] # ET.tostring type: bytes From 02ac20b8ac0387e21bd3755fed8ab3492666b05d Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 19:04:19 +0800 Subject: [PATCH 27/53] add setting for refilling control --- fluxclient/fcode/g_to_f.py | 5 +++-- fluxclient/printer/__init__.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index c7a428b..0606371 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -136,7 +136,7 @@ def analyze_metadata(self, input_list, comment): if input_list[i] is not None: extrudeflag = True if self.absolute: - if tmp_path != 0: + if self.config['flux_refill_empty'] == '1' and tmp_path != 0: if input_list[i] - self.current_pos[i - 1] == 0: input_list[i] = self.previous[i - 4] * tmp_path + self.current_pos[i - 1] self.G92_delta[i - 1] += self.previous[i - 4] * tmp_path @@ -146,7 +146,8 @@ def analyze_metadata(self, input_list, comment): self.filament[i - 4] += input_list[i] - self.current_pos[i - 1] self.current_pos[i - 1] = input_list[i] else: - if tmp_path != 0: + if self.config['flux_refill_empty'] == '1' and tmp_path != 0: + print('hi') if input_list[i] == 0: input_list[i] = self.previous[i - 4] * tmp_path else: diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index 1b9eaf9..729f8f6 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -214,6 +214,7 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( wipe = 0 xy_size_compensation = 0 z_offset = 0 +flux_refill_empty = 0 flux_first_layer = 0''' ini_constraint = { @@ -347,5 +348,6 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'wipe': False, 'xy_size_compensation': False, 'z_offset': [float_range, 0, 23.5], + 'flux_refill_empty': [binary], 'flux_first_layer': [binary], } From a08d2e7aec0c8cf7e21783a2e1a6c505e5e15801 Mon Sep 17 00:00:00 2001 From: Yen Date: Wed, 30 Dec 2015 20:06:17 +0800 Subject: [PATCH 28/53] fix for avoiding truly empty layer --- fluxclient/fcode/fcode_base.py | 5 ++++- fluxclient/printer/stl_slicer.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fluxclient/fcode/fcode_base.py b/fluxclient/fcode/fcode_base.py index 28b399b..c18469e 100644 --- a/fluxclient/fcode/fcode_base.py +++ b/fluxclient/fcode/fcode_base.py @@ -11,12 +11,14 @@ def __init__(self): super(FcodeBase, self).__init__() self.filament_this_layer = [0., 0., 0.] self.empty_layer = [] + self.counter_between_layers = 0 def process_path(self, comment, moveflag, extrudeflag): """ convert to path list(for visualizing) """ # TODO?: reconsider if theese two flag necessary + self.counter_between_layers += 1 if moveflag: if 'infill' in comment: line_type = 0 @@ -27,9 +29,10 @@ def process_path(self, comment, moveflag, extrudeflag): elif 'move' in comment: line_type = 3 if 'to next layer' in comment: - if self.filament == self.filament_this_layer: + if self.filament == self.filament_this_layer and self.counter_between_layers > 1: self.empty_layer.append(self.layer_now) tmp = findall('[0-9]+', comment)[-1] + self.counter_between_layers = 0 self.layer_now = int(tmp) self.path.append([self.path[-1][-1][:3] + [line_type]]) self.filament_this_layer = self.filament[:] diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 2bad4e8..efd33e2 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -95,6 +95,7 @@ def __del__(self): self.end_slicing() def reset(self, slic3r): + self.working_p = [] # process that are slicing self.models = {} # models data self.parameter = {} # model's parameter self.user_setting = {} # slcing setting @@ -110,7 +111,6 @@ def reset(self, slic3r): self.path = None self.image = b'' self.ext_metadata = {'CORRECTION': 'A'} - self.working_p = [] def upload(self, name, buf): """ From ec3405bc655e452a6eeb034469682a780b94e36d Mon Sep 17 00:00:00 2001 From: Yen Date: Thu, 31 Dec 2015 16:39:34 +0800 Subject: [PATCH 29/53] slicing out of range error --- fluxclient/fcode/g_to_f.py | 1 - fluxclient/hw_profile/__init__.py | 2 +- fluxclient/printer/stl_slicer.py | 4 ++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 0606371..9805308 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -318,7 +318,6 @@ def process(self, input_stream, output_stream): if len(self.empty_layer) > 0 and self.empty_layer[0] == 0: self.empty_layer.pop(0) - print('tmppty', self.empty_layer) # warning: fileformat didn't consider multi-extruder, use first extruder instead self.md['FILAMENT_USED'] = ','.join(map(str, self.filament)) diff --git a/fluxclient/hw_profile/__init__.py b/fluxclient/hw_profile/__init__.py index 47749d0..9f2c295 100644 --- a/fluxclient/hw_profile/__init__.py +++ b/fluxclient/hw_profile/__init__.py @@ -1,6 +1,6 @@ HW_PROFILE = { 'model-1': { - 'radius': 17., + 'radius': 85., 'scan_full_len': 360., 'height': 240., # 'step_setting': {400: (3, 2.7), 800: (7, 3.15)} diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index efd33e2..b8ee724 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -11,6 +11,7 @@ from PIL import Image +from fluxclient.hw_profile import HW_PROFILE from fluxclient.printer import _printer from fluxclient.fcode.g_to_f import GcodeToFcode from fluxclient.scanner.tools import dot, normal @@ -337,6 +338,9 @@ def gcode_generate(self, names, ws, output_type): if slic3r_error or len(m_GcodeToFcode.empty_layer) > 0: ws.send_warning("{} empty layers, might be error when slicing {}".format(len(m_GcodeToFcode.empty_layer), repr(m_GcodeToFcode.empty_layer))) + if float(m_GcodeToFcode.md['MAX_R']) >= HW_PROFILE['model-1']['radius']: + fail_flag = True + slic3r_out = "gcode area too big" del m_GcodeToFcode if output_type == '-g': From 777cf52f0eb6e5444ef817ce0f4f6258cecdc918 Mon Sep 17 00:00:00 2001 From: Yen Date: Sat, 2 Jan 2016 00:10:51 +0800 Subject: [PATCH 30/53] minor --- fluxclient/utils/svg_parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fluxclient/utils/svg_parser.py b/fluxclient/utils/svg_parser.py index 71eb927..76626ae 100644 --- a/fluxclient/utils/svg_parser.py +++ b/fluxclient/utils/svg_parser.py @@ -1,5 +1,6 @@ import xml.etree.ElementTree as ET from re import split +from os import environ from math import sin, cos, pi, radians, sqrt, acos, copysign From f78434f6a54bdcd851c6f0b097405b98a10ebf8c Mon Sep 17 00:00:00 2001 From: Yen Date: Sat, 2 Jan 2016 01:44:08 +0800 Subject: [PATCH 31/53] fix for using __main__ --- fluxclient/scanner/image_to_pc.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fluxclient/scanner/image_to_pc.py b/fluxclient/scanner/image_to_pc.py index e2e43f7..27ed61c 100644 --- a/fluxclient/scanner/image_to_pc.py +++ b/fluxclient/scanner/image_to_pc.py @@ -10,10 +10,10 @@ from . import freeless from .tools import write_pcd except: - raise import freeless from tools import write_pcd + from fluxclient.hw_profile import HW_PROFILE try: from . import _scanner @@ -61,6 +61,7 @@ def feed(self, buffer_O, buffer_L, buffer_R, step, l_cab, r_cab): img_R = self.to_image(buffer_R) indices_L = self.fs_L.subProcess(img_O, img_L, self.settings.img_height) + indices_L = [[p[0], p[1] + l_cab]for p in indices_L] # indices_L = [[i, step] for i in range(self.settings.img_height)] point_L_this = self.fs_L.img_to_points(img_O, img_L, indices_L, step, 'L', l_cab, clock=True) @@ -72,7 +73,6 @@ def feed(self, buffer_O, buffer_L, buffer_R, step, l_cab, r_cab): point_R_this = self.fs_R.img_to_points(img_O, img_R, indices_R, step, 'R', r_cab, clock=True) self.points_R.extend(point_R_this) # return [[], self.points_to_bytes(point_R_this)] - return [self.points_to_bytes(point_L_this), self.points_to_bytes(point_R_this)] def points_to_bytes(self, points): @@ -192,11 +192,13 @@ def after(l): if __name__ == '__main__': import subprocess - m_image_to_pc = image_to_pc(400) + from fluxclient.scanner.scan_settings import ScanSetting + ss = 10 + m_image_to_pc = image_to_pc(ss, ScanSetting()) img_location = sys.argv[1].rstrip('/') print(img_location) - for i in range(400): + for i in range(ss): tmp = [open(img_location + '/' + str(i).zfill(3) + '_' + j + '.jpg', 'rb').read() for j in ['O', 'L', 'R']] m_image_to_pc.feed(*tmp, step=i, l_cab=-10, r_cab=-10) print_progress(i, 400) From 8d02a100a45cbe25bfda0c4b21813d533e388a69 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Sat, 2 Jan 2016 22:39:19 +0800 Subject: [PATCH 32/53] Setup bugfix --- fluxclient/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxclient/__init__.py b/fluxclient/__init__.py index 148ce1d..259dde1 100644 --- a/fluxclient/__init__.py +++ b/fluxclient/__init__.py @@ -3,7 +3,7 @@ def check_pcl(): try: from .scanner import _scanner return True - except ImportError: + except (ImportError, AttributeError): return False From 96601181c77c289ddb660ab571dd5de11c80ea24 Mon Sep 17 00:00:00 2001 From: Yen Date: Sat, 2 Jan 2016 22:39:52 +0800 Subject: [PATCH 33/53] minor: some setting update --- fluxclient/printer/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index 729f8f6..edff991 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -219,8 +219,8 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( ini_constraint = { 'avoid_crossing_perimeters': [binary], - 'bed_shape': [constant], - 'bed_temperature': [constant], + 'bed_shape': [ignore], + 'bed_temperature': [ignore], 'before_layer_gcode': [free], 'bottom_solid_layers': [int_range, 0, 20], 'bridge_acceleration': [binary], @@ -242,7 +242,7 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'extra_perimeters': [binary], 'extruder_clearance_height': False, 'extruder_clearance_radius': False, - 'extruder_offset': [constant], + 'extruder_offset': [ignore], 'extrusion_axis': False, 'extrusion_multiplier': False, 'extrusion_width': False, @@ -277,7 +277,7 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'max_fan_speed': [percentage], 'max_print_speed': False, 'max_volumetric_speed': False, - 'min_fan_speed': [constant], + 'min_fan_speed': [int_range, 0, 100], 'min_print_speed': False, 'min_skirt_length': False, 'notes': False, From 2dad4ee7fcc8c17a5ad9796b68d015e7f9ee7a05 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Sun, 3 Jan 2016 18:40:39 +0800 Subject: [PATCH 34/53] Robot: add stop load filament command --- fluxclient/robot/v0002.py | 21 ++++++++++++++------- fluxclient/robot_console.py | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/fluxclient/robot/v0002.py b/fluxclient/robot/v0002.py index 606c27e..3bd7858 100644 --- a/fluxclient/robot/v0002.py +++ b/fluxclient/robot/v0002.py @@ -475,16 +475,23 @@ def maintain_load_filament(self, index, temp, navigate_callback): if ret == b"continue": while True: - ret = self.get_resp().decode("ascii", "ignore") - if ret.startswith("CTRL "): - navigate_callback(ret[5:]) - elif ret == "ok": - return - else: - raise_error(ret) + try: + ret = self.get_resp().decode("ascii", "ignore") + if ret.startswith("CTRL "): + navigate_callback(ret[5:]) + elif ret == "ok": + return + else: + raise_error(ret) + except KeyboardInterrupt: + self._send_cmd(b"stop_load_filament") + logger.info("Interrupt load filament") else: raise_error(ret.decode("ascii", "utf8")) + def maintain_stop_load_filament(self): + self._send_cmd("stop_load_filament") + def maintain_unload_filament(self, index, temp, navigate_callback): ret = self._make_cmd( ("unload_filament %i %.1f" % (index, temp)).encode()) diff --git a/fluxclient/robot_console.py b/fluxclient/robot_console.py index e3a9856..4f69577 100644 --- a/fluxclient/robot_console.py +++ b/fluxclient/robot_console.py @@ -65,6 +65,7 @@ def __init__(self, robot_obj): "eadj": self.maintain_eadj, "cor_h": self.maintain_hadj, "load_filament": self.maintain_load_filament, + "stop_load_filament": self.maintain_stop_load_filament, "unload_filament": self.maintain_unload_filament, "play": { "info": self.play_info @@ -292,6 +293,9 @@ def callback(nav): callback) logger.info("ok") + def maintain_stop_load_filament(self): + self.robot_obj.maintain_stop_load_filament() + def maintain_unload_filament(self, index, temp): def callback(nav): logger.info("NAV: %s", nav) From f949f3e023e380b1620cd0cd9fca4c3e3b312126 Mon Sep 17 00:00:00 2001 From: Yen Date: Sun, 3 Jan 2016 19:08:01 +0800 Subject: [PATCH 35/53] some calibration fix --- fluxclient/scanner/freeless.py | 7 ++++++- fluxclient/scanner/scan_settings.py | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fluxclient/scanner/freeless.py b/fluxclient/scanner/freeless.py index 8c59713..1b273b3 100644 --- a/fluxclient/scanner/freeless.py +++ b/fluxclient/scanner/freeless.py @@ -41,7 +41,12 @@ def __init__(self, laserX, laserZ, scan_settings): self.RANGE_DISTANCE_THRESHOLD = scan_settings.LaserRangeMergeDistance self.numSuspectedBadLaserLocations = 0 self.results = [] - self.laser_plane = [[0, 0, 0], normalize([laserZ, 0, -1 * laserX])] + if laserX > 0: + d = (scan_settings.cab_r - scan_settings.cab_m) * 35 / 125 + self.laser_plane = [[d, 0, 0], normalize([laserZ, 0, -1 * (laserX - d)])] + else: + d = (scan_settings.cab_l - scan_settings.cab_m) * 35 / 125 + self.laser_plane = [[d, 0, 0], normalize([laserZ, 0, -1 * (laserX - d)])] self.place = {} def img_to_points(self, img_o, img_red, indices, step, side, cab_offset, clock=False): diff --git a/fluxclient/scanner/scan_settings.py b/fluxclient/scanner/scan_settings.py index e7ac4bf..89b3f06 100644 --- a/fluxclient/scanner/scan_settings.py +++ b/fluxclient/scanner/scan_settings.py @@ -18,6 +18,10 @@ def __init__(self): self.focalLength = 3.6 # ######### mockup 2, measure by solidwork### + self.cab_m = self.img_width / 2 + self.cab_l = self.img_width / 2 + self.cab_r = self.img_width / 2 + self.cameraX = 0.0 self.cameraY = 22.28 + 8 self.cameraZ = -174.70 From 17eabbaf853508e681d8bba21791bba1f7c6be1c Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Sun, 3 Jan 2016 20:47:19 +0800 Subject: [PATCH 36/53] USB: coding style fix --- fluxclient/usb/task.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fluxclient/usb/task.py b/fluxclient/usb/task.py index 57968d6..214c8d9 100644 --- a/fluxclient/usb/task.py +++ b/fluxclient/usb/task.py @@ -8,10 +8,9 @@ # for windows import platform -from time import sleep -from serial import serialutil as SerialUtil +from serial.serialutil import SerialTimeoutException -from fluxclient import encryptor as E +from fluxclient import encryptor as E # noqa logger = logging.getLogger(__name__) @@ -31,8 +30,9 @@ def is_windows(): class UsbTask(object): + s = None + def __init__(self, port, baudrate=115200): - self.s = 0 # Select does not work with windows.. if is_windows(): self.s = Serial(port=port, baudrate=115200, timeout=0.1) @@ -41,8 +41,8 @@ def __init__(self, port, baudrate=115200): self.s.write(b"\x00" * 16) if is_windows(): try: - str_read = self.s.readall() # Normally returns with empty string - except SerialUtil.SerialTimeoutException: + self.s.readall() # Normally returns with empty string + except SerialTimeoutException: logger.error("Serial timeout") else: while True: From 391e8d08621565f96f97792f62a7df72b8f638b5 Mon Sep 17 00:00:00 2001 From: Yen Date: Sun, 3 Jan 2016 22:02:40 +0800 Subject: [PATCH 37/53] fix when using g_to_f not by studio --- fluxclient/fcode/g_to_f.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 9805308..3fe78f9 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -136,7 +136,7 @@ def analyze_metadata(self, input_list, comment): if input_list[i] is not None: extrudeflag = True if self.absolute: - if self.config['flux_refill_empty'] == '1' and tmp_path != 0: + if self.config is not None and self.config['flux_refill_empty'] == '1' and tmp_path != 0: if input_list[i] - self.current_pos[i - 1] == 0: input_list[i] = self.previous[i - 4] * tmp_path + self.current_pos[i - 1] self.G92_delta[i - 1] += self.previous[i - 4] * tmp_path @@ -146,8 +146,7 @@ def analyze_metadata(self, input_list, comment): self.filament[i - 4] += input_list[i] - self.current_pos[i - 1] self.current_pos[i - 1] = input_list[i] else: - if self.config['flux_refill_empty'] == '1' and tmp_path != 0: - print('hi') + if self.config is not None and self.config['flux_refill_empty'] == '1' and tmp_path != 0: if input_list[i] == 0: input_list[i] = self.previous[i - 4] * tmp_path else: From 29c17a553512651adc054247e8eef4a58bf6244c Mon Sep 17 00:00:00 2001 From: Yen Date: Sun, 3 Jan 2016 22:26:02 +0800 Subject: [PATCH 38/53] remove G28 at the end of laser gcode --- fluxclient/laser/laser_bitmap.py | 1 - fluxclient/laser/laser_svg.py | 1 - 2 files changed, 2 deletions(-) diff --git a/fluxclient/laser/laser_bitmap.py b/fluxclient/laser/laser_bitmap.py index 357b532..4660de7 100755 --- a/fluxclient/laser/laser_bitmap.py +++ b/fluxclient/laser/laser_bitmap.py @@ -91,7 +91,6 @@ def gcode_generate(self, res=1): gcode += self.turnOff() gcode += self.turnOff() - gcode += ["G28"] gcode = "\n".join(gcode) + "\n" logger.debug("generate gcode done:%d bytes" % len(gcode)) ######################## fake code #################################### diff --git a/fluxclient/laser/laser_svg.py b/fluxclient/laser/laser_svg.py index 74d57c2..44cf7db 100644 --- a/fluxclient/laser/laser_svg.py +++ b/fluxclient/laser/laser_svg.py @@ -82,7 +82,6 @@ def gcode_generate(self, names, ws=None): if ready_svg[-1]: self.add_image(ready_svg[-1], ready_svg[-3], ready_svg[-2], *ready_svg[3:-3], thres=100) gcode += self.turnOff() - gcode += ["G28"] ################ fake code ############## if environ.get("flux_debug") == '1': self.dump('./preview.png') From da348392ee4a73e286b01be0c8496924a9516e16 Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 4 Jan 2016 15:11:44 +0800 Subject: [PATCH 39/53] fix bug can't detect white frame only one white point in row(cause by resizing) --- fluxclient/laser/laser_base.py | 14 +++++++------- fluxclient/laser/laser_bitmap.py | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/fluxclient/laser/laser_base.py b/fluxclient/laser/laser_base.py index cb76a30..e500b8d 100755 --- a/fluxclient/laser/laser_base.py +++ b/fluxclient/laser/laser_base.py @@ -213,7 +213,7 @@ def rotate(x, y, rotation, cx=0., cy=0.): return x, y pix = Image.frombytes('L', (img_width, img_height), buffer_data) - # pix.save('tmp.png', 'png') + # pix.save('get.png', 'png') # image center (rotation center) cx = (x1 + x2) / 2. @@ -255,27 +255,27 @@ def rotate(x, y, rotation, cx=0., cy=0.): new_pix = Image.new('L', (pix.size[0] + 2, pix.size[1] + 2), 255) new_pix.paste(pix, (1, 1)) new_pix = new_pix.rotate(degrees(rotation), expand=1) - new_pix = new_pix.resize((gy2_on_map - gy1_on_map, gx2_on_map - gx1_on_map)) + for h in range(new_pix.size[1]): # using white frame to find starting and ending index # find_start, find_end for each row flag = False # whether find white frame for find_s in range(new_pix.size[0]): - if new_pix.getpixel((find_s, h)) > 0: + if new_pix.getpixel((find_s, h)) == 255: # check this thres? find_s = find_s + 1 flag = True break if not flag: - find_s = new_pix.size[0] + find_s = 0 flag = False for find_e in range(new_pix.size[0] - 1, -1, -1): - if new_pix.getpixel((find_e, h)) > 0: + if new_pix.getpixel((find_e, h)) == 255: flag = True break - if not flag: - find_e = 0 + if not flag or find_e < find_s: # only one white point in this row(cause by resizing) + find_e = new_pix.size[0] for w in range(find_s, find_e): if (gx1_on_map + h - len(self.image_map) / 2.) ** 2 + (gy1_on_map + w - len(self.image_map) / 2.) ** 2 < (len(self.image_map) / 2.) ** 2: diff --git a/fluxclient/laser/laser_bitmap.py b/fluxclient/laser/laser_bitmap.py index 4660de7..389c34a 100755 --- a/fluxclient/laser/laser_bitmap.py +++ b/fluxclient/laser/laser_bitmap.py @@ -96,6 +96,8 @@ def gcode_generate(self, res=1): ######################## fake code #################################### if environ.get("flux_debug") == '1': self.dump('./preview.png') + with open('output.gcode', 'w') as f: + print(gcode, file=f) ####################################################################### return gcode From 547067b7ffcca9fad02a4a98169eb839871c230f Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 4 Jan 2016 17:40:05 +0800 Subject: [PATCH 40/53] fix bug(should resize pix before put white frame on it) --- fluxclient/laser/laser_base.py | 44 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/fluxclient/laser/laser_base.py b/fluxclient/laser/laser_base.py index e500b8d..22df475 100755 --- a/fluxclient/laser/laser_base.py +++ b/fluxclient/laser/laser_base.py @@ -223,8 +223,11 @@ def rotate(x, y, rotation, cx=0., cy=0.): ox1, oy1 = rotate(x1, y1, -rotation, cx, cy) ox3, oy3 = rotate(x2, y2, -rotation, cx, cy) + # 1 4 + # 2 3 ox2, oy2 = ox1, oy3 ox4, oy4 = ox3, oy1 + pix = pix.resize(tuple(map(lambda x: int(x * self.pixel_per_mm), ((ox3 - ox1), (oy1 - oy3))))) # rotate four corner ox1, oy1 = rotate(ox1, oy1, rotation, cx, cy) @@ -235,6 +238,7 @@ def rotate(x, y, rotation, cx=0., cy=0.): # find upper-left corner after rotation(edge) gx1 = min(ox1, ox2, ox3, ox4) gy1 = max(oy1, oy2, oy3, oy4) + gy1_on_map = round((gx1 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.)) gx1_on_map = round(-(gy1 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.)) @@ -243,44 +247,38 @@ def rotate(x, y, rotation, cx=0., cy=0.): gy2_on_map = round((gx2 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.)) gx2_on_map = round(-(gy2 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.)) - # shrink size if image too big, to avoid white frame disappear - if pix.size[0] >= len(self.image_map) or pix.size[1] >= len(self.image_map): - if pix.size[0] >= pix.size[1]: - new_size = (len(self.image_map), len(self.image_map) * pix.size[1] // pix.size[0]) - else: - new_size = (len(self.image_map) * pix.size[0] // pix.size[1], len(self.image_map)) - pix = pix.resize(new_size) - # add white frame on each side new_pix = Image.new('L', (pix.size[0] + 2, pix.size[1] + 2), 255) new_pix.paste(pix, (1, 1)) new_pix = new_pix.rotate(degrees(rotation), expand=1) - new_pix = new_pix.resize((gy2_on_map - gy1_on_map, gx2_on_map - gx1_on_map)) for h in range(new_pix.size[1]): # using white frame to find starting and ending index # find_start, find_end for each row - flag = False # whether find white frame + flag1 = False # whether find white frame for find_s in range(new_pix.size[0]): - if new_pix.getpixel((find_s, h)) == 255: # check this thres? + if new_pix.getpixel((find_s, h)) > 0: # check this thres? find_s = find_s + 1 - flag = True + flag1 = True break - if not flag: - find_s = 0 - flag = False + flag2 = False for find_e in range(new_pix.size[0] - 1, -1, -1): - if new_pix.getpixel((find_e, h)) == 255: - flag = True + if new_pix.getpixel((find_e, h)) > 0: + find_e = find_e + flag2 = True break - if not flag or find_e < find_s: # only one white point in this row(cause by resizing) - find_e = new_pix.size[0] - for w in range(find_s, find_e): - if (gx1_on_map + h - len(self.image_map) / 2.) ** 2 + (gy1_on_map + w - len(self.image_map) / 2.) ** 2 < (len(self.image_map) / 2.) ** 2: - if new_pix.getpixel((w, h)) <= thres: - self.image_map[gx1_on_map + h][gy1_on_map + w] = new_pix.getpixel((w, h)) + # only one white point in this row(cause by resizing) + # if find_e < find_s and abs(h - (new_pix.size[1] / 2)) > 1: + # find_e = new_pix.size[0] + + # NOTE: flag1 always equal to flag2 + if flag1: # at least one white point in this row + for w in range(find_s, find_e): + if (gx1_on_map + h - len(self.image_map) / 2.) ** 2 + (gy1_on_map + w - len(self.image_map) / 2.) ** 2 < (len(self.image_map) / 2.) ** 2: + if new_pix.getpixel((w, h)) <= thres: + self.image_map[gx1_on_map + h][gy1_on_map + w] = new_pix.getpixel((w, h)) def dump(self, file_name='', mode='save'): """ From 8e439723e4a8dec1410e7764190295cc9c5c7392 Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 4 Jan 2016 17:55:31 +0800 Subject: [PATCH 41/53] only record setting when using printing gcode --- fluxclient/fcode/g_to_f.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxclient/fcode/g_to_f.py b/fluxclient/fcode/g_to_f.py index 3fe78f9..4e06836 100644 --- a/fluxclient/fcode/g_to_f.py +++ b/fluxclient/fcode/g_to_f.py @@ -329,7 +329,8 @@ def process(self, input_stream, output_stream): self.md['TIME_COST'] = str(self.time_need) self.md['CREATED_AT'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(time.time())) self.md['AUTHOR'] = getuser() # TODO: use fluxstudio user name? - self.md['SETTING'] = str(comment_list[-130:]) + if self.md['HEAD_TYPE'] == 'EXTRUDER': + self.md['SETTING'] = str(comment_list[-130:]) self.write_metadata(output_stream) except Exception as e: print('FcodeError:', file=sys.stderr) From bb5e01a72a5e28f521e887ded322a5e69f107901 Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 4 Jan 2016 18:20:30 +0800 Subject: [PATCH 42/53] flux_raft.py: first draft --- fluxclient/printer/flux_raft.py | 347 ++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 fluxclient/printer/flux_raft.py diff --git a/fluxclient/printer/flux_raft.py b/fluxclient/printer/flux_raft.py new file mode 100644 index 0000000..59240ab --- /dev/null +++ b/fluxclient/printer/flux_raft.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python3 +import sys +import time +import math +import re +from queue import Queue +from math import ceil, sqrt + +import numpy as np + + +class Raft(): + def __init__(self): + self.move_re = re.compile(r"G1 ?([XYZEF] ?\-?\d+\.?\d+)?([XYZEF] ?\-?\d+\.?\d+)?([XYZEF] ?\-?\d+\.?\d+)?([XYZEF] ?\-?\d+\.?\d+)?") + self.axis_re = re.compile(r"([XYZEF]) ?(\-?\d+\.?\d+)") + self.extrusion = 0.0759617 * 0.8 + self.line_width = 0.4 + self.resolution = 0.3 + self.first_layer = 0.3 + self.layer_height = 0.2 + self.count = 3 + self.z_space = 0.12 + self.width = ceil(172 / self.resolution) + self.grid = [[]] + + def print_start_gcode(self): + code = """M107 ; disable fan +M104 S220 ; set temperature +G28 ; home all axes +G1 Z5 F5000 ; lift nozzle + +M109 S200 ; wait for temperature to be reached +G21 ; set units to millimeters +G90 ; use absolute coordinates +M82 ; use absolute distances for extrusion +G92 E0 ; reset extrusion distance +G1 Z0.3 F9000.000 ; move to next layer (0) +G1 E-2.00000 F2400.00000 ; retract +G92E0 +G1 F1800 +""" + + print(code) + + def process(self, gcode, debug=True): + #Process all gcode on first few layers, and fill the grid, skip skirt... + self.grid = self.fill_grid(gcode) + #Select all connected islands, find the edge points at each one + islands = self.find_islands() + print(";Islands found %d" % len(islands), file=sys.stderr) + #Print start gcode + self.print_start_gcode() + #Print raft gcode + raft_gcode = self.generate_gcode(islands) + #Debug output + if debug: + self.output_grid() + #Print other gcode ( uplift Z by elf.count*self.layer_height+self.z_space ) + skip = 15 + for line in gcode: + #Skip first 15 lines + if skip > 0: + skip = skip - 1 + continue + #Lift Z + line = re.sub("Z ?(-?[\d.]+)", self.z_rep, line) + print(line, end="") + + def z_rep(self, matchobj): + z_old = float(matchobj.group(1)) + return "Z" + str(z_old + self.count * self.layer_height + self.z_space) + + def generate_gcode(self, islands): + island_id = 0 + for island in islands: + island_id = island_id + 1 + print(";Island #%d" % island_id) + edge = island + + x = edge[0][0] + y = edge[0][1] + last_point = [0, 0] + + sorted_edge = [[x, y]] + + #Traverse the edge + while len(edge) > 0: + if self.is_edge(edge, x - 1, y): + x = x - 1 + elif self.is_edge(edge, x + 1, y): + x = x + 1 + elif self.is_edge(edge, x, y - 1): + y = y - 1 + elif self.is_edge(edge, x, y + 1): + y = y + 1 + elif self.is_edge(edge, x - 1, y - 1): + (x, y) = (x - 1, y - 1) + elif self.is_edge(edge, x + 1, y + 1): + (x, y) = (x + 1, y + 1) + elif self.is_edge(edge, x + 1, y - 1): + (x, y) = (x + 1, y - 1) + elif self.is_edge(edge, x - 1, y + 1): + (x, y) = (x - 1, y + 1) + + if last_point[0] == x and last_point[1] == y: + x = edge[0][0] + y = edge[0][1] + continue + else: + edge.remove([x, y]) + + self.grid[x][y] = 4 + last_point = [x, y] + sorted_edge.append([x, y]) + + #Outline of raft + print("G92 E0") + print("G1 Z%lf" % self.first_layer) + + extruded = 0 + (x_min, y_min, x_max, y_max) = (999999, 999999, -1, -1) + last_point = [0, 0] + for pt in sorted_edge: + if x_min > pt[0]: + x_min = pt[0] + if x_max < pt[0]: + x_max = pt[0] + if y_min > pt[1]: + y_min = pt[1] + if y_max < pt[1]: + y_max = pt[1] + + x = self.m2g(pt[0]) + y = self.m2g(pt[1]) + + if last_point[0] == 0 and last_point[1] == 0: + last_point = [x, y] + + e = self.dist(last_point[0], last_point[1], x, y) * self.extrusion + extruded = extruded + e + + last_point = [x, y] + print("G1X%lfY%lfE%lf" % (x, y, extruded)) + + #Infill of raft + horizontal_lines = abs(ceil((y_max - y_min) * self.resolution / self.line_width)) + vertical_lines = abs(ceil((x_max - x_min) * self.resolution / self.line_width)) + + print("Lines / Horizontal %lf Vertical %lf" % (horizontal_lines, vertical_lines), file=sys.stderr) + print("Xmin %lf Xmax %lf Ymin %lf Ymax %lf" % (x_min, x_max, y_min, y_max), file=sys.stderr) + width = len(self.grid) + + for l in range(0, self.count): + print("G1 Z%lf" % (self.first_layer + l * self.layer_height)) + if l % 2 == 0: + for r in range(0, horizontal_lines): + y = self.g2m(self.m2g(y_min) + self.line_width * r) + range_of_x = range(0, width) + if r % 2 == 1: + range_of_x = reversed(range_of_x) + + inside = False + fill_start = 0 + for x in range_of_x: + if self.grid[x][y] > 0 and not inside: + inside = True + fill_start = self.m2g(x) + elif self.grid[x][y] == 0 and inside: + e = abs(self.m2g(x) - fill_start) * self.extrusion + extruded = extruded + e + + print("G1 X%lf Y%lf ; H line" % (fill_start, self.m2g(y))) + print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded)) + inside = False + else: + for r in range(0, vertical_lines): + x = self.g2m(self.m2g(x_min) + self.line_width * r) + range_of_y = range(0, width) + if r % 2 == 1: + range_of_y = reversed(range_of_y) + + inside = False + fill_start = 0 + for y in range_of_y: + if self.grid[x][y] > 0 and not inside: + inside = True + fill_start = self.m2g(y) + elif self.grid[x][y] == 0 and inside: + e = abs(self.m2g(y) - fill_start) * self.extrusion + extruded = extruded + e + + print("G1 X%lf Y%lf ; V line" % (self.m2g(x), fill_start)) + print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded)) + inside = False + + def is_edge(self, edge, x, y): + if [x, y] in edge and self.check_grid(x, y) == 3: + return True + else: + return False + + def dist(self, x, y, x2, y2): + return sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)) + + def m2g(self, val): + return (val - ceil(86 / self.resolution)) * self.resolution + + def g2m(self, val): + return round(val / self.resolution) + ceil(86 / self.resolution) + + def check_grid(self, x, y): + if x >= 0 and y >= 0 and x < self.width and y < self.width: + return self.grid[x][y] + return 0 + + def fill_grid(self, gcode): + self.grid = np.zeros((ceil(172 / self.resolution), ceil(172 / self.resolution))) + self.width = ceil(172 / self.resolution) + print("Grid size %d^2" % len(self.grid), file=sys.stderr) + x = y = z = 0 + expansion = self.expansion / self.resolution + last_point = [0, 0] + min_division = self.resolution * expansion / 10.0 + for ln in range(0, len(gcode)): + line = gcode[ln] + if "skirt" in line: + continue + if z > 2: + print("Gcode parsing end", file=sys.stderr) + break + if self.move_re.match(line): + for (axis, number) in self.axis_re.findall(line): + if axis == 'X': + x = float(number) + if axis == 'Y': + y = float(number) + if axis == 'Z': + z = float(number) + + if (x - last_point[0]) * (x - last_point[0]) + (y - last_point[1]) * (y - last_point[1]) > min_division * min_division: + denom = int(ceil(sqrt((x - last_point[0]) * (x - last_point[0]) + (y - last_point[1]) * (y - last_point[1])) / min_division)) + for numer in range(0, denom + 1): + lx = last_point[0] + (x - last_point[0]) * numer / denom + ly = last_point[1] + (y - last_point[1]) * numer / denom + (rx, ry) = (self.g2m(lx), self.g2m(ly)) + self.fill_circle(rx, ry, 0, 0, expansion * expansion) + else: + (rx, ry) = (self.g2m(x), self.g2m(y)) + self.fill_circle(rx, ry, 0, 0, expansion * expansion) + + last_point = [x, y] + + return self.grid + + def fill_circle(self, rx, ry, x, y, r): + Q = Queue() + Q.put([x, y]) + while not Q.empty(): + n = Q.get() + (x, y) = n + if x * x + y * y < r: + if rx + x >= 0 and ry + y >= 0 and rx + x < self.width and ry + y < self.width and self.grid[rx + x][ry + y] == 0: + self.grid[rx + x][ry + y] = 1 + Q.put([x - 1, y]) + Q.put([x + 1, y]) + Q.put([x, y - 1]) + Q.put([x, y + 1]) + + #find all connected islands + def find_islands(self): + islands = [] + #iterate all points on grid + for x in range(0, self.width): + for y in range(0, self.width): + if self.grid[x][y] == 1: + edge = [] + self.find_all_connected_points(edge, x, y) + islands.append(edge) + + return islands + + #flood grouping + def find_all_connected_points(self, edge, x, y): + grid = self.grid + width = len(self.grid) + Q = Queue() + if x >= width or y >= width or x < 0 or y < 0: + return + if self.grid[x][y] != 1: + return + + Q.put([x, y]) + + while not Q.empty(): + n = Q.get() + (x, y) = n + + if self.grid[x][y] == 1: + #Edge detection + #If surrounded by filled area, then it's not + if self.check_grid(x, y - 1) > 0 and self.check_grid(x - 1, y) > 0 and self.check_grid(x + 1, y) > 0 and self.check_grid(x, y + 1) > 0: + self.grid[x][y] = 2 + else: # n is on edge + edge.append([x, y]) + self.grid[x][y] = 3 + if self.check_grid(x - 1, y) == 1: + Q.put([x - 1, y]) + if self.check_grid(x + 1, y) == 1: + Q.put([x + 1, y]) + if self.check_grid(x, y - 1) == 1: + Q.put([x, y - 1]) + if self.check_grid(x, y + 1) == 1: + Q.put([x, y + 1]) + + #debug tool + def output_grid(self): + from PIL import Image + im = np.zeros((self.width, self.width, 3)) + for x in range(0, self.width): + for y in range(0, self.width): + if self.grid[x][y] == 1: + im[x][y] = [0, 255, 0] + elif self.grid[x][y] == 2: + im[x][y] = [0, 0, 255] + elif self.grid[x][y] == 3: + im[x][y] = [255, 0, 0] + elif self.grid[x][y] == 4: + im[x][y] = [0, 128, 255] + else: + im[x][y] = [255, 255, 255] + + Image.fromarray(im.astype(np.uint8)).save("grid.png") + +if __name__ == '__main__': + #Read gcode + fname = sys.argv[1] + gcode = [] + with open(fname) as f: + gcode = f.readlines() + + raft = Raft() + raft.resolution = 0.5 + raft.expansion = 10 # flux only param : equals to raft exapansion + raft.first_layer = 0.3 # equal to first layer height + raft.layer_height = 0.2 # equal to layer height + raft.count = 3 # equal to raft layers + raft.process(gcode) From 924936ed0e7dbb2d2c1e3cc811570e400d02aeac Mon Sep 17 00:00:00 2001 From: Yen Date: Mon, 4 Jan 2016 21:54:43 +0800 Subject: [PATCH 43/53] #949: custom raft --- fluxclient/printer/__init__.py | 4 ++- fluxclient/printer/flux_raft.py | 50 ++++++++++++++++++-------------- fluxclient/printer/stl_slicer.py | 11 +++++++ 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index edff991..cc21a55 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -215,7 +215,8 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( xy_size_compensation = 0 z_offset = 0 flux_refill_empty = 0 -flux_first_layer = 0''' +flux_first_layer = 0 +flux_raft = 0''' ini_constraint = { 'avoid_crossing_perimeters': [binary], @@ -350,4 +351,5 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'z_offset': [float_range, 0, 23.5], 'flux_refill_empty': [binary], 'flux_first_layer': [binary], + 'flux_raft': [binary], } diff --git a/fluxclient/printer/flux_raft.py b/fluxclient/printer/flux_raft.py index 59240ab..c07b9c9 100644 --- a/fluxclient/printer/flux_raft.py +++ b/fluxclient/printer/flux_raft.py @@ -3,6 +3,7 @@ import time import math import re +import os from queue import Queue from math import ceil, sqrt @@ -22,6 +23,7 @@ def __init__(self): self.z_space = 0.12 self.width = ceil(172 / self.resolution) self.grid = [[]] + self.gcode = [] def print_start_gcode(self): code = """M107 ; disable fan @@ -39,10 +41,9 @@ def print_start_gcode(self): G92E0 G1 F1800 """ + print(code, file=self.output_stream) - print(code) - - def process(self, gcode, debug=True): + def process(self, gcode, debug=False): #Process all gcode on first few layers, and fill the grid, skip skirt... self.grid = self.fill_grid(gcode) #Select all connected islands, find the edge points at each one @@ -64,7 +65,7 @@ def process(self, gcode, debug=True): continue #Lift Z line = re.sub("Z ?(-?[\d.]+)", self.z_rep, line) - print(line, end="") + print(line, end="", file=self.output_stream) def z_rep(self, matchobj): z_old = float(matchobj.group(1)) @@ -74,7 +75,7 @@ def generate_gcode(self, islands): island_id = 0 for island in islands: island_id = island_id + 1 - print(";Island #%d" % island_id) + print(";Island #%d" % island_id, file=self.output_stream) edge = island x = edge[0][0] @@ -114,8 +115,8 @@ def generate_gcode(self, islands): sorted_edge.append([x, y]) #Outline of raft - print("G92 E0") - print("G1 Z%lf" % self.first_layer) + print("G92 E0", file=self.output_stream) + print("G1 Z%lf" % self.first_layer, file=self.output_stream) extruded = 0 (x_min, y_min, x_max, y_max) = (999999, 999999, -1, -1) @@ -140,7 +141,7 @@ def generate_gcode(self, islands): extruded = extruded + e last_point = [x, y] - print("G1X%lfY%lfE%lf" % (x, y, extruded)) + print("G1X%lfY%lfE%lf" % (x, y, extruded), file=self.output_stream) #Infill of raft horizontal_lines = abs(ceil((y_max - y_min) * self.resolution / self.line_width)) @@ -151,7 +152,7 @@ def generate_gcode(self, islands): width = len(self.grid) for l in range(0, self.count): - print("G1 Z%lf" % (self.first_layer + l * self.layer_height)) + print("G1 Z%lf" % (self.first_layer + l * self.layer_height), file=self.output_stream) if l % 2 == 0: for r in range(0, horizontal_lines): y = self.g2m(self.m2g(y_min) + self.line_width * r) @@ -169,8 +170,8 @@ def generate_gcode(self, islands): e = abs(self.m2g(x) - fill_start) * self.extrusion extruded = extruded + e - print("G1 X%lf Y%lf ; H line" % (fill_start, self.m2g(y))) - print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded)) + print("G1 X%lf Y%lf ; H line" % (fill_start, self.m2g(y)), file=self.output_stream) + print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded), file=self.output_stream) inside = False else: for r in range(0, vertical_lines): @@ -189,8 +190,8 @@ def generate_gcode(self, islands): e = abs(self.m2g(y) - fill_start) * self.extrusion extruded = extruded + e - print("G1 X%lf Y%lf ; V line" % (self.m2g(x), fill_start)) - print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded)) + print("G1 X%lf Y%lf ; V line" % (self.m2g(x), fill_start), file=self.output_stream) + print("G1 X%lf Y%lf E%lf" % (self.m2g(x), self.m2g(y), extruded), file=self.output_stream) inside = False def is_edge(self, edge, x, y): @@ -331,17 +332,24 @@ def output_grid(self): Image.fromarray(im.astype(np.uint8)).save("grid.png") + def main(self, gcode, output_stream, debug): + if type(gcode) == str: + with open(gcode) as f: + gcode = f.readlines() + self.output_stream = output_stream + + self.resolution = 0.5 + self.expansion = 10 # flux only param : equals to raft exapansion + self.first_layer = 0.3 # equal to first layer height + self.layer_height = 0.2 # equal to layer height + self.count = 3 # equal to raft layers + self.process(gcode) + + if __name__ == '__main__': #Read gcode fname = sys.argv[1] - gcode = [] with open(fname) as f: gcode = f.readlines() - raft = Raft() - raft.resolution = 0.5 - raft.expansion = 10 # flux only param : equals to raft exapansion - raft.first_layer = 0.3 # equal to first layer height - raft.layer_height = 0.2 # equal to layer height - raft.count = 3 # equal to raft layers - raft.process(gcode) + raft.main(gcode, output_stream=sys.stdout, debug=True) diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index b8ee724..873e75c 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -16,6 +16,7 @@ from fluxclient.fcode.g_to_f import GcodeToFcode from fluxclient.scanner.tools import dot, normal from fluxclient.printer import ini_string, ini_constraint, ignore +from fluxclient.printer.flux_raft import Raft def slicing_worker(command, config, image, ext_metadata, output_type, child_pipe): @@ -323,8 +324,18 @@ def gcode_generate(self, names, ws, output_type): if p.poll() != 0: fail_flag = True + # TODO: design a intermedia data structure for gcode and write a general preprocessor + if self.config['flux_raft'] == '1': + m_preprocessor = Raft() + raft_output = io.StringIO() + m_preprocessor.main(tmp_gcode_file, raft_output, debug=False) + raft_output = raft_output.getvalue() + with open(tmp_gcode_file, 'w') as f: + print(raft_output, file=f) + # analying gcode(even transform) ws.send_progress('analyzing metadata', 0.99) + fcode_output = io.BytesIO() with open(tmp_gcode_file, 'r') as f: m_GcodeToFcode = GcodeToFcode(ext_metadata=self.ext_metadata) From cebd825b775f7c4b0f73ab577f421de86288cb04 Mon Sep 17 00:00:00 2001 From: Yagami Cerberus Date: Tue, 5 Jan 2016 11:03:28 +0800 Subject: [PATCH 44/53] Increase version --- fluxclient/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxclient/__init__.py b/fluxclient/__init__.py index 259dde1..dcd94ac 100644 --- a/fluxclient/__init__.py +++ b/fluxclient/__init__.py @@ -7,5 +7,5 @@ def check_pcl(): return False -__version__ = "0.8b2" +__version__ = "0.8b3" SUPPORT_PCL = check_pcl() From 5fb7e13fca106c9e35a39ceffe3836879e0387aa Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 11:08:28 +0800 Subject: [PATCH 45/53] force close laser --- fluxclient/laser/laser_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxclient/laser/laser_base.py b/fluxclient/laser/laser_base.py index 22df475..7e9e5d7 100755 --- a/fluxclient/laser/laser_base.py +++ b/fluxclient/laser/laser_base.py @@ -61,7 +61,7 @@ def header(self, header): gcode.append(";" + i) # force close laser - self.laser_on = False + self.laser_on = True gcode += self.turnOff() # setting @@ -69,6 +69,7 @@ def header(self, header): # move to proper height gcode.append("G1 F5000 Z%.5f" % (self.focal_l + self.obj_height)) + return gcode def turnOn(self): From 43bdc50c78ef33cc84c6603d16988a026721abcd Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 11:15:48 +0800 Subject: [PATCH 46/53] test: deleting useless lib --- setup_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup_utils.py b/setup_utils.py index 88927e5..9280951 100644 --- a/setup_utils.py +++ b/setup_utils.py @@ -125,8 +125,7 @@ def create_scanner_extentions(): libraries += ["pcl_common", "pcl_octree", "pcl_io", "pcl_kdtree", "pcl_search", "pcl_sample_consensus", "pcl_filters", "pcl_features", "pcl_segmentation", "pcl_surface", - "pcl_registration", "pcl_keypoints", "pcl_tracking", - "pcl_recognition", "pcl_outofcore", "pcl_people", ] + "pcl_registration", "pcl_keypoints"] if has_package("pcl_common-1.8"): include_dirs += [locate_includes("pcl_common-1.8")] elif has_package("pcl_common-1.7"): From 531e0e862ea166c7e5a3c9ab9222f4da2bd7841a Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 13:36:19 +0800 Subject: [PATCH 47/53] #896: brute force solver, simply cut the bottom --- fluxclient/printer/__init__.py | 4 +- fluxclient/printer/stl_slicer.py | 2 +- src/printer/printer.pyx | 8 +- src/printer/printer_module.cpp | 194 +++++++++++++++++++++++-------- src/printer/printer_module.h | 1 + 5 files changed, 157 insertions(+), 52 deletions(-) diff --git a/fluxclient/printer/__init__.py b/fluxclient/printer/__init__.py index cc21a55..81fef69 100644 --- a/fluxclient/printer/__init__.py +++ b/fluxclient/printer/__init__.py @@ -216,7 +216,8 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( z_offset = 0 flux_refill_empty = 0 flux_first_layer = 0 -flux_raft = 0''' +flux_raft = 0 +flux_floor = -1''' ini_constraint = { 'avoid_crossing_perimeters': [binary], @@ -352,4 +353,5 @@ def float_or_percent(key, value, percent_start=float('-inf'), percent_end=float( 'flux_refill_empty': [binary], 'flux_first_layer': [binary], 'flux_raft': [binary], + 'flux_floor': [float_range, -1, 240], } diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 873e75c..0b59d47 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -250,6 +250,7 @@ def gcode_generate(self, names, ws, output_type): m_mesh = _printer.MeshObj(points, faces) m_mesh.apply_transform(self.parameter[n]) m_mesh_merge.add_on(m_mesh) + m_mesh_merge = m_mesh_merge.cut(float(self.config['flux_floor'])) bounding_box = m_mesh_merge.bounding_box() cx, cy = (bounding_box[0][0] + bounding_box[1][0]) / 2., (bounding_box[0][1] + bounding_box[1][1]) / 2. @@ -414,7 +415,6 @@ def begin_slicing(self, names, ws, output_type): tmp = tempfile.NamedTemporaryFile(suffix='.ini', delete=False) tmp_slic3r_setting_file = tmp.name # store gcode - ws.send_progress('merging', 0.2) m_mesh_merge = _printer.MeshObj([], []) for n in names: points, faces = self.read_stl(self.models[n]) diff --git a/src/printer/printer.pyx b/src/printer/printer.pyx index 685ef20..e0eaf4c 100644 --- a/src/printer/printer.pyx +++ b/src/printer/printer.pyx @@ -12,7 +12,8 @@ cdef extern from "printer_module.h": int add_on(MeshPtr base, MeshPtr new_mesh) int STL_to_List(MeshPtr triangles, vector[vector [vector [float]]] &data) int apply_transform(MeshPtr triangles, float x, float y, float z, float rx, float ry, float rz, float sc_x, float sc_y, float sc_z) - int bounding_box(MeshPtr triangles, vector[float] &b_box); + int bounding_box(MeshPtr triangles, vector[float] &b_box) + int cut(MeshPtr input_mesh, MeshPtr out_mesh, float floor_v) cdef class MeshObj: cdef MeshPtr meshobj @@ -32,6 +33,11 @@ cdef class MeshObj: def add_on(self, MeshObj new_mesh): add_on(self.meshobj, new_mesh.meshobj) + def cut(self, float floor_v): + out_mesh = MeshObj([], []) + cut(self.meshobj, out_mesh.meshobj, floor_v) + return out_mesh + cpdef write_stl(self, file_name, flag=None): cpdef vector[vector [vector [float]]] tri STL_to_List(self.meshobj, tri) diff --git a/src/printer/printer_module.cpp b/src/printer/printer_module.cpp index b621525..042fd18 100644 --- a/src/printer/printer_module.cpp +++ b/src/printer/printer_module.cpp @@ -1,8 +1,9 @@ #include - +#include #include "printer_module.h" + MeshPtr createMeshPtr(){ MeshPtr mesh(new pcl::PolygonMesh); return mesh; @@ -33,28 +34,28 @@ int push_backFace(MeshPtr triangles, int v0, int v1, int v2){ } int add_on(pcl::PolygonMesh::Ptr base, pcl::PolygonMesh::Ptr add_on_mesh){ - pcl::PointCloud::Ptr cloud (new pcl::PointCloud); - fromPCLPointCloud2(base->cloud, *cloud); - int size_to_add_on = cloud->size(); + pcl::PointCloud::Ptr cloud (new pcl::PointCloud); + fromPCLPointCloud2(base->cloud, *cloud); + int size_to_add_on = cloud->size(); - pcl::PointCloud::Ptr cloud2 (new pcl::PointCloud); - fromPCLPointCloud2(add_on_mesh->cloud, *cloud2); + pcl::PointCloud::Ptr cloud2 (new pcl::PointCloud); + fromPCLPointCloud2(add_on_mesh->cloud, *cloud2); // add cloud together - *cloud += *cloud2; + *cloud += *cloud2; - pcl::Vertices v; - v.vertices.resize(3); + pcl::Vertices v; + v.vertices.resize(3); // add faces, but shift the index for add on mesh - for (uint32_t i = 0; i < add_on_mesh->polygons.size(); i += 1){ - v.vertices[0] = add_on_mesh->polygons[i].vertices[0] + size_to_add_on; - v.vertices[1] = add_on_mesh->polygons[i].vertices[1] + size_to_add_on; - v.vertices[2] = add_on_mesh->polygons[i].vertices[2] + size_to_add_on; - base->polygons.push_back(v); - } + for (uint32_t i = 0; i < add_on_mesh->polygons.size(); i += 1){ + v.vertices[0] = add_on_mesh->polygons[i].vertices[0] + size_to_add_on; + v.vertices[1] = add_on_mesh->polygons[i].vertices[1] + size_to_add_on; + v.vertices[2] = add_on_mesh->polygons[i].vertices[2] + size_to_add_on; + base->polygons.push_back(v); + } - toPCLPointCloud2(*cloud, base->cloud); - return 0; + toPCLPointCloud2(*cloud, base->cloud); + return 0; } int bounding_box(MeshPtr triangles, std::vector &b_box){ @@ -199,9 +200,104 @@ int apply_transform(MeshPtr triangles, float x, float y, float z, float rx, floa toPCLPointCloud2(*cloud, triangles->cloud); return 0; +} + +int find_intersect(pcl::PointXYZ a, pcl::PointXYZ b, float floor_v, pcl::PointXYZ &p){ + // find the intersect between line a, b and plane z=floor_v + std::vector v(3); // vetor a->b + v[0] = b.x - a.x; + v[1] = b.y - a.y; + v[2] = b.z - a.z; + + float t = (floor_v - a.z) / v[2]; + p.x = a.x + t * v[0]; + p.y = a.y + t * v[1]; + p.z = a.z + t * v[2]; + return 0; +} + + +int cut(MeshPtr input_mesh, MeshPtr out_mesh, float floor_v){ + pcl::PointCloud::Ptr cloud (new pcl::PointCloud); + fromPCLPointCloud2(input_mesh->cloud, *cloud); + + pcl::Vertices v; + v.vertices.resize(3); + pcl::Vertices on, under; + // consider serveral case + + for (uint32_t i = 0; i < input_mesh->polygons.size(); i += 1){ + // on.vertices.clear(); + // under.vertices.clear(); + pcl::Vertices on, under; + for (uint32_t j = 0; j < 3; j += 1){ + + if ((*cloud)[input_mesh->polygons[i].vertices[j]].z <= floor_v){ + under.vertices.push_back(input_mesh->polygons[i].vertices[j]); + } + else{ + on.vertices.push_back(input_mesh->polygons[i].vertices[j]); + } + } + + if(on.vertices.size() == 3){ + out_mesh->polygons.push_back(on); + } + else if(under.vertices.size() == 3){ + // do nothing + } + else if(under.vertices.size() == 2){ + pcl::PointXYZ upper_p; + upper_p = (*cloud)[on.vertices[0]]; + for (int j = 0; j < 2; j += 1){ + pcl::PointXYZ lower_p, new_p; + lower_p = (*cloud)[under.vertices[j]]; + find_intersect(upper_p, lower_p, floor_v, new_p); + cloud -> push_back(new_p); + on.vertices.push_back(cloud -> size() - 1); + } + out_mesh->polygons.push_back(on); + } + else if(under.vertices.size() == 1){ + pcl::PointXYZ mid; + mid.x = ((*cloud)[on.vertices[0]].x + (*cloud)[on.vertices[1]].x) / 2; + mid.y = ((*cloud)[on.vertices[0]].y + (*cloud)[on.vertices[1]].y) / 2; + mid.z = ((*cloud)[on.vertices[0]].z + (*cloud)[on.vertices[1]].z) / 2; + cloud -> push_back(mid); + int mid_index = cloud -> size() - 1; + + pcl::PointXYZ intersect0, intersect1; + find_intersect((*cloud)[on.vertices[0]], (*cloud)[under.vertices[0]], floor_v, intersect0); + cloud -> push_back(intersect0); + int intersect0_index = cloud -> size() - 1; + find_intersect((*cloud)[on.vertices[1]], (*cloud)[under.vertices[0]], floor_v, intersect1); + cloud -> push_back(intersect1); + int intersect1_index = cloud -> size() - 1; + + pcl::Vertices v1, v2, v3; + v1.vertices.push_back(on.vertices[0]); + v1.vertices.push_back(intersect0_index); + v1.vertices.push_back(mid_index); + out_mesh->polygons.push_back(v1); + + v2.vertices.push_back(mid_index); + v2.vertices.push_back(intersect0_index); + v2.vertices.push_back(intersect1_index); + out_mesh->polygons.push_back(v2); + + v3.vertices.push_back(mid_index); + v3.vertices.push_back(intersect1_index); + v3.vertices.push_back(on.vertices[1]); + out_mesh->polygons.push_back(v3); + } + } - int STL_to_List(MeshPtr triangles, std::vector > > &data){ + toPCLPointCloud2(*cloud, out_mesh->cloud); + return 0; +} + +int STL_to_List(MeshPtr triangles, std::vector > > &data){ // point's data // data =[ // t1[p1[x, y, z], p2[x, y, z], p3[x, y, z]], @@ -209,49 +305,49 @@ int apply_transform(MeshPtr triangles, float x, float y, float z, float rx, floa // t3[p1[x, y, z], p2[x, y, z], p3[x, y, z]], // ... // ] - pcl::PointCloud::Ptr cloud (new pcl::PointCloud); - fromPCLPointCloud2(triangles->cloud, *cloud); + pcl::PointCloud::Ptr cloud (new pcl::PointCloud); + fromPCLPointCloud2(triangles->cloud, *cloud); - int v0, v1, v2; + int v0, v1, v2; - std::vector tmpvv(3, 0.0); - std::vector< std::vector > tmpv(3, tmpvv); - data.resize(triangles->polygons.size()); + std::vector tmpvv(3, 0.0); + std::vector< std::vector > tmpv(3, tmpvv); + data.resize(triangles->polygons.size()); - for (size_t i = 0; i < triangles->polygons.size(); i += 1){ - data[i] = tmpv; + for (size_t i = 0; i < triangles->polygons.size(); i += 1){ + data[i] = tmpv; - v0 = triangles->polygons[i].vertices[0]; - v1 = triangles->polygons[i].vertices[1]; - v2 = triangles->polygons[i].vertices[2]; + v0 = triangles->polygons[i].vertices[0]; + v1 = triangles->polygons[i].vertices[1]; + v2 = triangles->polygons[i].vertices[2]; - data[i][0][0] = (*cloud)[v0].x; - data[i][0][1] = (*cloud)[v0].y; - data[i][0][2] = (*cloud)[v0].z; + data[i][0][0] = (*cloud)[v0].x; + data[i][0][1] = (*cloud)[v0].y; + data[i][0][2] = (*cloud)[v0].z; - data[i][1][0] = (*cloud)[v1].x; - data[i][1][1] = (*cloud)[v1].y; - data[i][1][2] = (*cloud)[v1].z; + data[i][1][0] = (*cloud)[v1].x; + data[i][1][1] = (*cloud)[v1].y; + data[i][1][2] = (*cloud)[v1].z; - data[i][2][0] = (*cloud)[v2].x; - data[i][2][1] = (*cloud)[v2].y; - data[i][2][2] = (*cloud)[v2].z; + data[i][2][0] = (*cloud)[v2].x; + data[i][2][1] = (*cloud)[v2].y; + data[i][2][2] = (*cloud)[v2].z; // std::cout << " polygons[" << i << "]: " < > &data){ +int STL_to_Faces(MeshPtr triangles, std::vector< std::vector > &data){ // index of faces // data = [ f1[p1_index, p2_index, p3_index], // f2[p1_index, p2_index, p3_index], ... // ] - data.resize(triangles->polygons.size()); - for (size_t i = 0; i < triangles->polygons.size(); i += 1){ - data[i].resize(3); - data[i][0] = triangles->polygons[i].vertices[0]; - data[i][1] = triangles->polygons[i].vertices[1]; - data[i][2] = triangles->polygons[i].vertices[2]; - } - return 0; + data.resize(triangles->polygons.size()); + for (size_t i = 0; i < triangles->polygons.size(); i += 1){ + data[i].resize(3); + data[i][0] = triangles->polygons[i].vertices[0]; + data[i][1] = triangles->polygons[i].vertices[1]; + data[i][2] = triangles->polygons[i].vertices[2]; } + return 0; +} diff --git a/src/printer/printer_module.h b/src/printer/printer_module.h index fd950c1..e596949 100644 --- a/src/printer/printer_module.h +++ b/src/printer/printer_module.h @@ -17,3 +17,4 @@ int STL_to_List(MeshPtr triangles, std::vector > int apply_transform(MeshPtr triangles, float x, float y, float z, float rx, float ry, float rz, float sc_x, float sc_y, float sc_z); int bounding_box(MeshPtr triangles, std::vector &b_box); int bounding_box(pcl::PointCloud::Ptr cloud, std::vector &b_box); +int cut(MeshPtr input_mesh, MeshPtr out_mesh, float floor_v); From 6be29b2ab8a108404215dde187f75bbbda934dbd Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 13:53:31 +0800 Subject: [PATCH 48/53] same as 43bdc50c78ef33cc84c6603d16988a026721abcd --- setup_utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup_utils.py b/setup_utils.py index 9280951..6de4062 100644 --- a/setup_utils.py +++ b/setup_utils.py @@ -145,9 +145,7 @@ def create_scanner_extentions(): "pcl_search_release", "pcl_sample_consensus_release", "pcl_filters_release", "pcl_features_release", "pcl_segmentation_release", "pcl_surface_release", - "pcl_registration_release", "pcl_keypoints_release", - "pcl_tracking_release", "pcl_recognition_release", - "pcl_outofcore_release", "pcl_people_release"] + "pcl_registration_release", "pcl_keypoints_release"] include_dirs += ["C:/Program Files (x86)/Eigen/include", "C:/Program Files (x86)/flann/include", "C:/Program Files/Eigen/include", From 885bc9ee7b0b75d47367fe24b3e1dad833d09102 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 15:49:08 +0800 Subject: [PATCH 49/53] error handling for non-stl file --- fluxclient/printer/stl_slicer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 0b59d47..4d7a922 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -246,7 +246,10 @@ def gcode_generate(self, names, ws, output_type): ws.send_progress('merging', 0.2) m_mesh_merge = _printer.MeshObj([], []) for n in names: - points, faces = self.read_stl(self.models[n]) + try: + points, faces = self.read_stl(self.models[n]) + except: + return False, 'can\'t parse %s,may not ba a stl file' % (n) m_mesh = _printer.MeshObj(points, faces) m_mesh.apply_transform(self.parameter[n]) m_mesh_merge.add_on(m_mesh) From fc3bdea55e22c7e39466c6f10f10ca02f0a779df Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 15:59:48 +0800 Subject: [PATCH 50/53] strip slicer error log minor --- fluxclient/printer/stl_slicer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 4d7a922..bf97528 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -249,7 +249,7 @@ def gcode_generate(self, names, ws, output_type): try: points, faces = self.read_stl(self.models[n]) except: - return False, 'can\'t parse %s,may not ba a stl file' % (n) + return False, 'can\'t parse %s, may not ba a stl file' % (n) m_mesh = _printer.MeshObj(points, faces) m_mesh.apply_transform(self.parameter[n]) m_mesh_merge.add_on(m_mesh) @@ -324,7 +324,7 @@ def gcode_generate(self, names, ws, output_type): ws.send_progress((line.rstrip())[3:], progress) elif "Unable to close this loop" in line: slic3r_error = True - slic3r_out = line + slic3r_out = line.strip() if p.poll() != 0: fail_flag = True From 0a8edc00a9b7f5aeb5737a46a60f6f325bfd1cc7 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 16:36:58 +0800 Subject: [PATCH 51/53] use pkg_resources to access static file data, deprecate the stupid bytes array minor --- fluxclient/laser/__init__.py | 1 - fluxclient/laser/laser_base.py | 7 +++---- fluxclient/printer/stl_slicer.py | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/fluxclient/laser/__init__.py b/fluxclient/laser/__init__.py index 06dba2f..e69de29 100644 --- a/fluxclient/laser/__init__.py +++ b/fluxclient/laser/__init__.py @@ -1 +0,0 @@ -Grid = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x07\xa6\x00\x00\x07\xa6\x08\x02\x00\x00\x003vH-\x00\x00\x00\tpHYs\x00\x00\x17\x12\x00\x00\x17\x12\x01g\x9f\xd2R\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\xc9e<\x00\x01\x0f\xacZ\xad^\xb8P\xfd\xc1\x0f~\xf0\xca+\xaf\x84#ozS\xdf\xff\xfc\x9f\xaf?\xe0\xado}\xeb\xca\xff\xa3\x89\xc4\xc0\x15\x1f\xb3m\xdb\xb6h4\xea\x7f\x10\x00\x00,\xf6\xa6\xb3g\x9fU\x05\x00\x00\xbaF=\x80\xbe\xf0\xc6\x9b\xd5\xe6\x07T*s\xaf\xbeZk\x1e\xa9\xd5j\x95J\xa5\x0b\xfe\xed\x91H$\x16\x8b\xb5\x0c\xc6\xe3\xf1`\xbc\xf91\xf1x\xac\xe9\xe6\x8f4\xdf\x04\x00\x80N\'\xf2\x06\x00\xa0\xad\x9d;w\xee\xc5\x17_\xbc\xae\xaeT*7\xc6K\xa5R\xe3\xb8\\.+\xd4\x9a\x88\xc5b\xd7_\x7f\xfd\x0f~\xf0\x83\xe0\xf8mo{\xdb\xbb\xde\xb5\xfd\xfa\xeb\xfb\xfb.\xe6\xe6\xb1Fn\x9eH$\x14\n\x00\x80\xb6%\xf2\x06\x00`s4\x96c7\x16b\xd7\x07.\xad\xc8\xee\x94\x14\xbb\xb1\xb0\xfa\xb5\xd7^;w\xee\xdc\x92\x8fy\xf7\xbb\xdf\xbd\xc2\x82\x04:\xe8\xff`\xb4.8\xf8\x91\x1f\t\x8a\x10\x0f\x07\x1b\x8dY$\xe3\x00\x00l\n\x917\x00\x00\xebbn\xaeR\xab\xbd\xdawq9\xf6\xc5\xf0\xba\xd1\x17{\x83\x83\xdd\x81\x817\xb4\xc6\xae7\xc1\xde\xd6\xf2\x98\xcb\xb5\xcf\xbe\xaa\xd0\xf6\xb9\xe7\xfe\xbf\x13\'N,y\xd7\xbf\xff\xf7\xff\xc7z\x14v\xa9\xf1\xd6\x86--\xbd\xc87>Uo|$\xd0\x88\xc5\xeb\xff\x0b\xa2}2q\x00\x00\xd6\x87\xed+\x01\x00X\xa5p\x99v=W\xbd\xd8\x08;\xec\x91\xbd~}\xb1\x1bk\x8a\xfb\xde\xd8\x9f\xba\x11\xa1\x86\xba>H\xbd\\\xeb\xedU\xfc\xc3\x9b\xd3\xf3\xc6\xff\xc7W\xea\x9e\x7f\xfe\xf9\xe0\xb8\xbf\xbf\xff\x07?\xf8\xc1\xb5\xfc\x0f\r\xfe\xda\xc6\x82\xfdbqv\x99\xff\xad\xe1\xcf/\x10\x07\x00\xe0\x1a\x89\xbc\x01\x00XNs\xae\xddX5\\\xa9\xb4.(^\xb5\xe6\x1d\x17\x1b)g\xd89\xfa\xa5\x97\xfe\xe9\xd5W_\xdd\xb6\xed\xe2\xa2\xecw\xbe\xf3\x9d\xdb\xb7\xbf\xd3\xff\x8e\xb5\xd5\x92\x9e\'\x93\xc9\xbe\x8b\xcd\xd3_\x0c\xec\xde\xbd{q\xd9\x9b\xb7\x06m\xf4Uol\x07\xba\xba%\xe4\x8d?\xb5d+\x9b\xe0\xb9\x11<\x13\xc2\xb5\xf9\xe1\xc6\x9b\xf6\xdb\x04\x00`y"o\x00\x00.\n\x17\xfc\x86\xb9v\x18b\xaeI\xae\x1dF\x96}Mqv\xd8Ed%\xc1e\x98\xbd\xfa_\xd3>\x9a\x17\xda/\xb3\n\xbb\x91\x8c7z\xad4b\xf1\xabm\xd1\x1e.0_\xf2\x0f\x85-k\xc2\x1f#|RY\x18\x0e\x00@\x9f\xc8\x1b\x00\xa0\xd7\x84qd\xb8c\xe4\x9aD\xdba\xa8\xdd\xe8\xd4\x1c.\xd0\xb6\x14\xb7\x97\xb5\xf4*\xb9\xdc\x93\xb0\xef\x87K\xc5\x1b\xdb\x96^U \x1e>8\xfc>=\xfd\xfax<~\xf1yx\xeb\xad\xb7\xdet\xd3M\x89\xc4\x80\xa7"\x00@\xaf\x11y\x03\x00t\xadp\xe1\xf6\xb7\xbf\xfdT\xadV{\xe1\x85\x17\xbe\xf7\xbd\xef\x9d?\x7f~u\x7fU\xb8\xa26\xec\xa0\xad\xdb2\xd7h\xf9L<|\xde6z\x8b\x97J\xa5\xbe\xab\xe9\xa5\x13\xf6\xde\t\xbf7\xa2\xf0\xb0\x7fN\xd8 %\xfcT\xc6\xb3\x17\x00\xa0[\x89\xbc\x01\x00\xbaA\x98\x12\x96J\xe5\xb0\xdd\xf6\xea\xba*\x87\xb1`\xb8^;\xec\x9b\xdc\'\xd7f\xc35\x16e\x87\xbd\xc5\xfb\xfa\x86Z\x9e\xe7\xe15\n?\xbc\\aEO\xf5p\x17\xcd\x96E\xe4rp\x00\x80\xae$\xf2\x06\x00\xe80\x8dP\xfb\xc2\x85j\xa9T\xaa\xb7\xde\xae\\\xd5\xdf\xb08\xda\xd6\xfc\x81\x8ep\xb9gi#\xff\xfe\xcew\xbe\xfb\xf2\x0f\xcd\xcf\xcf_\xf1W\xe9r9xxAC"1\xb0\xad\x9e\x88\xab<\x00@\x07\x11y\x03\x00\xb4\xb50\xcbk,\xdf\xbe\xda\xbe\xdb\xd1h\xf4\x86\x1bn\xd8\xb6m[\xf8\xfd\'~\xe26\xebX\xe9>\x8dN)?\xf2#75\x06w\xed\xba\xbdq\xf5C_\xbdA\xcaJ>\x1f\xfaa\x0e\xfe\x86\x16\xe1\x03\x03\x03\xe1GD\xf1x,\\\x12\xae\xe6\x00\x00mK\xe4\r\x00\xd0F\x1a\x01w\xb8h\xf5\xaav\xf3\x0bS\xbf\xc6\xea\xd4\xc6\xc2\xed\xd9\xd9\xd3\x8d\xc7\xc8\xbb\xe9)ol\xce3\xd4\xfc[VO\xc3k+\xcc\xc1\xc3\xdf\xc4bq\xb61\x12vD\x11\x82\x03\x00\xb4!\x917\x00\xc0\xa6\t\x17n\xcf\xcdU\xaa\xd5\xea\xd5\xae\xe0\x1e\x18\x18\xd0\x83\x18V!\xfcp\xa8%\x07o\xe9\x86\x7f\xc5_\xc6J\xdd\x92!\xb8v(\x00\x00\x9bK\xe4\r\x00\xb0q\xea\xe9\xf6\xc5\xe5\xa5\xa5Ri\xe5;L6\x9a\x0b\xd7\x17q_\xea2\xac\x98\xb0\x86\x96\xdc\xac5\xfc=\r\x9b\xe6_\xf1\x17\xb6\x11\x827\xb7Ci\xfc\xda\xfaP\n\x00`\xc3\x88\xbc\x01\x00\xd6Q\xa9T\xaa/\x18\x9d[y\x97\x92\xc6\x12\xd4\xfa:\xd1\xa8\xa4\x0c6K\xd3o\xdf\xeb\x8b\xc1\xc3O\xad\xc2_\xea\xe5;\xa2\x94\xdf\xb89f\x98}[\x06\x0e\x00\xb0\xdeD\xde\x00\x00k&l\x89P*\x95+\x95K\xedJ\xae\xf8G\xac\xe0\x86\x0eR\xff%\x8d%\x93\xc9\xc6\xc8\xcaW\x82\x87\xf76\x96\x81\x87\xbf\xfb\x89DB7p\x00\x80\xb5%\xf2\x06\x00X\xbd\xb0\x07w\xb8\xe4s\x85\x19w=\xe0\xbe\x98pY\xe9\t]\xa0e%xK\x83\xfee\xae\xed\x08\x1e\xd9\xb2\x0c<\x1e\x8f\xef\xd8\xb1#\x16\xdb\xf1\xe3?\xfe\xe3\xefy\xcf{\xd4\x16\x00`uD\xde\x00\x00Wa~~\xfe\xef\xff\xfe\xef\x9f}\xf6\xec\n3\xee\xc6"\xee\xb0\xa1\x81\x85\x9c\xd0\xdd\xc2\xbdd\x9b\xfb\x115>\x18\xbb\xe22\xf0\xfa\xc3\xe6\x1a7\xc3V\xe0^:\x00\x00\xae\x96\xc8\x1b\x00\xe0\nJ\xa5\xd2\xd3O?}\xf6\xecs\xe7\xce\x9d{\xf9\xe5\x97\x97\x7fp\xa3]o\xd8\xa5\xc4"n\xe8qaw\xfez/\x94\xd7\x97\x81\x97J\xe5\x1f\xf6\x04\xbfl7\xf0\xe65\xe0\xcd]P\xbc\xb0\x00\x00,O\xe4\r\x00\xd0*lT\xf2\xc3\x9d\'+\xcb?\xb8yK:\x9d\xb8\x81\xe5-^\x06\x1e\xbe\xd4\x94\xcb\xe5\xe0\xd5\xe6\xc2\x85\x0bK\xfe\xa9\x96.(\xcd/;v\xb8\x05\x00h!\xf2\x06\x00\xb8\x18\'\x85\xa9S\xf0}\x99\xde\xbb\xa1\xb7\xbe\xf5\xad\xefy\xcf\xbbe\xdc\xc0\x9a\x08\x13\xf0\xf7\xbd\xef}/\xbe\xf8bp\xf3\xf9\xe7\x9f_XX\xf8\xe7\x7f\xfe\xa7e>rk\xd9\t\xb3\xb1\x00\\\x0b\x14\x00\x80>\x917\x00\xd0\xb3\xc2\x80\xbb\xbe\x9a\xbb\xbc|K\xeeH$\xf2\xcew\xbe\xf3\xedo\x7f\xfb\xcd7\xdf\x1c|\x8f\xc7\xe3\xdb\xb7\xbfS\x01\x81\xf5\xb0c\xc7\x8e\xe0\x05\xa7\xf1"\xf3\xc35\xe0\xa5e6\x0f\xa8T^\x0f\xc7\xeb\xab\xc8\x07,\x00\x07\x00z\x99\xc8\x1b\x00\xe8!\xa5\x8b\xca\xf5\xa4\xbbR\xab\xd5\x96ydc\xe3\xb8D"\x11\x8dF\xcf\x9d{1\\\x80\t\xb0\x91\xc25\xe0\x83\x83\xe9\xbe7^\x8fr\xb9\x17\xb1`\xb0X\x9cmY\x00\x1e^\x92\xa2\x038\x00\xd0#D\xde\x00@7\x0b\x13\xa2F\xcc\xbd\xcc#\xa3\xd1h\xb842\x8c\xb9\x95\x0eh7\x91H$Y\x17\xee\x84\x19\xee:\xd0H\xc0\x97\xfc#\xe1\x02\xf0|>\xdf\xfc*\x17vAQO\x00\xa0[\x89\xbc\x01\x80nS\xadVK\x97\\\xa1c\xc9\xc0\xc0@\x18\xfd\x04\xdf\xb5\xe4\x06:K\xf0\xda\x15|\xa5R\x97n^\xf1*\x96\xe0\xf5\xb0P8\xd5\xd7\x17|]\xea\x7fR\x7f\t\x14\x7f\x03\x00\xddF\xe4\r\x00t\x83\x15\xc6\xdc\x8d\x94\xc7Rn\xa0\xcb\x84-P\x9a\x17\x80/\xf3\x92\xd8\xe8\x7f\x12\xde\xbc\x14~k\xff\r\x00t\x05\x917\x00\xd0\xa9V\x18s\x87\xd7\xf2\x87a\x90V\xb6@/\xf8\xe1\x02\xf0\x8b+\xc0W\xd2\xdf\xa9\\\x17\xb6\xff\x16\x7f\x03\x00\x9dN\xe4\r\x00t\x92\x15\xc6\xdc\x8d\x1d\xdbt,\x01z\\S\x07\xf0\x8b\x1a\xf1w\xb9\\^\xf2\xf1\xe2o\x00\xa0\xd3\x89\xbc\x01\x80v\xb7\xc2\x98{`` \x1e\x8f\x8b\xb9\x01\x96\xd1\xdc\xff\xe4\x8a\xed\xbf\x1b\xf1\xb7\xde\xdf\x00@\x07\x11y\x03\x00\xedh%W\xe2\xf7Y\x81\x08p\rZ\xda\x7f\xd7\x97~_\xfc\xb68\xfen\xee\xfd\x1d\xc6\xdf\xc9dR\xb7(\x00\xa0=\x89\xbc\x01\x806\x12\xc6\xdc\xc5bq\x99\x98;lZ\x92L\xee\x12s\x03\xac\x95\xb0\xfd\xf7\xe0`\xba\xef\x87\xf1w\xf0R\xbcd\xf3\x93\xe6\xf8;\xdc,a` q\xfb\xed?\xb9e\xcb\x16e\x04\x00\xda\x81\xc8\x1b\x00\xd8d\xd5j\xf5\xa9\xa7\x8a\x97[Z\x18\xd2\x9b\x1b`\xc34\xc7\xdf\xcb\xf7\xfe\x0e^\xc0\x0b\x85S\xc1Wp\xfc\xf6\xb7\xbf\xfd}\xef{\xdfO\xfd\xd4\x1d>\x8f\x04\x006\x97\xc8\x1b\x00\xd8\x04\xf3\xf3\xf3g\xce\x9c)\x16\x8b\xcb\xb4\xe7\x0e\x17\x0f\x86\xd7\xce\x8b\xb9\x016EK\xef\xefbq\xf6r\xfd\xa6\xce\x9f?\xffx]\xa3\xf1\xf7\x1dw$u>\x01\x006\x9e\xc8\x1b\x00\xd88g\xce\x9cy\xf2\xc9o>\xfd\xf4\xd3\xe7\xcf\x9f_\xf2\x01Z\xc4\x02\xb4\xad\x1f\xc6\xdf\x97\xb6[\xb8\xdc\xc7\x96\x8d\xce\'\x93\x93\x93\xc1+y\xfd%\xdd5:\x00\xc0\xc6\x11y\x03\x00\xeb\xab\x9e}\x14\xc3\xb5\x81\x97\xeb[\x12\xeeB\x99L&\xe3\xf1\x98\x8a\x01\xb4\xb9H$\x92\xac\xeb\xab\xf76\xf9\xf2\x97\xff\xe2\x85\x17^x\xfe\xf9\xe7\x17\x16\x16Z\x1e\x19\xdc\x9b\xaf\x0b_\xea\xc3O4\xbd\xd4\x03\x00\xebJ\xe4\r\x00\xac\x8b\xb9\xb9J\xb1\xeer\x1bQZ\xfa\x07\xd0\x05\x82\x17\xf3]u\xc1\xf1\xf3\xcf?\xff/\xff\xf2/\x97{\xe5/\xd75\xbf\xfe\x87\xa19\x00\xc0\xda\x12y\x03\x00kf\xf9K\xdd\x03\xfd\xfd\xfd;v\xec\xb8\xf9\xe6\x9bo\xb9\xe5\x96\xbb\xee\xbaS\xc5\x00\xbaI\xf0\n\xbfk\xd7\xed\xc3\xc3C\x8d\xeb{\x96|;h^\xfa\x9dL\xee\xd2\xf5\x1b\x00X["o\x00\xe0ZU\xab\xd5\xa7\x9e*\x96\xcb\x17[\x97,\xf9\x80X,V\xef[\xb2\xeb{\xdf{M\xb9\x00\xba^$\x12I\xd5\xf5\xd5/\xfa\t?\r\r\x97x\xb7ht\xfd\x0e\xdf)\x82?\xa2\xed\t\x00p\x8dD\xde\x00\xc0*\xcd\xcdU\n\x85B\xa9T\xba\\\xeb\x92drW\xcbF\x94\xb3\xb3\xa7\xd5\r\xa0\xa7\xc4\xe3\xb1\xe0kp0\xdd\xb8\x12h\xc9\xad\x1d*u\xf9|\xbe\xde(\xfc\xd2\xdb\x87\xb6W\x00\xc0*\x88\xbc\x01\x80\xabS\xbcd\xe9\xbd(uh\x05`I\xcd\x9b^.\xb3\xdfC\xf0\xe6R(\x9c\n\xbe\xfa\xb4=\x01\x00VE\xe4\r\x00\\Y\xd8\x955L\xba\x97|\xc0\xc0\xc0@\xb8"\xcf\x05\xe9\x00\\Q\xb8\xf4{xx\xa8Z\xad66\x81X\xfcIjs\xdb\x93T*\xe5]\x06\x00X\t\x917\x00pYa\x93\xeeB\xa1\xb0d\xeb\x92\xf0\xda\xf3z\x93\xee\xa4k\xcf\x01X\x85h4\xda\xe8\xfa\x1d\x06\xdf\xc1\xf7\xc5;^\x06oC\x93\x93\x93}?\xbc\x96H\xcbo\x00`\x19"o\x00\xa0\xd52\xd7\x9b\xf7i]\x02\xc0\xfa\x08\xdb\x9e\x8c\x8c\xec_\xe6m\xa8Z\xad\xe6\xeb\x1a-\xbf\xbd\x19\x01\x00-D\xde\x00\xc0%\xe1v\x94K.\xaf\x0b\xc4b\xb10Y\xb0\xb0\x0e\x80u\xd5\xdc\xf6\xe4\xa9\xa7\x8a\xe5riq[\xadF\xcbo\xd97\x00\xd0B\xe4\r\x00\xbdn\xf9\xa4;l\xd2m\xeb0\x006^\xf0\xd638\x98\x0e\xbe\x1a[J,n\xf9\xdd\xb2\xdde\x98}k\xb7\x05\x00\xbdL\xe4\r\x00=\xaa\x91\x1d,\x99tK\r\x00h\x1f\xc1\x9bQs\xcb\xefp;\xe5\xcbmw\xd9\xd7w\xc2\xbb\x18\x00\xf42\x917\x00\xf4\x96e\x92\x02\xdbQ\x02\xd0\xfe\x1a=L\x96\xd9\xeeR\xf6\r\x00\xbdL\xe4\r\x00=\xa1T*\xd5\xbb\x97\\6\xe9\xd6\x05\x15\x80\xce\xd2\xbc\xdd\xe5\xe5:t\xc9\xbe\x01\xa0\x07\x89\xbc\x01\xa0\x9b-\x93\x02H\xba\x01\xe8\x0e\xf5\xed.\xf7\xcb\xbe\x01\x80\x90\xc8\x1b\x00\xba\x90\xa4\x1b\x80\x1e\xb4\xf2\xec;\x12\x99\x0c\xde\r\xdf\xfb\xde\xf7\xee\xde\xbd[\xdd\x00\xa0\xcb\x88\xbc\x01\xa0{\x04\'\xf6O<\x11\x9c\xe3\x17$\xdd\x00\xf4\xb2+f\xdf\xb5Z\xadP8\x15|\xfd\xb7\xff\xf6\xf9\xdbn\xbb-xs\xdc\xbb7\xa5n\x00\xd0\x1dD\xde\x00\xd0\xf1\x82\xd3\xf8\xa7\x9e*\x06\xa7\xf4\x95J\xa5\xe5.I7\x00\xbd\xec\x8a\xd9\xf7\xc2\xc2\xc2l\xdd\x17\xbf\xf8\xc5;\xef\xbc3\x95J\x05\x7fD\xdd\x00\xa0\xa3\x89\xbc\x01\xa0S\xcd\xcf\xcf\x7f\xfb\xdb\xdf~\xf2\xc9o\x96\xcb\xe5\xc5\xf7&\x93\xbb\x82\xf3vI7\x00\xf4\xbd1\xfb\xce\xe7g\x16\xef\xe7\xfc\xdak\xaf\xe5\xeb\xa2\xd1h\xf0\x06\xbawo*8P7\x00\xe8D"o\x00\xe8\xb5\xee{\xe3\xa6\x94\xe7\xce\xbd\x18P.\x00XW\xf1x,\x1e\xdf?2\xb2\xbfx\xc9l\xadVk~@\xa5R\xc9\xe5N\xf4\xf5\x9dH\xa5\xf6\x84o\xd3\x8a\x06\x00\xed\xe0Mg\xcf>\xab\n\x00\xb0\x89\xe6\xe7\xe7O\x9d:\xf5W\x7f\xf5\xd7\xe7\xcf\x9fo\xb9k\xcb\x96-\xbbv\xed\xba\xe5\x96[\xde\xf2\x96\xb7(\x14\xb4\xb9\x0b\x17.\x9c\xd0\xe9\x16\x16\x16\xce\x9e=\xfb\xb7\x7f\xfb\xb7/\xbc\xf0\xc2\x92\x0f\x08\xde\xac\xdf\xff\xfe\xf7\xff\xcc\xcf|\xe8]\xefz\x97r\x01\xc0&\x12y\x03\xc0\xa6\x99\x9d\x9d=y\xf2k\xcf<\xf3Lp\x16\xdd<\xde\xdf\xdf\xbfs\xe7\xce\xdbn\xbbm\xdb\xb6m\xaa\x04\x9dB\xe4\r=\xe2\xe5\x97_>{\xf6l\xf0&>??\xbf\xe4\x03\xe2\xf1\xf8\xbf\xfe\xd7\x1f\xdc\xb3g\xcf\x96-[\x94\x0b\x006\x9e\xc8\x1b\x006\xda\xb9s\xe7\xbe\xf1\x8d\'\xbf\xfa\xd5\xaf\x06\xe7\xcc-w\xddr\xcb-;w\xee\x0c\xbe\xab\x12t\x1c\x917\xf4\xe0o\xfd\xec\xec\xec\xd9\xb3g[>\xba\x0e\xf5\xf7\xf7\xdfv\xdbm\xbf\xf0\x0b\xbfp\xeb\xad?\xa6V\x00\xb0\x91\xf4\xf2\x06\x80\x8d\xf3\xc4\x13\x85@\xb9\\n\x19\xd7\xc0\x04\x00:\xce\xb6m\xdb\xd2\xe9\xf4\xe5\x1a\x9e\x04\xe3\xb3uo\x7f\xfb\xdbw\xef\xde\x9dN\xff\xacE\xdf\x00\xb01\xac\xf2\x06\x80uW_\xfb\xf9\xb5\xaf\x7f\xfd\xeb/\xbd\xf4R\xf3\xf8\x8d7\xde\xf8\x93?\xf9\xbe\x9f\xfe\xe9\x0f\xed\xd8q\xf3\xca\xff\xb6\x97.\xfa\xa7\xf0x\xeb\xd6\xb7m\xdd\xba\xb5\x83Jq\xe6\xcc\xeb\x13\x8f\xceZ\xf5\xa6\xec\xca~Esss\x13\x13\x93K\xde5>>\xa6\xec\x9e\xed\xca\xde\xf5e\x0f\xfe\xae\'\xeb\x1a\x7fg\x8b\x0f~\xf0\x83{\xf7\xa6n\xbb\xed6S#\x00XWVy\x03\xc0:*\x14\n\xc5\x8bf[\xc6\x07\x06\x06\x82\x93\xded2\x19\x89D\xae\xf6\xef\x9c\x9f\x7f\xa5q|\xfd\xf5\xfd7\xddtS\x87\x16\xa7\xb3~reW\xf6+\xba\xf1\xc6\x88\xb2{\xb6+{/\x97=\xf8\xe3\xf1x\xfcW~\xe5W\xeao\xfd\xc5B\xe1T\xcb\x03\xbeQ\x17\x8dF\xd3\xe9t0\rX\xc5\x1c\x00\x00X\t\x917\x00\xac\xbdj\xb5:3\x93/\x14\n\xb5Z\xady<8\xb9M\xa5R\x83\x83\xe9\xe0tW\x95\x00\xa0+%\xebFFF\x9ex\xa2\x90\xcf\xe7\x83YA\xcb$a\xb2.\x95\xda\x13\xcc\n\x12\x89\x84\x8a\x01\xc0\xda\x12y\x03\xc0Z*\x16\x8b33\xf9\xc5\xdd\xba\x93\xc9]\xc1\xd9opf\xabD\x00\xd0\x0b"\x91\xc8\xe0`:\xf8*\x95J\xf5\xab\xbef[>\x08/\x14N\x05_\x16}\x03\xc0\x9a\x13y\x03\xc0\x1a\xa8V\xab\xe1\xd6\x94-+\xb9\x82\xf3\xd8T*\x15\x9c\xc7Z\xd6\r\x00\xbd)QW\xab\xd5\xc2\xcf\xc5+\x95J\xcb\x14\xc2\xa2o\x00X["o\x00\xb8&\xf5f\x9d\x85\xc5\xdd\xba\x93\xc9]\xc1\x89k2\x99T"\x00 ln\x16\x98\x9b\xab\xe4\xf33\xcb,\xfa\x1e\x1e\x1eZ\xddn\x1f\x00@H\xe4\r\x00\xab\x11\x9c\xa6.\xd9\xa038A\r/O\xb6\xac\x1b\x00X,\x1e\x8fe2\x99p\xd1\xf7\xd4\xd4\xf4\xe2N\xdf\xb9\xdc\x89Hd2\x99\xdc\x95N\x0f\x06\x0fV1\x00\xb8Z"o\x00\xb8:\xe1\xe2\xacB\xe1T\xcb\xf8\xc0\xc0\xc0\xde\xbd)\xdd\xba\x01\x80+j,\xfa\x0e;}\xb7\xcc+j\xb5Z\xb8\xe8\xdb\xec\x02\x00VA\xe4\r\x00+\x15\x9c\x8f.n\xc1\x19\x9e\xb2\x0e\x0e\xa6-\xeb\x06\x00\xaeV\xd8\xe9{ddd\xc9\xab\xc7\xcauSS\xd3\xb6\x06\x01\x80\x95\x13y\x03\xc0\x15\x84[S\x06g\xa1-=7c\xb1\xd8\xe0`Z\xb7M\x00\xe0\x1a\x05s\x89`R\x11|-\xb9GH0\x15\x99\xae\xb3\xc5%\x00\xac\x84\xc8\x1b\x00.k\xc9k\x8d\x03\xc1\t\xa7\xf6\x9a\x00\xc0\x9aK\xd6]\xee\xe3\xf6\xb0\xdbI\xf8\xa1\xbbn\'\x00p9"o\x00X\xc2\x92=L\xa2\xd1h\xd8\xc3\xc4\xb2n\x00`\xfd\x04S\x8e\xe1\xe1\xa1\xe0k\xc9\tIp3\x97;\xf1\xc7\x7f\xfc\x85\xbd{\xf7~\xf8\xc3?\xb3}\xfbv\x15\x03\x80f"o\x00x\xdd\xe5\x16U\r\x0c\x0c\x84=L\x94\x08\x00\xd80\xe1\x16\x97Kn\x9d\xbd\xb0\xb0\xf0x\xdd\xed\xb7\xdf\xfes?7\xa8\xdb\t\x004\x88\xbc\x01\xe0\xa2%{\x98D"\x91dr\xd7\xf0\xf0\xb0\xdd\xa2\x00\x80\xcd\x12\x8f\xc72\x99\xcc\xc8\xc8\xc8\xccL>\x98\xac\xb4lqy\xbaN\xb7\x13\x00h\x10y\x03\xd0\xeb\x1e}\xf4\xd1\xd9\xd9\xd3\xe5r\xb9y0\x1a\x8d\xa6\xd3\xe9\xbd{Sz\x98\x00\x00\xed \x98\x934\xba\x9d<\xf1D\xa1e\xea\x12v;\x99\x9a\x9a\xd6\x84\r\x00D\xde\x00\xf4\xa8\xf9\xf9\xf9|\xfe\xb1\x93\'O\xbe\xfc\xf2\xcb\xcd\xe3z\x98\x00\x00\xed,\xecv\x12Lcfgg\x9fy\xe6\x99\xe6\xbb\xaa\xd5\xeat]*\xb5\xc7ej\x00\xf4,\x917\x00=\'8\x1b\x9c\x99\xc9\x9f\xc1<\'\x93\xc9\x8c\x8c\x8c,\x9e\x0b\x05\xc7\xf9:[\x98\x00\xd0\xc5D\xde\x00t\x9bpeS\xb18\xdb|\x82\x17\x89D\xd2\xc1\x89\x9d\x8by\x01\x80\xde\x10\xccy\x86\x87\x87\x82\xaf%\xafx\xb3\xbf%\x00]L\xe4\r@\xf7X\xf22\xdeh4\x1a\x9c\xcb%\x93Ia7\x00\xd0\x83\xc26\xdfK\xeek\x12\xeeo900\xb0wo\xca\xfe\x96\x00t\r\x917\x00\xdd`\xc9\xcd\x9ab\xb1\xd8\xe0`\xda\xf9\x1b\x00@\xb2.\x982\xe5\xf3\xf9bq\xb6\xf9\xaer]0\x95\x1a\x1e\x1e2q\x02\xa0\x0b\x88\xbc\x01\xe8lK.Yr\x95.\x00\xc0b\x89\xba\xcb\xedo\x99\xcb\x9d\x98\x9a\x9a\x0e\xf7\xb7ty\x1c\x00\x9dK\xe4\r@\xa7Z\xb21\xa5\xbd\x98\x00\x00\x96\x17\xeeo9<<\xfc\xc4\x13\x85\x96\xfd-\x83\x99\xd5\xf4\xf4t0h\x13\x14\x00:\x97\xc8\x1b\x80\xces\xb9\xb0;8s\x0bN\xe1\xd4\x07\x00\xe0\x8a\xc2\xfdN\x06\x07\xd333\xf9\x96\xe0;8\x0e\x83\xefp\xc5\xb7\xf9\x15\x00\x9dE\xe4\r@\xc7\x08\xce\xbe\x82S\xb2B\xa1\xd0\x1cvG"\x11\xab\x90\x00\x00V\'\x98A\r\x0f\x0f\x05_\x8b\x97\x14\x04S\xaf|\x9d\x85\x05\x00t\x16\x917\x00\x1d \x0c\xbb[\xd6\x1f\t\xbb\x01\x00\xd6J\xaan\xc9k\xe9\n\x85S\xc1\x97\xe0\x1b\x80N!\xf2\x06\xa0\xad-\x19v\x87\xd7\xe1&\x93Ia7\x00\xc0\x1a\n\x83\xef%\xb7\x07o\x04\xdf\xf6M\x01\xa0\xcd\x89\xbc\x01hS\xcb\x84\xdd\xc1\x99\x98\xfa\x00\x00\xac\x93d]\xa9T\x9a\x9a\x9a^2\xf8\x1e\x18\x18\x08\xa6d\x89DB\xad\x00hC"o\x00\xda\x8e\xb0\x1b\x00`\xd3%\x12\x89\xf1\xf1\xc4\x92\xc1wp3\x9b}P\xf0\r@{\x12y\x03\xd0F\xaa\xd5\xea\xd4\xd4T\xa1p\xaay08\x9b\xda\xbb7%\xec\x06\x00\xd8x\x8d\xe0\xbbp\xd1\x1b&i\x82o\x00\xda\x93\xc8\x1b\x80\xb6p\xb9\xb0\xdb\x19\x14\x00\xc0\xa6K\xd4\r\x0f\x0f/\x9e\xb0\t\xbe\x01h7"o\x006\x99\xb0\x1b\x00\xa0#D\xa3\xd1L&#\xf8\x06\xa0\xcd\x89\xbc\x01\xd84\xc2n\x00\x80\x8e#\xf8\x06\xa0\xcd\x89\xbc\x01\xd8\x04KnP\xe9\xec\x08\x00\xa0S\x08\xbe\x01h["o\x006\x94\xb0\x1b\x00\xa0k\x08\xbe\x01hC"o\x006\x88\xb0\x1b\x00\xa0+]1\xf8N&w\x8d\x8c\x8c\x04\x0fS+\x006\x80\xc8\x1b\x80u\'\xec\x06\x00\xe8z\xcb\x04\xdf\xc5\xe2l\xf0\x95J\xed\t\xee\x15|\x03\xb0\xdeD\xde\x00\xac#a7\x00@OY&\xf8\x0en\x06_\x1f\xf8\xc0\xfb\x87\x86\x86\xde\xf5\xaew\xa9\x15\x00\xebD\xe4\r\xc0z)\x14\nSS\xd3\xd5j\xb5\xf9\x14hdd\x7f2\x99T\x1c\x00\x80.\x16\x06\xdf\xe9\xf4\xe0\xc4\xc4D\xb9\\n\xbe\xeb\x9b\xdf\xfcV\xf0\xb5k\xd7\xae\x8f}\xec\xd7\xb6l\xd9\xa2V\x00\xac9\x917\x00ko\xc9\xb0{xx(\x95J)\x0e\x00@\x8f\x88\xc7c\xe3\xe3c\xa5R)\x98\x19\xb6\x04\xdf\xb3\xb3\xb3\xf7\xdf\xff\xb7\x1f\xfe\xf0\xcf\xdc}\xf7\xdd\x91HD\xad\x00XC"o\x00\xd6RpJ\x93\xcb\x9d\x10v\x03\x00\x10J$\x12\xe3\xe3\x89\xc5\xc1\xf7\xc2\xc2\xc2\xff\xf8\x1f\x7f\xf9\xd5\xaf\x9eL\xa7\xd3\x83\x83i\xc17\x00kE\xe4\r\xc0\xda\xf8\xcew\xbe\xf3\x95\xaf\xfc\xbf\xcd\xa71\xc1y\xcb\xc8\xc8~a7\x00\x00\x8d\xe0\xfb\x8f\xfe\xe8\x8f\xcf\x9d;\xd7\x18\xaf\xd5j\xd3\xd3\xd3\xf9|\xde\xbc\x11\x80\xb5"\xf2\x06\xe0Z\x9d9\xf3\xec\x17\xbe\xf0\x85\xb9\xb9\xb9\xc6H$\x12\xb1Z\x07\x00\x80\x16\x89Dbtt\xf4\xaf\xff\xfa\xaf\xbf\xf1\x8do\xcc\xcf\xcf7\xc6k\xb5Z.wbjj\xda\xd5\x81\x00\\;\x917\x00\xab\xf7\x8f\xff\xf8\x8f\x93\x93_:}\xfatcD\xd8\r\x00\xc0\xf2v\xd6=\xf3\xcc3\xdf\xfa\xd6\xb7\xfe\xf9\x9f\xff\xb91^\xadVs\xb9\x1333\x17W|\'\x12\t\x85\x02`uD\xde\x00\xacF\xadV\x9b\x9a\xbax\tj\xf3`*\xb5gddD\xd8\r\x00\xc0\x15\xed\xdc\xb9\xf3C\x1f\xfa\xd0\x93O>\x19L)\x83\xb9ec\xbcR\xa9d\xb3\x0f\x0e\x0c\x0c\x0c\x0f\x0f\t\xbe\x01X\x05\x917\x00W\'8!\x99\x99\xc9\xb7\x9c\x99\x04g,w\xdf}\xf7m\xb7\xedT\x1f\x00\x00Vnxxhp0\xbdxzY.\x97\xb3\xd9\x07S\xa9=\xc3\xc3\xc3\xd1hT\xa1\x00X9\x917\x00W\xa1P(LMMW\xab\xd5\xc6\xc8\xcd7\xdf|\xd7]wm\xdb\xb6\xedmo{\x9b\xfa\x00\x00p\xb5"\x91H\x18|OLL\x14\n\xa7\xde8\xf9<\x15|\xa5\xd3\xe9\xe0\x01.%\x04`\x85D\xde\x00\xacH\xa9T\xca\xe5N4\x87\xdd\xb1X\xec\xe7~\xee\xe7\x9c{\x00\x00p\xed\x82Ye&\x93\x19\x1e\x1e\x9e\x98\x98(\x16g\x9b\xef\xca\xe7\xf3\x85B\xc1\x861\x00\xac\x90\xc8\x1b\x80+(\x95JSS\xd3\xe5r\xb91\x12\x8dF\x87\x87\x87R\xa9\xd4\xb9s/\x06\x94\x08\x00\x805\x11\xcc3GGG\x17\xcf?k\xb5\xda\xf4\xf4t\xa1P\x08g\xa1\n\x05\xc02D\xde\x00\\V\xb5Z\x9d\x9a\x9aj\xbe\xbc4\x12\x89\x0c\r]\xbc\xecTq\x00\x00X\'\x89Db|<\xb1\xf8*\xc3\xe08\x18\x99\x99\xc9\x8f\x8c\xec\xb7\xb3%\x00\x97#\xf2\x06`\t\xe1\x1e\x95\xd3\xd3\xd3\xcd\x83a\xd8\xedbR\x00\x006@"\x918|\xf8\x81B\xa1011\xd9\xbc\xb3e\xa5R\xc9f\x1f\x1c\x18\x18\xb8\xf7\xde\x8c\x9d-\x01XL\xe4\r@\xab0\xecn>\xafH\xa5\xf6\x0c\x0f\x0f;\xa3\x00\x00`\x83\xa5R\xa9d2\x19LP\x03\xcd\x13\xd4r\xb9|\xff\xfd\x0f\x04\xd3\xd4\x91\x91\x11k2\x00h&\xf2\x06\xe0u\x8b\xaf\x1e\x1d\x18\x18\x08\xce"\xe2\xf1\x98\xe2\x00\x00\xb0)"\x91\xc8\xf0\xf0\xc5\xcb\r\'&&\x9a{\xee\x05\x82\x9b\xc5\xe2\xac\x9d-\x01h&\xf2\x06\xe0\xa2\xb9\xb9Jp\n\xd1\xb2Ge&s@\x93D\x00\x00\xdaA$\x12\xc9d2\xc3\xc3\xc3\x8f<\x92\xb3\xb3%\x00\xcb\x10y\x03\xf4\xba\xe0$\xa1e\xbd\x8c=*\x01\x00hO\xd1ht||\xecr;[>\xf1\xc4\xc5\xe0\xdb\xa2\r\x80\x1e\'\xf2\x06\xe8i\x7f\xfa\xa7\x7f\xfaW\x7f\xf5\xd7\xaf\xbd\xf6Zc\xe4\xc3\x1f\xfe\xf0\x9e={n\xbc\xf1\xc6s\xe7^\xbc\xe2\x1f\x7f\xe5\x95W\x9a\x8fW\xf2G\xdaSg\xfd\xe4\xca\xae\xec\xca\xde\x9e^z\xe9%e\xf7lWveW\xf6\x8d)\xfb\x8f\xfe\xe8[\x7f\xfb\xb7\x7f\xfb\xa9\xa7\x9e\xfa\xcaW\xbe\xd2<\x95-\x97\xcb\xd9\xec\x83\x1f\xf8\xc0\xfb?\xf2\x91\x8f\xbc\xe3\x1d\xef0\xdb\x07\xe8Mo:{\xf6YU\x00\xe8AOI\xb8\xeb\xae\xbb\x82\x93\x04\xc5\x01\xb8FVy\x03l\xae\xe7\x9f\x7f\xfek_\xfbZ\xf0j\xdc2\x1e\x8f\xc7?\xfa\xd1{n\xbd\xf5V%\x02\xe8\x11"o\x80^1=\xfd\xe5\xbf\xfc\xcb\xbfl\xeeu\xb8w\xef\xde\x0f|\xe0\x037\xdcp\xc3\xaa\xff\xce\x85\x85\x85\xef\x7f\xff\xfb\xe1\xf1\xf5\xd7_\xdf\xdf\xdf\xdfA\x05i\xee#y\xd3M7u\xd0O\xae\xec\xca\xae\xec\xed\xe9\xc5\x17_|\xf4\xd1G\x97\xbc\xebW\x7f\xf5W\x95\xdd\xb3]\xd9\x95]\xd97\xa6\xec\x7f\xf37\x7f\xf3\xd8c\x8f5OzCw\xdcq\xc7\xaf\xfd\xda\xafvV\xad\x00X\x1d\x8dM\x00\xba_\xa9T\x9a\x98\x98\xacT*\x8d\x91dr\xd7\xc8\xc8H4\x1a\xbd\xc6\xbf\xf9\xdc\xb9\x17\x03\xe1\xf1\xd6\xad[\xb7o\x7fg\x07\x95ev\xf6t\xe3\xf8\xd6[\x7f\xac\x83~reWveoOo~\xf3\x9b/w\x97\xb2{\xb6+\xbb\xb2+\xfb\x86\x95=\xa8\xc6/\xfc\xc2\xcf\xcf\xcc\xe4\xa7\xa7\xa7\x9b\xc7\x9fz\xea\xa9g\x9eyfhhH\x9f\x13\x80\xae\'\xf2\x06\xe8f\xd5jubb\xa2X\x9cm\x8cD\xa3\xd1L\xe6@"\x91P\x1c\x00\x00\xbaR$\x12\x19\x1e\x1e\xda\xbb7\xf5\xc8#\xb9r\xb9\xdc\x18\xaf\xd5j\x93\x93\x93\xf9|\xde|\x18\xa0\xbb\x89\xbc\x01\xba\xd6\xd4\xd4t0\xa1\x0ff\xf6\x8d\xa9\xbfU-\x00\x00\xf4\x88h4:>>V*\x95r\xb9\x13\xd5j\xb51\x1e\x1cg\xb3\x0f\xae\xd5U\x8f\x00\xb4!\x917@\x17Z<\xb3O\xa5\xf6\x04s\xfaH$\xa28\x00\x00\xf4\x8eD"q\xf8\xf0\x03-kA\x02\xc5\xe2l\xa9TN\xa7\xd3\xc3\xc3C\xaa\x04\xd0eD\xde\x00]eq\'\x93\x81\x81\x81\x91\x91\x91x<\xa68\x00\x00\xf4\xa6\xe1\xe1\x8b\x17;\x06\xf3\xe4B\xe1Tc\xb0V\xabMOO\x17\n\x05}N\x00\xba\x8c\xc8\x1b\xa0K\x04S\xf6\x96]z"\x91\xc8\xc8\xc8\xfeT*\xa58\x00\x00\xf4\xb8`n\x9c\xc9d\x82\xb9q\xcb\xbe\xeea\x9f\x93\x81\x81\x81{\xef\xcd\xe8s\x02\xd0\x1dD\xde\x00\xdd`q\'\x93\xf0"M\x9dL\x00\x00\xa0!\x91H\x1c:t0\\)\xd2\xdc\xe7\xa4\\.\xdf\x7f\xff\x03CCC\xfa\x9c\x00t\x01\x917@g[\xb2\x93\x89%*\x00\x00p9\x83\x83\xe9\xbd{Sa\x83\xef\xe6q}N\x00\xba\x83\xc8\x1b\xa0\x83\xb5\xec\xc3\x13\x8dFGF\xf6\'\x93I\x95\x01\x00\x80e4z\x00NLL\x94\xcb\xe5\xc6x\xd8\xe7$\x99\xdc522b\x11\t@\x87\x12y\x03t\xa4\xc5\x9dL\x86\x86.\xee\xc9\xa3\x93\t\x00\x00\xacP<\x1e\x1b\x1f\x1f+\x14\n\x13\x13\x93\xcd}N\x8a\xc5\xd9R\xa9\x1c\xb6\nT%\x80\x8e#\xf2\x06\xe80\xc1\\<\x97\xcb\xb5t2\x19\x19\x19\t\xe6\xeb\x8a\x03\x00\x00W+\x95J%\x93\xc9\x89\x89\x89B\xe1T\xf3\xac{zz\xbaX,\x8e\x8c\xec\xd7\xe7\x04\xa0\xb3\x88\xbc\x01:I\xcbN;\x8d\xeb1U\x06\x00\x00V-\x98Wg2\x99z\x9f\x93\xc9J\xa5\xd2\x18\x0f\x8e\xb3\xd9\x07S\xa9=###\xae\xa7\x04\xe8\x14"o\x80\xce07W\xc9\xe5r\xcd\xf3\xef\xf0BK3o\x00\x00X\x13\x89D\xe2\xd0\xa1\x83-\xabL\x02\x85\xc2\xa9bq\xd6Z\x13\x80N!\xf2\x06hw\xc1l\xbbe7\xf9X,\x96\xc9dt2\x01\x00\x80578\x98\xbe\xe3\x8e\x8b}N\x9a{\t\xd6\xbb\x0b\x9e\xc8\xe7\x1f\xfb\xe8G\xef\xb9\xf5\xd6[U\t\xa0\x9d\x89\xbc\x01\xdaZ\xb1X\x9c\x98\x98llS\x19\x89D\xc2m*U\x06\x00\x00\xd6I4\x1a\x1d\x1d\x1d]\xbcc\xfc\xdc\xdc\xdc\xa7?\xfd{?\xfb\xb3?\xfbK\xbf\xf4\xbfl\xd9\xb2E\xa1\x00\xda\x93\xc8\x1b\xa0M\x05s\xeb\x96\xa5%\xc9\xe4\xae\x91\x91\x91`\xfe\xad8\x00\x00\xb0\xde\x9a\xfb\x9c4\x8f?\xf6\xd8c\xdf\xfc\xe67\xff\xcd\xbf\xf9\r\xdbZ\x02\xb4\'\x917@;ji \x18\x8dF3\x99\x03\xa6\xd4\x00\x00\xb0\x91"\x91\xc8\xf0\xf0\xd0\xde\xbd\xa9G\x1e\xc9\x95\xcb\xe5\xc6\xf8\xcb/\xbfl[K\x80\xb6%\xf2\x06h/\x8b\xb7\xa9\x0c;\x99\x98I\x03\x00\xc0\xa6\x88F\xa3\xe3\xe3c\x85B\xe1\x8f\xff\xf8\x0b\x0b\x0b\x0b\x8dq\xdbZ\x02\xb4\'\x917@\xbb\x98\x9f\x7fezz\xfa\xf1\xc7\x1fo\x8c\xd8\xa6\x12\x00\x00\xdaD*\x95\xba\xee\xba\xeb\xf3\xf9\xfc\xd9\xb3g\x1b\x83\xe1\xb6\x96O\x98N\xa7\x87\x87\x87,\xf7\x06X5\x917\xc0*\x05\xf3\xd1\\.W,\xce6F\x86\x86\x86\x82\xb9\xa9\xca\x00\x00\x00W\x14.\xf7N$\x06r\xb9\x13\x8d54\x81|>_,\x163\x99\x03\x96{\x03\xac\x8e\xc8\x1b`5\x829h\xf3\xc44\x16\x8be2\x99x<\xa62\x00\x00\xc0\xca%\x93\xc9\xc3\x87\x13-\x8bi\xaa\xd5j\xb8\xdc{dd\xbf\x12\x01\\-\x917\xc0\xd5\xa9\xd5j\x13\x13\x13\x85\xc2\xa9\xc6\x88\xc5\xdd\x00\x00\xc0\xaaE"\x91\xd1\xd1\xd1\x96U5}\xf5\xe5\xde\xa5R\xc9\xda\x1a\x80\xab%\xf2\x06\xb8\n\xc1\x8c\xb3y\x93\x19\x8b\xbb\x01\x00\x805\xb1\xe4r\xefJ\xa5r\xf4\xe8Q\x8bl\x00\xae\x8a\xc8\x1b`\xa5&&&\x9b\xf7\x96\xb1\xab\x0c\x00\x00\xb0\x86\xc2\xe5\xde33\xf9\xe9\xe9\xe9\xe6\xe5\xde\xc1\xcdR\xa9t\xef\xbd\x99h4\xaaJ\x00W$\xf2\x06\xb8\xb2\xb9\xb9J.\x97\xabT*\xe1\xcd`\xa2i3\x19\x00\x00`=\x0c\x0e\xa6\xef\xb8#\xf9\xc8#\xb9r\xb9\xdc\x18\x0c\x8e\x8f\x1c9:2\xb2?\x95J)\x11\xc0\xf2D\xde\x00W03\x93\x9f\x9c\x9cl\xdcL&we2\x19\x8b\xbb\x01\x00\x80u\x12\x8dF\xc7\xc7\xc7\xa6\xa6\xa6\x03\x8d\xc1Z\xad\x96\xcb\x9d(\x16\x8b\xceG\x00\x96\'\xf2\x06\xb8\xac`N\xf9\xf0\xc3\xc7\x1bk+\x82ie&s \x99L\xaa\x0c\x00\x00\xb0\xde\x86\x87\x87\x82\xb3\x8f\xe6\xebM\x03\xc5\xe2\xec\xfd\xf7?0:\xfa\tW\x9d\x02\\\xce\xbfR\x02\x80%\x15\x8b\xc5`*\xd9\xc8\xbb\x07\x06\x06\x0e\x1d:(\xef\x06\x00\x006L<\x1e\x1b\x1f\x1fK\xa7\xd3\xcd\x83\xb5Z-\x9b}pbbR}\x00\x96d\x957@\xab`\x06911Q(\x9cj\x8c\xec\xdf\xbf\x7fp0\xad2\x00\x00\xc0\x06\x8bD"##\xfb\x93\xc9]\xc7\x8f\x7f\xaeyO\xcb|>_*\x952\x99L<\x1eS%\x80fVy\x03\xbc\xc1\xdc\\\xe5\xc8\x91\xa3\x8d\xbc;\x16\x8b\x1dt\xe8`,\xf6\x86f&\xe1\x9e\x96\xa5RI}\x00\xfaD\xde\x00}\x8bv\xaaL&w\x1d>\xfc\x80\r\xd0\x01\x00\x806\x14\x8dF\x0f\x1d:844\xd4444<<\xa4,\x00\x00@\x17\x88D"##\xfb\x13\x89\x81\\\xeeD\xf3\x9e\x96\xc1I\xd0w\xbe\xf3\x9d\x8f\x7f\xfc\xde-[\xb6\xa8\x12\xd0\x0b\xac\xf2\x06zB0\xe1;v,\xdb\xc8\xbb\x83\xb9\xe0\xd8\xd8\'\xe5\xdd\x00\x00@\x97I&\x93\x87\x0e\x1d\x8c\xc5\xde\xd0\xcc\xe4;\xdf\xf9\xce\xfd\xf7?p\xfa\xf4i\xf5\x01z\x81\xc8\x1b\xe8~\xa5R)\x98\xde\x95\xcb\xe5\x1fN\x01w\x1d>\xfc@"\x91P\x19\x00\x00\xa0\xfbD\xa3\xd1C\x87\x0e\x0e\r\xbda\x89\xcf\xc2\xc2\xc2g?\xfb\xf0\x17\xbe\xf0E\xf5\x01\xba\xde\x9b\xce\x9e}V\x15\x80.\x16L\xe9\x1e\x7f\xfc\xf1\xc6\xcd;\xef\xbcs\xd7\xae]\xca\x02\xc0\x9a\xbbp\xe1\xc2\xc9\x93\'\x97\xbck\xdf\xbe}\xea\x03\xc0\xc6{\xfe\xf9\xe7\xbf\xf2\x95\xaf,,,4\x0f\xc6b\xb1\xdf\xfd\xdd\xdf\xd1\xe4\x04\xe8bVy\x03]k~~\xfe\xe8\xd1\xff\xd8\xc8\xbb\x83)\xdd\xc8\xc8\x88\xbc\x1b\x00\x00\xe8\x11;v\xec\xf8\xd8\xc7>v\xf3\xcd77\x0fV*\x95\xfb\xef\x7f`vvV}\x80n%\xf2\x06\xba\xd3\xe9\xd3\xa7\x83i\xdc\xdc\xdc\\x\xf3\x96[n\xb9\xe7\x9e{\xb6m\xdb\xa62\x00\x00@\xef\xe8\xef\xef\xdf\xb7o\xdf\xee\xdd\xbb\x9b\x07\x17\x16\x16\x1e~\xf8\xf8\x17\xbf8\xa1>@W\xbaN\t\x80\xee\xf3\x87\x7f\xf8G_\xfd\xeaW\x1b753\x01\x00\x00z\xd9\xee\xdd\xbbo\xbe\xf9\xe6\x96&\'\x8f=\xf6\xd8\xdf\xfd\xdd\xdf\xfd\xce\xef\xfc\xb6&\'@\x97\x11y\x03]e~~\xfe3\x9fy\xa8R\xa9\x847\xb7n}\xdb\xbd\xf7~|\xc7\x8e\x9b\xdb\xfc\xc7>s\xe6\xf5m\x15n\xbd\xf5\xc7:\xa8\xe0/]\xf4O\x8djo\xdd\xba\xb5\x83~xeWveW\xf6\xb5\xd5\xdf\x7f\xfd\xe5\xeeRv\xcfveWveW\xf6M/{\xf0\xfdc\x1f\xfb\xd8_\xfc\xc5_\xbc\xf0\xc2\x0b\x8d\xf1\xb9\xb9\xb9\xc3\x87\xff\xcfO|\xe2\x7f\xbd\xed\xb6\xdb\x9cN\x02]C\xe4\rt\x8f3g\xce<\xf4\xd0\xef7\x96-$\x93\xbb2\x99L$\x12\xe9\xac\x7f\xc5M7\xdd\xd4A?\xed\xfc\xfc+\x8d\xe3\xeb\xaf\xef\xef\xac\x1f^\xd9\x95]\xd9\x95}m\xddxcD\xd9=\xdb\x95]\xd9\x95]\xd9\xdb\xb9\xeca\x93\x93\xef~\xf7\xbb\x8d\x1d\x8f\x02\xdf\xfb\xde\xf7>\xf3\x99\x87\xf6\xef\xdf?8\x98vR\tt\x07\x917\xd0%\xbe\xf2\x95\xaf\xfc\xf9\x9f\xff?\x8d\x9bfl\x00\x00\x00\x8b}\xf8\xc3\x1f\xfe\xa9\x9f\xba\xe3\xf8\xf1\xcf\xd5j\xb5\xc6\xe0\xe4\xe4d\xb9\\\xea\xc45C\x00\x8b\xd9\xbe\x12\xe8x\xc1D\xed\xf8\xf1\xe3\x8d\xbc{\xcb\x96-\xa3\xa3\xa3\xf2n\x00\x00\x80%%\x12\x89\xc3\x87\x1f\x18\x18\x18h\x1e,\x16g\x8f\x1c9:7WQ\x1f\xa0\xd3\x89\xbc\x81\xce\x16L\xc8\x82iY09\x0bo\xder\xcb-\xf7\xdcs\xcf\xf6\xed\xdbU\x06\x00\x00\xe0r"\x91\xc8\xf8\xf8\xd8\xd0\xd0P\xf3`\xb5Z=z\xf4h\xa1PP\x1f\xa0\xa3il\x02t\xb0`*611\xd9\xb8\x1cow\x9d\xb2\x00\x00\x00\xac\xc4\xf0\xf0P<\x1e\xcb\xe5N479\tn\x96J\xa5\x91\x91\x11MN\x80\x0e%\xf2\x06:U.\x97+\x14N\x85\xc7\xc1T\xec\x9e{\xee1!\x03\x00\x00\xb8*\xc9d\xf2\xd0\xa1\xf8\xc3\x0f\x1f\xafT^oi\x12\x9cj\xcd\xcdU2\x99L<\x1eS"\xa0\xe3hl\x02t\x9ej\xb5z\xe4\xc8\xd1F\xde\x1d\x8b\xc5\x0e\x1f~\xe0=\xefy\x8f\xca\x00\x00\x00\\\xadh4z\xe8\xd0\xc1TjO\xf3`\xa5R\xc9f\xb3\xc5bQ}\x80\x8e#\xf2\x06:L\xa9T:r\xe4hc\x01B:\x9d\x0e&g\xd6w\x03\x00\x00\\\x8b\xccE\x07\x9a\xcf\xadj\xb5\xda\xf1\xe3\x9f\x9b\x98\x98T\x1c\xa0\xb3hl\x02t\x92\xa9\xa9\xe9@x\x1cL\xc5\x82\tY2\x99T\x16\x00\x00\x80k\x97J\xa5b\xb1x.\x97knr\x92\xcf\xe7\xe7\xe6\xe6\xee\xbbo\xd4J#\xa0SX\xe5\rt\x86\xfa\xfa\x82\xe3\x8d\xbc;\x16\x8b\x8d\x8d\x8d\xc9\xbb\x01\x00\x00\xd6P<\x1e\x1b\x1f\x0fN\xb5v5\x0f\x96\xcb\xe5#G\x8e\xce\xcdU\xd4\x07\xe8\x08"o\xa0\x03\x04S\xabc\xc7\xb2\xc5\xe2lx3\x95\xda\x13L\xc2\xec\xa3\x02\x00\x00\xb0\xe6"\x91\xc8\xe8\xe8\xe8\xfe\xfd\xfb\x9b\x07\xab\xd5\xea\xd1\xa3G\x0b\x85\x82\xfa\x00\xedOc\x13\xa0\xdd\x05\x93\xaa\x89\x89\xc9Z\xad\x16\xde\x0c&^\x83\x83ie\x01\x00\x00X?\xc1iW<\x1e;~\xfcs\x8ds\xb1@.w\xa2T*e2\x19\xf5\x01\xda\x99U\xde@[\x9b\x98\x98\x0c&U\xe1\x1c+\x12\x89\x8c\x8d}R\xde\r\x00\x00\xb0\x01\x12\x89\xc4\xa1C\x07c\xb17\\_[(\x9c:r\xe4hs\x0e\x0e\xd0nD\xde@\x9b\n\xa6P\xc7\x8ee\xf3\xf9|x3\x98f\x1d>\xfc@0\xe5R\x19\x00\x00\x80\x8d\x11\x8dF\x0f\x1d:\x98J\xedi\x1e\xacT*\xf7\xdf\xff\x80\xd6\xde@\xdb\x12y\x03\xed(\x98<\x1d9r\xb4\\.\x877\x83\tV0\xcd\xb2?8\x00\x00\xc0\xc6\xcb\\t\xa0y\xa4V\xabi\xed\r\xb4-\xbd\xbc\x81\xb6\xd3\xd2\xbc;\x98Z\xa5R)e\x01\x00\x00\xd8,\xc1IY,\x16\xcff\xb3Z{\x03\xed\xcf*o\xa0\xbd\xb44\xef>x\xf0\xa0\xbc\x1b\x00\x00`\xd3\xc5\xe3\x17\xbbMj\xed\r\xb4?\x917\xd0.\x96l\xde\x1dL\xaaT\x06\x00\x00\xa0\x1dD"\x11\xad\xbd\x81\xf6\'\xf2\x06\xda\x82\xe6\xdd\x00\x00\x00\x1dAko\xa0\xcd\xe9\xe5\rl\xbeb\xb1\xd8hf\xd2\xa7y7\x00\x00@{\xd3\xda\x1bhgVy\x03\x9bljj\xfa\xf8\xf1\xcfi\xde\r\x00\x00\xd0A.\xd7\xda\xfb\xd8\xb1\xac\xd6\xde\xc0\xe6\x12y\x03\x9b&\x98\x06\xe5r\xb9\xe9\xe9\xe9\xf0f0U:t\xe8\xa0\xe6\xdd\x00\x00\x00\x1d!\x12\x89\x8c\x8f\x8f\xb5\xb4\xf6.\x97\xcbG\x8e\x1c\xd5\xda\x1b\xd8D"o`sT\xab\xd5c\xc7\xb2\x85\xc2\xa9\xf0f0I\n\xa6J\xd1hTe\x00\x00\x00:E$\x12\xc9d2\xfb\xf7\xefo9\xdd\xcbf\xb3\xc5bQ}\x80M!\xf2\x066A\xb8Ye\xa5r\xe9c\xff`z\x14L\x92lV\t\x00\x00\xd0\x89\x06\x07\xd3cc\x9fl>\xa7\xab\xd5j\xc7\x8f\x7fnjjZq\x80\x8d\'\xf2\x066Z\xa1P8z\xf4h\xa3y\xf7\xe8\xe8\'\x82\xe9\x91\xb2\x00\x00\x00t\xaeD"166\xd6\xd2\xda{zz:\x97\xcbi\xed\rl0\x917\xb0\xa1&&&s\xb9\x13\xe1q4\x1a\r\xa6D\xc9dRY\x00\x00\x00:]<\x1e\x1b\x1f\x1f\x1b\x18\x18h\x1e\xb4\xa1%\xb0\xf1D\xde\xc0\x06\xa9_\xd7v<\x9f\xcf\x877\x83i\x90\xcd*\x01\x00\x00\xbaI\xb8\xa1e:\x9dn\x1e\xacT*\xf7\xdf\xff\x80\r-\x81\r#\xf2\x066B\xb8Ye\xb18\x1b\xde\x0c7\xab\xd4\xbc\x1b\x00\x00\xa0\xfb\x8c\x8c\xec\xcfd\x0e4\x8f\xd4j\xb5l6[(\x14\x14\x07\xd8\x00\xd7)\x01\xb0\xde\xe6\xe6*\xc1\xe4\xa6q![0\xf5I\xa5R\xca\x02\x00\x00\xd0\xad\x82\x93\xbeX,\xde|&\x18\x1c\xe4r\'.\\\xa8\x0e\x0f\x0f\xa9\x0f\xb0\xae\xac\xf2\x06\xd6W\xcbf\x95cc\x9f\x94w\x03\x00\x00t\xbdx\xae\xdf\xbf\x7f\x7f0\xb5Q\x16\x00\x00\x80^\x96J\xa5\xc6\xc6>\xd9\xbc\x16\xaaV\xab\x1d?\xfe\xb9B\xa1\xa08\xc0\xda\x12y\x03k\xa9X,6\xb6\xe4\xae_\xbf\xf6\x89\xc1\xc1\xb4\xb2\x00\x00\x00\x90H$\xc6\xc6\xc6Z6\xb4\xcc\xe5N\xe4r9\xc5\x01\xd6\x90\xc8\x1bX3\x85B\xe1\xf8\xf1\xcf5\xf2\xee`*\x93L&\x95\x05\x00\x00\x80P<\x1e\x1b\x1foM\xbd\x0b\x85S\xc7\x8f\x1f\xb7\xa1%\xb0VD\xde\xc0\xda\xc8]t"<\x0e\xa6/\x87\x0f?`\xb3J\x00\x00\x00ZD"\x91C\x87\x0e\xb6lhY,\xce\x1e;\x96\x95z\x03kB\xe4\r\\\xab`R\x92\xcb\xe5\x1a\x9bU&\x93\xbblV\t\x00\x00\xc022\x99\xcc\xd0\xd0P\xf3H\xa5rq_\xa8\xb9\xb9\x8a\xe2\x00\xd7H\xe4\r\\\x93Z\xadv\xecX\xb6\x91w\xa7R{FGG\xe5\xdd\x00\x00\x00,oxx(\x939\xd0r\x82\x99\xcdfK\xa5\x92\xe2\x00\xd7B\xe4\r\xac\xde\xdc\\\xe5\xc8\x91\xa3\x95\xca\xa5\x0f\xe1\x83\xc9J&\x93Q\x16\x00\x00\x00V"\x95J\x1d\xfe\xa5/\xfdIx\x1c\x8b\xc5\xc6\xc7\xc7\x9a\xb7\r\x01\x00\x00\x80\x8d\x94N\xa7[R\xefr\xb9,\xf5\x06\x96$\xf2\x06Z}\xf6\xb3\x0f\xcf\xce\xce\x86\xc7\xa9\xd4\x9eC\x87\x0e\xca\xbb\x01\x00\x00\xd8\\\xe9t:\x939\xd0\xd9|-rp2+\xf5\x06\x9a\x89\xbc\x81KS\x84c\xc7\xb2\x95\xca\xa5)B:\x9d\xde\xb5k\x97\xb2\x00\x00\x00\xd0n\x12\x89\xc4\xd8\xd8XK\xea}\xf4\xe8\xd1B\xa1\xa08@\x9f\xc8\x1b\x08\xcc\xcdU\xee\xbf\xff\x810\xef\xee\xef\xef_\xbc+\x08\x00\x00\x00\xb4\x8fx<666\x16\x8dF\x9b\x07s\xb9\x13Ro p\x9d\x12@\x8f{\xee\xb9\xe7\x1e|\xf03\xaf\xbd\xf6Zp|\xc3\r7|\xe4#\x1f\xd9\xb6m[x\xd7\xb9s/v\xd0?\xe4\x95W^i>\xee\xac\x1f\xbe\x99\xb2+\xbb\xb2+\xbb\xb2wh\xd9_z\xe9%e\xf7lWveWveW\xf6\r+\xfb\xf5\xd7_\xff\x9b\xbf\xf9\x9b\x8f<\xf2\xc8\xb9s\xe7\x1a\x83\xb9\xdc\x89\xef\x7f\xff\xfb\x1f\xfa\xd0\x87\x9c\xecC/{\xd3\xd9\xb3\xcf\xaa\x02\xf4\xac3g\xce<\xf4\xd0\xef/,,\xf4\xd5\xd7w\xef\xdb\xb7\xaf\x91w\x03\x00W\xe5\xc2\x85\x0b\'O\x9e\\\xf2\xae\xe0\x1dV}\x00`=\x04\xe7\xb3\x7f\xfe\xe7\x7f\x1e\xbc\x0b7\x0f\xde~\xfb\xed\xbf\xf5[\xf7)\x0e\xf4,\x8dM\xa0w\xcd\xcc\xe4?\xfd\xe9\xdf\x0b\xf3\xeem\xdb\xb6\xc9\xbb\x01\x00\x00\xe8,\xe1\xe2\xad[n\xb9\xa5y\xf0\xf4\xe9\xd3\x0f?|\\q\xa0g\x89\xbc\xa1G=\xfa\xe8\xa3\x93\x93\x93\xe1\xb1\xbc\x1b\x00\x00\x80\x0e\xd5\xdf\xdf\x7f\xf7\xddw\xb7lI5;;\xfb\xd9\xcf>\xac8\xd0\x9b\xf4\xf2\x86^\xf4\xd8c\x8f\x7f\xe9K\x7f\x12\x1e\xbf\xe3\x1d\xef\xf8\xe8G?z\xc3\r7\x847\x9b[\xbc\xddt\xd3M\x1d\xf4\x8fZXX\xf8\xfe\xf7\xbf\x1f\x1e_\x7f\xfd\xf5\xc1\xa4\xa7\x83~xeWveWve\xef\x82\xb27\xd7\xb9\x85\xb2{\xb6+\xbb\xb2+\xbb\xb2+\xfbz\x97\xfd\x97\x7f\xf9\x97\xaf\xbb\xee\xba\xa7\x9f~\xba1r\xfa\xf4\xe9\xff\xf0\x1f\xfe\xaf\x7f\xf7\xef\xfe\xf7\xce\xfa\x9f\x05\\;\x917\xf4\x9c\x89\x89\xc9|>\x1f\x1e\x0f\x0c\x0c\xdcw\xdfh$\x12i\xdc;;{\xbaq|\xeb\xad?\xd6A\xff\xaes\xe7^\x0c\x84\xc7[\xb7n\xdd\xbe\xfd\x9d\x1d\xf4\xc3+\xbb\xb2+\xbb\xb2+{\x17\x94\xfd\xcdo~\xf3\xe5\xeeRv\xcfveWveWve\xdf\x80\xb2\xff\xdb\x7f\xfb\xbf5\x9f\xf0\x06\x82\x7f\xf5\x83\x0f~f||\xac\xf9\xb4\x17\xe8z\x1a\x9b@o\xc9\xe5r\x8d\xb7\xffTj\x8f7~\x00\x00\x00\xba\xc6\xc8\xc8\xfeL\xe6@\xf3H\xa5R9v,[\xab\xd5\x14\x07z\x87\xc8\x1bzH.\x97+\x14N\x85\xc7\xa9\xd4\x9eL&\xa3&\x00\x00\x00t\x93T*\xb5d\xea]\xadV\x15\x07z\x84\xc8\x1bz\x85\xbc\x1b\x00\x00\x80^\xb0d\xea}\xe4\xc8\xd1\xb9\xb9\x8a\xe2@/\x10yC\xf7\xab\xd5j\xc7\x8ee\x1by\xf7\xd0\xd0\x90\xbc\x1b\x00\x00\x80.\x96J\xa5FG?\xd1\xdc\xc9385\xcef\xb3Ro\xe8\x05"o\xe8ra\xde].\x97\xc3\x9b\x99\xcc\x81\xe1\xe1!e\x01\x00\x00\xa0\xbb%\x93\xc9\xb1\xb11\xa97\xf4 \x917t\xb30\xef\xaeT.\xbd\x9dg2\x07R\xa9\x94\xb2\x00\x00\x00\xd0\x0b\xe2\xf1\x98\xd4\x1bz\x90\xc8\x1b\xba\x96\xbc\x1b\x00\x00\x80\x1ew\xb9\xd4\xbbX,*\x0et+\x917t\'y7\x00\x00\x00\xf4]&\xf5>~\xfcs\x85BAq\xa0+\x89\xbc\xa1\x0b\xcd\xcdU\x1ayw\xf0\xa6~\xf0\xe0Ay7\x00\x00\x00=+\x1e\x8f\x1d>\xfc@,\x16k\x1e\xcc\xe5NH\xbd\xa1+\x89\xbc\xa1\xdb\xcc\xcdU\xb2\xd9\xd7\xf3\xee\xb1\xb1\xb1\xe0\xad]Y\x00\x00\x00\xe8e\xc1\t\xf2\xf8\xf8\x98\xd4\x1bz\x81\xc8\x1b\xbaJ\x98w\xd7j\xb5>y7\x00\x00\x004\x91zC\x8f\x10yC\xf7\x90w\x03\x00\x00\xc02\xa4\xde\xd0\x0bD\xde\xd0%\xe4\xdd\x00\x00\x00pERo\xe8z"o\xe8\x06\xf2n\x00\x00\x00X!\xa97t7\x917t\xbc\xe6\xbc;\x1a\x8d\xca\xbb\x01\x00\x00`ya\xea=00\xd0<\x98\xcb\x9d\xc8\xe5r\x8a\x03\x9dN\xe4\r\x9d\xad9\xef\x8e\xc5b\x87\x0e\x1d\x94w\x03\x00\x00\xc0\x15\x85\xa9w*\xb5\xa7y\xb0P8%\xf5\x86N\'\xf2\x86\x0e\xd6\x92w\x07o\xd5\xc1\x1b\xb6\xb2\x00\x00\x00\xc0\ne2\x19\xa97t\x19\x917t*y7\x00\x00\x00\\;\xa97t\x19\x917t$y7\x00\x00\x00\xac\x15\xa97t\x13\x917t\x1ey7\x00\x00\x00\xac-\xa97t\r\x917t\x18y7\x00\x00\x00\xac\x07\xa97t\x07\x917t\x12y7\x00\x00\x00\xac\x1f\xa97t\x01\x917t\x0cy7\x00\x00\x00\xac7\xa97t:\x917t\x06y7\x00\x00\x00l\x0c\xa97t4\x917t\x00y7\x00\x00\x00l$\xa97t.\x917\xb4;y7\x00\x00\x00l<\xa97t(\x917\xb45y7\x00\x00\x00l\x16\xa97t"\x917\xb4/y7\x00\x00\x00l.\xa97t\x1c\x917\xb4)y7\x00\x00\x00\xb4\x83%S\xef\x99\x99\xbc\xca@{\x12yC;\x92w\x03\x00\x00@\xfbX\x9czONN\x16\n\x05\x95\x816$\xf2\x86\xb6#\xef\x06\x00\x00\x80v\xb38\xf5\xce\xe5NH\xbd\xa1\r\x89\xbc\xa1\xbd4\xe7\xdd\xd1hT\xde\r\x00\x00\x00m"\x93\xc9$\x93\xbb\x9aG\xa4\xde\xd0\x86D\xde\xd0F\x9a\xf3\xeeH$2::*\xef\x06\x00\x00\x80\xf6\x91\xc9db\xb1X\xf3\x88\xd4\x1b\xda\x8d\xc8\x1b\xdaEK\xde=66\x16\x8f\xc7\x94\x05\x00\x00\x00\xdaGp\xc2>>>&\xf5\x86v&\xf2\x86\xb6P\xab\xd5r\xb9\x9c\xbc\x1b\x00\x00\x00\xda\x9c\xd4\x1b\xda\x9c\xc8\x1b6_\xadV;v,[\xa9T\xfa\xe4\xdd\x00\x00\x00\xd0\xf6\xa4\xde\xd0\xceD\xde\xb0\xc9\xe4\xdd\x00\x00\x00\xd0q\x96L\xbd\'&&\xe7\xe6*\x8a\x03\x9bK\xe4\r\x9bI\xde\r\x00\x00\x00\x1djq\xea\x1d\x9c\xe6g\xb3Y\xa97l.\x917l\x9a\xe6\xbc; \xef\x06\x00\x00\x80\xce\x12\xa6\xde\xd1h\xb4\xf9d_\xea\r\x9bK\xe4\r\x9b\xe6\xe1\x87\x8f7\xf2\xeeL\xe6\x80\xbc\x1b\x00\x00\x00:N$\x12\x19\x1d\x1d\r\xbe7F\xc2\xd4\xfb\xb9\xe7\x9eS\x1c\xd8\x14"o\xd8\x1c\xb9\\\xae\\.\x87\xc7\x99\xcc\x81T*\xa5&\x00\x00\x00\xd0\x89\xe2\xf1\xd8\xd8\xd8XK\xea\xfd\xe0\x83\x9f9s\xe6\x8c\xe2\xc0\xc6\x13y\xc3&\xc8\xe5r\x85\xc2\xa9\xf0X\xde\r\x00\x00\x00\x9dnq\xea\xfd\xdak\xaf=\xf2Hn~\xfe\x15\xc5\x81\r&\xf2\x86\x8d&\xef\x06\x00\x00\x80\xee\xb38\xf5>\x7f\xfe\xfc\xa7>\xf5\xa9\xf9\xf9y\xc5\x81\x8d$\xf2\x86\r511\xd9\xc8\xbb\x87\x86\x86\xe4\xdd\x00\x00\x00\xd05\xe2\xf1\xd8\xe8\xe8\'\x9aG\xea\xa9\xf7\x7fz\xf5\xd5W\x15\x076\x8c\xc8\x1b6N\xa1P\xc8\xe7\xf3\xe1q*\xb5gxxHM\x00\x00\x00\xa0\x9b$\x12\x89L\xe6@\xf3\xc8\xf9\xf3\xe7?\xfd\xe9\xdf\xab\xd5j\x8a\x03\x1bC\xe4\r\x1b\xa4P(\xe4r\'\xc2\xe3TjO&\x93Q\x13\x00\x00\x00\xe8>\xa9T\xaa%\xf5\xfe\x87\x7f\xf8\x87\x89\x89\t\x95\x81\x8d!\xf2\x86\x8d \xef\x06\x00\x00\x80\xde\x91J\xa5\xf6\xed\xdb\xd7\xad\xd5j\xc7\x8f\x1f\x0f\xbe+\x0e\xac!\x917\xac\xa5\\.W(\x9c\n\x8f\x17o\xca\x0c\x00\x00\x00\xf4\xb2x<666\xd6\x9czW\xab\xd5c\xc7\xb2RoXC"oX3\x85\x8b.\xe5\xddw\xdey\xa7\xbc\x1b\x00\x00\x00h\x11\xa6\xde\xcd#\x95JE\xea\rk\xe8Mg\xcf>\xab\np\xed\x1e}\xf4\xd1/}\xe9O\xc2\xe3\x9d;w\xa6\xd3i5\x01\x80\x9er\xe1\xc2\x85\x93\'O.y\xd7\xbe}\xfb\xd4\x07\x00h\xf6\xcc3\xcf\xe4\xf3\xf9\xe6\x91\xdbo\xbf\xfd\xb7~\xeb>\x95\x81kg\x957\xac\x81\xd9\xd9Yy7\x00\x00\x00\xb0B\x8b\xd3\x83\xd3\xa7O\x7f\xf6\xb3\x0f\xab\x0c\\;\x917\\\xab3g\x9e\xfd\x83?\xf8/\xe1\xf1\xb6m\xdb\xe4\xdd\x00\x00\x00\xc0\x15\xed\xdc\xb9\xf3\xf6\xdboo\x1e9}\xfa\xf4\x7f\xff\xefS*\x03\xd7H\xe4\r\xd7\xe4\xcc\x993\x0f=\xf4\xd0\xc2\xc2B_=\xefv\xd92\x00\x00\x00\xb0Bw\xdduW\xcbN`_\xfe\xf2\x97\x1f}\xf4Q\x95\x81kq\x9d\x12\xc0\xaa\xbd\xfa\xea\xab\x7f\xf8\x87\x7f\x14\xe6\xdd[\xb7\xbe\xedw\x7f\xf7w#\x91\x1b\x83\xe3\x97.\xfa\xa7\xf01\xc1\xf8\xd6\xad[;\xe8\x1fu\xe6\xcc\xeb\xfd\xfdo\xbd\xf5\xc7:\xe8\'WveWveWve\xdf\\\xfd\xfd\xd7_\xee.e\xf7lWveWveWve\xbf\\\xd9\x83\x7f\xd4\x7f\xfd\xaf\x8f<\xfd\xf4\xd3\x8d\x91/}\xe9O\xb6n\x8d\xbe\xff\xfd?\xd5\x07\xac\x8a\xc8\x1bV\xa9V\xabe\xb3\x0f\xbe\xf0\xc2\x0b\xc1q$\x12\xb9\xef\xbe\xdfz\xfb\xdb\xb7\x85w\xcd\xcf\xbf\xd2x\xd8\xf5\xd7\xf7\xdft\xd3M\x1d\xfao\xec\xac\x9f\\\xd9\x95]\xd9\x95]\xd9\x95}s\xddxcD\xd9=\xdb\x95]\xd9\x95]\xd9\x95]\xd9WQ\xf6\xdf\xf8\x8d_?v,[\xa9T\x1a#\x9f\xff\xfc\xe7\xdf\xf1\x8ew\xc4\xe3\xb1>\xe0\xeail\x02\xab\x94\xcb\xe5\xc2w\xa3H$266\xe6}\x08\x00\x00\x00X\x85H$2>>\x16\x8b\xbd\x1e,\xd4\x97\xd9e\xab\xd5\xaa\xe2\xc0*\x88\xbca5r\xb9\\\xb18\x1b\x1e\x8f\x8c\xec\x97w\x03\x00\x00\x00\xab\x16\x89D2\x99L\xf0\xbd1R\xab\xd5\x1e~\xf8x\xf0]q\xe0j\x89\xbc\xe1\xaa\xcd\xcc\xe4\x0b\x85S\xe1q&s \x95J\xa9\t\x00\x00\x00p-\xe2\xf1\xd8\xd8\xd8Xs\xea]\xa9T\x8e\x1d\xcbJ\xbd\xe1j\x89\xbc\xe1\xea\x14\n\x85\xc9\xc9\xc9\xf08\x95\xda#\xef\x06\x00\x00\x00\xd6D<\x1e\x1b\x19\xd9\xdf\x08\x82\xa7\x1e\x1a\xd6\xcc\xb7\x8b\x94\xf1\xe53\xbf\x87[\xea\xf5z++\xe7\x93u\xbd~Z\xdf\r\x00\x00\x00\x1c\xb0r\xb9\xb4\xbc\xbc\x94\xde\x19\x0c\x06+++\x92\x81[Qy\xc3\xce\x86\xc3\xd1\xb8\xef\xae\xd5\xe6\x9a\xcd\xa6L\x00\x00\x00\x80\x83W\xaf\xd7\x97\x96\xb6\xb4\xde\xdd\xee\xc5\xf5\xf5\x8ed`G*o\xd8Ar#D2\x1b\xabT*\xe9\xbb\x01\x00\x00\x80C4?\xdf\xa8\xd7O\xa7wVWW\xbb\xdd\xaed`;\x957d\xc5q\xfc\xfb\xbf\x7f\xb3\xef\x0e\x82\xe0\xb9\xe7\xb6\xcc\xcc\x02\x00\x00\x008x\xcdf\xb3R\xa9\xa4wZ\xad\xd5\xe1p$\x19\xc8PyCV\xab\xd5\x1a\x8d\xde\xf9\x17F\x10\x04\x99;"\x00\x00\x00\x00\x0e\xcb3\xcf\x9c-\x95J\xe3\xc7\xf4\x0f\xa9\x03c*o\xd8\xa2\xd5Z\xedv/&\xebf\xf3\xa9r\xb9$\x13\x00\x00\x00`\x12\x04A\xf0\xcc3g\xd3\x87\xf3\xd2?\xaa\x0e$T\xde\xf0\xaen\xb7\xdb\xe9t\x92\xf5\xd2\xd2R\xadV\x93\t\x00\x00\x0009\xc20|\xf6\xd9g\xd3;\xa3\xd1heeE20\xa6\xf2\x86\x9b\x86\xc3\xcd\x7fC\x9cO\xd6\xf5\xfa\xe9\xf9\xf9\x86L\x00\x00\x00\x80IS.\x97\x9a\xcd\xa7\xd2;\xbd\xdeF\xab\xb5*\x19H\xa8\xbc\xe1\x1dQ\x14=\xff\xfc\xf3\xc9\xbaR\xa94\x9bM\x99\x00\x00\x00\x00\x93\xa9^\xaf7\x1a\x8d\xf4N\xa7\xd3\xe9v\xbb\x92\x81\x19\x957\xcc\xdc\x98{\xf5\xc2\x0b\xe7\x92\xb9W\xa5R\xe9\x99g\xce\xca\x04\x00\x00\x00\x98d\xcb\xcbK\xf5\xfa\xe9\xf4\xce\xca\xca\xf9\xe1p$\x19Py\xc3\xe6\xbf\x12VF\xa3w\xfe\x95\x10\x04A\xb3\xd9L\xdf\x02\x01\x00\x00\x000\x99\x96\x97\x97K\xa5Rz\xe7\xf9\xe7\x9f\x8f\xa2H2L9\x957\xd3\xae\xd5Z\xed\xf56\x92\xf5\xd9\xb3\x9f)\x97K2\x01\x00\x00\x00&_\x10\x04\xcf=\xf7l\xfa\xe8^\xfa\x07\xd9aj\xa9\xbc\x99j\xddn\xb7\xd3\xe9$\xebf\xf3\xa9j\xb5*\x13\x00\x00\x00 /\x82 x\xf6\xd9-\xad\xf7h4ZYY\x91\x0c\xd3L\xe5\xcd\xf4\x1a\x0e7\xff\x1dp>Y\xd7\xeb\xa7\xeb\xf5\xbaL\x00\x00\x00\x80|)\x97K\xcb\xcbK\xe9\x9d^o\xa3\xd5Z\x95\x0cSK\xe5\xcd\x94\x8a\xa2\xe8\xf9\xe7\x9fO\xd6\x95J\xa5\xd9l\xca\x04\x00\x00\x00\xc8\xa3z\xbd\xbe\xb0\xb0\x90\xde\xe9t:\xddnW2L\'\x957\xd3(=\xd9*\x0c\xc3g\x9e9+\x13\x00\x00\x00 \xbf\x16\x17\x17j\xb5\xb9\xf4\xce\xca\xca\xf9\xe1p$\x19\xa6\x90\xca\x9bi\xd4j\xb5F\xa3w\xfe\xd0\x0f\x82\xe0\xec\xd9\xb3\xe9\x89W\x00\x00\x00\x00y\xd4l6K\xa5Rz\xe7\xf9\xe7\x9fw\x95%SH\xe5\xcd\xd4Y[kw\xbb\x17\xff\xeb\xbf\x0c\x9e*\x97K2\x01\x00\x00\x00\xf2.\x08\x82g\x9e\xd9r\xb0/\x8e\xe3\xdf\xff}\xad7SG\xe5\xcdt\xe9\xf5z\xedv;Y/--\xd5j5\x99\x00\x00\x00\x00\xc5\x10\x86\xe1\xb3\xcf>\x9b\xde\x19\x8dF\xadVK2L\x15\x957Sd8\x1c\xad\xac\x9cO\xd6\xf5\xfa\xe9\xf9\xf9\x86L\x00\x00\x00\x80")\x97K\xcd\xe6S\xe9\x9dn\xf7\xe2\xfazG2L\x0f\x957\xd3"\x8e\xe3s\xe7n^YY*\x95\x96\x97\x97e\x02\x00\x00\x00\x14O\xfd\x1d\xa7\xd3;\xab\xab\xab\xfd~_2L\t\x957\xd3\xe2\x85\x17\xceEQ4\xb3\xd3d+\x00\x00\x00\x80"\xd9~\x95\xe5\xb9s\x9f\x1f\x0eG\x92a\x1a\xa8\xbc\x99\n\xad\xd6\xea`0H\xd6\xcf>\xfbl\x18\x862\x01\x00\x00\x00\n\xec\xb9\xe7\xb6\x14 q\x1c\xaf\xac\xac\xb8\xca\x92i\xa0\xf2\xa6\xf8\xba\xddn\xa7\xd3I\xd6\xcd\xe6S\xe5rI&\x00\x00\x00@\xb1\x05Ap\xf6\xec\x96\x1fs\x1f\x8dF+++\x92\xa1\xf0T\xde\x14\xdcp8j\xb5V\x93u\xbd~\xba^\xaf\xcb\x04\x00\x00\x00\x98\x06\xe5riyy)\xbd\xd3\xebm\xac\xad\xb5%C\xb1\xa9\xbc)\xb2\xcc\x95\x95\xcdfS&\x00\x00\x00\xc0\xf4\xa8\xd7\xeb\x8dF#\xbd\xd3n\xb7{\xbd\x9ed(0\x957E\x96\xbe\xb2\xf2\xb9\xe7\x9e\x15\x08\x00\x00\x000m\x96\x97\x97*\x95Jzge\xe5\xbc\xab,)0\x957\x85\x95\xb9\xb22=\xbb\n\x00\x00\x00`z<\xf3\xccYWY2=T\xde\x14\x93++\x01\x00\x00\x00\x12\xae\xb2d\xaa\xa8\xbc) WV\x02\x00\x00\x00\xa4\xedx\x95\xe5\xfazG2\x14\x8f\xca\x9b\xa2I\xffl\x8e++\x01\x00\x00\x00\x12\xdb\xaf\xb2\\]]\xed\xf7\xfb\x92\xa1`T\xde\x14\xcd\xca\xca\xcah\xf4\xce\r\x0c\xae\xac\x04\x00\x00\x00H\xdb~\x95\xe5\xb9s\x9f\x8f\xa2H2\x14\x89\xca\x9bBY[k\xf7z\x1b\xc9\xfa\xec\xd9\xcf\xb8\xb2\x12\x00\x00\x00 \xed\x99g\xb6\x0c\xf5\x8e\xe3\xf8\x85\x17\xce\x89\x85"QyS\x1c\xfd~\xbf\xddn\'\xeb\xa5\xa5\xa5j\xb5*\x13\x00\x00\x00\x80\xb4 \x08\x9e}v\xcb\x8f\xc5\xbb\xca\x92\x82QyS\x10Q\x14\x9d;\xf7\xf9d]\xaf\x9f\x9e\x9fo\xc8\x04\x00\x00\x00`\xbbr\xb9\xd4l>\x95\xde\xe9v/v\xbb]\xc9P\x0c*o\n\xe2\x85\x17\xce\x8d\xaf\xac\\^^\x16\x08\x00\x00\x00\xc0\xad\xd4\xdfq:\xbd\xd3j\xad\x0e\x87#\xc9P\x00*o\x8a }ee\xb3\xd94\xc2\x1b\x00\x00\x00\xe0\xf6\x96\x97\x97K\xa5\xd2\xf81\x8e\xe3s\xe7n\x1e(\x84\\Sy\x93{\xddw\\L\xd6\xcd\xe6S\xe5rI&\x00\x00\x00\x00\xb7\x17\x04A\xe6*\xcb(\x8a\x0c\xf5\xa6\x00T\xde\xe4\xdbp8j\xb5V\x93u\xa3\xd1\xa8\xd5j2\x01\x00\x00\x00\xb8\x13a\x18f\x86z\xf7z\x1bkkm\xc9\x90k*or,\xfd\x1377Fx/\xc9\x04\x00\x00\x00\xe0\xce\xd5j\xb5F\xa3\x91\xdei\xb7\xdb\x1b\x1b\x1b\x92!\xbfT\xde\xe4\xd8\xca\xcaJ\x14E37~\x12\xe7\xb9\xe7\x9e\x15\x08\x00\x00\x00\xc0\xddZ^^\xaaT*\xe9\x9d?\xfc\xc3?\xbav\xed\x9ad\xc8)\x957y\xb5\xbe\xde\xe9\xf5n\xfe\x95\xe3\xd9\xb3\x9fqe%\x00\x00\x00\xc0\xeed\x86z_\xbf~\xfd\xdf\xfd\xbb\xffU,\xe4\x94\xca\x9b\\\x1a\x0eG\xab\xab7Gx/,,T\xabU\x99\x00\x00\x00\x00\xecN\x10\x04g\xcf~&\xbd\xf3\xc6\x1bo\xbc\xf8\xa2\xab,\xc9%\x957\xf9\x13\xc7\xf1\xf3\xcf?\x9f\xack\xb5\xb9\xc5\xc5\x05\x99\x00\x00\x00\x00\xdc\x8bj\xb5\xba\xb4\xb4\xe5\x9a\xb4\x8b\x17/\xbe\xf4RW2\xe4\x8e\xca\x9b\xfcy\xe1\x85\x9bWV\xde\xb8V\xb8)\x10\x00\x00\x00\x80{7?\xdf\xa8\xd5\xe6\xd2;_\xf8\xc2\x17\x92{\xd4 G> \x02\xf2\xe5K_\xfa\xd2`0H\xd6\xcb\xcb\xcb\xff\xf0\x0fW7\xffo\xd2\xbe\xc8\xb7\xdez+\xbd\xbe|\xf9\xf5\x9c\xa6\x9d\xaf\xaf\\\xecb\x17\xbb\xd8\xc5.\xf6\xc3\xf5\xe6\x9bo\x8a\xdd\xdb.v\xb1\x8b]\xecb\x17{\xdec\x7f\xf2\xc9\xdf\xf8\xf1\x8f\x7f\xf2\xb3\x9f\xfd,y\xbc~\xfd\xfa\x7f\xf8\x0f\xff\xc7g?\xfb\xbb3\x90\x1f\xef{\xed\xb5\x1fI\x81\xbc\xd8\xd8\xd8x\xe1\x85s\xc9\xfa\xf1\xc7\x1f\x9f\x9b\x9b\x93\t\x000!\xae\\\xb9r\xe1\xc2\x85\x1d\x7f\xe9\xcc\x993\xf2\x01\x00r\xf4\xbfjZ\xadVz\xe7\x13\x9f\xf8\xc4\xa7?\xfd\xb4d\xc8\x0b\x83M\xc8\x8dk\xd7\xde\xfa\xc3?\xfc\xa3d}\xf2\xe4I}7\x00\x00\x00\xc0\x9e;~\xfc\xf8\xe3\x8f?\x9e\xde\xf9\xf6\xb7\xbf\xdd\xed^\x94\x0cy\xa1\xf2&7\xfe\xe0\x0f\xfe\xe0\xfa\xf5\xeb\x9b\x8b\xa3G\x8f6\x1a\r\x81\x00\x00\x00\x00\xec\x87\xb9\xb9\xb9\x93\'O\xa6w\xfe\xfc\xcf\xff\xfc\xd2\xa5K\x92!\x17\xcc\xf2&\x1fVWW\x87\xc3a\xb2\xfe\xad\xdf\xfa\xadc\xc7\x8eM\xf2W{\xfd\xfa\xf5\xb7\xdf~;Y\x1f9rdvv6GQ\xa7g\x8d\xdd\x7f\xff\xfd9\xfa\xca\xc5.v\xb1\x8b]\xecb\x9f\x9c\x9c3\xc4\xeem\x17\xbb\xd8\xc5.v\xb1\x8b=w\xb17\x1a\x8d/~\xf1\x8b\xd7\xae]\x1b\x7f;\xe7\xce}\xfe_\xff\xeb\xffi\x06&\x9e\xca\x9b\x1c\xd8\xd8\xd8X_\xef$\xeb\xa5\xa5\xa5z\xfd\xf4\x84\x7f\xc1\x97/\xbf\xbe)Y\x1f;v\xec#\x1f\xf9\xe5\\\xa5\xfd\xcax\xfd\xd0C\x1f\xcb\xd1W.v\xb1\x8b]\xecb\x17\xfb\xe1z\xff\xfb\xdf\x7f\xab_\x12\xbb\xb7]\xecb\x17\xbb\xd8\xc5.\xf6\xdc\xc5>;;\xfb\x1b\xbf\xf1\x1b\xe9\xa1\xde\x9b\xdfN\xab\xb5\xba\xbc\xbc4\x03\x93\xcd`\x13&]z\x84w\xad67?\xdf\x90\t\x00\x00\x00\xc0~\xdb>\xd4\xbb\xd3\xe9\xf4z=\xc90\xe1T\xdeL\xba\xf1\x08\xef0\x0c\x9b\xcd\xa6@\x00\x00\x00\x00\x0e\xc6\xdc\xdc\\\xad6\x97\xdeYY9\x1fE\x91d\x98d*o&\xda\x97\xbf\xfc\x95\xf1\x08\xef\xb3g\xcf\x06A \x13\x00\x00\x00\x80\x03\xd3l6\xc30\x1c?\xc6q\xfc\xc2\x0b\xe7\xc4\xc2$Sy3\xb9^}\xf5\xd5\xbf\xf8\x8b\xbfH\xd6KKK\xe5rI&\x00\x00\x00\x00\x07)\x08\x82\xb3g\xcf\xa6wF\xa3Q\xab\xb5*\x19&\x96\xca\x9b\t\x15\xc7\xf1\xe7?\xff\x7f&\xeb\x93\'O\x1a\xe1\r\x00\x00\x00p(\xca\xe5\xd2\xd2\xd2\x96[+;\x9dN\xbf\xdf\x97\x0c\x93I\xe5\xcd\x84ZYY\xb9z\xf5\xea\xe6bvv\xb6\xd1h\x08\x04\x00\x00\x00\xe0\xb0\xcc\xcf7*\x95Jz\xe7\xdc\xb9\xcf\xc7q,\x19&\x90\xca\x9bI\xb4\xbe\xde\xe9\xf56\x92\xf5\x93O>9;;+\x13\x00\x00\x00\x80C\xf4\xcc3[nY3\xd4\x9b\x89\xa5\xf2f\xe2\x0c\x87\xa3v\xbb\x9d\xacO\x9d:\xf5\xe0\x83\x0f\xca\x04\x00\x00\x00\xe0p\xdd\x18\xea\xfd\x99\xf4\xce`0X[kK\x86I\xa3\xf2f\xb2\xc4q\xbc\xb2\xb2\x92\xfc\\\xcc\x89\x13\'N\x9d:%\x13\x00\x00\x00\x80IP\xadV\x17\x16\x16\xd2;\xedv{8\x1cI\x86\x89\xa2\xf2f\xb2\xac\xad\xb5G\xa3w\xfe\xa0\x0c\x82\xc0\x08o\x00\x00\x00\x80\x89\xb2\xb8\xb8P*\x95\xd2;\xe7\xce\x9d3\xd4\x9b\x89\xa2\xf2f\x82\xf4z\xbdN\xa7\x93\xac\x9b\xcd\xa7\x1ex\xe0\x01\x99\x00\x00\x00\x00L\x94\xccP\xef(\x8aZ\xad\x96X\x98\x1c*o&\xc5\x8d\x91&\xe7\x93u\xa3\xd1\xa8\xd5j2\x01\x00\x00\x00\x984a\x186\x9bO\xa5w\xba\xdd\x8b\xddnW2L\x08\x957\x93\xe2\x85\x17n\xfe\x14L\xa9TZ\\\\\x10\x08\x00\x00\x00\xc0d\xaa\xd5j\xf5\xfa\xe9\xf4N\xab\xb5\x1aE\x91d\x98\x04*o&\xc2\xdaZ{0\x18$\xebf\xb3\x99\xfe\xe9\x18\x00\x00\x00\x00&\xcd\xf2\xf2r\x18\x86\xe3\xc78\x8e_x\xe1\x9cX\x98\x04*o\x0e\xdfp8j\xb7\xdb\xc9zii\xa9\\.\xc9\x04\x00\x00\x00`\x92\x05Ap\xf6\xec\xd9\xf4\xceh4Z[kK\x86C\xa7\xf2\xe6\x90\xc5q|\xee\xdc\xcd\xbf\x03\xac\xd5\xe6\xe6\xe7\x1b2\x01\x00\x00\x00\x98|\xe5riii)\xbd\xd3n\xb7\xfb\xfd\xbed8\\*o\x0eY\xab\xd5J&=\x05A\xd0l6\x05\x02\x00\x00\x00\x90\x17\xf3\xf3\x8dJ\xa5\x92\xdeYY9\x9f\xdc\xd6\x06\x87E\xe5\xcda\xea\xf5z\xdd\xee\xc5d}\xf6\xecg\x8c\xf0\x06\x00\x00\x00\xc8\x97g\x9e9\x9b\xaet\xa2(ZYY\x11\x0b\x87H\xe5\xcd\xa1\x89\xe3xe\xe5|\xb2n4\x1a\xd5jU&\x00\x00\x00\x00\xf9r\xe3\x07\xf7\x9fJ\xef\xf4z\x1b\xddnW2\x1c\x16\x957\x87\xe6\x85\x17\xce%?\xe7R*\x95\x16\x17\x17\x04\x02\x00\x00\x00\x90G\xb5Z\xad^?\x9d\xdei\xb5V\x93I\xb6p\xf0T\xde\x1c\x8e\xf5\xf5\xce`0H\xd6\xcdf\xd3H\x13\x00\x00\x00\x80\xfcZ^^\x0e\xc3p\xfc\x18\xc7\xf1\x8b/\x1ao\xc2\xe1Pys\x08\x86\xc3\xd1\xea\xeaj\xb2^ZZ*\x97K2\x01\x00\x00\x00\xc8\xaf \x08\xce\x9e=\x9b\xde\x19\x0c\x06kkm\xc9p\xf0T\xde\x1c\x82\xf1%\x06\x95Je~\xbe!\x10\x00\x00\x00\x80\xbc+\x97K\x0b\x0b[F\xd7\xb6\xdb\xed\xe1p$\x19\x0e\x98\xca\x9b\x83\xd6j\xad\x8eF\xef\xfca\x17\x04\xc1\xd3O7\x05\x02\x00\x00\x00P\x0c\x8b\x8b\x0b\xa5\xd2\x96\x9f\xe6_YYI\xeer\x83\x03\xa3\xf2\xe6@\xf5\xfb\xfdN\xa7\x93\xac\x9b\xcd\xa7\xd23\x9e\x00\x00\x00\x00\xc8\xbbg\x9e9\x9b\xbe\xb3m4\x1a\x19o\xc2\x01Sysp\xe28^Y9\x9f\xack\xb5\xb9Z\xad&\x13\x00\x00\x00\x80"\t\xc303\xde\xa4\xd3\xe9\xf4\xfb}\xc9p`T\xde\x1c\x9cV\xab\x15EQ\xf2g_\xb3i\xa4\t\x00\x00\x00@\x01\xcd\xcf7j\xb5\xb9\xf4\xce\xca\xcay\xe3M80*o\x0eH\xaf\xd7\xebv/&\xebf\xf3\xa9\xf4O\xb8\x00\x00\x00\x00P$\xcdf3]\xfeDQ\xb4\xb2\xb2"\x16\x0e\x86\xca\x9b\x83\x90\x1ei\xd2h4\xaa\xd5\xaaL\x00\x00\x00\x00\x8a*\x08\x82f\xf3\xa9\xf4N\xaf\xb7\xd1\xeb\xf5$\xc3\x01Pys\x10\xc6\x97\xf3\x96J\xa5\xc5\xc5\x05\x81\x00\x00\x00\x00\x14[\xadV\xab\xd7O\xa7w\x8c7\xe1`\xa8\xbc\xd9w\xddn\xb7\xd7\xdbH\xd6\x99\x9fj\x01\x00\x00\x00\xa0\xa8\x96\x97\x97\xc30\x1c?\xde\x18\x03`\xbc\t\xfbN\xe5\xcd\xfe\x8a\xa2\xa8\xd5ZM\xd6\x0b\x0b\x0b\xe5rI&\x00\x00\x00\x00\xd3`\xc7\xf1&\xeb\xeb\x1d\xc9\xb0\xafT\xde\xec\xaf\x17_4\xd2\x04\x00\x00\x00`JU\xab\xd5F\xa3\x91\xdei\xb7\xdbQ\x14I\x86\xfd\xa3\xf2f\x1f\xad\xafw\x06\x83A\xb2n6\x9b\x02\x01\x00\x00\x00\x986\x8b\x8b\x0b\x99\xf1&/\xbeh\xbc\t\xfbH\xe5\xcd~\x89\xa2\xa8\xddn\'k#M\x00\x00\x00\x00\xa6\xd3\xf6\xf1&\x83\xc1\xc0x\x13\xf6\x8f\xca\x9b\xfd2\x1eiR\xa9T\x8c4\x01\x00\x00\x00\x98Z\xd5juaaK;d\xbc\t\xfbG\xe5\xcd\xbe\x18\x8f4\t\x82\xe0\xe9\xa7\x8d4\x01\x00\x00\x00\x98j\x8b\x8b\x0b\xa5\xd2\xbb3\x00\x8c7a\xff\xa8\xbc\xd9{\x99\x91&\xe9iM\x00\x00\x00\x00L\xa7\xccMo\xc6\x9b\xb0OT\xde\xec\xbd\xf4H\x93\xf9\xf9\x86@\x00\x00\x00\x00(\x97K\xc6\x9bp\x00T\xde\xec1#M\x00\x00\x00\x00\xd8\x91\xf1&\x1c\x00\x957{\xc9H\x13\x00\x00\x00\x00n\xc3x\x13\xf6\x9b\xca\x9b\xbdd\xa4\t\x00\x00\x00\x00\xb7a\xbc\t\xfbM\xe5\xcd\x9e1\xd2\x04\x00\x00\x00\x80\xf7d\xbc\t\xfbJ\xe5\xcd\xde0\xd2\x04\x00\x00\x00\x80;d\xbc\t\xfbG\xe5\xcd\xde0\xd2\x04\x00\x00\x00\x80;d\xbc\t\xfbG\xe5\xcd\x1e0\xd2\x04\x00\x00\x00\x80\xbbb\xbc\t\xfbD\xe5\xcd\xbd2\xd2\x04\x00\x00\x00\x80]0\xde\x84\xfd\xa0\xf2\xe6^\x19i\x02\x00\x00\x00\xc0.\x18o\xc2~PysO\xba\xddn2\xd2d\xd3\xf2\xf2\xb2@\x00\x00\x00\x00\xb8s\xf3\xf3\x8d\xf4\xcc\x00\xe3M\xb8w*ovo\xf3\xcf\xa0Vk5Y/,,\x94\xcb%\x99\x00\x00\x00\x00p\xe7\x82 h6\x9fJ\xef\x0c\x06\x83^\xaf\'\x19vM\xe5\xcd\xee\xad\xac\xdc\x1ciR*\x95\x16\x17\x17\x04\x02\x00\x00\x00\xc0\xdd\xaaV\xab\x8dF#\xbd\xb3\xb2r>)\x9d`\x17T\xde\xecR\xef\x1d\x1b\xc9:s\xd5\x00\x00\x00\x00\x00\xdc\xb9\xc5\xc5\x85\xccx\x93\x95\x15\xe3M\xd8%\x957\xbbq\xe3\xcf\x9d\xf3\xc9\xdaH\x13\x00\x00\x00\x00\xee\xc5\xf6\xf1&\xbd\xde\x86\xf1&\xec\x8e\xca\x9b\xddX[k\'?]\x12\x86\xe1\xfc|C \x00\x00\x00\x00\xdc\x8bj\xb5Z\xab\xcd\xa5wZ\xadU\xe3M\xd8\x05\x957w\xad\xdf\xefw:\x9dd\xddl>\x15\x04\x81L\x00\x00\x00\x00\xb8G\xcdf3]4EQ\xb4\xb6\xd6\x16\x0bwK\xe5\xcd\xddI\x8f4i4\x1a\xd5jU&\x00\x00\x00\x00\xdc\xbb\xed\xe3M:\x9dN\xbf\xdf\x97\x0cwE\xe5\xcd\xddY_\xefDQ\x94\xfc\x19\xb4\xb8\xb8 \x10\x00\x00\x00\x00\xf6J\xadV\xabT*\xe9\x9dVkU,\xdc\x95\xf7\xbd\xf6\xda\x8f\xa4\xc0\x1dz\xf5\xd5W\xff\xfd\xbf\xff\xdf\x92\xf5\x93O>y\xf2\xe4I\x99\x00\x00$\xae\\\xb9r\xe1\xc2\x85\x1d\x7f\xe9\xcc\x993\xf2\x01\x00\xb8CW\xaf^m\xb5Z\xd7\xaf_\x1f\xef<\xf1\xc4\x13\xff\xf2_\xfe\x0f\x92\xe1\x0e9\xe5\xcd]x\xf1\xc5\x95dq\xf2\x06\x81\x00\x00\x00\x00\xb0\xb7\x1ex\xe0\x81S\xa7N\xa5w\xbe\xf1\x8do\\\xbatI2\xdc!\x957w\xea+_Y{\xe3\x8d76\x17\xb3\xb3\xb3\x8f?\xfe\xb8@\x00\x00\x00\x00\xd8\x0fsss\xc7\x8f\x1fO\xef\xfc\xd1\x1f\xfd_b\xe1\x0e\xa9\xbc\xb9#\x97.]\xfa\xda\xd7\xbe\x96\xacO\x9d:\xf5\xc0\x03\x0f\xc8\x04\x00\x00\x00\x80}\xd2h4\xd2\x8f\xc3\xe1\xf0\xcb_\xfe\x8aX\xb8\x13\x1f\x10\x01w\xe2?\xfe\xc7/%\x13\x94N\x9c8\xf1\x9b\xbf\xf9/\x0e\xe6\x1f\xfa\xea\xab\xef\x0e\x9a\x7f\xe8\xa1\x8f\xe5(\xae7\xdf\xf1\xf7\xc9\xfa\xd8\xb1\x0f\x1f;v,G_\xbc\xd8\xc5.v\xb1\x8b]\xecb\xdf\x9d\xd9\xd9#\xb7\xfa%\xb1{\xdb\xc5.v\xb1\x8b]\xecb\x17\xfb\xdd\xda\xfc\xe7^\xbat\xe9\xaf\xff\xfa\xaf\xc7;_\xff\xfa\xd7?\xf5\xa9\xf9_\xf8\x85_\x98\x81\xdbRy\xf3\xdez\xbd\xde\xf7\xbf\xff\xfdd\xfd\xe9O\x7f\xfa\xfe\xfb\xef?\xf8\xaf\xe1P\xfe\xa1\xbbv\xed\xda[\xe3\xf5\x91#\xb3\xf9\xfa\xe2\xc5.v\xb1\x8b]\xecb\x17\xfb\xee\xdcw_ vo\xbb\xd8\xc5.v\xb1\x8b]\xecb\xdfC\xbf\xf9\x9b\xff\xe2\x07?\xf8A\x14E\xc9\xe3?\xfd\xd3?\x9d?\x7f\xfe\xec\xd9\xb33p[\x06\x9b\xf0\x1e\xe28n\xb5V\x93\xf5\xc2\xc2B\xb9\\\x92\t\x00\x00\x00\x00\xfb-\x08\x82f\xf3\xa9\xf4N\xaf\xb7\xd1\xef\xf7%\xc3\xed\xa9\xbcy\x0fkk\xed\xe4/\xd3\xc20\x9c\x9fo\x08\x04\x00\x00\x00\x80\x83Q\xadVk\xb5\xb9\xf4\xce\xca\xca\xf98\x8e%\xc3m\xa8\xbc\xb9\x9d\xe1p\xd4\xe9t\x92u\xb3\xf9T\x10\x042\x01\x00\x00\x00\xe0\xc04\x9b\xcdt%\x15E\xd1\xfazG,\xdc\x86\xca\x9b\xdbYYYI\x16\xb5\xda\\\xb5Z\x15\x08\x00\x00\x00\x00\x07)\x08\x82\x85\x85\x85\xf4N\xbb\xdd\x1e\x0f\xf8\x86\xedT\xde\xdc\xd2\xfazg4\x1a%\x7f\xb2,//\x0b\x04\x00\x00\x00\x80\x837?\xdf(\x95\xb6\\/\xf7\xe2\x8b+b\xe1VT\xde\xec,\x8e\xe3v\xbb\x9d\xac\x17\x16\x16\xc20\x94\t\x00\x00\x00\x00\x87\xa2\xd9l\xa6\x1f\x07\x83A\xb7\xdb\x15\x0b;Ry\xb3\xb3\x95\x95\x95\xe4*\x80R\xa9\xe4\xd6J\x00\x00\x00\x00\x0eQ\xb9\\j4\x1a\xe9\x9dVk\xd5=\x96\xecH\xe5\xcd\x0e\xfa\xfd~\xaf\xb7\x91\xac3\x7f\x87\x06\x00\x00\x00\x00\x07oqq!}\x8fe\x1c\xc7kkm\xb1\xb0\x9d\xca\x9b\x1d\xac\xac\x9cO\x16\x8dF\xa3\\.\t\x04\x00\x00\x00\x80\xc3\x15\x04A\xb3\xf9Tz\xa7\xd3\xe9\xf4\xfb}\xc9\x90\xa1\xf2&km\xed\xe6\xa5\xb7\x9b\x7f\x8e,..\x08\x04\x00\x00\x00\x80IP\xab\xd5*\x95Jz\xa7\xd5Z\x15\x0b\x19*o\xb6\x88\xa2\xa8\xd3\xe9$\xeb\xe5\xe5\xa5\xf4O\x8b\x00\x00\x00\x00\xc0\xe1z\xfa\xe9-3xG\xa3\xd1\xfazG,\xa4\xa9\xbc\xd9\xa2\xd5j%\x83\xff+\x95J\xbd^\x17\x08\x00\x00\x00\x00\x93#\x0c\xc3\x85\x85-c\t\xda\xed\xb6{,ISy\xf3\xae\xf4\xad\x95\xcb\xcb\xcb\x02\x01\x00\x00\x00`\xd2\xcc\xcf7\xc20\x1c?\xc6q\xdcj\xb5\xc4\xc2\x98\xca\x9bw\xfft\x18\xdfZ\xb9\xb0\xb0\xe0\xd6J\x00\x00\x00\x00&\xd0\xf6{,\xbb\xdd\x8b\xee\xb1dL\xe5\xcdM\xeb\xeb\x9d\xe4\xd6\xca0\x0c\xe7\xe7\x1b\x02\x01\x00\x00\x00`2U\xab\xd5Zm.\xbd\xe3\x1eK\xc6T\xde\xbc#\x8a\xa2v\xbb\x9d\xac\xddZ\t\x00\x00\x00\xc0\x84[^^NWX\xee\xb1dL\xe5\xcd;\xc6\x03\x8f*\x95J\xadV\x13\x08\x00\x00\x00\x00\x93,\x0c\xc3F\xa3\x91\xdei\xb7\xdb\xff\xf8\x8f\xff(\x19T\xdel\xb9\xb5\xf2\xe9\xa7\x9b\x02\x01\x00\x00\x00`\xf2-..d\xee\xb1\xfc\xb3?\xfb3\xb1\xa0\xf2ff|ke\xa3\xb1\xe5\xba[\x00\x00\x00\x00\x98d\xcb\xcbK\xe9\xc7\xbf\xf9\x9b\xefmll\x88e\xca\xa9\xbc\xa7\xdd\xdaZ;\xb9\xb52\x08\x82\xc5\xc5\x05\x81\x00\x00\x00\x00\x90\x17\xb5Z\xadR\xa9\xa4wVW\xffo\xb1L9\x95\xf7T\x8b\xa2\xa8\xd3\xe9$k\xb7V\x02\x00\x00\x00\x90;\x999\xbdo\xbc\xf1\xc6W\xbe\xb2&\x96i\xa6\xf2\x9ej\xadV+\x8e\xe3\x99\x1b\xb7V\xd6\xebu\x81\x00\x00\x00\x00\x90/a\x18.,l\x19]\xf0\xb5\xaf}\xed\xda\xb5k\x92\x99Z*\xef\xe9\x95\xbe\xb5ryyY \x00\x00\x00\x00\xe4\xd1\xfc\xfc\x96\x0b\xea\xae_\xbfn\xbc\xc94SyO\xafVk5Y\xd4\xeb\xa7\xcb\xe5\x92@\x00\x00\x00\x00\xc8\xa3\xedw\xd4}\xfb\xdb\xdf\xfe\xf1\x8f\x7f,\x99\xe9\xa4\xf2\x9eR\xeb\xeb\x9d\xd1h\x94\xfc\x89\xe0\x887\x00\x00\x00\x00\xb9V\xaf\xd73\xf7X~\xf1\x8b-\xb1L\'\x95\xf74\x8a\xe3\xb8\xddn\'\xeb\x85\x85\x05\xb7V\x02\x00\x00\x00\x90w\x99c\x9d\xaf\xbd\xf6Z\xaf\xd7\x13\xcb\x14RyO\xa3\xb5\xb5vrke\xa9T\x9a\x9fo\x08\x04\x00\x00\x00\x80\xbc+\x97K\xb5Z-\xbd\xd3j\xad&%\x18SE\xe5=u\xa2(\xeat:\xc9zyyI \x00\x00\x00\x00\x14\xc3\x93O>9;;;~\x8c\xa2h}\xbd#\x96i\xa3\xf2\x9e:/\xbe\xb8\x92,j\xb5\xb9j\xb5*\x10\x00\x00\x00\x00\x8a\xe1\xbe\xfb\xee;u\xeaTz\xa7\xd3\xe9DQ$\x99\xa9\xa2\xf2\x9e.\xbd^o0\x18$k\xb7V\x02\x00\x00\x00P0sssG\x8f\x1e\x1d?\xc6q\xbc\xb6\xb6&\x96\xa9\xa2\xf2\x9e.\xad\xd6j\xb2XXX\x08\xc3P \x00\x00\x00\x00\x14L\xa3\xd1H?v\xbb\x17\xfb\xfd\xbeX\xa6\x87\xca{\x8a|\xe9K_J~\x8e#\x08\x02\xb7V\x02\x00\x00\x00PH\x0f>\xf8\xe0\x89\x13\'\xd2;kkm\xb1L\x0f\x95\xf7\xb4\xb8v\xed\xda7\xbf\xf9_\x92\xf5\xf2\xf2R\x10\x042\x01\x00\x00\x00\xa0\x902\x07\xbd\x07\x83A\xb7\xdb\x15\xcb\x94PyO\x8b\xf3\xe7\xff\xf8\xe7?\xff\xf9\xe6\xa2T*\xd5\xebu\x81\x00\x00\x00\x00PT\x0f<\xf0\xc0\xe9\xd3\xa7\xd3;kk\xed8\x8e%3\rT\xdeS\xe1\xd5W\x7f\xf4\xca+\xaf$\xeb\xe5\xe5%\x81\x00\x00\x00\x00PlO<\xf1Dz\xceA\x14E\xeb\xeb\x1d\xb1L\x03\x95\xf7T\xf8\xc2\x17\xbe\x90,j\xb5\xb9j\xb5*\x10\x00\x00\x00\x00\x8a\xed\xbe\xfb\xee[XXH\xeft:\x9d\xe4\xa2;\x8aM\xe5]|\x1b\x1b\x1b\xc3\xe10Y///\x0b\x04\x00\x00\x00\x80i0?\xdf\x08\xc3p\xfc\x18\xc7\xf1\xda\xda\x9aX\nO\xe5]|\x7f\xf2\'\x7f\x9a,\x9ex\xe2\x89\xf4or\x00\x00\x00\x00(\xb6f\xf3\xa9\xf4c\xb7{q8\x1c\x89\xa5\xd8T\xde\x05\xf7\xd5\xaf~\xf5\xea\xd5\xab\x9b\x8b\xd9\xd9\xd9\xcc\xcc~\x00\x00\x00\x00(\xb6j\xb5Z\xa9T\xd2;\xadVK,\xc5\xa6\xf2.\xb28\x8e\xbf\xfa\xd5\xbfL\xd6\xa7N\x9d\xba\xef\xbe\xfbd\x02\x00\x00\x00\xc0T\xc9L\xfa\x1d\x0c\x06\xbd^O,\x05\xa6\xf2.\xb2\xf5\xf5\xce\xcf\x7f\xfe\xf3\xcd\xc5\xd1\xa3G\xe7\xe6\xe6\x04\x02\x00\x00\x00\xc0\xb4)\x97K\xf5\xfa\x96\xe1\x07\xad\xd6\xaaX\nL\xe5]XQ\x14\xb5\xdb\xedd\xddh4\x04\x02\x00\x00\x00\xc0tZ^^\x0e\x82`\xfc\x18E\xd1\xfazG,E\xa5\xf2.\xac\xf1\xfd\xb3\'N\x9cx\xf0\xc1\x07\x05\x02\x00\x00\x00\xc0t\n\x82 s$\xb4\xddn\xc7q,\x99BRy\x17S\xbf\xdf\xefv/&\xebO~\xf2\x93\x02\x01\x00\x00\x00`\x9a\xcd\xcf7\xc20\x1c?\xc6q\xec\xa0wQ\xa9\xbc\x8bim\xed\xe6H\x93Z\xadv\xfc\xf8q\x81\x00\x00\x00\x000\xcd\x82 X\\\\H\xef\xb4\xdb\xed(\x8a$S<*\xef\x02\xea\xf7\xfb\x83\xc1 Y?\xf1\xc4\x13\x02\x01\x00\x00\x00\x80z\xbd\x9e>\xe8=\x93\x9a\x0cL\x91\xa8\xbc\x0bhe\xe5|\xb2XXX\xf8\xf0\x87?,\x10\x00\x00\x00\x00\xd8\xd4l>\x95~\xecv/\x0e\x87#\xb1\x14\x8c\xca\xbbh\xba\xddn\xf2\x13\x19A\x10\xcc\xcf7\x04\x02\x00\x00\x00\x00\x89j\xb5Z\xa9T\xd2;\xadVK,\x05\xa3\xf2.\x948\x8e\xc7S\xbc\x17\x16\x16\x82 \x90\t\x00\x00\x00\x00\x8c-//\xa7\x1f\x07\x83A\xbf\xdf\x17K\x91\xa8\xbc\x0be}\xbd\x93\x1c\xf1\x0e\xc3\xd0\x11o\x00\x00\x00\x00\xc8(\x97K\xf5\xfa\xe9\xf4N\xab\xb5*\x96"Qy\x17G\x1c\xc7\x9dN\'Yg\xee\x9f\x05\x00\x00\x00\x00\x12\x8b\x8b\x8b\xe9\xc7\xd1h\xd4\xedv\xc5R\x18*\xef\xe2X[k\xc7q\xbc\xb9(\x95J\xf5z] \x00\x00\x00\x00\xb0]\x18\x86\x8dF#\xbd3\x9e\x15L\x01\xa8\xbc\x0b"\x8a\xa2\xf1\x11\xef\xe5\xe5%\x81\x00\x00\x00\x00\xc0\xad,.n\xb9\x06/\x8a\xa2\xf5\xf5\x8eX\x8aA\xe5]\x10kkk\xc9\xa2R\xa9T\xabU\x81\x00\x00\x00\x00\xc0\xad\x04A\x909\xe8\xddn\xdf\x9c\xa0@\xde\xa9\xbc\x8b`8\x1cu\xbb\x17\x93u\xe6\xceY\x00\x00\x00\x00`\xbb\xf9\xf9F\x18\x86\xe3\xc78\x8e\x1d\xf4.\x06\x95w\x11\xb4Z\xaddQ\xaf\x9f.\x97K\x02\x01\x00\x00\x00\x80\xdb\x0b\x82`qq!\xbd\xd3\xe9t\x1c\xf4.\x80\x0f\x88 \xef~\xf0\x83\x1f\x0c\x06\x83d\xfd\x89O\x9c\xbe|\xf9\xf5\xf4\xaf\xbe\xf5\xd6[\xe9u\xe6Ws$__\xb9\xd8\xc5.v\xb1\x8b]\xecb\x9f\xc2\xd8\xdf|\xf3M\xb1{\xdb\xc5.v\xb1\x8b]\xecb\x17{\xbeb?y\xf2c\x1f\xfa\xd0\x87~\xf6\xb3\x9f%\x8fq\x1c\xff\xe9\x9f\xfe\xe9\xef\xfc\xce\xef\xcc\x90g\xef{\xed\xb5\x1fI!\xd7>\xf7\xb9\xdf\x1b\x0e\x87\x9b\x8b\x87\x1f~83\x81\x08\x00\x80\x03s\xe5\xca\x95\x0b\x17.\xec\xf8Kg\xce\x9c\x91\x0f\x00\xc0d\xfa\xe1\x0f\x7f\xd8\xe9t\xd2;\x9f\xfd\xec\xef~\xf4\xa3\x1f\x95L~\x19l\x92o\xaf\xbc\xf2J\xd2w\xcf\xce\xce~\xf2\x93\x9f\x14\x08\x00\x00\x00\x00\xdc\xb9\x87\x1f~\xf8\xc4\x89\x13\xe9\x9d\xff\xf4\x9f\xfe\x1f\xb1\xe4\x9a\xca;\xdf\xfe\xf8\x8f\xff$Y\xcc\xcd\xcd\xcd\xce\xce\n\x04\x00\x00\x00\x00\xee\xca\xa9S\xa7\xd2\x8f\x1b\x1b\x1b\x97.]\x12K~\x99\xe5\x9dc_\xff\xfa7\xae^\xbd\xba\xb9\xf8\xe0\x07?X\xaf\xd77\xff\xff\xf6\xff\xcc\xf5\xeb\xd7\xdf~\xfb\xedd}\xe4\xc8\x91|\xd5\xe2\xe9\xe9K\xf7\xdf\x7f\x7f\x8e\xber\xb1\x8b]\xecb\x17\xbb\xd8\xc5>\x85\xb1\xa7s\xce\x10\xbb\xb7]\xecb\x17\xbb\xd8\xc5.v\xb1Or\xec\xd5j\xb5\\.\'\xa3\x14\x12/\xbe\xb8\xf2\xaf\xfe\xd5\xff8C>\xa9\xbcs\xeck_\xfbZ\xb2\xf8\xd4\xa7>\xf5\xab\xbf\xfa\xf1\x1d\xff3\x97/\xbf\xbe)Y\x1f;v\xec#\x1f\xf9\xe5\x1c}\x83\x1b\x1b\xaf\x8c\xd7\x0f=\xf4\xb1\x1c}\xe5b\x17\xbb\xd8\xc5.v\xb1\x8b}\nc\x7f\xff\xfb\xdf\x7f\xab_\x12\xbb\xb7]\xecb\x17\xbb\xd8\xc5.v\xb1Ox\xecKK\xff\xfd\xf3\xcf\xff\xef\xe3\xc7\x9f\xfc\xe4\'\xfd~\xbfZ\xad\xce\x90C\x06\x9b\xe4U\xb7\xdb\x8d\xa2hs\x11\x04\xc1\xfc|C \x00\x00\x00\x00\xb0;\xd5j\xb5R\xa9\xa4w\xd6\xd6\xdab\xc9)\x95w^\x8d\x7f\xd7-//\x05A \x10\x00\x00\x00\x00\xd8\xb5\xa7\x9fn\xa6\x1f\x07\x83A\xbf\xdf\x17K\x1e\xa9\xbcsim\xad\x9d\x1c\xf1\x0e\xc3\xb0^\xaf\x0b\x04\x00\x00\x00\x00\xee\xc5\x8d\x9e\xedtz\xc7A\xef\x9cRy\xe7O\x1c\xc7\x9dN\'Y/..\x08\x04\x00\x00\x00\x00\xee\xdd\xe2\xe2b\xfa\xd1A\xef\x9cRy\xe7\xcf\xfaz\'\x8e\xe3\x19G\xbc\x01\x00\x00\x00`\xefl?\xe8\xddj\xad\x8a%wT\xde9\xe3\x887\x00\x00\x00\x00\xec\x93\xccA\xef\xd1h\xd4\xedv\xc5\x92/*\xef\x9cq\xc4\x1b\x00\x00\x00\x00\xf6\x89\x89\xde\x05\xa0\xf2\xce\x93\xf4\x11\xef\xe5\xe5%\x81\x00\x00\x00\x00\xc0\xde\xca\x1c\xf4\x8e\xa2\xc8A\xef|Qy\xe7\xc9\xf8\x88w\xa5R\xa9\xd5j\x02\x01\x00\x00\x00\x80\xbd\x15\x86\xe1\xc2\xc2\x96y\xc2\x0ez\xe7\x8b\xca;7L\xf1\x06\x00\x00\x00\x80\x030?\xdf\x08\x82`\xfc\xe8\xa0w\xbe\xa8\xbcs#}\xc4\xbbZ\xad\n\x04\x00\x00\x00\x00\xf6C\x10\x04\x8dF#\xbd\xe3\xa0w\x8e\xa8\xbc\xf3!\x8a"G\xbc\x01\x00\x00\x00\xe0`8\xe8\x9d_*\xef|X[[s\xc4\x1b\x00\x00\x00\x00\x0e\x86\x83\xde\xf9\xa5\xf2\xce\x81\x1b\x7f\x89t1Y;\xe2\r\x00\x00\x00\x00\x07\xc0A\xef\x9cRy\xe7\xc0\xda\xdaZ\xb2p\xc4\x1b\x00\x00\x00\x00\x0e\x86\x83\xde9\xa5\xf2\x9et\x8ex\x03\x00\x00\x00\xc0\xa1p\xd0;\x8fT\xde\x93\xce\x11o\x00\x00\x00\x008\x14\x0ez\xe7\x91\xca{\xa29\xe2\r\x00\x00\x00\x00\x87\xc8A\xef\xdcQyO4G\xbc\x01\x00\x00\x00\xe0\x109\xe8\x9d;*\xef\xc9\x15\xc7\xb1#\xde\x00\x00\x00\x00p\xb8\x1c\xf4\xce\x17\x95\xf7\xe4Z_\xef$\x0bG\xbc\x01\x00\x00\x00\xe0\xb08\xe8\x9d/*\xef\t\x15\xc7q\xa7\xd3I\xd6\x8ex\x03\x00\x00\x00\xc0!r\xd0;GT\xde\x13j}\xbd\x13\xc7\xf1\x8c#\xde\x00\x00\x00\x00p\xd8\x1c\xf4\xce\x11\x95\xf7$r\xc4\x1b\x00\x00\x00\x00&\x8a\x83\xdey\xa1\xf2\x9eD\x8ex\x03\x00\x00\x00\xc0Dq\xd0;/T\xde\x13\'}\xc4\xfb\xb1\xc7\xea\x02\x01\x00\x00\x00\x80I\x90)\xeb\x1c\xf4\x9eL*\xef\x893>\xe2\x1d\x86a\xbd\xae\xf2\x06\x00\x00\x00\x80\x89p\xa3\xaf;\x9d\xdeY_\xef\x88e\xd2\xa8\xbc\'\x8b)\xde\x00\x00\x00\x000\xb1\x16\x17\x17\xd3\x8f\xa3\xd1\xa8\xdf\xef\x8be\xa2\xa8\xbc\'\x8b#\xde\x00\x00\x00\x000\xb1\xb6\x1f\xf46\xd1{\xd2\xa8\xbc\'\xcbx\xfa\x8f#\xde\x00\x00\x00\x000\x812\x07\xbd\x07\x83\x81\x83\xde\x13E\xe5=A\xba\xddn\x14E3\x8ex\x03\x00\x00\x00\xc0\xa4r\xd0{\xc2\xa9\xbc\'\xc8\xf8\xf7\x86#\xde\x00\x00\x00\x000\xb1\x1c\xf4\x9ed*\xefI1>\xe2\x1d\x04A\xadV\x13\x08\x00\x00\x00\x00L\xa60\x0c+\x95Jz\xa7\xd3\xe9\x88eB\xa8\xbc\'\xc5\xf8\x88w\xa3\xd1\x08\x82@ \x00\x00\x00\x000\xb12s\x1az\xbd\x8d\xe4<+\x87N\xe5=\x11z\xbd\xde\xf8\x88\xf7\xfc|C \x00\x00\x00\x000\xc9\xaa\xd5j\xe6\xa0\xf7\xda\xda\x9aX&\x81\xca{"\xac\xafw\x92\x85#\xde\x00\x00\x00\x00\x90\x0b\x99\x83\xde\xdd\xeeE\x07\xbd\'\x81\xca\xfb\xf0\xf5\xfb\xfd\xc1`\x90\xac\x1d\xf1\x06\x00\x00\x00\x80\\\xa8V\xab\xa5R)\xbd\xe3\xa0\xf7$Py\x1f\xbe\xf1\x14\xefz\xfd\xb4#\xde\x00\x00\x00\x00\x90\x17\x99\x03\xac\xbd\xdeF\x1c\xc7b9\\*\xefC\x16E\xd1\xf8\x88\xf7\xe2\xe2\xa2@\x00\x00\x00\x00 /\xea\xf5z\x18\x86\xe3\xc78\x8e\xc7\x13\x8c9,*\xefC6\xfea\x87z\xfdt\xfa\xb7\x07\x00\x00\x00\x000\xf92\x13\xbd;\x9d\x8e\x83\xde\x87K\xe5}\x98\xa2(\xeav/&\xebFc^ \x00\x00\x00\x00\x90/\xf5z==\xac8\x8e\xe3\x97^\xea\x8a\xe5\x10\xa9\xbc\x0f\xd3\xf8\x88w\xa5R)\x97K\x02\x01\x00\x00\x00\x80\xdci4\x1a\xe9\xc7N\xa7#\x93C\xa4\xf2>4q\x1c\xf7z\x1b\xc9:\xf3\xe3\x0f\x00\x00\x00\x00@^\xcc\xcf7\xd2\x07\xbdo\x8cvp\xd0\xfb\xd0\xa8\xbc\x0f\xcd\xfa\xfa\xcd\xb1>\xa5R\xa9Z\xad\n\x04\x00\x00\x00\x00\xf2(\x08\x82z\xbd\x9e\xdeY[k\x8b\xe5\xb0\xa8\xbc\x0f\xcd\xf8\x07\x1c\xe6\xe7\x1b\xd2\x00\x00\x00\x00\x80\xfc\xcaT|Q\x14\xf5\xfb}\xb1\x1c\n\x95\xf7\xe1\xe8v\xbb\xc9\x11\xef0\x0c3\x7f\x05\x04\x00\x00\x00\x00\xe4\xcb\x8d\x96\xeftz\xc7A\xef\xc3\xa2\xf2>\x1c\xe37\xde\x14o\x00\x00\x00\x00(\x80\xc5\xc5\xc5\xf4\xe3`0\x18\x0eGb9x*\xefC\xd0\xeb\xf5\xa2(\x9a\xb91\xe5\xa7V\xab\t\x04\x00\x00\x00\x00\xf2.\x0c\xc3J\xa5\x92\xde\xe9t\xd6\xc5r\xf0T\xde\x87`}\xbd\x93,\x1a\x8d-w\xb9\x02\x00\x00\x00\x00\xf9\x95\x99\xe8\xd0\xed^LN\xber\x90T\xde\x07\xad\xdf\xef\x0f\x06\x83d\xed\xe2J\x00\x00\x00\x00(\x8cj\xb5Z*\x95\xd2;\xe3\xc3\xaf\x1c\x18\x95\xf7A\xebv\xbb\xc9\xa2^?\xed\x887\x00\x00\x00\x00\x14I\xe6\x90k\xb7\xdb\x8d\xe3X,\x07I\xe5}\xa0\xa2(\xeav/&\xeb\xcc<{\x00\x00\x00\x00 \xef\xea\xf5z\x18\x86\xe3\xc78\x8e_z\xa9+\x96\x83\xa4\xf2>P\xe3\x1fd\xa8T*\xe9W\x1f\x00\x00\x00\x00(\x86z\xbd\x9e~\xect:29H*\xef\x83\x13\xc7\xf1x\xaaIf\x92=\x00\x00\x00\x00P\x0c\xf3\xf3\x8d\xf4@\xe3\x1b\x83\x1f\x1c\xf4>8*\xef\x83\xf3\xd2K7\x07\xf7\x84aX\xadV\x05\x02\x00\x00\x00\x00\xc5\x13\x04A\xad6\x97\xde1\xdb\xe4 \xa9\xbc\x0f\xce\xf8G\x18\x1c\xf1\x06\x00\x00\x00\x80\x02\xcb\\\xe37\x18\x0c\xfa\xfd\xbeX\x0e\x86\xca\xfb\x80t\xbb\xdd(\x8afn\xfc%Of\x9a\x0f\x00\x00\x00\x00P$a\x18f\x0ez\x9bmr`\xde\xf7\xdak?\x92\xc2\x01\xf8\xdc\xe7~o8\x1cn.N\xdd \x10\x00\x80\x82\xb9r\xe5\xca\x85\x0b\x17v\xfc\xa53g\xce\xc8\x07\x00`\xda\xfc\xf4\xa7?\xfd\xf2\x97\xbf\x9c\xde\xf9\xecg\x7f\xf7\xa3\x1f\xfd\xa8d\xf6\x9bS\xde\x07acc#\xe9\xbb7\xcd\xcd\xcd\t\x04\x00\x00\x00\x00\x8a\xed\xc1\x07\x1f<~\xfcxz\xe7\xab_\xfdK\xb1\x1c\x00\x95\xf7A\xf8\xd6\xb7^J\x16\x0f?\xfc\xf0\xec\xec\xac@\x00\x00\x00\x00\xa0\xf02\x87__~\xf9\xe5k\xd7\xde\x12\xcb~Sy\xef\xbbK\x97.mll\xec\xf8\x96\x03\x00\x00\x00\x00E\x959\xffz\xfd\xfa\xf5\x8b\x17M\xf4\xdew\x1f\x10\xc1~\xfb\xf6\xb7\xbf\x93,\x1ez\xe8c\x9f\xf8\xc4\x7f{\xc0\xff\xf47\xdf\xf1\xf7\xc9\xfa\xd8\xb1\x0f\x1f;v,G\xd1\xbd\xfa\xea\xbb\x83\xe67\xd3\xcb\xd1W.v\xb1\x8b]\xecb\x17\xbb\xd8\xa70\xf6\xd9\xd9#\xb7\xfa%\xb1{\xdb\xc5.v\xb1\x8b]\xecb\x17\xfb\xd4\xc6\xfe\xc4\x13\xff\xdd_\xfd\xd5\x7f\x1e?v:_\xff\xd4\xa7>5\xc3~Ry\xef\xbbo~\xf3\x9b\xc9\xe2\xd7\x7f\xfd\xd7\xef\xbf\xff\xfe\x03\xfe\xa7\xa7\x7fV\xe2\xc8\x91\xd9\x83\xff\x02\xf6J\xbe\xber\xb1\x8b]\xecb\x17\xbb\xd8\xc5>\x85\xb1\xdfw_ vo\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17{\xc6\x93O>\x99\xae\xbc\xdf|\xf3\xcd~\xbf_\xadVg\xd87\x06\x9b\xec\xafn\xb7\x1b\xc7\xf1\xe6"\x0c\xc3Z\xad&\x10\x00\x00\x00\x00\x98\x1eA\x10\xd4\xeb\xa7\xd3;kkm\xb1\xec+\x95\xf7\xfeZ_\xef$\x8bF\xa3!\r\x00\x00\x00\x00\x986\x8d\xc6|\xfaq0\x18DQ$\x96\xfd\xa3\xf2\xdeG\xfd~\x7f4\x1a\xcd\xdc\xf8\xcb\x9c\xc7\x1e\xab\x0b\x04\x00\x00\x00\x00\xa6M\xb9\\\xaaT*\xe9\x9d\xb5\xb55\xb1\xec\x1f\x95\xf7>\xeavo^\xc0Z\xab\xcd\x05A \x10\x00\x00\x00\x00\x98B\x99\xe3\xb0\xbd\xdeF2\x0c\x99\xfd\xa0\xf2\xde/Q\x14u\xbb\x17\x93\xf5\xe2\xe2\xa2@\x00\x00\x00\x00`:\xd5\xeb\xf50\x0c\xc7\x8fq\x1c\xbf\xf4RW,\xfbD\xe5\xbd_\xc6om\xa5RI\xbf\xd0\x00\x00\x00\x00\xc0\xb4\xa9\xd7\xb7\x1c\xf4\xeet:2\xd9\'*\xef\xfd2~k\xe7\xe7\x1b\xd2\x00\x00\x00\x00\x80i\x96)\t\xa3(\xea\xf7\xfbb\xd9\x0f*\xef}\xd1\xedv\x93q\xba\xa5Z\xbcz\xf5j\xbf\xdf\x17\xcb\xae\xa9\xbcw\xaf\xd7\xebEQ4ss\xcc\xbc\xa9&\x00\x00\x00\x00\xc0]\x0b\xc3\xb0V\x9bK\xef\x8c\x0f\xda\xb2\x0b*\xef\xdd\x1b\xbfy\xfan\x00\x00\x00\x00`\xd72\x05c\xb7{1\x8ec\xb1\xec\x8e\xca{\x97\xd2\x17W\xce\xcf7\x04\x02\x00\x00\x00\x00\xecN\xadV;z\xf4hz\xa7\xd7\xeb\x89ewT\xde\xbb\xf4\xf2\xcb7\xdf\xb9J\xa5\xe2\xe2J\x00\x00\x00\x00\xe0^<\xf2\xc8#\xe9\xc7\xf5\xf5\x8eLvG\xe5\xbdK\x9d\xce\xcdw\xee\xb1\xc7L5\x01\x00\x00\x00\x00\xee\xc9\xc3\x0f?\x9c~\x1c\x8dF\xc3\xe1H,\xbb\xa0\xf2\xde\x8d~\xbf?\xbe\xb8\xb2V\xab\t\x04\x00\x00\x00\x00\xb8\x17\x0f<\xf0\xc0\x89\x13\'\xd2;.\xb1\xdc\x1d\x95\xf7n\x8c\xdf\xb6Zm.\x08\x02\x81\x00\x00\x00\x00\x00\xf7(3\xdbD\xe5\xbd;*\xef\xbb\x16\xc7\xf1\xf8\xe2\xcaFc^ \x00\x00\x00\x00\xc0\xbd{\xf8\xe1\x87ggg\xc7\x8fq\x1ck\xbdwA\xe5}\xd7z\xbd\xde\xe6\xdb\xb6\xb9\x08\xc3\xb0\\.\t\x04\x00\x00\x00\x00\xd8\x13\'O\x9eL?\xf6z=\x99\xdc-\x95\xf7]\x1b_\x96\xdah4\xa4\x01\x00\x00\x00\x00\xec\x95\xb9\xb9\xb9\xf4c\xaf\xb7\x91\xdc)\xc8\x9dSy\xdf\x9dK\x97.\x8dF7oJ}\xf4Q\x17W\x02\x00\x00\x00\x00{\xe6\xf8\xf1\xe3G\x8f\x1eM\xef\xbc\xfc\xb2\x83\xdewG\xe5}w\xbe\xfa\xd5\xbfL\x16\xb5\xda\\\x18\x86\x02\x01\x00\x00\x00\x00\xf6P\xe6\xa0w\xa7\xd3\x91\xc9]Qy\xdf\x9d\xbf\xfd\xdb\xbfM\x16\xf5z]\x1a\x00\x00\x00\x00\xc0\xdez\xe4\x91G\xd2\x8fQ\x14\xf5\xfb}\xb1\xdc9\x95\xf7]\xe8v/^\xbdzus\x11\x04A\xadf\xaa\t\x00\x00\x00\x00\xb0\xc7fggk\xb5-\x07\xbd\xbb\xdd\xaeX\xee\x9c\xca\xfb.\xbc\xfc\xf2\xcb\xc9\xc2\x11o\x00\x00\x00\x00`\x9fd\xea\xc7^oC&wN\xe5}\xa7\xae]\xbb\xb6\xb1\xb1\xb1\xe3;\x07\x00\x00\x00\x00\xb0Wj\xb5Z\x10\x04\xe3\xc78\x8e\x1d\xf4\xbes*\xef;u\xf1\xe2\xc5d\x11\x86a\xb9\\\x12\x08\x00\x00\x00\x00\xb0O2\xb3Mz\xbd\x9eL\xee\x90\xca\xfbN}\xf3\x9b\xff%Y4\x1a\ri\x00\x00\x00\x00\x00\xfb\xa7\xd1\x98O?\xf6z\x1bQ\x14\x89\xe5N\xa8\xbc\xef\xc8\xa5K\x97\xdex\xe3\x8dd\xfd\xe8\xa3.\xae\x04\x00\x00\x00\x00\xf6Q\xb9\\\n\xc30\xbd\xf3\xf2\xcb\x0ez\xdf\x11\x95\xf7\x1d\x19\x1f\xf1>y\xf2d\xe6U\x03\x00\x00\x00\x00\xd8s\x99i\x13\x9dNG&wB\xe5}G\xbe\xf7\xbd\xef%\x8b\x93\'OJ\x03\x00\x00\x00\x00\xd8o\x99i\x13Q\x14\r\x87#\xb1\xbc\'\x95\xf7{\xdb|\x93\xae^\xbd\xba\xb9\x98\x9d\x9dUy\x03\x00\x00\x00\x00\x07 \x0c\xc3J\xa5\x92\xde\xe9v\xbbbyO*\xef\xf7\xd6\xe9\xac\'\x8b\x93\'O\xce\xce\xce\n\x04\x00\x00\x00\x008\x00\x8f=VO?\xaa\xbc\xef\x84\xca\xfb\xbd\xf5z\x1b\xc9\xc2\x11o\x00\x00\x00\x00\xe0\xc0\xd4j[f\x9b\xc4q\xdc\xeb\xb9\xc4\xf2=\xa8\xbc\xdf\xc3\xe6;\xb4\xf9&m.\x8e\x1e=\xaa\xf2\x06\x00\x00\x00\x00\x0eL\x10\x04\xf5\xfa\xe9\xf4\x8e\xca\xfb=\xa9\xbc\xdf\xc3\xf8\x87\x05\xf4\xdd\x00\x00\x00\x00\xc0\x01\xcb\x1c\xf4\xee\xf56\x92\x13\xba\xdc\x8a\xca\xfbvn\xfc\xa4\xc0\xcd\xa9&\x8f<\xf2\x88@\x00\x00\x00\x00\x80\x83T\xab\xd5\x82 \x18?\x9am\xf2\x9e> \x82\xdb\xf8\xeew\xbf\x9b,\x8e\xdf\x90\xac/_~=G\xdf\xc2[o\xbd\x95^\xe7\xeb\x8bO\x13\xbb\xd8\xc5.v\xb1\x8b]\xecb\x9f\xf0/\xfe\xcd7\xdf\x14\xbb\xb7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b}?b\x9f\x9b\x9b\xbbx\xf1\xe2\xf8\xf1\xbb\xdf\xfd\x9bz\xbd>\xc3-\xbc\xef\xb5\xd7~$\x85[\xf9\xdc\xe7~o8\x1cn.\x1e\x7f\xfc\xf1\xcd\x17K \x00\x00\xdc\xca\x95+W.\\\xb8\xb0\xe3/\x9d9sF>\x00\x00\xdc\xcb\xff\xd4l\xb5Z\xe9\x9d\x7f\xfbo\xff\x97\xa3G\x8fJfG\x06\x9b\xdc\xd2\xe5\xcb\x97\x93\xbe{\xc6 o\x00\x00\x00\x00\xe0\x90\x1c?~\xdbd8\x1c\x89eF\xe5\x9d\xd8|\x1b\xa2(\x9a1\xd5\x04\x00\x00\x00\x00\xc8\x83\xed\xb3M\xba\xdd\xaeXfT\xde\x99\xb7\xc1T\x13\x00\x00\x00\x00 \x17\xb6\xcd61\xce\xfb\x1d*\xef-o\x83#\xde\x00\x00\x00\x00@.d\xca\xcc(\x8a\xcc6\x99Qy\xcf\x98j\x02\x00\x00\x00\x00\xe4\x90\xd9&;Ry\x9bj\x02\x00\x00\x00\x00\xe4\x92\xd9&\xdb\xa9\xbc\xdf}\x0f\xaa\xd5\xaa4\x00\x00\x00\x00\x80\xbc\xc8T\x9af\x9b\xcc\xa8\xbc\xc7SMf\x0c\xf2\x06\x00\x00\x00\x00r%\x0c\xc3R\xa9\x94\xde1\xdbd\xda+\xef\xd4\xc5\x95sA\x10\xf8M\x02\x00\x00\x00\x00\xe4H\xbd^O?\xf6\xfb\xfd)\x0fD\xe5=\xae\xbc\x1d\xf1\x06\x00\x00\x00\x00r\xe6\xd1G\xb7\x14\x9b\xa3\xd1\xbbc-\xa6\xd3TW\xde\x9b\x9f\xfd\xe6\x1b\x90\xacU\xde\x00\x00\x00\x00@\xeel\x9fm\xf2\xf2\xcbS}\x89\xe5TW\xde\xe3\xcf\xbeR\xa9\x98j\x02\x00\x00\x00\x00\xe4Q\xe68\xef\x94\x8f\xf3\x9e\xea\xca{\xfc\xd9;\xe2\r\x00\x00\x00\x00\xe4T\xa6\xde\x9c\xf2\xd9&\xd3[y\xc7q<\x9ej\x92\x99w\x03\x00\x00\x00\x00\x90\x17\xe5r)\x0c\xc3\xf4\xce4_b9\xbd\x95\xf7\xf8\xe2\xcaR)\xfbB\x00\x00\x00\x00\x00\xe4H\xe6\xa0\xf7\xb8\xfc\x9cB*oSM\x00\x00\x00\x00\x80|\xab\xd5\xe6\xd2\x8f\xbd\xdeF\x1c\xc7\xd3\x19\xc54W\xde\x1b\xff\xf5mPy\x03\x00\x00\x00\x009V\xadV\x83 H\xefL\xedA\xef)\xad\xbc\xc7\x9fw\x18\x86\xe5r\xc9o\t\x00\x00\x00\x00 \xd72\x07\xbd\xa7v\x9c\xf7\xb4W\xde\x8ex\x03\x00\x00\x00\x00\x05\xb0m\x9c\xf7\xc6t\xe60\xb5\x95\xf7\xcd\xcf\xbbZ\xad\xf8\xcd\x00\x00\x00\x00\x00\xe4]\xb5ZM?\xc6q<\x9d\x07\xbd\xa7\xb1\xf2\x1e\x0eG\xc9\xec\xf6 \x08\x9c\xf2\x06\x00\x00\x00\x00\n\xe0F\xdb\x99\xbd\xc4r\ns\x98\xc6\xca\xbb\xdb\xed&\x8b\xcc\x1b\x00\x00\x00\x00\x00\x90_\xdbf\x9bL\xe3\r\x96\xd3Xy\x8f\xcf\xf3g\x8e\xfa\x03\x00\x00\x00\x00\xe4W\xa6\xf0\x8c\xa2h8\x1cM[\x08SWyo~\xcc\xa3\xd1\xcd\x8f\xd9T\x13\x00\x00\x00\x00\xa00\xc20,\x95J\xe9\x9d)\x1c\xe7=u\x95\xf7\xcb/\xdf<\xcc_\xa9T\x82 \xf0\xdb\x00\x00\x00\x00\x00(\x8c\xcc1\xdf\xf1\x90\xe7\xe91u\x95\xf7`\xd0\xdf\xf1\xb3\x07\x00\x00\x00\x00\xc8\xbbL\xed9\x1a\x8d\xe28\x9e\xaa\x04\xa6\xab\xf2\xde\xfct\xc7\xb7\x94\x1a\xe4\r\x00\x00\x00\x00\x14L\xb9\\\xca\x0c\xb7\x98\xb6K,\xa7\xab\xf2\x1eO\xae\t\xc3p\xf3\xb3\xf7\x1b\x00\x00\x00\x00\x00(\x98Zm.\xfd8m\xe3\xbc\xa7\xab\xf2\x1e\xff\x85\x86\xa9&\x00\x00\x00\x00@!e\xca\xcf\xf1\xdc\x8b)1m\xa7\xbc\x07\xc9\xa2Z\xadx\xf5\x01\x00\x00\x00\x80\xe2\xc9\x8ct\x8e\xe3x\xaa\x0ezOQ\xe5=\x1c\x8e\xa2(J\xd6Ny\x03\x00\x00\x00\x00\x85\x14\x04A\xa5\xb2\xe5\xc8\xefT\x1d\xf4\x9e\xa2\xca;5\xd5d\xce{\x0f\x00\x00\x00\x00\x14U\xe6\xc8\xafS\xde\xc5d\x907\x00\x00\x00\x000\r\x1e}tK\x05:\x1a\xbd;\x00\xa3\xf0\xa6\xa5\xf2\x8e\xe3x\xf3sM\xd6\x99Y6\x00\x00\x00\x00\x00E\x12\xde\x90\xde\x99\x9e\x83\xde\xd3Ry\x8f\x8fx\x97J\xa5\xcc\x87\r\x00\x00\x00\x00P0\x99Y\x17\xe3\x82\xb4\xf0\xa6\xa5\xf2\x1e\xff%\x86#\xde\x00\x00\x00\x00@\xe1U\xab[n\xb0\xec\xf7\x07S\xf2\x8dO\xcf)\xef\x9bw\x92\xba\xbb\x12\x00\x00\x00\x00(\xbc\xcc)\xef8\x8e\xa7d\xb6\xc9TT\xde\xc3\xe1h\xf3\x13\xdd\\\x04A\xe0\x947\x00\x00\x00\x000\r2\xc7\x7f\xc7\xc7\x82\x8bm**\xef\xf1\x9c\x9a\xcca~\x00\x00\x00\x00\x80\xa2\xaaT\xb6\x1c\xffu\xca\xbb8\xc6\x95w\xe63\x06\x00\x00\x00\x00(\xaa\xcc\xc4\x8b\xd1h\x14EQ\xe1\xbf\xeb\xe2W\xdeq\x1co~\x96\xc9\xfa\xd1Gk^t\x00\x00\x00\x00`\x1a\x94\xcb\xa50\x0c\xd3;\xd3p\xd0\xfb}\xaf\xbd\xf6\xa3b\x7f\x87/\xbd\xd4=\x7f\xfe\xfc\xe6\xe2\xe8\xd1\xa3\xbf\xfd\xdb\xbf\xedE\x07\x00`?\\\xb9r\xe5\xc2\x85\x0b;\xfe\xd2\x993g\xe4\x03\x00\xc0\xa1\xe8t:?\xfc\xe1\x0f\xc7\x8f\x95J\xe5\xb9\xe7\x9e-\xf6\xb7\\\xfcS\xde/\xbf\xfcr\xb28y\xf2\xa4W\x1c\x00\x00\x00\x00\x98\x1e\x99R\xf4\'?\xf9I\xe1\xbf\xe5\xe2W\xde?\xfe\xf1\x8f\x93\xc5\x83\x0f>\xe8\x15\x07\x00\x00\x00\x00\xa6G\xa6\x14\xbd~\xfd\xfa\xab\xaf\x16|\xecG\xc1+\xefK\x97.]\xbdzu\xc7O\x17\x00\x00\x00\x00\xa0\xd8fgg\x8f\x1f?\x9e\xde\xf9\xeew\xbf[\xeco\xf9\x03\xc5\xfe\xf6\xbe\xff\xfd\xef\'\x8b\x87\x1e\xfa\xd8\xc7?\xfe\xc8\xae\xff{\xd2\x7f\xf5\xb1\xf9_\x95\xa3\x04\xde|\xc7\xdf\'\xebc\xc7>|\xec\xd8\xb1\x1c}\xf1b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec9\x8a}v\xf6\xc8\xad~I\xec\xdev\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6C\x8c\xfd\x9f\xfd\xb3\xff\xe6\xaf\xfe\xea?\x8f\x1f\x87\xc3\xe1L\xa1\x15\xbc\xf2~\xf5\xd5W\x93\xc5#\x8f|\xfc\xfe\xfb\xef\xdf\x93\xff\xce\xbd\xfa\xef9\x18\xd7\xae\xbd5^\x1f92\x9b\xaf/^\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=G\xb1\xdfw_ vo\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17\xfb\x04\xc6\xfek\xbf\xf6k\xe9\xca\xfb\xd5W_\x8d\xe38\x08\x82\x99\x82*\xf8`\x93~\x7f\x90,j\xb5\xda\x0c\x00\x00\x00\x00\xc0\x94\xa9V\xab\x99\x82\xbb\xdf\xef\x17\xf8\xfb-r\xe5\xbd\xf9\xc9\xc5q\xbc\xb9\xd8\xfcD\xcb\xe5\x92\x97\x1b\x00\x00\x00\x00\x98B\xd5j%\xfd8>(\\H\xc5\xae\xbc\x07;~\xa2\x00\x00\x00\x00\x00\xd3\xa3R\xa9\xa6\x1f{\xbd^\x81\xbf\xd9"W\xde\xe3O\xceT\x13\x00\x00\x00\x00`j=\xfa\xe8\x96\x824\xba\xa1\xa8\xdfla+\xef8\x8eG\xa3Q\xb2\xaeV\xab^k\x00\x00\x00\x00`:\x857\xa4w\n<\xce\xbb\xb0\x95\xf7\xf83\xdb\xfeq\x02\x00\x00\x00\x00L\x95m\xe3\xbcU\xdeyc\x907\x00\x00\x00\x00@"3\t\xa3\xd7\xdb(\xeawZ\xfcS\xde\x06y\x03\x00\x00\x00\x00S.S\x93\xc6q<\x1c\x8e\n\xf9\x9d\x16\xb3\xf2\x8e\xa2\xc8 o\x00\x00\x00\x00\x80D\x10\x04\xa5R)\xbdS\xd4\xd9&\xc5\xac\xbc\xc7\x9f\xd6\xe6\xa7\xb8\xf9Yz\xa1\x01\x00\x00\x00\x80)\x979\x1c<\x18\xa8\xbc\xf3c\\y;\xe2\r\x00\x00\x00\x000\xb3\xc3\r\x96\x83B~\x9bE\xad\xbc\xdd]\t\x00\x00\x00\x00\xf0\xae\xcc\xf9\xe0\xa2\x8e\xf3.`\xe5\x1d\xdd\xb0\xe3\xa7\x08\x00\x00\x00\x000\x9d\xa6d\x9cw\x01+o\x83\xbc\x01\x00\x00\x00\x00\xb6\xcb\x1c\x11\xee\xf5z\xc5\xfb\x1e\x8b\\y\xd7j5/1\x00\x00\x00\x00@"3\x08z0(\xe08\xefBV\xde\x06y\x03\x00\x00\x00\x00dm?%\\\xbc\xd9&E\xab\xbc\r\xf2\x06\x00\x00\x00\x00\xb8\x95Je\xcbA\xe1\xf1\x01\xe2\xc2(Z\xe5=\xfeK\x89\xcc\'\x07\x00\x00\x00\x00@\xe6\xa0\xb0S\xde\x93n\xfc\t9\xe2\r\x00\x00\x00\x00\x90Q\xf8q\xde\xc5\xab\xbc\r\xf2\x06\x00\x00\x00\x00\xd8\xd9\xf6\xb3\xc2\x05;\xe8]\xa8\xca\xdb o\x00\x00\x00\x00\x80\xdb+\xf68\xefBU\xde\x06y\x03\x00\x00\x00\x00\xdc^\xb1\xc7y\x17\xb3\xf2.\x97\xcb^\\\x00\x00\x00\x00\x80\xed\xca\xe5R\xfa\xb1`\xe3\xbc\x0bVy\x1b\xe4\r\x00\x00\x00\x00p;\xc5\x1e\xe7]\x9c\xca\xdb o\x00\x00\x00\x00\x80\xf7\x14\x04A\xa9\xb4\xe5\xa0\xf7p8*\xccwW\x9c\xca{\xfc\x17\x11\x9b\x9f\xd6\xe6g\xe6\xc5\x05\x00\x00\x00\x00\xd8Q\xe6\xd0\xf0`\xe0\x94\xf7\xe4\x19W\xde\x8ex\x03\x00\x00\x00\x00\xdcFf4\xf4xdt\x01\x14\xa9\xf26\xc8\x1b\x00\x00\x00\x00\xe0\xbde\xce\r\xc7q\\\x98\xd9&\x05\xa9\xbc7?\x12\x83\xbc\x01\x00\x00\x00\x00\xee\xc4\xf6q\xde\x85\xb9\xc1\xb2 \x95\xf7\xf8\xf3\x08\xc3\xd0 o\x00\x00\x00\x00\x80\xdb+\x97\xb7T\xde\x85\x19\xe7]\x98\xca\xdbT\x13\x00\x00\x00\x00\x80;\x95\x99\x96a\xb0\xc9dqw%\x00\x00\x00\x00\xc0\x9d\xcbT\xa9\xd1\r\x05\xf8\xbe\nRy\x8fF\xa3\x1d?\'\x00\x00\x00\x00\x00\xb6\x0boH\xef\x14c\x9cw\x11*\xef\xf1\'\x11\x04A\xe6C\x02\x00\x00\x00\x00`G\x99q\xde\xc5\x98mR\x8c\xca\xdb o\x00\x00\x00\x00\x80\xbbS\xa9l\x99\x99\xe1\x94\xf7\xa4\x18\x7f\x12\x99O\x08\x00\x00\x00\x00\x80[\xc9\x8c\x89\x1e\x8dFq\x1c\xe7\xfd\x9b*B\xe5=\x1e\xe4\x9d9\x87\x0f\x00\x00\x00\x00\xc0\xadl/T\x87\xc3a\xde\xbf\xa9\xdcW\xde\xc3\xe1\xbb\x7f\xf3\xe0\xeeJ\x00\x00\x00\x00\x80;W\xa9l\x19\x16=\x1e"\x9d_\xb9\xaf\xbcSSM\x0c\xf2\x06\x00\x00\x00\x00\xb8\x0b\x99c\xc4\x05\x18\xe7\x9d\xfb\xca{4\x1a\xee\xf8\xd9\x00\x00\x00\x00\x00p{\x99\xd9&\x83\x81S\xde\x87m|\xd2\xde o\x00\x00\x00\x00\x80\xbb\xb2\xfd$\xf1p8\xca\xf5w\x94\xef\xca;\x8e\xe3(\x8an\xf5\xd9\x00\x00\x00\x00\x00p\x1bA\x10\x94J[\x0e\x13\xe7}\xb6I\xbe+\xefq\xfaa\x18n~6^P\x00\x00\x00\x00\x80\xbb\x92\x99\x9f1\x1e%\x9dS\xf9\xae\xbc\xc7g\xec\xabUwW\x02\x00\x00\x00\x00\xdc\xb5m7X\xe6{\x9cwANy\x97Je\xaf&\x00\x00\x00\x00\xc0\xdd\xca\x94\xabQ\x14\xc5q\x9c\xdfo\'\xdf\x95\xf7\xf8\xfePwW\x02\x00\x00\x00\x00\xec\xc2\xf6r5\xd7\xe3\xbcs\\y\xa7o\x0euw%\x00\x00\x00\x00\xc0\xeeT*[\x06G\xa7\xab\xd7\xdc\xc9q\xe5=\x1e\xa3\x9e\xf9<\x00\x00\x00\x00\x00\xb8s\xdb\xc6y;\xe5}\x18\xc6\xb9\x97\xcb\x06y\x03\x00\x00\x00\x00\xecRf\xb6\xc9h\xe4\x94\xf7a\x18\x9f\xae7\xc8\x1b\x00\x00\x00\x00`\xd72\xa7\x8a\xe38\xce\xefl\x93\\\x0f6\xb9\x19\xbaA\xde\x00\x00\x00\x00\x00\xbb\x16\xde\x90\xde\x19\x8f\x95\xce\x9d\xbcV\xde\xe3\xa9&A\x10d>\x0c\x00\x00\x00\x00\x00\xeeJf\x96\x86S\xde\x07\xad\xdf\x1f$\x8bR\xc9T\x13\x00\x00\x00\x00\x80{R*m\x99m2\x1c:\xe5}\xb0\xc6\xe7\xeaM5\x01\x00\x00\x00\x00\xb8G\xd5j%\xfd8\x18\x0cr\xfa\x8d\xe4\xb5\xf2\x1e\x9f\xab\xcf|\x12\x00\x00\x00\x00\x00\xdc\xad\xedg\x8b\xc7\xc3\xa5\xf3%\x97\x95w\x1c\xc7Q\x14%\xeb\xcc]\xa2\x00\x00\x00\x00\x00\xecBf\x88tN\xc7y\x7f \x8f_\xf4k\xaf\xbd\x96,>\xf4\xa1\x0f\xfd\xc3?\\\xdd\xfc\xbf\x83\xfc\xa7_\xbe\xfcz\x8e\xb2z\xeb\xad\xb7\xd2\xeb|}\xf1b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec9\x8a\xfd\xcd7\xdf\x14\xbb\xb7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xd7\xb1\x1f?~|4z\xb7\xe6~\xed\xb5\x1f\xcd\xcc4r\x97\xde\xfbn|\xdd9\xf3\x85/|\xf1\x1b\xdf\xf8\xc6\xe6\xe2\xe4\xc9\x93O>\xf9\xe4\x0c\x00\x00\x1c\xb6+W\xae\\\xb8pa\xc7_:s\xe6\x8c|\x00\x00\x98|\x1b\x1b\x1b\xdf\xfa\xd6\xb7\xc6\x8f\xbf\xf8\x8b\xbf\xf8o\xfe\xcd\xff\x9c\xbb\xef"\x97\x83M~\xfa\xd3\x9f&\x8b\xe3\xc7\x8f{\x11\x01\x00\x00\x00\x00\xee]\xa6n}\xe3\x8d7\xf2\xf8]\xe4\xb2\xf2\xbe|\xf9r\xb28q\xe2\x84\x17\x11\x00\x00\x00\x00\xe0\xde=\xf8\xe0\x83\x99\x9d\x8d\x8d\x8d\xdc}\x17\xf9\x9b\xe5\xfd\xfa\xeb\xaf_\xbdzsx\xf7\xaf\xfc\xca\xaf|\xf0\x83\x1f<\x80\x7fhz\x0c\xd0\xfd\xf7\xdf\x9f\xa3\xb8\xae_\xbf\xfe\xf6\xdbo\'\xeb#G\x8e\xcc\xce\xce\xe6\xe8\x8b\x17\xbb\xd8\xc5.v\xb1\x8b]\xecb\xcfQ\xec\xe9\x9c3\xc4\xeem\x17\xbb\xd8\xc5.v\xb1\x8b]\xecb\xcfK\xec\xbf\xf4K\xbf\xf4w\x7f\xf7w\xe3\xc7\xe1p4777\x93+\xf9\xab\xbc/]\xba\x94,\xc20\xfc\xd5_\xfd\xf8\xc1\xfcC76^\x19\xaf\x1fz\xe8c9\x8a\xeb\xf2\xe5\xd77%\xebc\xc7\x8e}\xe4\xffg\xef~~\xe48\xef;\x01\xb7\x86\xe2\x0ck\x18Z\x9cnE\xa4U\x05*\xa2\xba%\x192\xc7\xa2bA\x89\x935\x14\xc0\x9bSx\xf2!\x87`s\x8bo\xce1>l\xae\x9b?\xc2\xb9e\x0f9\xd8\xb7\xe4\x12 \x80\x05-B\x88k\x04\x81\x86\x0e`\xa9\x1b\x16\xd7\xa9\x16M\xc5\xddtLqJ&ex)\xf5\xa8XS=\xfc!N\xcf\xd4\xfbV?\xcf\xe9\xed\xa6!\xbe\xfd\xe9W\x80\xf5\xe9\x17\xdf:\xf5TD\x9b\x17\xbb\xd8\xc5.v\xb1\x8b]\xecb\x8f(\xf6#G\x8e\xdc\xeb\x8f\xc4\xee\xb4\x8b]\xecb\x17\xbb\xd8\xc5.v\xb1\xc7\x12\xfb\x9d\xbf\xbaZyO&\xf1\xcd6\x89o\xb0I\x9e\xef<34\xcb\xd2\x0e\x00\x00\x00\x00\x00\x0b\x92\xa6Y\xf5eY\xc6F$\xbe\xca{<\xce\xf7L\x1f\x00\x00\x00\x00\x80\xfd\xa8\xdd3\x1e\x8fU\xde\x07\xaf\xfcaa0\xe8;\x82\x00\x00\x00\x00\x00\x8b2\x18\x0cj\xef\x0c\x87\xc3\xb8>Bd\x95wQ\x14\xd3\xe9t\xb6\xce2\xb7\xbc\x01\x00\x00\x00\x00\x16)Mw]\xf4\x8en\xb6Id\x95w\x9e\xefL5\xe9v\xbbI\x928\x7f\x00\x00\x00\x00\x00\x0b47\xdb$\x8fk\xff\x91U\xde\xc3\xe1h\xcf\xdc\x01\x00\x00\x00\x00\xd8\xbf\xd8\x9f`\x19Y\xe5\xed\xd9\x95\x00\x00\x00\x00\x00\x07\'\xf6\'XF7\xd8d\xbcg\xee\x00\x00\x00\x00\x00\xec\xdf\xfc3\x14\xe3\xba\xe8\x1dY\xe5\xed\xd9\x95\x00\x00\x00\x00\x00\x07\'I\x92n\xb7[}\'\xaeq\xde1U\xde\xc3\xe1\xf0^\xa1\x03\x00\x00\x00\x00\xb0\x10\xb5\x19\x1bny\x1f\x942\xd945\xd5\x04\x00\x00\x00\x00\xe0@\xcc=\xc1\xd2-\xef\x83Q\xde\x9f7\xd5\x04\x00\x00\x00\x00\xe0\x80\xd4ny\x8fF\xa3\x886\x1fS\xe5=\x99L\xf7L\x1c\x00\x00\x00\x00\x80E\x99\xbfs\\>d1|1U\xde\xe5\x8f\t\xb5{\xf5\x00\x00\x00\x00\x00,J\xb7\xdbM\x92\xa4\xfaND\xb3M\xa2\xa9\xbc\xab#\xd2\xdd\xf2\x06\x00\x00\x00\x0088\xb5\xe7)F\xf4\x04\xcbh*\xef\xe9t\xb2g\xd6\x00\x00\x00\x00\x00,Vm\xb6I\xf9\x9c\xc5\xf0\xc5w\xcb\xdb\x15o\x00\x00\x00\x00\x80\x03U\xaba\xdd\xf2^\xbc\xe1p8[t\xbb=\x07\x0e\x00\x00\x00\x00\xe0\xe0t\xbb\xdd\xeaK\x8f\xaf\\\xbc2\xd3\xc1\xa0\xef\xc0\x01\x00\x00\x00\x00\x1c\x9c\xc1`P{\xa7\xbc\x94\x1c\xb88*\xef\xa2(\xca\xca\xbb\xd7s\xcb\x1b\x00\x00\x00\x00\xe0`\xd5.z\xc72\xdb$\x8e\xca;\xcfw\x86\xa3\'IR\x0b\x1a\x00\x00\x00\x00\x80\x85\xab\x8d\xf3\x8ee\xb6I,\x95\xf7\xce\x0f\x08i\xea\xd9\x95\x00\x00\x00\x00\x00\x07.M\xb3\xea\xcb\xf2^r\xe0\xe2\xa8\xbc\xcb\x1f\x10\xb2,s\xd4\x00\x00\x00\x00\x00\x0eZ\xed\x96\xf7xl\xb0\xc9\xe2\x94? \x98j\x02\x00\x00\x00\x00p\x08\xba\xdd]OU,>\x15\xfe\xb6\xe3\xa8\xbc\xcb\x1f\x10j?,\x00\x00\x00\x00\x00p\x10\xe6\xcb\xd8(f\x9bDPyO\xa7\xd3\xf2\xd7\x03\x83M\x00\x00\x00\x00\x00\x0eG\xed\xd9\x8a\xc3\xe1(\xfc=GPyO&\x93\xd9\xa2\xdb\xed&I\xe2\x9c\x01\x00\x00\x00\x00\x1c\x82\xdaE\xef\xe9t\x12\xfe\x9e#\xa8\xbc\xcb\x9f\x0e\x0c\xf2\x06\x00\x00\x00\x0084\xb5q\xde\x93\xc94\xfc=G1\xd8d\xe7\xa7\x83\xc1`\xe0\x90\x01\x00\x00\x00\x00\x1c\x8e\xc1\xa0_}9\x1a\x19l\xb2\x08\xe5O\x07\xbd\x9e[\xde\x00\x00\x00\x00\x00\x87\xa4\xd7\xeb\xd5\xde\x99NC\xbf\xe8\x1dA\xe5]\xfet`\xb0\t\x00\x00\x00\x00\xc0\xa1\x99\xafd\xcb\'/\x06+\xf4\xca\xbb\xfa\xa3A\x96e\x0e\x19\x00\x00\x00\x00\xc0\xa1I\xd3]O\xb0,\x9f\xbc\x18\xac\xd0+\xef\xf2G\x83\xe4SN\x18\x00\x00\x00\x00\xc0\xa1\xa9\x8d\x9b.\x9f\xbc\x18\xac\xd0+\xef\xf2G\x83\xda\x8f\t\x00\x00\x00\x00\x00\x1c\xb44\xdd5{\xa3|\xf2b\xb0B\xaf\xbc\x8b\xa2\x98-L5\x01\x00\x00\x00\x008dY\xb6\xeb.\xf2x<\x0e|\xc3\xa1W\xdey\x9e\xcf\x16\x9e]\t\x00\x00\x00\x00p\xc8\xba\xdd^\xf5e\xf1\xa9\x907\x1cz\xe5]\xfehP\xfb1\x01\x00\x00\x00\x00\x80\x836_\xcc\x96\xd7\x94\xc3\x14t\xe5]\xfd\xc5\xc0`\x13\x00\x00\x00\x00\x80\xc3W{\xceb\x9e\x07=\xdb$\xe8\xca\xbb\xfasA\x92$\xce\x16\x00\x00\x00\x00\xc0!\xabu\xb3\x06\x9b<\xba\xe9t\xe7\xe9\x9f\xfd~\xdf\xc1\x02\x00\x00\x00\x008|\x83\xc1\xa0\xfar8\x1c\x86\xbc\xdb\xa0+\xef\xc9d\xa7\xf2\xee\xf5<\xbb\x12\x00\x00\x00\x00\xa0\x01\xb5z\xb6\xbc\xa9\x1c\xa6\xa0+\xef\xf2\xe7\x82\xdaSA\x01\x00\x00\x00\x008\x1c\xdd\xae\xca{A*\xcf\xaeL\x1d,\x00\x00\x00\x00\x80\xc3\x97eY\xed\x9d\x90\x9f`\x19t\xe5=\x1e\xef\x04\xe7\xd9\x95\x00\x00\x00\x00\x00\x8d\x98\xafg\xa7\xd3I\xb0\xbb\r\xb7\xf2\xae\xfePP\x9b\x8f\x0e\x00\x00\x00\x00\xc0\xa1\xe9\xf7\xfb\xd5\x97ny?\x8a\xa2\xd8\x9e-j\x93b\x00\x00\x00\x00\x008LsO\xb0t\xcb\xfb\xf3\x1b\x0eG\xb3\x85\xca\x1b\x00\x00\x00\x00\xa0A\xddn\xaf\xfar2\t\xf7\t\x96!\xdf\xf2.\x9f]\x999R\x00\x00\x00\x00\x00M\xc9\xb2\xb4\xfa\xb2|\nc\x80B\x9e\xe5\x9d\xcf\x16\x9e]\t\x00\x00\x00\x00\xd0\xa0ZI[\xdeW\x0eP\xb8\x95\xf7t\xbas7~0\xe8;R\x00\x00\x00\x00\x00M\x19\x0c\x06\xb5w\x86\xc3a\x98[\x8d\xa0\xf2N\x92uG\n\x00\x00\x00\x00\xa0A\xb1\\\xf4\x0e\xb4\xf2\xce\xf3\xbb\xb3`jcb\x00\x00\x00\x00\x008di\xba\xab\xa7\xadV\xb8A\t\xb4\xf2.\x8a\xed\xd9\xa2\xdb\xed:L\x00\x00\x00\x00\x00\xcd\xea\xf5vU\xb5\xd3\xe9$\xcc}\x06Zy\x0f\x87\xa3\xd9B\xe5\r\x00\x00\x00\x00\xd0\xb8n\xb7W}9\x99L\xc3\xdcg\xb0\xb7\xbcw\x06\xc1dY\xe60\x01\x00\x00\x00\x004\xab6\x80z<6\xd8\xe4\xf3\xc8\xf3|\xb6\xa8\xcdD\x07\x00\x00\x00\x00\xe0\xf0y|\xe5\xbeTny{v%\x00\x00\x00\x00@\xc3\xe6\x07r\x0c\x87\xc3\x00\xf7\xf9\xd8\x95+\xef\x05\xb8\xado\x7f\xfb/g\x8b?\xf9\x93?y\xfa\xe9\xa7\x9d\'\x00\x00\x027\x99L.^\xbc\xb8\xe7\x1f]\xb8pA>\x00\x00\xb4\xc0w\xbf\xfb\xdd\xea\xcbo}\xeb/\xce\x9d;\x17\xda&C\xbc\xe5\xfd\xb3\x9f\xfd\xac\\\xeb\xbb\x01\x00\x00\x00\x00B\xf0\xc5/~\xb1\xfa\xf2\xc7?~\'\xc0M\x86Xy\xff\xfc\xe7?\x9f-VWW\x1d#\x00\x00\x00\x00\x80\x10\xac\xad\xadU_~\xf4\xd1G\x01n2\xc4\xca\xfb\x83\x0f>\x98-z\xbd\x9ec\x04\x00\x00\x00\x00\x10\x82Za\xfb\xfe\xfb\xef\x07\xb8\xc9\xc7\x03\xdc\xd3\xcd\x9b\xdb\xb3\xc5\xc6\xc6\xc6\xd9\xb3\xcf\x86\xb0\xa5\x9f\xfc\xe4\xee\xc4\xf3@\xb6\xf4\x90\xae\x7f\xe2\x17\x9f\xe5y\xf2N\xa4\x11m^\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xa2\xd8WW\x8f\xde\xeb\x8f\xc4\xee\xb4\x8b]\xecb\x17\xbb\xd8\xc5.v\xb1\xb7#\xf6Z\xc7\xfd\xeb_\xff:\xc0M\x86Xy\xff\xecgWg\x8bg\x9ey\xe6\xf8\xf1\xe3\xa1m/\xc0-\xdd\xc7\x87\x1f\xde,\xd7G\x8f\xae\xc6\xb5y\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\x88b?v,\x11\xbb\xd3.v\xb1\x8b]\xecb\x17\xbb\xd8\xc5\xde\xee\xd8k]\xfc\xd5\xabW\x03\xdcd\x88\x83M\xb6\xb7\x8b\xd9"I\x92\x0e\x00\x00\x00\x00\x00\x01H\x92\xf5\xda;\xd3\xe94\xb4M\x86Xy\x8f\xc7\xe3\xd9"\xcbR\xc7\x08\x00\x00\x00\x00 \x04\xf3\x85\xedd2\tm\x93!V\xdeEQ\xde\xf2^w\x8c\x00\x00\x00\x00\x00\x02Q\x9b\xcc\xe1\x96\xf7\x83\xe5\xf9\xb8\\\xbb\xe5\r\x00\x00\x00\x00\x10\x8e4\xdd\xd5\xd9N&*\xef\x07)\x8a\xed\xd9\xc2 o\x00\x00\x00\x00\x80\xa0\xac\xaf\xd7ny\x1bl\xf2 \xe5-\xef\xda\xcf\x05\x00\x00\x00\x00\x004+M\xb3\xeaK\xb7\xbc\x1f\xac\x1c\xe4]\xfb\xb9\x00\x00\x00\x00\x00\x80f\x99\xe5\xfd\xb9\x8d\xc7\xf9lQ\xfb\xb9\x00\x00\x00\x00\x00\x80f\xd5\x9e\xbf\xa8\xf2~\xb0\xed\xed\x9d[\xdefy\x03\x00\x00\x00\x00\x04%I\xd6k\xef\x94s;\x02\x11\xe0-\xef\x9dY\xde\xb5\x9f\x0b\x00\x00\x00\x00\x00h\xd6|m\x9b\xe7yP;\x0cw\x967\x00\x00\x00\x00\x00\x81s\xcb\xfb~\xaa\x93_\x06\x83\x81\xe3\x02\x00\x00\x00\x00\x10\x94~\xbf_}\x99\xe7\xe3\xa0\xb6\x17V\xe5=\x99L\x9c\x18\x00\x00\x00\x00\x00\x1eMX\x95wy\x07\xbe\xf6C\x01\x00\x00\x00\x00\x00!\xa8\xcd\xe7\x18\x0e\x87Am/\xac\xca;\xb4;\xf0\x00\x00\x00\x00\x00D$\xd0[\xdeY\x96\xf9n\x00\x00\x00\x00\x00B\x93ei\xf5\xe5xl\x96\xf7\xbd\xe5y>[$I\xe2\xe8\x00\x00\x00\x00\x00\x84\xa6V\xde\x96\xf7\x98\x03\xb1\x12fj\xbd^\xd7\xd1\x01\x00\x00\x00\x00\x08M\xaf\xd7\xab\xbd3\x9dN\xc3\xd9^X\x95wy\x07\xbe\xdbUy\x03\x00\x00\x00\x00\x04g\xbe\xbc\x9dL&\xe1l/\xd0Y\xdeI\xb2\xee\xe8\x00\x00\x00\x00\x00\x84/\xa8\xd9&\x01U\xde\xd5\xdb\xef\xb5\t\xe8\x00\x00\x00\x00\x00\x04\xa2\xdf\xefW_\xe6y@O\xb0\x0c\xa8\xf2\x0e\xea\xf6;\x00\x00\x00\x00\x00\xd1\t\xa8\xf2.o\xbf\xa7\xa9+\xde\x00\x00\x00\x00\x00\x81\xca\xb2\xac\xfar8\x1c\x86\xb3\xb7\x80*\xef\xf2\xf6{\x92$\x0e\r\x00\x00\x00\x00@\x98B\xaepW\x02\xdc\xd3\xfa\xba\xca\x1b\x00\x00\x00\x00 P\xb5\xca\xbb\xfa\x98\xc6\xc6\x05Ty\x8f\xc7\xf9l\x91\xa6\x99C\x03\x00\x00\x00\x00\x10\xa6,\xdb5\x9bZ\xe5\xbd\xb7\xed\xed\xc2Y\x01\x00\x00\x00\x00\xe0\x91\x85\xf8\xf8\xca\xdaO\x04\x00\x00\x00\x00\x00\x84\xa3\xf6\xf8\xcaNHO\xb0\x0cj\xb0\x89\xc7W\x02\x00\x00\x00\x00\x84\xce\xe3+?o^\xeb\x0e\r\x00\x00\x00\x00@\xb0\x82}\x82e(\x95w\x9e\x8f\xcb\xb5\xc1&\x00\x00\x00\x00\x00!K\xd3]-\xeed\xa2\xf2\xde\xad(\xb6\x9d\x12\x00\x00\x00\x00\x00\xf6#\xb8\xc1&\xb5\x1f\x07\x00\x00\x00\x00\x00\x08M\xed\t\x96\x1e_Y7\x1c\x8ef\x0b\xcf\xae\x04\x00\x00\x00\x00\x08\\\xb0E\xee\x8a\xef\x06\x00\x00\x00\x00\x80\xfd(\x8a"\x90\x9d\xac\x84\x96\xc8`0p>\x00\x00\x00\x00\x00B6\x18\xf4\xab/\xc7\xe3q \x1b\x0b\xa5\xf2\xce\xf3\xdc)\x01\x00\x00\x00\x00`?\x0c6\x01\x00\x00\x00\x00`\xbf\xa6\xd3i\x08\xdbX\t-\x8e\xda}x\x00\x00\x00\x00\x00B3?\xa1z2\x99\x84\xb0\xb1\xe0*o\x00\x00\x00\x00\x00x4\xc1\r6I\x92u\xdf\n\x00\x00\x00\x00@\xe0\x92$\xa9\xbe4\xd8d\xef,\xb2,uV\x00\x00\x00\x00\x00\x02\x97\xa6\xbb\xba\xdc\xc9D\xe5}7\x8b\x89\xf3\x01\x00\x00\x00\x00\xc0>\x855\xd8\xa4v\x13\x1e\x00\x00\x00\x00\x800\xad\xaf\xd7\x06\x9bx|\xe5\xdd,vn\xbc\xd7n\xc2\x03\x00\x00\x00\x00\x10\xa64\xcd\xaa/\r6\t.\x0b\x00\x00\x00\x00\x00\xa2\xb6"\x02\x00\x00\x00\x00\x00\xf6\xa9\x1c\xe6\xd1\xac@\x06\x9b\xec\x0cy\x19\x0c\x06N\x06\x00\x00\x00\x00@\xf8\x06\x83~\xf5\xa5\xca\xfb.\x83M\x00\x00\x00\x00\x00\xd8?\x83M\x00\x00\x00\x00\x00X\x80\xa2(\x1a\xdfCX\x95w\x96\xa5\x8e\x05\x00\x00\x00\x00@\xf8\xb2,\xab\xbd\x93\xe7y\xe3\xbb\n\xa2\xf2\x1e\x8dF\xb3E\x92$\x0e\n\x00\x00\x00\x00@\xf8\xc2\xacs\r6\x01\x00\x00\x00\x00\xa0%\xc2\xaa\xbc\x93d\xddW\x02\x00\x00\x00\x00\x10\x85\xdaE\xef<\x1f7\xbe\xa5\xe6+\xefj\nfy\x03\x00\x00\x00\x00\xc4"Mw5\xba\x1e_9Ka\xdb\xc9\x00\x00\x00\x00\x00`\xff\x1eo|\x07\x1f\x7f\xfcq\xb9\xbev\xed\x83\xf0#\x8bb\x93\xa5\x9b7oV\xd7qm^\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xa2\xd8\xaf_\xbf.v\xa7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b}\xd9b\xbf}\xfbv\xf5\xe5\x7f\xfd\xd7\x7f5\xbe\xa5\xc7\xae\\y\xaf\xd9\x1d\\\xbe|\xf9\xbb\xdf\xfd\xdb;\x8b^\xaf\xf7\xcdo~\xb3\x03\x00\x00\x11\x9aL&\x17/^\xdc\xf3\x8f.\\\xb8 \x1f\x00\x00Z\xe9\x8d7\xdex\xf7\xddw\xcb\x97Y\x96}\xe7;\x7f\xd5\xec\x96\x9a\x1fl\xf2\xce;;\x89\xac\xae\xae:"\x00\x00\x00\x00\x00\xb18q\xe2Dh[j\xbe\xf2\xfe\xcdo~\xe3d\x00\x00\x00\x00\x00\xb0\x7f\xcd\xcf\xf2>rd\xe5\xb3\xc5\x91\xe3\xc7\x8f\x87\x19Su\x0cP\xb0\x9b\xdc\xd3\xad[\xb7\xcay:G\x8f\x1e\x8d\xeb*\xbd\xd8\xc5.v\xb1\x8b]\xecb\x17{D\xb1Ws\xae\x11\xbb\xd3.v\xb1\x8b]\xecb\x17\xbb\xd8\xc5\xde\xd6\xd8\xef\xe4\\}\xf9\xcb_\xfe\xb2\xf1-5_y\x1f;\x96\xcc\x16\xfd~\xff\xec\xd9g\xc3\xfc\xe6._\xfeQ\xb9\x0ev\x93{\xbav\xed\x83;f\xeb\x8d\x8d\x8dS\xa7\x9e\x8ah\xf3b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x11\xc5~\xe4\xc8\x91{\xfd\x91\xd8\x9dv\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\xb6\xc6\xfe\xe1\x877\xdez\xeb\xad\xf2e\x08\x95w\xf3\x83M\x86\xc3\xe1l\x91$I\x07\x00\x00\x00\x00\x80H\x04X\xea\xae\xf8V\x00\x00\x00\x00\x00h\x07\x957\x00\x00\x00\x00\x00\x8bQ\x14E\xb3\x1b\x08\xa8\xf2\xee\xf5\xba\x0e\x04\x00\x00\x00\x00@,z\xbd^\xed\x9d<\xcf\x9b\xddR\xf3\x95\xf7h4\x9a-\xba]\x957\x00\x00\x00\x00@4\x02,u\r6\x01\x00\x00\x00\x00\xa0%T\xde\x00\x00\x00\x00\x00\xb4\x84\xca\x1b\x00\x00\x00\x00\x80\xc5\x18\x0eG\xcdn\xa0\xe1\xca{:\x9d\x96\xeb\xc1`\xe0@\x00\x00\x00\x00\x00D\xa4\xdf\xef\x07\xb5\x9f\x86+\xef\xc9d\xe2L\x00\x00\x00\x00\x00\xb0\x10\x06\x9b\x00\x00\x00\x00\x00\xd0\x12*o\x00\x00\x00\x00\x00\x16\xa3(\x8af7\x10J\xe5\x9d$\x89\xd3\x00\x00\x00\x00\x00\x10\xb5<\xcf\x9b\xdd@(\x8f\xafL\xd3\xd4i\x00\x00\x00\x00\x00\x88\xcb`0\x08j?\x8d?\xber\xeaL\x00\x00\x00\x00\x00\xb0\x10fy\x03\x00\x00\x00\x00\xd0\x12*o\x00\x00\x00\x00\x00ZB\xe5\r\x00\x00\x00\x00\xc0b\x8c\xc7\xe3f7\x10J\xe5\xdd\xebu\x9d\x06\x00\x00\x00\x00\x80\xb8\xd4\xaa\xdd\xa2(\x9a\xddO\xc3\x95\xf7x\x9c\xcf\x16\xddn\xcf\xe1\x00\x00\x00\x00\x00\x88K\xb7\x1b\xd6m\xe6\x86+\xef\xed\xed\xc2\x99\x00\x00\x00\x00\x00`!\xcc\xf2\x06\x00\x00\x00\x00\xa0%T\xde\x00\x00\x00\x00\x00\xb4\x84\xca\x1b\x00\x00\x00\x00\x80\x85\xc9\xf3q\x83\x7f\xbb\xca\x1b\x00\x00\x00\x00\x80\x85)\x8a\xed\x06\xff\xf6\x95\xa6?\xfc\xce\xe3+\x07\x83\xbe\xa3\x00\x00\x00\x00\x00\x10\x97\xc1`\x10\xd4~\x1a\xae\xbc\xc7\xe3\xb13\x01\x00\x00\x00\x00\xc0B\x18l\x02\x00\x00\x00\x00@K\xa8\xbc\x01\x00\x00\x00\x00h\t\x957\x00\x00\x00\x00\x00-\xa1\xf2\x06\x00\x00\x00\x00`a\x8a\xa2h\xf0oWy\x03\x00\x00\x00\x00\xb00y>n\xf0oWy\x03\x00\x00\x00\x00\xd0\x12MV\xde\xd5\xfb\xed\x83\xc1\xc0\x97\x01\x00\x00\x00\x00\x10\x9d~\xbf\x1f\xcef\x9a\xac\xbc\xf3\xf8`\xcf?:s\xe6\x8c\xd8\x9dv\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\xb6\xc6~G\x9e\xe7\xe3\xf1\xb8|y\xea\xd4\xa9\xbf\xfe\xeb\xff\xd9\xd4f\x1eo0\x88\x8f?\xfeu\xf9\x9f\x07?\xfd\xe9Oc\xf9\xfe&\x93I\x07\xb1\x8b\x1d\xb1\x8b\x1d\xb1\x8b\x9d\x87\x16\xd1\xff\xd7u\xda\x11\xbb\xd8\x11\xbb\xd8\x11\xbb\xd8\x1f\xc1\x8d\x1b7\xaa/?\xfe\xf8\xe3\x067c\xb0\t\x00\x00\x00\x00\x00-\xa1\xf2\x06\x00\x00\x00\x00\xa0%\x9a\xac\xbc\x1f{L\xfe\x00\x00\x00\x00\x00\xad\xf2X\xa3\xcdo\x93\x95\xf7o~\xe3\xdb\x07\x00\x00\x00\x00h\x95\xdf4\xda\xfc\x1al\x02\x00\x00\x00\x00@K\xa8\xbc\x01\x00\x00\x00\x00h\x89\xc7\x1b\xfc\xbb\x8f\x1f?>[\x9c:u\xeaO\xff\xf4OC\x8e\xe9\xbd\xf7\xde+\xd7\xcf>\xfblD_\xf0\xf5\xeb\xd7\x7f\xf1\x8b_\xcc\xd6\'O\x9e\xdc\xd8\xd8\x88h\xf3b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x11\xc5~\xed\xda\xb5\x7f\xfe\xe7\x7f\xde\xf3\x8f\xfe\xec\xcf\xfeL\xecN\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17{[c\xbf\xe3\xe2\xa7\xca\x97\'N\x9chp3MV\xde\x8f?\xbe\xf3\xb7\xaf\xad\xad=\xf3\xcc\x99\x90\xbf\xb3_\xfe\xf2\x97\xe5:\xf0\xad\xd6\x1c;v\xec\xc8\x91#\xb3\xf5SO=u\xea\xd4S\x11m^\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xde\xd8\xab\xc4\xee\xb4\x8b]\xecb\x17\xbb\xd8\xc5.v\xb1\xb78\xf6;\xfe\xfd\xdf\xff\xbd\xfa\xb2,~\x1ba\xb0\t\x00\x00\x00\x00\x00-\xa1\xf2\x06\x00\x00\x00\x00\xa0%T\xde\x00\x00\x00\x00\x00\xb4D\x10\x95\xf7t:\xf5M\x00\x00\x00\x00\x00\xc4h:\x9d\x84\xb3\x19\x957\x00\x00\x00\x00\x00\x8fn2\t\xa8\xe0m\xb2\xf2\x1e\x0c\xfaN\x03\x00\x00\x00\x00\x00\x8bb\x967\x00\x00\x00\x00\x00-\xa1\xf2\x06\x00\x00\x00\x00\xa0%T\xde\x00\x00\x00\x00\x00\xb4\x84\xca\x1b\x00\x00\x00\x00\x80\x96Py\x03\x00\x00\x00\x00\xb00Y\x965\xf8\xb7\xab\xbc\x01\x00\x00\x00\x00X\x98$I\x1a\xfc\xdbU\xde\x00\x00\x00\x00\x00\xb4\x84\xca\x1b\x00\x00\x00\x00\x80\x96Py\x03\x00\x00\x00\x00\xd0\x12*o\x00\x00\x00\x00\x00Z"\x94\xca;\xcf\xc7\xbe\x0c\x00\x00\x00\x00\x80\xe8\x8c\xc7\x01\xb5\xbbMV\xde\xbd^\xaf\\\x17\xc5\xb6\x93\x01\x00\x00\x00\x00\x10\x9d\xa2(\xc2\xd9L\x93\x95w\xb7\xdbu\x1a\x00\x00\x00\x00\x00X\x14\xb3\xbc\x01\x00\x00\x00\x00h\t\x957\x00\x00\x00\x00\x00\x0b\xd3\xeb59\xdeC\xe5\r\x00\x00\x00\x00\xc0\xc24;\xd1Z\xe5\r\x00\x00\x00\x00@K\xa8\xbc\x01\x00\x00\x00\x00h\x89P*\xef<\x1f\xfb2\x00\x00\x00\x00\x00\xe2\x12Z\xb5\xdbp\xe5\x9d$\xc9lQ\x14\x85\xc3\x01\x00\x00\x00\x00\x10\x97\xa2\xd8\x0ej?\rW\xdei\x9a:\x13\x00\x00\x00\x00\x00,\x84Y\xde\x00\x00\x00\x00\x00\xb4\x84\xca\x1b\x00\x00\x00\x00\x80\x85\x19\x0c\x06\r\xfe\xed*o\x00\x00\x00\x00\x00Z"\x94\xca\xdb\xe3+\x01\x00\x00\x00\x00\xa2\x13Z\xb5\x1bJ\xe5\x9d\xe7\xb9\xc3\x01\x00\x00\x00\x00\x10\x97<\x1f\x07\xb5\x9f\x86+\xef,\xcb\x9c\t\x00\x00\x00\x00\x00\x16\xa2\xe1\xca;I\x12\xdf\x01\x00\x00\x00\x00\x00\x0b\xe1\xf1\x95\x00\x00\x00\x00\x00,F\xbf\xdfov\x03*o\x00\x00\x00\x00\x00Z"\x94\xca{:\x9d\xfa2\x00\x00\x00\x00\x00\xe22\x1e\xe7A\xed\'\x94Y\xde*o\x00\x00\x00\x00\x80\xe8lo\x17A\xed\xa7\xe1\xca;\xcbRg\x02\x00\x00\x00\x00\x80\x850\xcb\x1b\x00\x00\x00\x00\x80\xc5\xe8\xf5\xba\xcdn@\xe5\r\x00\x00\x00\x00\xc0bt\xbb\xbdf7\x10P\xe5\x9d\xe7c\x07\x02\x00\x00\x00\x00 "\xe3qX\xbdn\xe3\x8f\xaf\\/\xd7E\xb1\xed|\x00\x00\x00\x00\x00D\xa4(<\xbe\xb2\xc2\xe3+\x01\x00\x00\x00\x00X\x14\xb3\xbc\x01\x00\x00\x00\x00X\x8c\xc6o9\x07Ty\x87v\x01\x1e\x00\x00\x00\x00\x80\xfb\x98/u\x93$ivK\x1e_\t\x00\x00\x00\x00\xc0\xa3\xc8\xf3<\xb4-5_y\xa7\xa9q\xde\x00\x00\x00\x00\x00,@\xf3\x95w\xe3\x17\xdd\x01\x00\x00\x00\x00X\x88$Yov\x03\x1e_\t\x00\x00\x00\x00\xc0bx|\xe5]\xc3\xe1\xd0\x81\x00\x00\x00\x00\x00\x88\xc5p8\nmK\xcdW\xde\xbd^\xd7\xc9\x00\x00\x00\x00\x00`\xff\x1eo|\x07\'N\x9c\x98-n\xdf\xbe}\xed\xda\x07\xe1G\x16\xc5&K7o\xde\xac\xae\xe3\xda\xbc\xd8\xc5.v\xb1\x8b]\xecb\x17{D\xb1_\xbf~]\xecN\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17\xfb\xb2\xc5^\xcd\xfc\x8e\xb5\xb5\xb5\xc6\xb7\xf4\xd8\x95+\xef5\xbb\x83\xef}\xef\xfbo\xbe\xf9f\xe7\x93\xeb\xde\xbdo~\xf3\x9b\x1d\x00\x00\x88\xd0d2\xb9x\xf1\xe2\x9e\x7ft\xe1\xc2\x05\xf9\x00\x00\xd0Jw\xfe?\xf0\x8f~\xf4\xa3\xf2e\x96e\xdf\xf9\xce_5\xbb\xa5\xe6\x07\x9b<\xf6\xd8c\xe5\x7f$8"\x00\x00\x00\x00\x00\xb1\x08\xb0\xd4m\xbe\xf2\xce\xb2\xcc\xc9\x00\x00\x00\x00\x00`\xffB\x98\xe5\xfd[\xe5\xfa\xf8\xf1\xe3a\xc6T\x1dI\x13\xec&\xf7t\xeb\xd6\xad\xdb\xb7o\xcf\xd6G\x8f\x1e]]]\x8dh\xf3b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x11\xc5^\x1bbX%v\xa7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b\xbd\xad\xb1\x1f9r\xa4\xfa\xb2\xd7\xeb5\xbe\xa5\xe6+\xef\xea\xc9;y\xf2\x89n\xb7\x1b\xe07w\xf9\xf2\xddy4g\xcf>\x1b\xd1\xbf*\xd7\xae}p\xc7l\xbd\xb1\xb1q\xea\xd4S\x11m^\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xa2\xd8k\xff_\xbfJ\xecN\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17{[c\xdf\xde\xde\xae\xbe|\xfa\xe9\xa7\x1b\xdf\xd2JP\x01\x19\xe7\r\x00\x00\x00\x00\x10\x8b\xe9t\x1a\xda\x96\x9a\xaf\xbc\x07\x83\x81\x93\x01\x00\x00\x00\x00\xc0\xfe\xad\x88\x00\x00\x00\x00\x00\x80\xfd\x1b\x0c\xfa\x8d\xef!\xac\xca{8\x1c9\x16\x00\x00\x00\x00\x00\xe1\x1b\x0e\x87\x01\xee*\x88\xca;\xccGV\x02\x00\x00\x00\x00\x10\x17\x957\x00\x00\x00\x00\x00\x0b\xd0\xeb\xf5\x1a\xdfCX\x83M\xc6\xe3\xdc\xb1\x00\x00\x00\x00\x00\x08_\x9e\x8fk\xef\x84p\xb99\x88\xca{}=\x99-\xb6\xb7\x0b\x07\x05\x00\x00\x00\x00 |E\x11b\x9d\x1bD\xe5\x9d\xa6\x99\xf3\x01\x00\x00\x00\x00\x10\xaf$IB\xd8FX\x83M\xa6\xd3\xa9\x93\x01\x00\x00\x00\x00\x10\xbe\xe9tR}\x99\xa6i\x08\xbbRy\x03\x00\x00\x00\x00\xf0\xb9M&!\xd6\xb9AT\xde\x83A\xdf\xf9\x00\x00\x00\x00\x00`\x9fVB\xdb\x90\x8b\xde\x00\x00\x00\x00\x00\xe1\xabu\xb9\x83\xc1 \x84]\x05WyO&\x13g\x05\x00\x00\x00\x00 pa^_\x0ed\xb0\xc9\xc0\xf9\x00\x00\x00\x00\x00`\x9f\x82\xbb\xe5\x9d\xe7c\xdf\n\x00\x00\x00\x00@\xc8\xe6\x8b\xdc@\x1e\xd9\x18J\xe5\x9d$\xc9lQ\x14\x85\xe3\x02\x00\x00\x00\x00\x10\xb2\xa2\xd8\x0esc\xa1T\xdei\x9a:%\x00\x00\x00\x00\x00\x91J\x92\xf5\x10\xb6\x11\xdc`\x93\xf18w8\x00\x00\x00\x00\x00B6?\xd8$\xcb\x82\xb8\xd6\x1cJ\xe5\xbd\xbe\xbe3\xd8d{\xdb`\x13\x00\x00\x00\x00\x80\xa0\x05;\xa1:\x9c\xc1&\x99S\x02\x00\x00\x00\x00\x10\xa3n\xb7\x1b\xc8N\x82\x1bl2\x1a\x8d\x9c\x0f\x00\x00\x00\x00\x80\x90\r\x87\xc3\xeaK\x95w]\xaf\xd7uJ\x00\x00\x00\x00\x00\xd8\x8fP*\xef\xea\x8f\x00\xd3\xe9\xd4\x17\x03\x00\x00\x00\x00\x10\xacZ\x8b\x9be\xa1L\xae^\t0\xac\xc9d\xe2\xc4\x00\x00\x00\x00\x00\x04\xabVy\'I\x12\xc8\xc6B\xa9\xbc\x07\x83\x81S\x02\x00\x00\x00\x00\x10#\x95\xf7\xfd\x0c\x87\x9e`\t\x00\x00\x00\x00\x10\xa8\xda\xb3+;\x9f\x0c6I\x03\xd9[@\x95w8\xcf\xf4\x04\x00\x00\x00\x00 F!V\xde\xd3\xa9Y\xde\x00\x00\x00\x00\x00\x81\xaa\r\xf2\xbe\xa3\xd7\xeb\x05\xb2\xb70\x1f_9uh\x00\x00\x00\x00\x00\xc24_\xe1\x863\xc3#\xa0\xca\xdb\x13,\x01\x00\x00\x00\x00\xd8\x8f\x10oy\x8fF\x1e_\t\x00\x00\x00\x00\x10\xa8\xda\xe3+\xfb\xfd~8{\x0b\xa8\xf2\xee\xf5<\xbe\x12\x00\x00\x00\x00\x80G\x17\xe2\xe3+\xef\xc8\xf3\xb1\xef\x06\x00\x00\x00\x00 @\xe3\xf1\xae\xfe6\xcb\xb2p\xf6\xb6\x12fdE\xb1\xed\xdc\x00\x00\x00\x00\x00\x04\xa8(\x8a\xea\xcb$I\xc2\xd9[\xa0\x8f\xaf\xacE\x06\x00\x00\x00\x00@\x08\xe6\xcb[\x95\xf7\x83\x19l\x02\x00\x00\x00\x00\x10\xa0<\xcfk\xefdY\x1a\xce\xf6\xc2\xaa\xbc\xd34ub\x00\x00\x00\x00\x00x4aU\xde\xe5\x05\xf8\xe1p\xe8\xbb\x01\x00\x00\x00\x00\x08\xcdp8\xaa\xbdS\x9dY\xdd\xb8\xb0*\xef^\xaf\xeb\xc4\x00\x00\x00\x00\x00\xf0h\xc2\xaa\xbc\xbb\xdd\xdel1\x1e\x9b\xe5\r\x00\x00\x00\x00\x10\x9c\xf1x\xd7,\xef\xd0\xa6U\x07:\xd8d\xfe\xa1\x9f\x00\x00\x00\x00\x004n{{Wy[\x96\xba\x81\x08\xab\xf2\xae>\xd93\xcf]\xf4\x06\x00\x00\x00\x00\x08KmDGh\xd3\xaaC\xbb\xe5\xbd^\xae\x8bb\xdb\xe9\x01\x00\x00\x00\x00\x08JmDG9\xad:\x10\xe1\xde\xf2\x9eN\xa7N\x0f\x00\x00\x00\x00@8\xe6k[\xb7\xbc\x1f\xd6d\xa2\xf2\x06\x00\x00\x00\x00\x08\xc8d2\xa9\xbd\xd3\xed\xaa\xbc\xef\xab\xdf\xef\xcf\x16\xd3\xe9\xc4\x01\x02\x00\x00\x00\x00\x08\xc7\xfc-\xef\xea\xb4\xea\x10\xb8\xe5\r\x00\x00\x00\x00\xc0C\x99\xafm\xab\xd3\xaaC\x10\\\xe5=\x18\x0cf\x0b\xb3\xbc\x01\x00\x00\x00\x00\x82R\x1b\xce\x91$Ih;\\\t8;\x957\x00\x00\x00\x00@@j\xb7\xbc\xd34\rm\x87\x01\xde\xf2\xee\x97k\xad7\x00\x00\x00\x00@8j\x9d\xed\xfa\xba[\xde\x9f\xc7\xfc\xd3?\x01\x00\x00\x00\x00hJ\xad\xf2N\xd3,\xb4\x1d\x86;\xcb\xbb\xe3\x967\x00\x00\x00\x00@0\xe6\x0b[\xb3\xbc?\x9f\xf9\xa7\x7f\x02\x00\x00\x00\x00\xd0\x88\xf9\xb1\x1cYf\x96\xf7C\xe8\xf7w\xc6y\xd7\x9e\xfe\t\x00\x00\x00\x00@S\xf6\xba\xe5\xbd\x1e\xda&\xdd\xf2\x06\x00\x00\x00\x00\xe0\xc1\xe6\x0b[\xb7\xbc\x1fJ9\xce\xdb,o\x00\x00\x00\x00\x80@\xd4\xc6r\x048\xc8\xfb\x8e\xc7\xae\\y/\xb4=}\xef{\xdf\x7f\xf3\xcd7g\xebo}\xeb[N\x12\x00\x00\xe1\x9bL&\x17/^\xdc\xf3\x8f.\\\xb8 \x1f\x00\x00Z\xe0\x1f\xfe\xe1\x1f\xae^\xbdZ\xbe\xcc\xb2\xec;\xdf\xf9\xab\xd06\x19\xe2-\xef\x17_|\xa1\xfa_\x0eN\x12\x00\x00\x00\x00@\xe3jm\xed\xc9\x93\'\x03\xdcd\x88\x95\xf7\xf1\xe3\xbfU\xae\x7f\xf5\xab_9I\x00\x00\x00\x00\x00\x8d\xbbu\xebV\xf5e\xaf\xd7\x0bp\x93!V\xdeg\xcf>[\xae\xab\xf7\xe4\x01\x00\x00\x00\x00h\xc4\xfb\xef\xbf_{\xa7\xdb\xdd\x08p\x9f\x8f\x87\x19\xdf\xb1c\xc7>\xfa\xe8\xa3;\x8b\x8d\x8d\x93\xd5\x06\xbc)?\xf9\xc9\xdd\x89\xe7!\xec\xe7\xe1]\xff\xc4/f\xeb;anllD\xb4y\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\x88b_]=z\xaf?\x12\xbb\xd3.v\xb1\x8b]\xecb\x17\xbb\xd8\xc5\xde\x8a\xd8\x7fS{\x9d\xa6i\x80\xbb\x0c\xb4\xf2\xce\xb2l4\x1a\xddY\\\xb9\xf2\xff\x8e\x1f?\x1e\xd4\xdeB\xdb\xcf\xfd}\xf8\xe1\xcdr}\xf4\xe8j\\\x9b\x17\xbb\xd8\xc5.v\xb1\x8b]\xecb\x8f(\xf6c\xc7\x12\xb1;\xedb\x17\xbb\xd8\xc5.v\xb1\x8b]\xec-\x8e\xfd?\xfe#\xaf\xbd\xf3\xcc3\xcf\x04\xb8\xcf\x950\xbf\xd4^\xaf;[\x14E\xd1\x01\x00\x00\x00\x00\xa0Q\xf3U\xed\xb1c\xc7\x02\xdcg\xa0\x95w\xb7\xbb3\xf8|<\x1e;L\x00\x00\x00\x00\x00\xcd\xca\xf3]\xb7\xbc\xfb\xfd~\x98\xfb\x0c\xb4\xf2\xce\xb2\xbbS`\xa6\xd3\xa9\xf3\x04\x00\x00\x00\x00\xd0\xa0Xz\xda@+\xef$\xb9;\tq2\x998O\x00\x00\x00\x00\x00\r\xaaU\xde\x83\xc1 \xcc}\x06ZyW\xf3\xcas\xb3M\x00\x00\x00\x00\x00\x1a3_\xd2Vo-\x07e%\xd8\x10\xcb\xc8<\xc1\x12\x00\x00\x00\x00\xa0AE\xb1]{\xa7:\x9b:(\xe1V\xdei\xba\x13\xd9p8t\xa4\x00\x00\x00\x00\x00\x9a2\x1c\x8ej\xef<\xf9\xe4\x93an5\xdc\xca\xbb\xd7\xeb\xce\x16ny\x03\x00\x00\x00\x004h\xbe\xa4\xdd\xd8\xd8\x08s\xab\xe1V\xde\xddno\xb6\x18\x8f\xcd\xf2\x06\x00\x00\x00\x00hL\x9e\xe7\xd5\x97\xe5\x88\x8e\x00\x85[yWg\xc1x\x82%\x00\x00\x00\x00@Sj\xf7\x92\xcb\x11\x1d\x01\x8a\xe0\xf1\x95\x9d\xbd\x86\xa3\x03\x00\x00\x00\x00p8j\x83M\xd24\x0bv\xab\xe1V\xde\x83\xc1\xa0\\\xcf\x0fG\x07\x00\x00\x00\x00\xe0\x10\x0c\x87\xc3\xda;ny?\xa2\xf2\xa2\xb7\'X\x02\x00\x00\x00\x004b\xbe\x9e\xedvU\xde\x8f\xa4\x1c\x82^\x1b\x8e\x0e\x00\x00\x00\x00\xc0\xe1\x98\x7f\xd4\xe2\x993g\x82\xddm\xd0\x95w\x96\xedL\x84\xa9\rG\x07\x00\x00\x00\x00\xe0p\x8c\xc7\xbbn$\'I\xb2\xb6\xb6\x16\xecn\r6\x01\x00\x00\x00\x00\xe0\x9e\xb6\xb7k\xcf\xaeLC\xdem\xd0\x95\xf7`\xd0/\xd7\xf3#\xd2\x01\x00\x00\x00\x008h\xa3\xd1\xa8\xfa2\xe4gWv\x02\xaf\xbc{\xbd^\xb9\x9eN\xa7\xce\x16\x00\x00\x00\x00\xc0a\x9a/f\xbb\xdd^\xc8\x1b\x0e\xba\xf2\xae>\xf7s2Qy\x03\x00\x00\x00\x00\x1c\xaa\xc9dR{\xa7:\x9c#@+\x81\x07\xda\xef\xef\xc4g\xb0\t\x00\x00\x00\x00\xc0!\x1b\x0eG\xb5w\x9e|\xf2\xc9\x907\x1cz\xe5\xbd\xbe\xbe\xf3\x04K\x83M\x00\x00\x00\x00\x00\x0e\xd9tZ\xbf\xe5\xbd\xb1\xb1\x11\xf2\x86C\xaf\xbc\xd34\xfb,Y\x957\x00\x00\x00\x00\xc0\xa1\xaaM\x9cN\xd34\xf0\r\x87^yg\xd9\xdd\x04\xcd6\x01\x00\x00\x00\x008L\xa3\xd1\xae\xc1&\xbd^7\xf0\r\x87^yW\x9f\xfeY\x14\x85\x13\x06\x00\x00\x00\x00p8\xe6+\xd9r,G\xb0b\xba\xe5\x9d\xe7c\x87\x0c\x00\x00\x00\x00\xe0p\xe4y^{\xa7Z\xd8\x86i%\xfcX\xcb\xe90\xe3q\xee\x90\x01\x00\x00\x00\x00\x1c\x8e\xf9[\xc8\xd5\xb1\x1ca\x8a\xa0\xf2.\xa7\xc3\xd4\x06\xa5\x03\x00\x00\x00\x00pp\xa6\xd3z%\xeb\x96\xf7\x02\x94\xd3a\xc6c\x83M\x00\x00\x00\x00\x00\x0eIm\xb0I9\x90#d\x11T\xde\xd5\xdf\r\x86\xc3\xa1s\x06\x00\x00\x00\x00p\x08F\xa3Q\xf5e9\x90#d\x11T\xde\xd5\xe90\xf3\x17\xe9\x01\x00\x00\x00\x00X\xb8\xf92\xb6\x1c\xc8\x11\xb2\xc8ny\x1b\xe7\r\x00\x00\x00\x00p\x08&\x93I\xed\x9d\xf0\x07yw\xa2\xa8\xbc;\x95\x191\x06\x9b\x00\x00\x00\x00\x00\x1c\x82\xe1pT{\xe7\xc9\'\x9f\x0c\x7f\xdbqT\xde\xe5\x8c\x18\x83M\x00\x00\x00\x00\x00\x0e\xc1tZ\xbf\xe5\xfd\xf4\xd3O\x87\xbf\xedXnyg\x9f\xa5<-\x8a\xc2i\x03\x00\x00\x00\x008Py>\xae\xbe,Gq\x04.\x8e\xca{0\xe8W\x82\xce\x9d6\x00\x00\x00\x00\x80\x035\x1e\xef\xaa\xbc\xa3\x18\xe4\xdd\x89g\xb0I\xaf\\\xd7~[\x00\x00\x00\x00\x00`\xb1\xe6k\xd8n\xb7\x17\xc5\xce\xe3\xa8\xbc\xbb\xddn\xb96\xce\x1b\x00\x00\x00\x00\xe0@\xcd\x0f\xf2\xae\x8e\xe2\x08\xd9J,\x11\xf7\xfb;\x81\x1al\x02\x00\x00\x00\x00p\xa0\xe6oy\xff\xf6o\xffv\x14;\x8f\xa6\xf2\xce\xb2\x9d\'X\x8eF#\x07\x0e\x00\x00\x00\x00\xe0\xe0\x0c\x87\xc3\xea\xcb$IN\x9e<\x19\xc5\xce\xa3\xa9\xbc\xcd6\x01\x00\x00\x00\x008\x1c\xb5\x0e6M\xd3Xv\x1e\xd1-\xef\xbb\x99\x9am\x02\x00\x00\x00\x00p@\x8a\xa2\xa8U\xde\xe5\x10\x8e\xf0ESy\x0f\x06\x83r=?G\x06\x00\x00\x00\x00\x80\x85\x98\xbfs\\\xbd\x91\x1c\xb8\x95\x88\x82.g\x9b\xd4\xe6\xc8\x00\x00\x00\x00\x00\xb0(\xc3a\xfdy\x8ai\xea\x96\xf7\x01(\x7fI0\xcb\x1b\x00\x00\x00\x00\xe0\x80L\xa7\x93\xda;ny\x1f\x88\xf2\x97\x84\xe9tZ\x14\x85\x93\x07\x00\x00\x00\x00\xb0p\xb5\xc9\xd2\x11=\xbb\xb2\x13W\xe5=\x18\xf4+\xa1{\x82%\x00\x00\x00\x00\xc0\xe2\x8d\xc7\xbb*\xef\x88\xaexw\xe2\xaa\xbc{\xbd^\xb9\x9e\x9f&\x03\x00\x00\x00\x00\xc0>\xcd?I\xb1\xdb\xedE\xb4\xff\xc8\x1e_\x99$\xc9l=?M\x06\x00\x00\x00\x00\x80}\x9a\x7f\x92bu\xfcF\xf8V\xe2\x8a\xbb\x9c\x1aS\x9b&\x03\x00\x00\x00\x00\xc0\xfe\xcdW\xafg\xce\x9c\x89h\xff\x91U\xde\x83\xc1`\xb6\xa8M\x93\x01\x00\x00\x00\x00`\xffj\x8fQ\xecv\xbbkkk\x11\xed?\xb2\xca\xbb:(}~\xa6\x0c\x00\x00\x00\x00\x00\xfb1\x1a\xedz\x8cb\\\xcf\xae\xecDWyW\x07\xa5\x9bm\x02\x00\x00\x00\x00\xb0@\xf3\xa5k\x9afq}\x84\x88oy\x8f\xc7\xb9#\x08\x00\x00\x00\x00\xb0(\xf3\xa5k\\\xcf\xae\xecDWy\xdf\xd1\xef\xefD\xec\x967\x00\x00\x00\x00\xc0\x02\xc5\xfe\xec\xcaN\x8c\x95w\x96\xed\\\xa4\xf7\x04K\x00\x00\x00\x00\x80\x05\x8a\xfd\xd9\x95\x9d8+oO\xb0\x04\x00\x00\x00\x00X\xbc\xda\xb3+\xbb\xddnt\x1f\xe1\xf1\xe8v|\xfa\xf4\xe9r\xfd\xe3\x1f\xbf\xf3\x85/\x00\x00\x84\xef\xddw\xdf}\xe3\x8d7\xaa\xef|\xeb[\x7fq\xee\xdc\xb9\xb8>\xc5J\x8c\xd1\x97\xe3\xbc\xef\xfcw\x85\x83\x08\x00\x00\x00\x00\xb0\x7f?\xff\xf9\xcfk\xef<\xf7\\?\xbaO\x11e\xe5\xfd\xc5/~q\xb6Py\x03\x00\x00\x00\x00,D\xadn=q\xe2\xc4\xfaz\x12\xdd\xa7x<\xc6\xe8\x9fy\xe6\x99\x1f\xfe\xf0\x87\xb3\xf5\xf5\xeb\xd7\xcbK\xdf\x07\xa7:\x06\xe8\xf8\xf1\xe3\x11eu\xeb\xd6\xad\xdb\xb7o\xcf\xd6G\x8f\x1e]]]\x8dh\xf3b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x11\xc5^\xcd\xb9F\xecN\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17{\x14\xb1_\xbdz\xb5\xfa\xb2\xbcy\x1c\x97(+\xefs\xe7\xbe\xfc\xfd\xef\x7f\x7f\xb6\xfe\xf5\xaf\x7f}\xf6\xec\xb3\x07\xfd7^\xbe\xfc\xa3r}\x08\x7f\xdd\x02]\xbb\xf6\xc1\x1d\xb3\xf5\xc6\xc6\xc6\xa9SOE\xb4y\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\x88b?r\xe4\xc8\xbd\xfeH\xecN\xbb\xd8\xc5.v\xb1\x8b]\xecb\x17{\xf8\xb1\x0f\x87\xc3\xda;\xcf=\xf7\\\'BQ\x0e6\xe9v\xbbI\xb2s\xa3~4\x1av\x00\x00\x00\x00\x00\xd8\x87<\x1f\xd7\xde\x19\x0c\xfa1~\x90\x95H\xbf\x804M\xef\xf5M\x00\x00\x00\x00\x00\xf0\xb9\x8c\xc7y\xed\x9d3g\xce\xc4\xf8Ab\xad\xbc\x07\x83\xc1l1\x9dN\x8b\xa2p"\x01\x00\x00\x00\x00\x1eY\xednq\xb7\xdb][[\x8b\xf1\x83\xc4ZygYZ\xf92r\'\x12\x00\x00\x00\x00\xe0\xd1\x14E1\x1e\xef\xaa\xbc#\x9dj\xd2\x89\xb9\xf2\xce\xca\xf5p8r(\x01\x00\x00\x00\x00\x1e\xcd\xfc\xad\xe24\xcd"\xfd,\xb1V\xde\xddO\xcd\xd6\xf3\xcf\x12\x05\x00\x00\x00\x00\xe0!\xcd\xdf*\xae\x8e\xd9\x88\xcbJ\xbc_C\x19z\xed\xca=\x00\x00\x00\x00\x00\x0fo\xfe\xd9\x95\xe5\xc3\x14\xa3\x13q\xe5]^\xad/\x8a\xa26[\x1d\x00\x00\x00\x00\x80\x87T\xbb\xe5\x9d\xa6i\xbc\x9f%\xe2\xca\xbb:@}\xfeW\x08\x00\x00\x00\x00\x00\x1eh:\x9d\x16EQ}\'\xde+\xde\x9d\xc8+\xef\xbb\xb9\xbb\xe5\r\x00\x00\x00\x00\xf0\x08\xe6\x9f]\x19\xef \xefN\xd4\x95w\xa7r\xc1\xde\x13,\x01\x00\x00\x00\x00\x1e\xc1\xfc\xb3+_x\xe1\x85x?N\xdc\x95wy\xd1\xdb\x13,\x01\x00\x00\x00\x00\x1eA\xed\x96w\x92$\'O\x9e\x8c\xf7\xe3\xc4]yW/\xd8\xbb\xe8\r\x00\x00\x00\x00\xf0y\x8dF\xedyve\'\xfe\xc1&Y\xb9\x9e\xbf~\x0f\x00\x00\x00\x00\xc0}\xcc\xdf$\x8e\xfa\xd9\x95\x9d\x16\xdc\xf2N\x92d\xb6\x1e\x8fs\x07\x14\x00\x00\x00\x00\xe0\xe1\xcd\xdf$\x1e\x0c\xfaQ\x7f\xa2\x95\xd8\xbf\x92\xf2\x0bp\xcb\x1b\x00\x00\x00\x00\xe0s\x99\xbfI\xec\x96w\xc3\xca\xd9&EQ\xe4\xb9\x87X\x02\x00\x00\x00\x00<\xac\xdaM\xe2\xd8\x07yw\xdat\xcb\xbbc\xb6\t\x00\x00\x00\x00\xc0C\x9bN\xa7EQT\xdf\x89\xfd\x8aw\xa7\x15\x95\xf7\xdd\xef`~\xd4:\x00\x00\x00\x00\x00{\x9a/T\xb3\xcc-\xef\x00\x94\x97\xed\x8d\xf3\x06\x00\x00\x00\x00xH\xf3\x95\xf7\x0b/\xbc\x10\xfb\x87jC\xe5]^\xf4\x9e\xbf\x87\x0f\x00\x00\x00\x00\xc0\x9ej\x0fGL\x92\xe4\xe4\xc9\x93\xb1\x7f\xa8vT\xdew\xc7y\x9bm\x02\x00\x00\x00\x00\xf0@EQ\x8c\xc7\xbb*\xefj\xd1\x1a\xaf6T\xdeY\x96\x95k\xb3M\x00\x00\x00\x00\x00\x1eh\xfe\xf6p\xbf?h\xc1\xe7jC\xe5\xdd\xfd\xd4\xbd\xbe\'\x00\x00\x00\x00\x00j\xe6o\x0f\xbf\xf0\xc2\xf3-\xf8\\+\xed\xf8z\xca+\xf7\xb5\xab\xf8\x00\x00\x00\x00\x00\xcc\xcb\xf3\xbc\xf6\xce\xd3O?\xdd\x82\xcf\xd5\x92\xca;M\xab\xb3M\\\xf4\x06\x00\x00\x00\x00\xb8\x9f\xd1h\xd7-\xef~\xbf\xdf\x8e\xcf\xd5\x9a[\xdew\xa7\xcc\x18\xe7\r\x00\x00\x00\x00p\x1f\xf3\xf7\x86\xab\x15k\xd4ZRygY\x9a$\xc9\xbd\xbe-\x00\x00\x00\x00\x00J\xf3\xf7\x86\xcb\xd9\xd1\xb1[i\xcd\x97T~%\xb5\x0b\xf9\x00\x00\x00\x00\x00T\xb9\xe5\x1d\x81~\x7fp\x9f/\x0c\x00\x00\x00\x00\x80\x99\xb6\x0e\xf2\xee\xb4\xeb\x96\xb7q\xde\x00\x00\x00\x00\x00\x0f0\x7fc8\xcb\xb2\xd6|\xba\xf6T\xdeY\x96\x96\xeb\xf18wp\x01\x00\x00\x00\x00\xe6\xb5x\x90w\xa7M\x95w\xa7r\xfd\xde-o\x00\x00\x00\x00\x80=\xcd\xdf\x18~\xe1\x85\x17Z\xf3\xe9ZUy\x97\xb3M\x8a\xa2\xc8\xf3\xb1\xb3\x0b\x00\x00\x00\x00PS\xbb1\x9c\xa6\xe9\xda\xdaZk>]\xcb*\xef~\xe5k\xf3\x04K\x00\x00\x00\x00\x80]\xf2|\\\x14E\xf5\x9d\xeaS\x12[\xa0\x9d\xb7\xbc;\x9f\xfb\x8e\x7fy\xf6\xec\xb3\x8f\xf0\x0f\xf9\xc9O\xeeN<\x7f\xb4\x7fBS\xae\x7f\xe2\x17\xb3\xf5\xc6\xc6\xc9\x8d\x8d\x8d\x886/v\xb1\x8b]\xecb\x17\xbb\xd8\xc5\x1eQ\xec\xab\xabG\xef\xf5Gbw\xda\xc5.v\xb1\x8b]\xecb\x17\xbb\xd8\x1b\x89\xfd_\xff\xf5_k\xef|\xf5\xab\xed\x7f\xd8a\xfb+\xef^\xaf\xd7\xedv\xa7\xd3\xe9\x9d\xf5{\xef]9~\xfc\xf8>\xff\x81\xfb\xff\'\x1c\xa6\x0f?\xbcY\xae\x8f\x1e]\x8dk\xf3b\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x11\xc5~\xecX"v\xa7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b=\xa8\xd8\x7f\xfa\xd3\x9f\xd6\xdey\xe9\xa5\x97:m\xd7\xfe\xc1&\x9d\xcax\x9a\xe9t\x9a\xe7\xe3\x0e\x00\x00\x00\x00@\xdbmm]\xae\xbeL\x92\xe4\xf4\xe9\xd3\xad\xff\xd4KQy\x0f\x06\xfdr=\x1c\x0e\x9du\x00\x00\x00\x00\xa0\xdd\xf2|\\\x14E\xf5\x9d\xcd\xcds\xcb\xf0\xc1\x97\xa4\xf2\x1e\x94\xeb\xad\xad-\xc7\x1d\x00\x00\x00\x00h\xb7\xf9"\xb4Z\x93\xb6\xd8RT\xdeI\x92\xf4\xfb;\x17\xbdG\xa3Q\xed\xc7\r\x00\x00\x00\x00\x80\x96\x99\xaf\xbc_~\xf9\xe5e\xf8\xe0+K\xf2\x05\x97\xe3\xbc;f\x9b\x00\x00\x00\x00\x00\xadV\x14\xc5x\xbc\xeb\xa1\x86i\x9a\xae\xad\xad-\xc3g_\x96\xca\xdbl\x13\x00\x00\x00\x00`I\xccW\xa0\xd5;\xc1\xed\xb6,\x95w\x96\xa5\xddn\xf7\xb3\xef\xfb\xb2C\x0f\x00\x00\x00\x00\xb4\xd5|\xe5\xfd\xca+\xe7\x97\xe4\xb3\xaf,\xcf\xd7\\\xfe\x8eQ\x14E\x9e\x8f\x9d{\x00\x00\x00\x00\xa0\x95\x86\xc3Q\xf5e\x92$\xa7O\x9f^\x92\xcf\xbeD\x95\xf7`\xd0/\xd7f\x9b\x00\x00\x00\x00\x00\xad4\x1c\x0e\x8b\xa2\xa8\xbe\xb3\xb9yny>\xfe2\xde\xf2\xee\xa8\xbc\x01\x00\x00\x00\x80\x96\x9a\x1f\xec\\}\xd2a\xeb\xad,\xd5\x97]\xfe\x9a1\x1e\x8f\xa7\xd3\xa9\xd3\x0f\x00\x00\x00\x00\xb4\xcc\xfc}\xdf\x97_~yy>\xferU\xde\xfd\xfe\xdd_3\x86\xc3\xa1\xd3\x0f\x00\x00\x00\x00\xb4\xc9\xf4S\xd5w\xfa\xfd\xfe\xda\xda\xda\xf2$\xb0\\\x95\xf7W\xbeb\xb6\t\x00\x00\x00\x00\xd0Zo\xbf]\xaf=\xab\x03\x9f\x97\xc1rU\xde\xddn7M\xd3\xd9\xba\xf6\xd0R\x00\x00\x00\x00\x80\xd8\x8dF\xf5\xe1\x16\xe7\xcf\xbf\xbcT\t\xac,\xdbW^Nj/\x8a\xc2Eo\x00\x00\x00\x00\xa05>\xedT\xdew\x99m\x02\x00\x00\x00\x00\x04\xceT\x93\xfbSyWO\x86\xd9&\x00\x00\x00\x00@\xd0L5\xb9?\x95\xf7]f\x9b\x00\x00\x00\x00\x00\x813\xd5\xe4\xfeT\xde\xbb\x98m\x02\x00\x00\x00\x00\x04\xcbT\x93\x07Rywv\x9f\x0f\xb3M\x00\x00\x00\x00\x80@\x99j\xf2@*\xef]\xcc6\x01\x00\x00\x00\x00\x82e\xaa\xc9\x03\xa9\xbc\xeb\xaa\xbf\x8a\xbc\xf1\xc6\x0f\x04\x02\x00\x00\x00\x00\x84\xe0\xd2\xa5K\xa6\x9a<\x90\xca\xbbnss3I\x92\xd9z\xfe7\x13\x00\x00\x00\x00\x80F\xccO5q\xc5{\x9e\xca\xbb\xae:\xdb\xa4(\n\x13\xbd\x01\x00\x00\x00\x80\xc6}\xdaU\xee\xba\xa1\x9b$\xc9W\xbf\xfaU\xc9\xd4\xa8\xbc\xf7\xe0!\x96\x00\x00\x00\x00@P\xf6zp\xe59\xb1\xccSy\xef\xc1l\x13\x00\x00\x00\x00 (\xa6\x9a<$\x95\xf7\xde\xcc6\x01\x00\x00\x00\x00\x02\xb1\xe7T\x93\x97^zI2\xf3T\xde{\xab\xce6\xb9t\xe9\x92@\x00\x00\x00\x00\x80\xa6\xbc\xf5V\xbd\xa24\xd5\xe4^\x1e\x17\xc1\x9e677\xd7\xd6\xd6~\xf5\xab_u>\x9dm\xf2\xca+\xbf\xbb\xba\xba:\xfb\xa3k\xd7>\x88\xe8\x83\xdc\xbcy\xb3\xba\x8ek\xf3Ub\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x81o\xfe\xfa\xf5\xebbw\xda\xc5.v\xb1\x8b]\xecb\x17\xbb\xd8\x0f(\xf6\x7f\xf9\x97\x7f\xa9\xbd\xf3\xea\xab\xafv\xd8\xcbcW\xae\xbc\'\x85=\xfd\xdd\xdf\xfd\xef\x1f\xfe\xf0\x87\xb3\xf5\xeb\xaf\xbf\xfe\xfc\xf3\xcf\xcb\x04\x00\x80{\x99L&\x17/^\xdc\xf3\x8f.\\\xb8 \x1f\x00\x00\x1e\xd9\x8d\x1b7\xfe\xfe\xef\xff\xbe\xfa\xce\x89\x13\'\xfe\xe6o\xfe\x97d\xf6d\xb0\xc9=\xfd\xe1\x1f\xfea\xb9\xber\xe5\x8a@\x00\x00\x00\x00\x80\xc37_N~\xe9K_\x12\xcb\xbd\xa8\xbc\xef\xe9\xec\xd9gO\x9c8Q\x9e\xaa\x1b7n\xc8\x04\x00\x00\x00\x008d\x97/_\xae\xbd\xf3\xf5\xaf\xff7\xb1\xdc\x8bY\xde\xf7\xf3\xd5\xaf\xfe\xee\x0f~\xf0\xc6l}\xe5\xca\x95s\xe7>\x19\t\x7f\xfc\xf8\xf1\x88>\xc2\xad[\xb7n\xdf\xbe=[\x1f=z\xb4\x9cH\x1e\x85\xea\xf4%\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\xc0c\xaf\xe6\\#v\xa7]\xecb\x17\xbb\xd8\xc5.v\xb1\x8b\xfd\x91c\xff\xcf\xff\xfc\xcf\x0f?\xfc\xb0\xfa\xbf\xfc\xc2\x17\xbe\xf0\xcc3\xcft\xb8\x07\x95\xf7\xfd\xbc\xfe\xfa\xebe\xe5\xfd\xee\xbb\xef\xce*\xef\xb3g\x9f\x8d\xe8#\\\xbb\xf6\xc1\x1d\xb3\xf5\xc6\xc6\xc6\xa9SOE\xb4\xf9\xcb\x97\x7fT\xae\xc5.v\xb1\x8b]\xecb\x17\xbb\xd8\x03\x8f\xfd\xc8\x91#\xf7\xfa#\xb1;\xedb\x17\xbb\xd8\xc5.v\xb1\x8b]\xec\x8f\x1c\xfb\xbf\xfd\xdb\xbf\xd5\xfe\x97\xdf\xf8\xc67:\xdc\x9b\xc1&\xf7\xd3\xedv\xd34\x9d\xad\'\x9f\x92\t\x00\x00\x00\x00ph.]\xbaT{\xe7\x95W\xce\x8b\xe5>T\xde\x0f\xf0\xdak\xaf\x95\xebw\xdeyG \x00\x00\x00\x00\xc0\xe1\xd8\xda\xda*\x8a\xa2\xfaN\x9a\xa6O<\xf1\x84d\xeeC\xe5\xfd\x00\xbf\xf7{w+\xef\xf9G\xa3\x02\x00\x00\x00\x00\x1c\x90\xad\xad\xad\xda;\x7f\xf4G\xaf\x8b\xe5\xfeT\xde\x0f\x90$\xc9\xe6\xe6\xb9\xd9\xfa\xc3\x0f?\xd4z\x03\x00\x00\x00\x00\x87\xa0(\x8aK\x97\xfeo\xed\xcd\xf3\xe7M5y\x00\x95\xf7\x83mnn\x96k\x957\x00\x00\x00\x00p\x08\xe6\xafxon\x9e[]]\x95\xcc\xfd\xa9\xbc\x1f\xec\xb5\xd7^+O\xd2\x95+Wj\xd3s\x00\x00\x00\x00\x00\x16\xee\xad\xb7\xea\x0f\xae\xfc\xda\xd7\xbe&\x96\x07Ry?\x94\xe7\x9f\x7f~\xb6\xb8u\xeb\xd6\xfc\xaf+\x00\x00\x00\x00\x00\x0b4\x9dNG\xa3Q\xf5\x9d$I^z\xe9%\xc9<\x90\xca\xfb\xa1|\xedk\xbf_\xae\xe7\x7f]\x01\x00\x00\x00\x00X\xa0\xf9\x12\xb2|\xe2 \xf7\xa7\xf2~(\xe7\xce\x9d;q\xe2\xc4l=\x1a\x8d\xa6\xd3\xa9L\x00\x00\x00\x00\x80\x03r\xe9R\xbd\xf2\xfe\xc67\xbe!\x96\x87\xa1\xf2~X/\xbe\xf8b\xb9~\xfbm\xb3M\x00\x00\x00\x00\x80\x03\x91\xe7\xe3\xda\xa5\xdbn\xb7{\xfa\xf4i\xc9<\x0c\x95\xf7\xc3\xfa\xe3?\xfe\xef\xe5\xfa\x8d7\xde\x10\x08\x00\x00\x00\x00p\x10\xdex\xe3\x07\xb5w^\x7f\xfdu\xb1<$\x95\xf7\xc3:}\xfa\xf4\x93O>9[O\xa7\xd3<\x1f\xcb\x04\x00\x00\x00\x00X\xb8\xad\xad\xcb\xb5w^y\xe5\xbcX\x1e\x92\xca\xfbs\xf8\xfa\xd7\xbf^\xae\xe7\x7fi\x01\x00\x00\x00\x00\xd8\xa7w\xdf}\xb7(\x8a\xea;\x9b\x9b\xe7\x9ex\xe2\t\xc9<$\x95\xf7\xe7\xf0\xea\xab\xaf\x96\xeb\xad\xad\xcb\xb5\x93\x07\x00\x00\x00\x00\xb0O\xef\xbc\xf3N\xed\x9d\xcd\xcdM\xb1<<\x95\xf7\xe7\xf0[\xbfu\xfc\xcb_\xfe\xf2l]\x14\xc5\xd6\x96\x87X\x02\x00\x00\x00\x00\x0bs\xe3\xc6\x8d\xabW\xafV\xdfI\x92\xe4\xfcySM>\x07\x95\xf7\xe7\xf3\x95\xaf|\xa5\\\xbf\xf5\xd6%\x81\x00\x00\x00\x00\x00\x8b\xf2\xee\xbb\xef\xd6\xde\xd9\xdc<\xb7\xba\xfa\xff\xd9\xbb\x9f\xdf8\xca<\x0f\xc0\x19\xcd\xa4\xa1\x14p6E\xb4\x13\xe4\x08\x0cj#EQ,e1.\'\x0e\xa1\xad43\xa4\x07{\xa4\r\x0c\x17v\xc4\x7f2\xfbw\xcc^gox\x0e\x0c\xeaH\x88\xc5}B\x94EfQ\x9b\x9d\x03m\xcd\xe4`\x071R\x8a\x95\x08*a.\x9buKMmu\xc2\xc6v\xff\xa8j?\xcf\xe9\xad\xd7\x91\xe2|T\x9d\xc3\xc7_\xbfoE2\x8fN\xe5\xbd?\x8b\x8bQ\x18\x86\xdd\xf5\xd6\xd6V\x92$2\x01\x00\x00\x00\x00\x06\xa2\xffT\x93z\xbd.\x96}Qy\xef[\x14E\xbd\xb5Ao\x00\x00\x00\x00` \xee\xdc\xb9s\xef\xde\xbd\xecN\x18\x86g\xce\x9c\x91\xcc\xbe\xa8\xbc\xf7mq\xf1\x87\xca;\x8eU\xde\x00\x00\x00\x00\xc0\x00\xf4\x9fjR\xab\xd5\xc4\xb2_*\xef}\x0b\xc3\xb0Z\xadv\xd7I\x92\xb8\xc4\x12\x00\x00\x00\x008\xa4\xdd\xdd\xdd\xfe\xca\xfb\xc5\x17\xffI2\xfb\xa5\xf2>\x88\xec\xa0\xb7\xca\x1b\x00\x00\x00\x008\xa4\xdb\xb7o\xe7v\xe6\xe6.LMMIf\xbfT\xde\x07177\x17\x04Aw\x1d\xc7\x1bi\x9a\xca\x04\x00\x00\x00\x008\xb0\xcd\xcd\xcd\xdc\xce\xe5\xcb\x97\xc5r\x00*\xef\x83\x08\x82`n\xeeB\xef\xd1%\x96\x00\x00\x00\x00\xc0\x81mo\xef\xdc\xbd{7\xbb\x13\x04\xc1\xf9\xf3\xe7%s\x00*\xef\x03\xaa\xd5\x96{\xebV\xab%\x10\x00\x00\x00\x00\xe0`Z\xad\xf5\xdcN\x14Eb9\x18\x95\xf7\x01\x9d=;}_w\x9d$I\xa7\xd3\x91\t\x00\x00\x00\x00\xb0_i\x9a\xb6\xdb\xf9SM\xea\xf5k\x929\x18\x95\xf7\xc1e\x7f\xd2\x12\xc7\xce6\x01\x00\x00\x00\x00\xf6\xad\xddn\xe7.\x0b\xacV\xab\'O\x9e\x94\xcc\xc1\xa8\xbc\x0fnq1\xca\xbc\x97\x9b.\xb1\x04\x00\x00\x00\x00\xf6\xab\xff\xa6\xc0l\xf1\xc8~\xa9\xbc\x0f.\x08\x82(Z\xe8\xae\xf7~\xfb\xa0-\x13\x00\x00\x00\x00\xe0\xd1%I\xb2\xb5\xb5\x95\xdd\xa9T*\x17/^\x94\xcc\x81\xa9\xbc\x0f%{\xb6\xc9\xfazK \x00\x00\x00\x00\xc0\xa3\xeb/\x15_x\xe1\x85J\xa5"\x99\x03Sy\x1f\xca\xec\xecl\x18\x86\xdd\xf5\xce\xce\xce\xf6\xf6\x8eL\x00\x00\x00\x00\x80G\xd4\x7fG\xe0k\xaf\xfdR,\x87\xa1\xf2>\xacZ\xad\xd6[\xb7Z\xeb\x02\x01\x00\x00\x00\x00\x1eE\x1c\xc7\xb9\x0b\x02O\x9f>\xfd\xec\xb3\xcfJ\xe60T\xde\x87\xe5\x12K\x00\x00\x00\x00\xe0\x00\xfa/\xae\xbcz\xf5\xaaX\x0eI\xe5}X.\xb1\x04\x00\x00\x00\x00\xf6\xeb\x81\x17W...J\xe6\x90T\xde\x03\x90\xbd\xc4\xb2\xd9\xbc)\x10\x00\x00\x00\x00\xe0\xc75\x9b\xcd\xdc\xce\x0b/\xbc\x10\x04\x8fK\xe6\x90T\xde\x03\x90\xbd\xc42I\x92N\xa7#\x13\x00\x00\x00\x00\xe0a\xf6\x8e\x8b\xd8\xccm\xba\xb8r T\xde\x83\x91\xbd\xc4\xb2\xff\x96U\x00\x00\x00\x00\x80\x9ev\xbb\xed\xe2\xca!Qy\x0fF\xf6\x12\xcb8\xdep\x89%\x00\x00\x00\x00\xf00\xeb\xeb\xad\xdc\xce\xcb/_\x11\xcb@\xa8\xbc\x07#{\x89\xe5\xb1\x07\xdd\xb5\n\x00\x00\x00\x00p\xdf\xf6\xf6\xce}\xd9\x9d \x08.]\xba$\x99\x81Py\x0fL\xf6\x12\xcbV\xab%\x10\x00\x00\x00\x00\xa0_\xab\xb5\x9e\xdb\x89\xa2(\x08\x02\xc9\x0c\x84\xca{`r\x97X\xb6\xdbm\x99\x00\x00\x00\x00\x00Yi\x9a\xc6\xf1Fn\xb3^\xbf&\x99AQy\x0fR\xa3q\xbd\xb7v\x89%\x00\x00\x00\x00\x90\xd3\x7f$r\xb5Z=y\xf2\xa4d\x06E\xe5=Hsss\xbd_@h\xb77\x93$\x91\t\x00\x00\x00\x00\xd0\xd3\x7f$\xf2\xd2\xd2e\xb1\x0c\x90\xca{\x90\x82 \x98\x9b\xbb\xd0{t\x89%\x00\x00\x00\x00\xd0\xd3\xe9trc\xb2a\x18\xce\xcf\xcfKf\x80T\xde\x03V\xab-\xf7\xd6.\xb1\x04\x00\x00\x00\x00z\xfa\x0b\xc3(\x8a\xc42X*\xef\x01;{v\xbaZ\xadv\xd7{G\xd1\x1b\xf4\x06\x00\x00\x00\x00\x8e%I\xd2no\xe66\xaf\\Y\x92\xcc`\xa9\xbc\x07oq\xf1\x87\x9f\xcc\xac\xaf\xb7\x04\x02\x00\x00\x00\x00\xf4W\x85Q\xb4055%\x99\xc1Ry\x0f^\x14Ea\x18v\xd7;;;\xdb\xdb;2\x01\x00\x00\x00\x80#\xae\xff@\x88+W\xae\x88e\xe0T\xdeC\x91=\x82\xa7\xd5Z\x17\x08\x00\x00\x00\x00\x1ceq\x1c\xa7i\x9a\xdd\t\xc3pffF2\x03\xa7\xf2\x1e\x8a\xec\xd9&q\xbc\x91{\x9b\x01\x00\x00\x00\x80#\xa5\xffT\x93F\xe3\xbaX\x86A\xe5=\x14a\x18F\xd1\xc2\x8f\xbc\xd0\x00\x00\x00\x00\xc0\x11\xd1\xe9tvv\xfe\xcf\xe9\xc7A\x10\\\xbcxQ2\xc3\xa0\xf2\x1e\x96\xec\xd9&\xfd\xc7\xf4\x00\x00\x00\x00\x00GD\x7f=\x18EQ\xa5R\x91\xcc0\xa8\xbc\x87evvvzz\xba\xbbN\x92D\xeb\r\x00\x00\x00\x00G\xd0^7\xb8\x91\xdb\xac\xd7\xafIfHT\xdeC\xb4\xbc\\\xeb\xad?\xf9D\xe5\r\x00\x00\x00\x00GN\x7f1X\xadVO\x9e<)\x99!Qy\x0fQ\x14EA\x10t\xd7[[[\xdb\xdb;2\x01\x00\x00\x00\x80#\xa5\xd5j\xe5v\x8cx\x0f\x95\xca{\xb8j\xb5Z\xe6\xe5^\x17\x08\x00\x00\x00\x00\x1c\x1dq\x1c\xa7i\x9a\xdd\t\xc3\xf0\xfc\xf9\xf3\x92\x19\x1e\x95\xf7p-.f/\xb1\xdcH\x92D&\x00\x00\x00\x00pD4\x9b7s;\xd9\x19Y\x86A\xe5=\\a\x18F\xd1B\xef\xd1\x89\xde\x00\x00\x00\x00pDt:\x9d\xdc\x08l\x10\x04KK\x97%3T?\xb9}\xfboR\x18\xaa\xcd\xcd\xcd\xdf\xff\xfe\xdf\xba\xebJ\xa5\xf2\xce;\xef\xc8\x04\x00`\xf2\xdc\xbd{\xf7\xe3\x8f?~\xe0\x97VVV\xe4\x03\x00p\x04}\xf0\xc1\x07\xb7o\xdf\xce\xee\xbc\xf4\xd2K\xbf\xfd\xed\xbfHf\xa8Ly\x0f\xdd\x85\x0b\x17N\x9f>\xdd]\xef\xee\xee~\xf1\xc5\x172\x01\x00\x00\x00\x80\xc9\xf6\xcd7\xdf\xe4\xfa\xee\xfb~\xf5\xab\x86d\x86M\xe5=\nW\xaf^\xed\xad?\xfd\xf4S\x81\x00\x00\x00\x00\xc0d\xbbu\xebVn\xa7Z\xad>\xf5\xd4S\x92\x196\x95\xf7(,/\xd7\x9e|\xf2\xc9\xee\xfa\xde\xbd{w\xee\xdc\x91\t\x00\x00\x00\x00L\xaa\xdd\xdd\xdd\xfe\x11\xef_\xfc\xe2U\xc9\x8c\xc0\xcfD0\x1a\x97.]\xfa\xe0\x83\x0f\xba\xeb\xbf\xfc\xe5\xbf\xae\\Y\x1a\xcd\xdf\xfb\xf5\xff\xfa\xef\xee\xfa\xd4\xa9\x7f8u\xeaT\x89B\xfb\xeb_\x7f8h\xfe\xf9\xe7\x9f+\xd1w.v\xb1\x8b]\xecb\x17\xbb\xd8\x8f`\xec\x95\xca\xf1\x87}I\xec\xdev\xb1\x8b]\xecb\x17\xbb\xd8\xc5~\xd4b\xff\xf0\xc3\x0fwww\xb3;O?\xfd\xf4\xb9s\xe7\x8e1|*\xef\x11\xa9\xd7\xaf\xf5*\xef\xfb\xffk|\xf7\xddwa\x18\x8e\xe0\xef\xbdw\xef\xdb\xde\xfa\xf8\xf1\xca\x89\x13\'J\x1a`\xb9\xbes\xb1\x8b]\xecb\x17\xbb\xd8\xc5~\x04c\x7f\xfc\xf1@\xec\xdev\xb1\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\xae?\xff\xf9?s;F\xbcG\xc6\xc1&#\x12\x04A\x14-\xf4\x1e\x9b\xcd\xa6L\x00\x00\x00\x00`\xf2\xc4q\x9c$Iv\'\x08\x82\xf9\xf9y\xc9\x8c\x86\xca{t\x1a\x8dF\xe6\xbd\xdfH\xd3T&\x00\x00\x00\x000a\xd6\xd7[\xb9\x9dZ\xad&\x96\x91Qy\x8fN\x18\x86\xd5j\xf5G^}\x00\x00\x00\x00\xa0\xd4:\x9d\xce\xce\xceNn\xb3^\xbf&\x99\x91Qy\x8fT\xa3q\xbd\xb7n\xb5Z\x02\x01\x00\x00\x00\x80I\xd2_\xfaE\xd1B\xa5R\x91\xcc\xc8\xa8\xbcGjvvvzz\xba\xbbN\xd34\x8ec\x99\x00\x00\x00\x00\xc0dH\x92\xa4\xdd\xde\xccm\xae\xae\xaeJf\x94T\xde\xa3\xb6\xbc\\\xeb\xad\x9b\xcd\x9b\x02\x01\x00\x00\x00\x80\xc9\xd0l6s;ss\x17\xa6\xa6\xa6$3J*\xefQ\x8b\xa2(\x0c\xc3\xeez\xef\xc7>m\x99\x00\x00\x00\x00@\xd9\xed\x1d\xea\xb0\x91\xdb|\xf5\xd5W%3b*\xef1\x88\xa2\xa8\xb7v\x89%\x00\x00\x00\x00L\x80\xfe\xa2ozzzffF2#\xa6\xf2\x1e\x83\xe5\xe5Z\x10\x04\xdd\xf5\xd6\xd6V\xa7\xd3\x91\t\x00\x00\x00\x00\x94W\x9a\xa6\xfd\x17W\xd6\xeb\xd7$3z*\xef1\x08\x82 ;\xe8\xdd\xffa\x00\x00\x00\x00\x00J\xe4\x93O\xe24M\xb3;a\x18\xce\xcf\xcfKf\xf4T\xde\xe3\x91\xbd\xc4\xb2\xdd\xdeL\x92D&\x00\x00\x00\x00PR\xfdS\xad\xb5ZM,c\xa1\xf2\x1e\x8f0\x0c\xa3h\xa1\xf7\xd8\x7f\x97+\x00\x00\x00\x00P\nq\x1c\xe7FZ\x83 XZ\xba,\x99\xb1Py\x8fM\xad\xb6\x9c\xf9Tl\x18\xf4\x06\x00\x00\x00\x802j6o\xe6vj\xb5Z\xa5R\x91\xccX\xa8\xbc\xc7\xe6\xec\xd9\xe9j\xb5\xda{\xfc\xe4\x93X&\x00\x00\x00\x00P.\x9dN\xa7\x7f\x98\xd5\xc5\x95c\xa4\xf2\x1e\xa7F\xe3zo\xddj\xb5r\'\xdc\x03\x00\x00\x00\x00\x05\xd7?\xe2\x1dE\x0bF\xbc\xc7H\xe5=N\xb3\xb3\xb3\xbdA\xef4M\xd7\xd7[2\x01\x00\x00\x00\x80\xb2\xe8t:[[[\xb9\xcd\xd5\xd5U\xc9\x8c\x91\xca{\xcc\x16\x17\xa3\xde\xba\xff^W\x00\x00\x00\x00\xa0\xb0\xfa\x0b\xbd(Z\x98\x9a\x9a\x92\xcc\x18\xa9\xbc\xc7,\x8a\xa20\x0c\xbb\xeb4M\xe3\xd8\x89\xde\x00\x00\x00\x00P\x02I\x92\xb4\xdb\x9b\xb9\xcdz\xbd.\x99\xf1Ry\x8f_\xf6D\xef\xfe\xa3\x7f\x00\x00\x00\x00\x80\x02j6\x9b\xb9\x9dj\xb5z\xe6\xcc\x19\xc9\x8c\x97\xca{\xfc\xb2\x83\xdeI\x92\x18\xf4\x06\x00\x00\x00\x80\x82\xdb\xeb\xf16r\x9b\xbf\xfe\xb5S\xbc\xc7O\xe5]\x08Q\xf4\xc3\x89\xde\x06\xbd\x01\x00\x00\x00\xa0\xe0\x1e8\xe2=33#\x99\xb1Sy\x17\xc2\xf2r-\x08\x82\xeez\xef\x0c\xa0\xb6L\x00\x00\x00\x00\xa0\x98\xf6\xee\xe4\xcb\x8fx/-]\x96L\x11\xa8\xbc\x0b!\x08\x82Z\xad\xd6{\\_o\xc9\x04\x00\x00\x00\x00\x8a\xa9\xbf\xbe\x0b\xc3p~~^2E\xa0\xf2.\x8a\xec\xa0\xf7\xd6\xd6V\xa7\xd3\x91\t\x00\x00\x00\x00\x14M\x9a\xa6\xadV+\xb7\xb9\xb2\xf2\xbad\nB\xe5]\x14A\x108\xd1\x1b\x00\x00\x00\x00\nn}\xbd\x95\xa6iv\xc7\x88w\xa1\xa8\xbc\x0bdy\xb9\xd6[\x1b\xf4\x06\x00\x00\x00\x80\xa21\xe2]|*\xef\x02\t\xc30\x8a\x16z\x8f\x06\xbd\x01\x00\x00\x00\xa0P\xfaG\xbc\x83 0\xe2](*\xefbi4\x1a\xbd\xb5Ao\x00\x00\x00\x00(\x8e\x07\x8ex\xd7j5\xc9\x14\x8a\xca\xbbXr\x83\xdeq\x1c\xcb\x04\x00\x00\x00\x00\x8a\xa0\xddn\xf7\x8fx\xd7\xeb\xd7$S(*\xef\xc2\xc9\x0ez\xc7\xf1F\x92$2\x01\x00\x00\x00\x80\xb1\xeb?\x88\xb8V\xabU*\x15\xc9\x14\x8a\xca\xbbp\xfaN\xf4n\xca\x04\x00\x00\x00\x00\xc6+\x8e\xe3\xdcp\xaa\x11\xefbRy\x17Q\xad\xb6\x9c\xf9,\x19\xf4\x06\x00\x00\x00\x8013\xe2]\x16*\xef":{v\xbaZ\xadf>N\x06\xbd\x01\x00\x00\x00`l\x8cx\x97\x88\xca\xbb\xa0\x1a\x8d\xeb\x99O\x94Ao\x00\x00\x00\x00\x18\x1b#\xde%\xa2\xf2.\xa8\xd9\xd9Y\x83\xde\x00\x00\x00\x000vF\xbc\xcbE\xe5]\\\x06\xbd\x01\x00\x00\x00`\xec\x8cx\x97\x8b\xca\xbb\xb8\x0cz\x03\x00\x00\x00\xc0x\xf5\x8fx\xdfw\xe5\xca\x92d\nK\xe5]h\x06\xbd\x01\x00\x00\x00`\x8c\xfaG\xbc\xa3hajjJ2\x85\xa5\xf2.4\x83\xde\x00\x00\x00\x000.\x0f\x1c\xf1^]]\x95L\x91\xa9\xbc\x8b\xce\xa07\x00\x00\x00\x00\x8c\x85\x11\xef2Ry\x17\x9dAo\x00\x00\x00\x00\x18=#\xde%\xa5\xf2.\x01\x83\xde\x00\x00\x00\x000bF\xbcKJ\xe5]\x02\x06\xbd\x01\x00\x00\x00`\x94\x8cx\x97\x97\xca\xbb\x1c\x0cz\x03\x00\x00\x00\xc0\xc8\xf4\x8fx\xd7j5#\xde\xa5\xa0\xf2.\x07\x83\xde\x00\x00\x00\x000\x1a\xfd#\xdeA\x10\xac\xac\xbc.\x99RPy\x97Fn\xd0{{{G&\x00\x00\x00\x000Xi\x9a\xae\xad\xfd1\xb7Y\xab\xd5*\x95\x8apJA\xe5]\x1a\xb9A\xef\xb5\xb55\x99\x00\x00\x00\x00\xc0`\xad\xaf\xb7\xd24\xcd\xee\x04AP\xaf_\x93LY\xa8\xbc\xcb$;\xe8\xbd\xb5\xb5\xd5\xe9td\x02\x00\x00\x00\x00\x83\x92\xa6i\xab\xd5\xcam\x1a\xf1.\x17\x95w\x99\xcc\xce\xce\xce\xcd]\xe8=\xf6\x1f\xa2\x0f\x00\x00\x00\x00\x1c\x98\x11\xef\t\xa0\xf2.\x99\x1b7n\xf4\xd6\x06\xbd\x01\x00\x00\x00`P\x8cxO\x06\x95w\xc9\x84a\x18E\x0b\xbdG\x83\xde\x00\x00\x00\x000\x10F\xbc\'\x83\xca\xbb|\x1a\x8dFom\xd0\x1b\x00\x00\x00\x00\x0e\xcf\x88\xf7\xc4Py\x97On\xd0{m\xed\x8f2\x01\x00\x00\x00\x80\xc3h6o\x1a\xf1\x9e\x0c*\xefR\xca\x0ez\xef\xec\xec\xc4q,\x13\x00\x00\x00\x008\x98$I\xfaG\xbcWVV\x8cx\x97\x91\xca\xbb\x94\x9c\xe8\r\x00\x00\x00\x00\x83\xd2l6s;a\x18\xbe\xfc\xf2\x15\xc9\x94\x91\xca\xbb\xacn\xdc\xb8\x11\x04Aw\x9d$\x89Ao\x00\x00\x00\x008\x80\xbdnm#\xb7\xb9\xb2\xf2\xbadJ\xeag"(\xa9 \x08\x96\x96.\x7f\xf8\xe1\x7ft\x1f\xff\xf4\xa7\xf7gf\x9e\xeb\xffc\xdf~\xfbmv\xfd\xd5W\x7f/\xe9\xbf\xb7\\\xdf\xb9\xd8\xc5.v\xb1\x8b]\xecb?\x82\xb1\x7f\xfd\xf5\xd7b\xf7\xb6\x8b]\xecb\x17\xbb\xd8\xc5.\xf62\xc6\xfe\xde{\xef\xe5vN\x9e<9??\x7f\x8cr\xfa\xc9\xed\xdb\x7f\x93BI\xdd\xbbw\xefw\xbf\xfb\xd7\xdd\xdd\xdd\xee\xe3\x8b{\xc4\x02\x000\x16w\xef\xde\xfd\xf8\xe3\x8f\x1f\xf8\xa5\x95\x95\x15\xf9\x00\x00\x14\xd3\x9d;w\xde\x7f\xff\xfd\xdc\xe6\x1bo\xdcx\xe5\x95W\x84SR\x0e6)\xb1\'\x9ex\xe2\xd2\xa5K\xbd\xc7\xcd\xcd\xcd^\xfd\r\x00\x00\x00\x00\xfc\xbfn\xdd\xba\x95\xdb9}\xfa\xb4\xbe\xbb\xd4T\xde\xe5\xf6\xdak\xbf\xec\xdd\x1b\xbb\xbb\xbb\xbb\xb9\xb9)\x13\x00\x00\x00\x00x\x14w\xee\xdc\xf9\xf2\xcb/s\x9b\xbf\xf9\xcd\x9b\x92)5gy\x97\xdb\x13O<\xb1\xba\xba\xfa\xee\xbb\xefv\x1f?\xff\xfc\xf3(\x8a\x1e{\xec\xb1\xde\x1f\xd8\xdd\xdd\xfd\xfe\xfb\xef\xbb\xeb\xe3\xc7\x8f\xf7\xfa\xf1R\xc8\x9e\xbet\xe2\xc4\x89\x12}\xe7b\x17\xbb\xd8\xc5.v\xb1\x8b\xfd\x08\xc6\x9e\xcd9G\xec\xdev\xb1\x8b]\xecb\x17\xbb\xd8\xc5^\xcc\xd8?\xfb\xec\xb3\xdc\xce3\xcf\xecKb\xf7\xb6\x8b]\xecb\x17\xbb\xd8\xc5.\xf6\x02\xc6\x1e\xc7\xf1\xf6\xf6vn\xf3\xcd7\xdf8F\xc99\xd8d\x124\x1a\xd73\x9f\xd5\x8dn\xfd\r\x00\x00\x00\x00xX2\x9dG\xe5\xdd\x81\x82 \x18\x1d\x1d\xa9\x1e\xbe\xf5\xd6[\xbf\xf8\xc5/\xc4\x02\x00\x00\x00@\xd7j|\xc4{``\xe0\xee\xbb\xef\x96L\xe7Qyw\xa6d2\x19\x8f\xc7\xab\x87\xb9\\N&\x00\x00\x00\x00t\xa7\xf9\xf9\x85r\xb9\\7|\xe2\x89\xc7%\xd3\x91T\xde\x1dk|\xfcP\xf5\xf5;\xef\xbc\xf3\xf6\xdbo\xcb\x04\x00\x00\x00\x80n\x13EQ\xe3\xf3\xa0\xc9\xe4\xde\xdbo\xbf]8\x1dI\xe5\xdd\xb1\x06\x07\x07\x07\x06\x06\xaa\x87\x1e\xf4\x06\x00\x00\x00\xa0\x0be\xb3\xd9(\x8aj\'A\x10LLLH\xa6S\xa9\xbc;\xd9\xa3\x8f\xa6\xab\xaf\xdf{\xef\xbd\xbf\xf8\x8b\xbf\x90\t\x00\x00\x00\x00\xdd\xa3\\.\xe7\xf3\x8bu\xc3T*\xd5\xdb\xdb+\x9cN\xa5\xf2\xeed\xb1X\xec\x0b_\xf8\xa7\xd5\xc3s\xe7\xce\xd5\xfdF\x0b\x00\x00\x00\x00:\xd8\x993a\xdd$\x16\x8b\r\x0f\x7fU2\x1dL\xe5\xdd\xe1\x0e\x1f>\\\xfd\x9d\xd5\x07\x1f|p\xfe|N&\x00\x00\x00\x00t\x83\xa5\xa5\xa5\xe5\xe5\xe5\xba\xe1\xd8\xd8\xd7{zz\x84\xd3\xc1T\xde\x1d\xeeS\x9f\xfa\xd4\x97\xbe\xf4\xa5\xea\xe1\xc2B\x93\xddi\x01\x00\x00\x00\xa0\xf3\x84\xe1\xd9\xbaI<\x1e\xdf\xb3g\x8fd:\x9b\xca\xbb\xf3\x8d\x8c\xfc\xcb\xdbn\xbb\xadz\x98\xcdfe\x02\x00\x00\x00@g[\\\\l|\xf4\xf3\xc1\x07\x0fK\xa6\xe3\xa9\xbc;\xdf\x8e\x1d;\x86\x87\x87\xab\x87\x85\xc2\xc5\xa5\xa5%\xb1\x00\x00\x00\x00\xd0\xa9VVV\xfe\xd3\x7f\xfaOu\xc3Db\xe8\xee\xbb\xef\x16N\xc7Syw\x85\x03\x07R\xfd\xfd\xfd\xd5\xc3lvN&\x00\x00\x00\x00t\xaa\x9f\xfe\xf4\xa7\x1f|\xf0A\xdd\xf0\xf0a\x8fxw\x05\x95w\xb7\x18\x1d\x1d\xa9\xbe.\x95J\xf9|^&\x00\x00\x00\x00t\x9e_\xfc\xe2\x17o\xbe\xf9f\xddpdd\xe4\xf6\xdbo\x17N7Pyw\x8b\xa1\xa1\xa1/|\xe1\x9fV\x0f\xb3\xd9\xb9(\x8a\xc4\x02\x00\x00\x00@\x87\xc9\xe5ru\x93 \x08\xbe\xfa\xd5\x7f.\x99.\xa1\xf2\xee"_\xff\xfa\xd7+\xff\xf7^}\x1dE\xd1\xf9\xf39\x99\x00\x00\x00\x00\xd0I\xde~\xfb\xedw\xdey\xa7n81\xf1@oo\xafp\xba\x84\xca\xbb\x8b\xec\xdc\xb93\x95JU\x0f\x17\x16\x16\x1aw\xad\x05\x00\x00\x00\x80\xf6\xd5\xf8\x88w<\x1e\xdf\xb3g\x8fd\xba\x87\xca\xbb\xbb\x1c8\x90\x8a\xc5b\xd5\xc33gB\x99\x00\x00\x00\x00\xd0\x19\xfe\xf3\x7f\xfe\xcf\xef\xbd\xf7^\xdd\xf0\xc1\x07\xedZ\xd9]T\xde\xdd%\x08\x82\xda},\x97\x97\x97\x97\x96\x96\xc4\x02\x00\x00\x00@\xbb\x8b\xa2(\x9f\xcf\xd7\r\x13\x89\xa1\xbb\xef\xbe[8]E\xe5\xddu\x92\xc9\xe4\xc0\xc0@\xf50\x0c\xcf\xca\x04\x00\x00\x00\x80v\x97\xcdf?\xf8\xe0\x83\xba\xe1\xe1\xc3\x1e\xf1\xee:*\xefn4>>^}].\x97\xe7\xe7\x17d\x02\x00\x00\x00@\xfbZZZ\xca\xe7\x17\xeb\x86###\xb7\xdf~\xbbp\xba\x8d\xca\xbb\x1b\xf5\xf7\xc7\x93\xc9\xbd\xd5\xc3\\.\x17E\x91X\x00\x00\x00\x00hS\x8d\xcft\xfe\xc3\x7f\xf8\x0f\x87\x87\xbf*\x99.\xa4\xf2\xeeR\xe3\xe3\xe3A\x10\xac\xbe\x8e\xa2(\x9b\xcd\xca\x04\x00\x00\x00\x80v\x94\xcf\xe7\x97\x97\x97\xeb\x86\xbf\xfd\xdb\xa3===\xc2\xe9B*\xef.\x15\x04\xc1\xc8\xc8H\xcdua\xd1>\x96\x00\x00\x00\x00\xb4\x9d\x8f\x9e\xe6\x9c\xab\x1b\xf6\xf7\xf7\x7f\xf9\xcb_\x16NwRyw\xaf\x03\x07R\xb1X\xacz\xd8xi\x00\x00\x00\x00\x80\x167?\xbf\xd0\xb8f\xef\xc3\x0f?$\x99\xae\xa5\xf2\xeej\xe9\xf4#\xd5\xd7\xa5R\xe9\xfc\xf9\x9cL\x00\x00\x00\x00h\x17\xc5b)\x97\xcb\xd5\r\x87\x86\x86>\xfb\xd9\xcf\n\xa7k\xa9\xbc\xbb\xda\xe0\xe0`"1T=\\XX\xb0\x8f%\x00\x00\x00\x00\xed\xa2q\x83\xba\xde\xde\xdeG\x1f}T2\xddL\xe5\xdd\xed\xea\xf6\xb1l\xdc\xdc\x16\x00\x00\x00\x00ZP\xa1Ph\xdc\xb5rxx8\x08n\x11N7Syw\xbbX,\x96J\xa5\xaa\x87\xb9\\\xaeX,\x89\x05\x00\x00\x00\x80V\xd6t\xd7\xca_\xfb\xb5_\xfb\x97\xff\xf2k\xc2\xe9r*on\x18\x1d\x1d\xf9\xf8>\x96Y\x99\x00\x00\x00\x00\xd0\xca\xce\x9f\xcf\x95\xcb\xe5\xba\xe1\x83\x0f\x1e\x96\x0c*o>4>~\xa8\xfazyy9\x9f\xcf\xcb\x04\x00\x00\x00\x80\xd6T.\x97\x17\x16\xea\x97\xe7M&\xf7\xfe\xc6o\xfc\x86pPy\xf3\xa1D"100P=\xccf\xe7\xecc\t\x00\x00\x00@k:s&\xac\x9b\x04A011!\x19nPyS\xf5\xe8\xa3\xe9\xea\xeb\x8f\xd6B\xb2\xbc\t\x00\x00\x00\x00-\'\x9f\xcf7\xeeZ966\xd6\xdb\xdb+\x1cnPyS\x15\x8b\xc5FFFj\xae\x1d\x8bKKKb\x01\x00\x00\x00\xa0u4\xdd\xb52\x1e\x8f\xef\xdf\xbfO8\xacRy\xf3\xf7\x1a\xf6\xb1\x9c\x93\t\x00\x00\x00\x00\xadc~~\xa1q=\xde\x87\x1f~H2T\xa9\xbc\xf9\x98t\xfa\x91\xea\xebR\xa9t\xfe|N&\x00\x00\x00\x00\xb4\x82b\xb1\x94\xcb\xe5\xea\x86\xc9\xe4\xde]\xbbv\t\x87*\x957\x1f388\x98H\x0cU\x0f\x17\x16\x16\xca\xe5\xb2X\x00\x00\x00\x00\xd8vah\xd7J>\x99\xca\x9bz\xe3\xe3\xe3\x95\x8b\xc5\xeak\xfbX\x02\x00\x00\x00\xd0\n\xce\x9f\xcf\x95J\xa5\xba\xa1]+i\xa4\xf2\xa6^,\x16K\xa5R\xd5\xc3B\xe1\xa2},\x01\x00\x00\x00\xd8FQ\x14-,,\xd4\r\xedZIS*o\x9a\x18\x1d\x1d\xa9\\2\xaa\x87ax\xb6q[\x00\x00\x00\x00\x00\xd8\x1aa\x186\xd6SG\x8f>!\x19\x1a\xa9\xbcin|\xfcP\xf5u\xb9\\\xb6\x8f%\x00\x00\x00\x00\xdbbii\xa9P\xb8X7L\xa5R}}}\xc2\xa1\x91\xca\x9b\xe6\x06\x07\x07\x93\xc9\xbd\xd5C\xfbX\x02\x00\x00\x00\xb0-\xc2\xf0l\xdd$\x08\x82\x83\x07\xc7$CS*o\xd6T\xbb\x8fe\xc5\x993\xa1L\x00\x00\x00\x00\xd8J\xf3\xf3M\x1e\xc4\x9f\x17\x0b\x00\x00\x00\x00[\xa3\\.7\xeeZ900\xf0\x9b\xbf\xf9\x9b\xc2a-*o\xd6\x93L&+\x17\x91\xeaa6;g\x1fK\x00\x00\x00\x00\xb6F\xe3\xaa\x03A\x10<\xf1\xc4\xe3\x92a\x1d*o>\xc1\xf8\xf8x\xf5u\x14Eahy\x13\x00\x00\x00\x006\xdd\xf9\xf3\xb9\xe5\xe5\xe5\xba\xe1\xf0\xf0Wo\xbf\xfdv\xe1\xb0\x0e\x957\x9f\xa0\xbf?>22R=,\x14..--\x89\x05\x00\x00\x00\x80\xcd\x13EQ\xe3\x92&\xf1x|xxX8\xacO\xe5\xcd\';p \x15\x8b\xc5\xaa\x87ax\xd6\xf2&\x00\x00\x00\x00l\x9e0\x0c\x1b\x0b\xa8\x87\x1f~H2|\xa2_\xb9t\xe9/\xa5\xc0\'\xbax\xf1\xe2\xe9\xd3\xb3\xd5\xc3\xdf\xfa\x88X\x00\x00\xaa._\xbe\xfc\xc6\x1bo4=566&\x1f\x00\x80+\xf7\xf6\xdbo\xff\xe9\x9f\xfei\xdd\xf0\x8b_\xfc\xe2c\x8f=*\x1c>\x91\xa7\xbc\xb9"CCC\xf7\xde{o\xf5\xf0\xc2\x85\x0b\x95\x0fub\x01\x00\x00\x00`c\xad\xac\xac\xe4r\xb9\xbaaoo\xef\xc4\xc4\x03\xc2\xe1J\xa8\xbc\xb9R\x8f<\xf2H\xe5\xe2R=l\xbc\xf4\x00\x00\x00\x00\xc0u\xfa\xe9O\x7f\xfa\xde{\xef\xd5\r\x1fz\xe8\xa1[n\xb9E8\\\t\x957Wj\xc7\x8e[\x7f\xfb\xb7G\xab\x87\x97/_\xbex\xf1\xa2X\x00\x00\x00\x00\xd8(\x97/_~\xf3\xcd7\xeb\x86\xfd\xfd\xfd{\xf6Xb\x97+u\x93\x08\xb8r\xf7\xdf\x7f\xff_\xfcE\xe1g?\xfb\xd9\xea\xe1\x7f\xff\xef\xff\xfd+_\xd9\x7f\xc7\x1dwl\xd2\xff\xdc\xcf~\xf6\xf7\x0b\xcd\xdfs\xcf\xe7\xda(\xa8\x9f\x7f\xe8\x7f\xad\xbe\xbe\xe3\x8eOo^Db\x17\xbb\xd8\xc5.v\xb1\x8b\xbdu\xf4\xf6\xf6\xacuJ\xec~\xda\xc5.v\xb1\x8b]\xecb\x17\xfb\x15z\xfd\xf5\xd7\xeb&\xb7\xdcr\xcb\xb7\xbf\xfd\xad\x1b\xe0\x8a\xa9\xbc\xb9:G\x8e\xe1pUT\xde\\\xb5\xd1\xd1\x91\xca\xe5\xa6z\x98\xcd\xce\xad>\xf4\r\x00\x00\x00\x00\xd7\xe6\xcc\x99\xb0q\xf8\xe4\x93G%\xc3\xd5Rys-\xd2\xe9t\xf5u\x14Ea\x18\xca\x04\x00\x00\x00\x80ks\xfe|nyy\xb9n822\xb2s\xe7N\xe1p\xb5T\xde\\\x8b\xfe\xfex\xe5\xa2S=,\x14.\x16\n\x05\xb1\x00\x00\x00\x00p\xb5\x9a.i\x12\x8b\xc5FGG\x84\xc35Pys\x8d\x0e\x1cHU.=\xd5\xc30\xe1\xb05T\xdel\x9d\xfe\xfe\xf8\xc8\xc8H\xf5\xb0T*Y\xde\x04\x00\x00\x00\xa0c\x14\n\x85|~\xb1n\x18\x8f\xc7\x87\x87\x87\x85\xc3\x96Qy\xb3\xa5FGG\x06\x06\x06\xaa\x87\xb9\\niiI,\x00\x00\x00\x00\xed\xae\xe9\x92&A\x10<\xf3\xcc\xb7\x85\xc3VRy\xb3\xd5\x1e}4]\xb9\xd8U\x0fgg_\xb5\xbc\t\x00\x00\x00@\xbb;}z\xb6\xb1\xe4\x19\x1b\x1b\xbb\xfd\xf6\xdb\x85\xc3VRy\xb3\xd5b\xb1\xd8\xf8\xf8\xa1\xea\xe1G\xbf\x00\x0c\xc5\x02\x00\x00\x00\xd0\xbe\xce\x9f\xcf-//\xd7\r\x13\x89\xa1\xfd\xfb\xf7\t\x87-\xa6\xf2f\x1b$\x93\xc9\xca%\xafzX(\\\xac\\\x16\xc5\x02\x00\x00\x00\xd0\x8e\x8a\xc5\xd2\xdc\xdc\\\xdd0\x08\x82#G\x8e\x08\x87\xad\xa7\xf2f{\xa4\xd3\x1f[\xdedaa\xa1q3_\x00\x00\x00\x00Z_\xd3\xbf\xe0?z\xf4\x89\xde\xde^\xe1\xb0\xf5T\xdel\x8f \x08&\'\x9f\xaa\x1eFQt\xfa\xf4\xacX\x00\x00\x00\x00\xdaK6;W*\x95\xea\x86\xa9Tj\xf7\xee\xdd\xc2a[\xa8\xbc\xd96\x83\x83\x83\x95\xcb_\xf5\xb0rq\x9c\x9f_\x10\x0b\x00\x00\x00@\xbbXZZ\xca\xe5ru\xc3X,v\xf0\xe0\x98p\xd8.*o\xb6\xd3\xf8\xf8\xa1x<^=\\XX\xa8\\(\xc5\x02\x00\x00\x00\xd0\xfa\xa2(\x9a\x9d}\xb5q\xfe\xec\xb3\xcf\xf4\xf4\xf4\xc8\x87\xed\xa2\xf2f\x9b\xd5-\xea]\xb9PV.\x97b\x01\x00\x00\x00hq\xa7O\xcf6\xd68\x07\x0f\x8e\xf5\xf5\xf5\t\x87m\xa4\xf2f\x9b\xf5\xf7\xc7GFF\xaa\x87\x95\x0be\xd3\x1d\x0f\x00\x00\x00\x00h\x1d\xe7\xcf\xe7\x96\x97\x97\xeb\x86\x03\x03\x03\xc3\xc3\xc3\xc2a{\xa9\xbc\xd9~\x07\x0e\xa4\x12\x89\xa1\xeaa\xa1p\xb1r\xd1\x14\x0b\x00\x00\x00@k*\x16Ksssu\xc3 \x08\x8e\x1e}B8l;\x957-\xa1ny\x93\x85\x85\x85\xca\xa5S,\x00\x00\x00\x00\xadf\xad\xbf\xd1?z\xf4\x89\xdbn\xbbM>l;\x957-!\x08\x82\xc9\xc9\xa7\xea.\x9d+++\x92\x01\x00\x00\x00h)\xd9l\xb6T\xaa\x7fT1\x99\xdc\xbb{\xf7n\xe1\xd0\nT\xde\xb4\x8a\xc1\xc1\xc1T*U=\xac\\:\x7f\xfa\xd3\x9f\x8a\x05\x00\x00\x00\xa0u\x14\n\x85|~\xb1n\x18\x8f\xc7\x0f\x1f>,\x1cZ\x84\xca\x9b\x162>~\xa8r\x89\xac\x1e\xbe\xf9\xe6\x9b\x97.]\x12\x0b\x00\x00\x00@+(\x97\xcbax\xb6q\xfe\xe4\x93G{zz\xe4C\x8bPy\xd3Z\xea\x16\xf5\xce\xe5r\xbf\xf8\xc5/\xc4\x02\x00\x00\x00\xb0\xedN\x9f\x9e\x8d\xa2\xa8n811\xb1s\xe7N\xe1\xd0:T\xde\xb4\x96\xfe\xfe\xf8\xf8\xf8\xa1\xea\xe1\xca\xca\xca\xb9s\xe7\xc4\x02\x00\x00\x00\xb0\xbd\xb2\xd9\xb9\xc6%\xbc\x13\x89\xa1\xfd\xfb\xf7\t\x87\x96\xa2\xf2\xa6\xe5$?\xb4\xb7zx\xf9\xf2\xe5\x0b\x17.\x88\x05\x00\x00\x00`\xbb,--\xe5r\xb9\xbaa\x10\x04G\x8e\x1c\x11\x0e\xadF\xe5M+\x1a\x1f\x1f\x8f\xc5b\xd5\xc3\x0b\x17.T.\xacb\x01\x00\x00\x00\xd8zQ\x14\xcd\xce\xbe\xda8\x7f\xee\xb9g{{{\xe5C\xabQy\xd3\x8a\x82 \x98\x9c\x9c\xac\x9dT.\xac\x8dkE\x01\x00\x00\x00\xb0\xd9\x9a.\xe1}\xf0\xe0\xd8\xae]\xbb\x84C\x0bRy\xd3\xa2\xfa\xfb\xe3_\xfb\xda\xd7\xaa\x87\x95\x0bk\xe5\xf2*\x16\x00\x00\x00\x80\xad4?\xbf\xb0\xbc\xbc\\7\x1c\x18\x18\x18\x1e\x1e\x16\x0e\xadI\xe5M\xeb\xfa\xfa\xd7\x7f\xbbr\x01\xad\x1eV.\xaf\x95\x8b\xacX\x00\x00\x00\x00\xb6\xc6\xdbo\xbf\xbd\xb0P\xdf\xc6\x04Ap\xf4\xe8\x13\xc2\xa1e\xa9\xbciiO>y\xb4vM\xa8\xcaE\xd6\xa2\xde\x00\x00\x00\x00[`ee\xe5\xdc\xb9s\x8d\xf3\xa3G\x9f\xb8\xed\xb6\xdb\xe4C\xcbRy\xd3\xd2v\xec\xd8\xf1\xc4\x13\x8f\xd7N,\xea\r\x00\x00\x00\xb0\x05\xfe\xec\xcf\xfelee\xa5n\x98J\xa5v\xef\xde-\x1cZ\x99\xca\x9bVw\xef\xbd\xf7~\xe5+_\xa9\x1eZ\xd4\x1b\x00\x00\x00`\xb3]\xb8p\xe1\x9dw\xde\xa9\x1b\xc6\xe3\xf1\xf1\xf1C\xc2\xa1\xc5\xdd$\x02Z\xdf\x03\x0f\xfc\xee_\xff\xf5__\xbati\xf5pyy\xf9?\xfc\x87\x9f\xd4\xf6\xe0\xad\xe6\x97\xbf\xfce\xed\xebw\xdf\xfd\x9b6M\xbe\xbd\xbes\xb1\x8b]\xecb\x17\xbb\xd8\xb7\xd7\xcf\x7f\xfes\xb1\xfbi\x17\xbb\xd8\xc5.v\xb1\x8b\xbd3b\x7f\xfb\xed\xb7/\\\xb8P7\xbc\xf9\xe6\x9b\xbf\xfd\xedo\xdd\x00-\xefW.]\xfaK)\xd0\xfa\xde{\xef\xbd\x97_~\xa5\xf6\xafi\xbe\xfe\xf5\xaf\x7f\xe63\x9f\x91\x0c\x00\xd0"._\xbe\xfc\xc6\x1bo4=566&\x1f\x00\xa0]\xac\xac\xac\xbc\xf6\xdak\x8dK\x9a<\xfe\xf8\xe3\xbf\xf5[_\x90\x0f\xad\xcf\xc2&\xb4\x87\xc6E\xbd\xcf\x9d;\xd7x\xf1\x05\x00\x00\x00\xe0z4]\xc2{\xef\xde\xbd\xfan\xda\x85\xca\x9b\xb6Q\xb7\xa8w\xe5\xe2[\xb9\x04\x8b\x05\x00\x00\x00`\xa34]\xc2\xfb\xae\xbb\xeez\xf4\xd1\xb4ph\x17\xd6\xf2\xa6\x9d<\xf0\xc0\xef^\xbat\xe9\xaf\xff\xfa\xafW\x0f+\x97\xe0B\xa1\xf0\xe5/\x7f\xb9\xd5\xbe\xcf\x95\x95\x95\xbf\xfb\xbb\xbf[}\xdd\xd3\xd3\xd3\xdb\xdb\xdbF!\xd7\xae5v\xeb\xad\xb7\xb6\xd1w.v\xb1\x8b]\xecb\x17{\xeb\xe4\\G\xec~\xda\xc5.v\xb1\x8b]\xecbo\x8b\xd8\x8b\xc5b\xd3%\xbc\xa7\xa7\xa7n\x80\xf6\xa1\xf2\xa6\xcd<\xf7\xdc\xb3/\xbf\xfcJ\x14E\xab\x87\xff\xf5\xbf\xfe\xd7\xa1\xa1{\x13\x89DK}\x93\xef\xbe\xfb7\x15\xab\xaf\xef\xb8\xe3\x8e_\xfd\xd5\xbe6J\xf8\xe2\xc57\xab\xaf\xef\xb9\xe7sm\xf4\x9d\x8b]\xecb\x17\xbb\xd8\xc5\xbe\xbdn\xbc\xf1\xc6\xb5N\x89\xddO\xbb\xd8\xc5.v\xb1\x8b]\xec\xad\x1f{\xb9\\\xfe7\xff\xe6\xdf4\xce\x9fz\xea\xc9O\x7f\xfa\xd37@\xfb\xb0\xb0\tm&\x08\x82\xc9\xc9\xa7j\'ax\xb6rQ\x96\x0c\x00\x00\x00\xc05;}z\xb6\xfa\x88a\xd5\x17\xbf\xf8\xc5\xdd\xbbw\x0b\x87\xf6\xa2\xf2\xa6\xfd\x0c\x0e\x0e\x1e:t\xa8zX\xb9\x1cW.\xcab\x01\x00\x00\x00\xb86\xd9\xec\\\xa9T\xaa\x1b\xdeu\xd7]\x8f=\xf6\xa8ph;*o\xda\xd2\x81\x03\xa9Db\xa8zX\xb9(\x87a(\x16\x00\x00\x00\x80\xab\x95\xcf\xe7s\xb9\\\xdd\xb0\xb7\xb7wj\xea;\xc2\xa1\x1d\xa9\xbciW\xe9t:\x16\x8b\xd5\\\x9d\x17+\x17h\xb1\x00\x00\x00\x00\\\xb9b\xb1\x94\xcd\xce5\xce\x9f~z\xf2\x8e;\xee\x90\x0f\xedH\xe5M\xbb\xfahQ\xef\xc9\xdaI\xe5\x02]\xb9LK\x06\x00\x00\x00\xe0JDQ\x14\x86a\xe3\x12\xde\xf7\xdf\x7f\xff\xe7?\xffy\xf9\xd0\xa6T\xde\xb4\xb1\xfe\xfex:\xfd\xc8\'^\xa6\x01\x00\x00\x00h\x94\xcdf\x1b\x97\xf0\x1e\x18\x18\xf8\xc67~G8\xb4/\x957\xed-\xf9\xa1\xbd\xd5C\x8bz\x03\x00\x00\x00\\\x89\xf3\xe7s\xf9\xfcb\xdd0\x16\x8b}\xfb\xdb\xdf\x12\x0emM\xe5M\xdb\x1b\x1f\x1f\x8f\xc7\xe3\xd5\xc3B\xe1b\xe5\x92-\x16\x00\x00\x00\x80\xb5\x14\x8b\xa5\xb9\xb9&Kx?\xfb\xec3\xbd\xbd\xbd\xf2\xa1\xad\xa9\xbci{A\x10\xa4\xd3\xe9\xca\xbf\xd5I\xe5\x92\xbd\xb4\xb4$\x19\x00\x00\x00\x80FQ\x14e2\x99\xc6\xf9\xc4\xc4D__\x9f|hw*o:A\xdd\xa2\xde\x15\xb3\xb3\xaf\x96\xcbe\xc9\x00\x00\x00\x00\xd4\x99\x99\xc94\xee\x85\x96L\xee\xdd\xbf\x7f\x9fp\xe8\x00*o:D"\x91H\xa5R\xd5\xc3\xca\x85\xfb\xf4\xe9Y\xb1\x00\x00\x00\x00\xd4\xcaf\xe7\x1a\xb7\xac\x8c\xc7\xe3\x87\x0f\x1f\x16\x0e\x9dA\xe5M\xe7\x18\x1f?400P=\xb4\x95%\x00\x00\x00@\xad|>\x9f\xcb\xe5\xea\x86A\x10LN>\xd5\xd3\xd3#\x1f:\x83\xca\x9b\x8e\xf2\xf4\xd3\x93\xb1X\xac\xe6:\xbeX\xb9\x94\x8b\x05\x00\x00\x00\xa0X,e\xb3M\xb6\xact\x0c\x957\x1d\xe5\xa3_KN\xd6N\xc2\xf0l\xe5\x82.\x19\x00\x00\x00\xa0\x9bEQ4;;\xdb\xb8\x84\xf7\xc1\x83c\xbbw\xef\x96\x0f\x9dD\xe5M\xa7i\xdc\xca2\x93i\xb2\'\x03\x00\x00\x00@\xf78}z\xb6\\.\xd7\r\x07\x06\x06\x86\x87\x87\x85C\x87Qy\xd3\x81\x92\x1f\xda[=\x8c\xa2hf&#\x16\x00\x00\x00\xa0;e\xb3s\xcb\xcb\xcbu\xc3X,\xf6\xcc3\xdf\x16\x0e\x9dG\xe5MgJ\xa7\xd3\xf1x\xbczh+K\x00\x00\x00\xa0;\xad\xb5e\xe5s\xcf=k\xcbJ:\x92\xca\x9b\x8e5==U\xb9|\xd7\\\xdfme\t\x00\x00\x00t\x97\xb5\xb6\xac\x9c\x98x`\xe7\xce\x9d\xf2\xa1#\xa9\xbc\xe9XA\x10LMM\xd5Nle\t\x00\x00\x00t\x8f\xb5\xb6\xacL\xa5R{\xf6\xec\x91\x0f\x9dJ\xe5M\'\xb3\x95%\x00\x00\x00\xd0\xb5\xd6\xda\xb2r|\xfc\x90p\xe8`*o:\\\xd3\xad,\xb5\xde\x00\x00\x00@g\x0b\xc3\xb0\xe9\x96\x95\xdf\xfe\xf6\xb7\x84CgSy\xd3\xf9\x1a\xb7\xb2\xccf\xb3b\x01\x00\x00\x00:U\xfeC\x8bu\xc3 \x08\x9e}\xf6\x99\xde\xde^\xf9\xd0\xd9T\xdet\x85\xc6\xad,\xcf\x9f\xcf\x89\x05\x00\x00\x00\xe8<\xc5b)\x0c\xcf6\xce\'&\x1e\xe8\xeb\xeb\x93\x0f\x1dO\xe5MWh\xdc\xcarnnniiI2\x00\x00\x00@\'\x89\xa2(\x93\xc94\xce\x87\x87\xbfj\xcbJ\xba\x84\xca\x9bn\xd1\xb8\x95\xe5\xec\xec\xab\xc5bI2\x00\x00\x00@gXk\x0f\xb3Db\xe8\xe0\xc1\x83\xf2\xa1K\xa8\xbc\xe9"\x8d[Y\x86ah+K\x00\x00\x00\xa03d\xb3\xd9R\xa9\xfe\xf1\xbex<\xfe\xf8\xe3\x8f\x0b\x87\xee\xa1\xf2\xa6\xbb\xa4\xd3\xe9\x81\x81\x81\xeaa\xe5m\xe0\xf4\xe9Y\xb1\x00\x00\x00\x00\xedn~~\xa1\xe9\x96\x95O>y\xb4\xa7\xa7G>t\x0f\x957]\xe7\xe9\xa7\'c\xb1X\xf5pyy9\x9b\x9d\x13\x0b\x00\x00\x00\xd0\xbe\n\x85\xc2\xc2\xc2B\xe3|r\xf2\xa9\x9d;w\xca\x87\xae\xa2\xf2\xa6\xeb\x04A099Y\xf9\xb7:\xc9\xe5r\xf9|^2\x00\x00\x00@;*\x16Kax\xb6q>11188(\x1f\xba\x8d\xca\x9bn\xd4\xb8\x95e\xe5\x8d\xc1V\x96\x00\x00\x00@\xdb\x89\xa2hvv\xb6q\xaf\xb2dr\xef\xfe\xfd\xfb\xe4C\x17Ry\xd3\xa5\x12\x89\xc4\xc8\xc8H\xed$\x93\xc9\x94\xcbe\xc9\x00\x00\x00\x00mdf\xa6I\xa1\x11\x8f\xc7\x1f|\xf0A\xe1\xd0\x9dT\xdet\xaf\xd1\xd1\x91dro\xf50\x8a\xa2\xd3\xa7\x9b\xfcR\x14\x00\x00\x00\xa05\x85aX*\xd5\xff\xd9z\x10\x04\xcf?\xff\xdd\x9bn\xbaI>t\'\x957]m||<\x1e\x8fW\x0f+o\x12\x95\xb7\n\xb1\x00\x00\x00\x00\xad\xef\xfc\xf9\\>\xbfX7\x0c\x82\xe0\xd8\xb1\x17z{{\xe5C\xd7Ry\xd3\xd5*o\x03\xd3\xd3S\xb5[Y\x16\n\x17\xb3\xd99\xc9\x00\x00\x00\x00\xad\xacP(\xcc\xcd5i0\x1e~\xf8\xa1\xbe\xbe>\xf9\xd0\xcdT\xdet\xbb \x08\xa6\xa6>\xd6z\xe7r\xb9|>/\x19\x00\x00\x00\xa05\x15\x8b\xa50<\xdb8?xp\xec\xbe\xfb\xee\x93\x0f]N\xe5\r7\xf4\xf7\xc7\xc7\xc7\x0f\xd5N*o\x1bKKK\x92\x01\x00\x00\x00ZM\x14E\x99L\xa6q7\xb2dr\xef\xf0\xf0\xb0|@\xe5\r\xab\xef\n\xc9\x91\x91\x91\xda\xc9\xec\xec\xab\xc5bI2\x00\x00\x00@\xeb\x88\xa2hf\xa6I\xdf\x1d\x8f\xc7\x1f|\xf0A\xf9\xc0\r*o\xa8\x1a\x1d\x1dI&\xf7\xd6\xbe\x85\x84a\xd8\xf8\x16\x02\x00\x00\x00\xb0]\xb2\xd9l\xa9T\xff\x88^\x10\x04\xcf?\xff\xdd\x9bn\xbaI>p\x83\xca\x1bj\x8d\x8f\x8f\xc7\xe3\xf1\xeaa\xe5-df&#\x16\x00\x00\x00\xa0\x15d\xb3s\xf9\xfcb\xdd0\x08\x82c\xc7^\xe8\xed\xed\x95\x0f\xacRy\xc3\xc7\xde$\xa6\xa7\xa7b\xb1XuR*\x95\xc20\x94\x0c\x00\x00\x00\xb0\xbd\xf2\xf9|.\x97k\x9cON>\xd5\xd7\xd7\'\x1f\xa8Ry\xc3\xc7\x04A099Y\xf9\xb7\xe6\x1deq~~A2\x00\x00\x00\xc0vYZZ\n\xc3\xb3\x8d\xf3\x89\x89\x89\xc1\xc1A\xf9@-\x957\xd4\xeb\xef\x8fON>U;YXX\xc8\xe7\xf3\x92\x01\x00\x00\x00\xb6^\xb1X\x9a\x9d}\xb5q\x9eL\xee\xdd\xbf\x7f\x9f|\xa0\x8e\xca\x1b\x9a\x18\x1c\x1cL\xa7\x1f\xa9\x9d\x84\xe1\xd9\xca\x1b\x8cd\x00\x00\x00\x80\xad\x14E\xd1\xec\xecl\xe5\xdf\xba\xf9\xc0\xc0@:\x9d\x96\x0f4RyCs\xc9\x0f\xed\xad\x9dd2\x19\xad7\x00\x00\x00\xb0e\xa2(\x9a\x99\xc9\x94\xcb\xe5\xbay<\x1e\x7f\xe6\x99o\xcb\x07\x9aRy\xc3\x9a\xd2\xe9t"1T\xfb6\xd3\xf4\xd7\xaa\x00\x00\x00\x00\x9b!\x0c\xc3R\xa9\xfe\xf1\xbb \x08\x9e{\xee\xb9\x9e\x9e\x1e\xf9@S*oXO:\x9d\x8e\xc7\xe3\xd5\xc3r\xb9<3\x93\xd1z\x03\x00\x00\x00\x9b-\x0c\xc3B\xe1b\xdd0\x08\x82c\xc7^\xd8\xb1\xe3V\xf9\xc0ZT\xde\xb0\x9e\xca\x1b\xc9\xf4\xf4T\xe5\xdf\xea\xa4T*e\xb3Y\xc9\x00\x00\x00\x00\x9b\'\xff\xa1\xc5\xc6\xf9\xc3\x0f?\xd4\xd7\xd7\'\x1fX\x87\xca\x1b>A\x10\x04SS\x1fk\xbd+o9a\x18J\x06\x00\x00\x00\xd8\x0c\xf9|>\x0c\xcf6\xce\'&&\xee\xbb\xef>\xf9\xc0\xfaT\xde\xf0\xc9\xfa\xfb\xe3\x93\x93O}\xfc\xbdg\xb1\xf2\xf6#\x19\x00\x00\x00`c\x15\x8b\xa5lv\xaeq\x9eL\xee\xdd\xbf\x7f\x9f|\xe0\x13\xa9\xbc\xe1\x8a\x0c\x0e\x0e\xa6\xd3\x8f\xd4N\xc2\xf0\xac\xd6\x1b\x00\x00\x00\xd8@\xc5b)\x93i\xb2\x8bX"1\x94N\xa7\xe5\x03WB\xe5\rW*\x99L\x8e\x8c\x8c\xd4N\xc2\xf0l\xe5\xadH2\x00\x00\x00\xc0\xf5\x8b\xa2hvv\xb6\xb1\xef\x8e\xc7\xe3\x8f?\xfe\xb8|\xe0\n\xa9\xbc\xe1*\x8c\x8e\x8e$\x93{k\'\x99LF\xeb\r\x00\x00\x00\\\xa7(\x8aff2\xe5r\xb9n\x1e\x8b\xc5\x9e\x7f\xfe\xbb==="\x82+\xa4\xf2\x86\xab\x93N\xa7\x07\x06\x06j\xdf\x90\x9a\xfe\x02\x16\x00\x00\x00\xe0\xca\x85aX*\xd5?T\x17\x04\xc1s\xcf=\xdb\xdb\xdb+\x1f\xb8r*o\xb8jO?=\x19\x8f\xc7\xab\x87\xe5ryf&\xa3\xf5\x06\x00\x00\x00\xaeM\x18\x86\x85\xc2\xc5\xc6\xf9\xb1c/\xec\xdc\xb9S>pUT\xdep\xd5\x82 \x98\x9e\x9e\xaa\xfc[\x9d\x94J\xa5\xd3\xa7g%\x03\x00\x00\x00\\\xad\xf9\xf9\x85|~\xb1q\xfe\xe4\x93G\xfb\xfa\xfa\xe4\x03WK\xe5\r\xd7"\x08\x82\xa9\xa9\x8f\xb5\xde\xcb\xcb\xcba\x18J\x06\x00\x00\x00\xb8r\xf9|~aa\xa1q~\xe4\xc8c\xf7\xddw\x9f|\xe0\x1a\xa8\xbc\xe1\x1a\xf5\xf7\xc7\xa7\xa6\xa6>\xfe.\xb5\xa8\xf5\x06\x00\x00\x00\xaeP>\x9f\x0f\xc3\xb3\x8d\xf3dr\xef\x9e={\xe4\x03\xd7\xe6W.]\xfaK)\xc05\xfb\x8f\xff\xf1?\xfe\xc9\x9f\xfc?\xb5\x93T*\xf5\x8f\xff\xf1?\x96\x0c\x00t\x9b\xcb\x97/\xbf\xf1\xc6\x1bMO\x8d\x8d\x8d\xc9\x07\x00h\xbcyx\xfd\xf5\xd7WVV\xea\xe6\xf7\xde{\xef7\xbf\xf9\xb4|\xe0\x9ay\xca\x1b\xae\xcb\xfd\xf7\xdf\xff\x8do\xfcN\xed$\x97\xcb\xbd\xf5\xd6[\x92\x01\x00\x00\x00\xd6\xb2V\xdf}\xd7]w\xe9\xbb\xe1:\xa9\xbc\xe1z\xdd\x7f\xff\xfdCCC\xb5\x93\\.\xf7\xf6\xdboK\x06\x00\x00\x00h\xb4\xb2\xb2\xb2V\xdf\xfd\xbd\xef}O>p\x9dT\xde\xb0\x01\x9e~z\xf2\xde{\xef\xad\x9d\x9c;w\xee\xf2\xe5\xcb\x92\x01\x00\x00\x00j\xad\xd5w\xf7\xf6\xf6~\xef{\xc7\x83\xe0\x16\x11\xc1u\xbaI\x04\xb0!\xbe\xf9\xcd\xa7\xff\xf0\x0f\xff\xf5\xcf~\xf6\xb3\xda7\xb0\xb1\xb1\xb1\x81\x81\xdf\xb8\xe3\x8e;\xda\xe8?\xe4g?\xfb\xfb\xf5\xfd\xef\xb9\xe7sm\xf4\x9d\xff\xfcC\xffk\xf5\xf5\x1dw|Z\xecb\x17\xbb\xd8\xc5.\xf6-\xd6\xdb\xdb\xb3\xd6)\xb1\xfbi\x17\xbb\xd8\xc5.v\xb1\x8b}5\xf6(z\xff\xf4\xe9\xd3\x8d\x0f\xc9\xddr\xcb-\xc7\x8f\x1f\x0b\x82\xe0\x06\xe0\xba\xa9\xbca\xc3|\xeb[\xdf\x9c\x99\xc9\x94J\xa5\xd5\xc3\x95\x95\x95?\xfb\xb3?\xfb\xdc\xe7\xbeu\xeb\xad\xb7\xb6\xe9\x7fQ{}\xe7\xef\xbd\xf7\xcb\xea\xeb\x9e\x9e^\xb1\x8b]\xecb\x17\xbb\xd8\xb7\xd8-\xb7\x04b\xf7\xd3.v\xb1\x8b]\xecb\x17\xfb\xfa\xb1\xbf\xf6\xdak\xef\xbc\xf3N\xddW\x06Ap\xec\xd8\x0b}}}7\x00\x1b\xc1\xc2&\xb0a*oQ\xd3\xd3S\xf1x\xbc\xe6\xed\xed\xbd3g\xceDQ$\x1c\x00\x00\x00\xe8ra\x18\x16\n\x17\x1b\xe7\x93\x93O\xe9\xbba\x03\xa9\xbca#\x05A\x90N\xa7o\xbe\xf9\xe6\xea\xe4\xddw\xdf\x9d\x99\xc9h\xbd\x01\x00\x00\xa0\x9b\x85a\x98\xcf/6\xce\x8f\x1cylppP>\xb0\x81T\xde\xb0\xc1\xfa\xfb\xe3\xdf\xf9\xces\xbd\xbd\xbd\xd5I\xa9T\xaa\xbc\xb1I\x06\x00\x00\x00\xba\xd3\xe2\xe2b\xd3\xbe{bbb\xcf\x9e=\xf2\x81\x8d\xa5\xf2\x86\x8d\xf7\xeb\xbf\xfe\xeb\xcf>\xfbL\xed\xa4P\xb8\xa8\xf5\x06\x00\x00\x80.\xf4\xd6[o\x9d;w\xaeq\xbeo\xdf\xbe\xfd\xfb\xf7\xc9\x076\x9c\xca\x1b6\xc5=\xf7\xdcs\xe8\xd0\xa1\xdaI>\xbf\xa8\xf5\x06\x00\x00\x80\xae\xf2\xd6[o\xe5r\xb9\xc6y2\xb9\xf7\xf0\xe1\t\xf9\xc0fPy\xc3f9p \xf5\x8do\xfcN\xed$\x9f_\xccf\xe7$\x03\x00\x00\x00\xdd\xe0\xd2\xa5KM\xfb\xeeDb(\x9dN\xcb\x076\x89\xca\x1b6\xd1\xfd\xf7\xdf_\xf7;\xdb\xca[]>\x9f\x97\x0c\x00\x00\x00t\xb6w\xdf}\xb7i\xdf\x1d\x8f\xc7\x8f\x1e=*\x1f\xd8<*o\xd8\\\xfb\xf6\xedK&\xf7\xd6N\xc2\xf0\xac\xd6\x1b\x00\x00\x00:X\xb1X\xfa\xa3?\xfa\xa3\x95\x95\x95\xbay<\x1e\x7f\xfe\xf9\xef\xdex\xe3\x8d"\x82\xcd\xa3\xf2\x86M\x97N\xa7\xb5\xde\x00\x00\x00\xd0%\x8a\xc5R&\x93\xf9\xe0\x83\x0f\xea\xe6\xab}woo\xaf\x88`S\xa9\xbca+4m\xbd\x0b\x85\x82d\x00\x00\x00\xa0\x93\x94\xcb\xe5L&\x13EQ\xdd<\x08\x82\xe7\x9e{N\xdf\r[@\xe5\r[$\x9dN\xc7\xe3\xf1\xdaI\x18\x9e-\x16K\x92\x01\x00\x00\x80\xce\x10E\xd1\xe9\xd3\xb3\x8d}\xf7\xcd7\xdf|\xfc\xf8\xb1\x1d;n\x15\x11l\x01\x957l\x9d\xe9\xe9\xa9\xda\xd6\xbb\xf2\x16\x98\xc9d\xb4\xde\x00\x00\x00\xd0\x01*\x1f\xf3gf2\xa5R\xfd\xc7\xfc\xde\xde\xde\xe7\x9f\xff\xee\xce\x9d;E\x04[C\xe5\r[\'\x08\x02\xad7\x00\x00\x00t\x9eu\xfa\xee\xdf\xfb\xbd\xe9\xcf|\xe63"\x82-\xa3\xf2\x86-\xa5\xf5\x06\x00\x00\x80\x0e\xb3V\xdf]11\xf1\xc0g?\xfbY\x11\xc1VRy\xc3V\x0b\x82\xe0\xe9\xa7\'+\xff\xd6\xbe56\xdd\xda\x02\x00\x00\x00h}\xa7O\xcf6\xed\xbb\x7f\xf7w\xc7\x93\xc9\xa4|`\x8b\xa9\xbca\x1b\xc4b\xb1\xa9\xa9\xa9\xba\xd6{fF\xeb\r\x00\x00\x00m&\x0c\xc3\xe5\xe5\xe5\xc6\xf9\xc3\x0f?\xf4\xcf\xfe\xd9?\x93\x0fl=\x957l\x8f\xfe\xfex]\xeb]*\x95\xb4\xde\x00\x00\x00\xd0F\xc20\xcc\xe7\x17\x1b\xe7G\x8e<\xf6\xe5/\x7fY>\xb0-T\xde\xb0m\xb4\xde\x00\x00\x00\xd0\xbe\xd6\xea\xbb\x0f\x1e\x1c\xdb\xb3g\x8f|`\xbb\xa8\xbca;i\xbd\x01\x00\x00\xa0\x1d\xad\xd5w\xef\xdb\xb7oxxX>\xb0\x8dT\xde\xb0\xcd\xfa\xfb\xe3\xe9\xf4#\xb5\x13\xad7\x00\x00\x00\xb4\xb2\xb5\xfa\xeedr\xef\xe1\xc3\x13\xf2\x81\xed\xa5\xf2\x86\xed\x97H$\xb4\xde\x00\x00\x00\xd0\x16\xd6\xe9\xbb\xd3\xe9\xb4|`\xdb\xa9\xbc\xa1%$\x93\xc9\xc6\xd6\xfb\xf4\xe9Y\xc9\x00\x00\x00@\xeb\x98\x9f_\xd0wC\x8bSyC\xabhl\xbd\x97\x97\x97\xc30\x94\x0c\x00\x00\x00\xb4\x82|>\xbf\xb0\xb0\xd0\xec\x13\xbd\xbe\x1bZ\x88\xca\x1bZHc\xeb\x9d\xcf/j\xbd\x01\x00\x00`\xdb\xe5\xf3\xf90<\xdb8O$\x86\xf4\xdd\xd0RT\xde\xd0Z\xb4\xde\x00\x00\x00\xd0j\xd6\xea\xbb\xe3\xf1\xf8\xd1\xa3G\xe5\x03-E\xe5\r-G\xeb\r\x00\x00\x00\xadc\x9d\xbe\xfb\xf8\xf1c7\xdex\xa3\x88\xa0\xa5\xa8\xbc\xa1\x15i\xbd\x01\x00\x00\xa0\x15\xac\xd3w\xbf\xf0\xc2\xf3\xfanhA*ohQ\xc9\x0f\xed\xfd\xf8\xbb\xac\xd6\x1b\x00\x00\x00\xb6\xce:}\xf7\xf3\xcf\x7f\xb7\xa7\xa7GD\xd0\x82T\xde\xd0\xba\xd2\xe9\xb4\xd6\x1b\x00\x00\x00\xb6\xc5\xfa}woo\xaf\x88\xa05\xa9\xbc\xa1\xa5i\xbd\x01\x00\x00`\xeb\xe9\xbb\xa1}\xa9\xbc\xa1\xd5i\xbd\x01\x00\x00`+\xe9\xbb\xa1\xad\xa9\xbc\xa1\rh\xbd\x01\x00\x00`k\xe8\xbb\xa1\xdd\xa9\xbc\xa1=h\xbd\x01\x00\x00`\xb3\xe9\xbb\xa1\x03\xa8\xbc\xa1mh\xbd\x01\x00\x00`\xf3\xe8\xbb\xa13\xa8\xbc\xa1\x9dh\xbd\x01\x00\x00`3\xe8\xbb\xa1c\xa8\xbc\xa1\xcdh\xbd\x01\x00\x00`c\xe9\xbb\xa1\x93\xa8\xbc\xa1\xfdh\xbd\x01\x00\x00`\xa3\xe8\xbb\xa1\xc3\xa8\xbc\xa1-i\xbd\x01\x00\x00\xe0\xfa\xe9\xbb\xa1\xf3\xdc$\x02hS\xe9t\xfa\xa3\xf7\xe6\xc5\x9a\xf7\xe9\xc5(\x8a*\xf3 \x08\xe4\x03\x00\x00\x00\xeb\x9b\x9f_\xa8h\x9c\xeb\xbb\xa1\xady\xca\x1b\xdaX\xe3\xb3\xde\x85\xc2\xc5\x99\x99L\x14E\xc2\x01\x00\x00\x80u\x84a\xa8\xef\x86\x8e\xa4\xf2\x86\xf6\xd6\xd8z\x97J%\xad7\x00\x00\x00\xac#\x0c\xc3\xda?\x9b\xae\xd2wC\x07PyC\xdbK\xa7\xd3\x87\x0e\x1d\xaa\x9dh\xbd\x01\x00\x00`-\xfan\xe8l*o\xe8\x04\x07\x0e\xa4\xd2\xe9Gj\'Zo\x00\x00\x00h\xb4N\xdf\xfd\xc2\x0b\xcf\xeb\xbb\xa1\x03\xa8\xbc\xa1C$\x93I\xad7\x00\x00\x00\xacc\x9d\xbe\xfb\xf8\xf1c==="\x82\x0e\xa0\xf2\x86\xce\xa1\xf5\x06\x00\x00\x80\xb5\xac\xd5w\'\x12C\xc7\x8f\x1f\xbb\xf1\xc6\x1bE\x04\x9dA\xe5\r\x1d\xa5i\xeb}\xf2\xe4\xa9b\xb1$\x1c\x00\x00\x00\xbaS\x14E33\x99\xa6}w2\xb9wrrR\xdf\r\x9dD\xe5\r\x9d\xa6\xb1\xf5.\x97\xcb\x99LF\xeb\r\x00\x00@\x17Z\xed\xbb\x97\x97\x97\x9b}\x82\xde\x9bN\xa7E\x04\x1dF\xe5\r\x1d\xa8\xb1\xf5\xae\xbc\xc1k\xbd\x01\x00\x00\xe86\xab}w\xa9Tj\xf6\xd9Y\xdf\r\x9dI\xe5\r\x9di\xb5\xf5\x0e\x82\xa0\xf6m^\xeb\r\x00\x00@\xf7\xd0wCwRyC\xc7J&\x93SSS\x8d\xad\xf7\xd2\xd2\x92p\x00\x00\x00\xe8l\xe5ry\xad\xbe{\xdf\xbe}\xfan\xe8`*o\xe8d\xfd\xfd\xf1f\xad\xf7\x8f\xf3\xf9\xbcp\x00\x00\x00\xe8T\xc5b\xe9\xe4\xc9SM\xfb\xee\x83\x07\xc7\x0e\x1f\x9e\x10\x11t0\x957t\xb8\xc6\xd6\xbb"\x0c\xcfj\xbd\x01\x00\x00\xe8H\xc5b)\x93\xc9DQ\xd4x\xea\xc8\x91\xc7\x86\x87\x87E\x04\x9dM\xe5\r\x9dO\xeb\r\x00\x00@\x97X\xbf\xef\xde\xb3g\x8f\x88\xa0\xe3\xa9\xbc\xa1+\xac\xb6\xde\xf1x\xbcv\x18\x86g\xe7\xe7\x17\x84\x03\x00\x00@g(\x14\n\xfan@\xe5\r\xdd\xa2\xbf?>=]\xdfz/,,\x84a(\x1c\x00\x00\x00\xda]>\x9f\x9f\x9d}\xb5\xb1\xef\x0e\x82\xe0\xe9\xa7\'\xf5\xdd\xd0=T\xde\xd0E*o\xf3\x8d\xadw>\xbf\xa8\xf5\x06\x00\x00\xa0\xad\xe5\xf3\xf90<\xdb\xf4\x83\xf0\xb1c/\x0c\r\r\x89\x08\xba\xc7M"\x80\xaeRy\xb3\x9f\x9a\xfa\xce\x1f\xfe\xe1\xbf\xfe\x1f\xff\xe3\x7f\xd4\xdc\x19,F\xd1\xfb\xff\xe2_\xfc\x8b[n\xb9\xa5\xf6\x8b\xdf}\xf7o\xda\xe8?\xed\x97\xbf\xfce\xed\xeb\xf6\xfa\xe6\xc5.v\xb1\x8b]\xec\x1d\x10\xfb\xcf\x7f\xfes\xb1\xfbi\x17\xbb\xd8\xc5.v\xb1oK\xec\x8b\x8b\x8b\xe7\xce\x9dk\x9c\xdf|\xf3\xcd\xbf\xf7{\xd3}}}\xda\x00\xe8*\xbfr\xe9\xd2_J\x01\xba\xcd{\xef\xbdw\xf6\xecko\xbe\xf9f\xed\xf0\xce;\xef\x1c\x1b\x1b\xeb\xed\xed\x95\x0f\x00\\\x83\xcb\x97/\xbf\xf1\xc6\x1bMOU\xdea\xe5\x03\x00\x9b$\x97\xcb\xbd\xf5\xd6[\x8d\xf3\xca\xc7\xdb\xef~\xf7\xbb\xfd\xfdq\x11A\xb7\xb1\xb0\tt\xa3\x1d;v|\xf3\x9bO\xd7\xfdaW\xe5\x83\xfa\xeb\xaf\xbf\xbe\xb2\xb2"\x1f\x00\x00\x00\xda\xc2Z}\xf7]w\xdd\xf5\xd2K?\xd4wCwRyC\xf7z\xfa\xe9\xc9{\xef\xbd\xb7v\xb2\xdazW\xfe\x15\x0e\x00\x00\x00\xadlee\xe5\xdc\xb9sk\xf5\xdd\xdf\xfb\xde\xf1O\x7f\xfa\xd3R\x82\xeed-o\xe8j\xdf\xfc\xe6\xd3sss\xe7\xcf\xe7\xaa\x93\xd5\xd6{ll\xec\xce;\xef\xbc\xf5\xd6[\xdb\xebv\xe7\xef\xfe\xee\xefV_\xf7\xf4\xf4\xb4\xd7\n-\xb5+\xeb\x89]\xecb\x17\xbb\xd8\xdb4\xf6\xda\x9c\xeb\x88\xddO\xbb\xd8\xc5.v\xb1\x8b}cc\xff\xe0\x83\x0f\xfe\xe4O\xfe\xe4\x7f\xfe\xcf\xff\xd9\xf8\xf5}}}\xc7\x8f\x1f\xab\xdb\xaa\n\xe8**o\xe8v\x87\x0e\x1d\x8a\xc7\xe3\xb5\x1b[Wn\x86V[\xef\xa1\xa1{\xdb\xe8?\xe4\xddw\xff\xa6b\xf5\xf5\x1dw\xdc\xf1\xab\xbf\xdaN\xfb\x93\\\xbc\xf8\xf7\xeb\xaa\xdfs\xcf\xe7\xc4.v\xb1\x8b]\xec\xed\x18\xfb\x8d7\xde\xb8\xd6)\xb1\xfbi\x17\xbb\xd8\xc5.v\xb1o`\xecQ\x14\xcd\xccd\x9a\xf6\xdd\x89\xc4\xd0\xd1\xa3G\xd7yS\x06\xba\x81\xca\x1b\xb8!\x99LV\xfe\xadk\xbd\xb3\xd9l\x10\xdc\xb2z\n\x00\x00\x00ZA\xb1X\xcad2Q\x145\xfbl\xbb7\x9dN\x8b\x08\xb0\x967\xb0zg\x90\x9c\x9a\xfaN\x10\x04\xb5\xc30<\x9b\xcf\xe7\x85\x03\x00\x00@+X\xa7\xef\xde\xb7o\x9f\xbe\x1bX\xa5\xf2\x06\xfe\x7f\x83\x83\x83SSSuk\xba\x85\xe1\xd9lvN8\x00\x00\x00l\xaf\xb7\xdezk\xad\xbe{bb\xe2\xf0\xe1\t\x11\x01\xabT\xde\xc0\xdf\xeb\xef\x8f?\xfb\xec3\xb7\xddv[\xed0\x97\xcb\x85a(\x1c\x00\x00\x00\xb6\xcb[o\xbdU\xf9p\xda\xb4\xef>r\xe4\xb1\xfd\xfb\xf7\x89\x08\xa8Ry\x03\x1fs\xcf=\xf7|\xff\xfb\xff\xe7]w\xddU;\xcc\xe7\x17ggg\x9b\xde[\x00\x00\x00\xc0\xa6\xbap\xe1B.\x97k\x9c\x07A05\xf5\x9d={\xf6\x88\x08\xa8\xa5\xf2\x06\xea\xed\xd8\xb1\xe3\x85\x17^\xa8k\xbd\x0b\x85\x8b33\x19\xad7\x00\x00\x00[)\x97\xcb]\xb8p\xa1q\x1e\x04\xc1\xb1c/\x0c\x0e\x0e\x8a\x08\xa8\xa3\xf2\x06\x9a\xd8\xb1\xe3\xd6\x17^x>\x99\xdc[;,\x95J33\x99b\xb1$\x1f\x00\x00\x006[\x14E\xb3\xb3\xb3o\xbd\xf5V\xe3\xa9 \x08\x8e\x1f?\xd6\xd7\xd7\'%\xa0\x91\xca\x1bhn\xc7\x8e\x1d\xe9t\xba\xb1\xf5\xced\xb4\xde\x00\x00\x00l\xae(\x8aff2\x85\xc2\xc5\xc6S\xf1x\xfc\x0f\xfe\xe0_\xed\xdc\xb9SJ@S*o`=\xe9t\xfa\xd0\xa1Cu\xb7\x1d\x99L&\x9f\xcf\x0b\x07\x00\x00\x80\xcdP,\x96N\x9e\x9f_\xab\xef\xbe\xf7\xde{\xf5\xdd\xc0\x95Py\x03W$\x91HLMM\xd5\xb5\xde\xb9\\.\x0cC\xe1\x00\x00\x00p\xfd\xf2\xf9|\x18\x9em\xdaw?\xf0\xc0\x03\xdf\xfc\xe6\xd3"\x02\xae\x84\xca\x1b\xb8R\xfd\xfd\xf1\x13\'^\x8c\xc7\xe3\x1f\xbf#Y\xbf\xd8x*\x08\x82\xef}\xef\xf8\xbe}\xff\x87\x94\x80+\xa7\xf2\x06\xaeN\xe5\x86czz*\x99\xdc[;,\x95>\xdc]D\xeb\r\x00\x00\xc0U\x89\xa2hf&S(\\l<\x15\x8b\xc5\x8e\x1f?\xf6\xd9\xcf~VJ\xc0UQy\x03W-\x08\x82t:]\xd7zWnS2\x99L>\x9f\x97\x0f\x00\x00\x00W\xa2X,\x9d)\x01\xd7I\xe5\rl\x80X,6==500P;,\x95>\xdc\x87\xa4X,\xc9\x07\x00\x00\x80(\x8aff2\x85\xc2\xc5\xc6SA\x10\x1c;\xf6\xc2}\xf7\xdd\'%\xe0\xfa\xa9\xbc\x81\x8dQ\xb9A\x99\x9e\x9eJ&\xf7\xd6\xdd\xd0\x9c:u*\x9f\xcf\xcb\x07\x00\x00\xa0\x9b\x15\x8b\xa5\x97_~\xa5Tj\xf2PT<\x1e\xff\xfd\xdf\xff\xfd\xbe\xbe>)\x01\x1bB\xe5\rl\xa4t:}\xe8\xd0\xa1\xbaa\x18\x9e\xcdf\xe7\x84\x03\x00\x00\xd0\x9d\xf2\xf9|&\xd3|\xc3\xa7\x81\x81\x81\x17^x~\xc7\x8e[\xa5\x04l\x94\x9bD\x00l\xac\x03\x07R\x9f\xfaT\x90\xcd\xce\xd5\xde\xcd\xe4r\xb9(\xfa\x7f\xc7\xc7\xc7\xeb6\xba\x04\x00\x00\xa0\xb3\x9d?\x9f\x9b\x9bk\xfe\x14T2\xb9\xd7f\x95\xc0\x86Sy\x03\x1b/\x99L\xc6\xe3\xfdu\xbf\xc3\xcf\xe7\x17\x8b\xc5\xd2\xf4\xf4\x94\xd6\x1b\x00\x00\xa0K\x84aX\xf90\xd8\xf4\xd4\xc4\xc4\x84\xcd*\x81\xcd`a\x13`S\xf4\xf7\xc7\x7f\xf4\xa3W\xe2\xf1x\xed\xb0T\xfap\xed6\x1bZ\x02\x00\x00t\xbc(\x8aN\x9e<\xd5\xb4\xef\x0e\x82`j\xea;\xfan`\x93\xa8\xbc\x81\xcd\xb2\xba\xa1e"1Tw\xd3\x93\xc9dlh\t\x00\x00\xd0\xc1\x8a\xc5\xd2\xc9\x93\xa7\x9anVY\xf9\xa8x\xec\xd8\x0b\x83\x83\x83R\x026\x89\xca\x1b\xd8D\x95[\x99\xc9\xc9\xc9T*U;\x8c\xa2(\x0c\xcf\xce\xcf/\xc8\x07\x00\x00\xa0\xf3\x14\n\x85L&S.\x97\x1bO\xc5\xe3\xf1?\xf8\x83\x7f\xd5\xd7\xd7\'%`\xf3X\xcb\x1b\xd8t\xe3\xe3\x87\xfa\xfb\xe3ax\xb6v\xb8\xb0\xb0P*\x15\xd3\xe9\xb4\xa5\xbd\x01\x00\x00:\xc6\xfc|\xe5\xd3^\xf3\'\x9c\x92\xc9\xbd\x0f>\xf8\xe0M7)\xa3\x80\xcd\xe5)o`+$\x93\xc9\x17_|\xb1\xae\xdd.\x14.\xce\xcc4\xff\xcd?\x00\x00\x00\xed\xe5\xa3\xbf\xe8\r\xd7\xea\xbb\x0f\x1e\x1cK\xa7\xd3\xfan`\x0b\xa8\xbc\x81-\xd2\xdf\x1f?q\xe2\xc5\xc6\r-O\x9e\xae\xb4\xbc\xbc\xdcx*\x08\x82\xa9\xa9\xef\xec\xdf\xbfOJ\xc0vQy\x03\xdb\xa9r34==\x95L\xee\xad\x1dFQ\x14\x86g\xb3\xd99\xf9\x00\x00\x00\xb4\x9a|>\x9f\xc9d\xca\xe5r\xe3\xa9x<~\xfc\xf8\xb1\xc1\xc1A)\x01\xdb\xc8\x1f\x98\x00\xdb,\x08\x82t:\x1d\x8f\xf7\xcf\xcd}\xac\xe3\xce\xe5r\xc5b\xf1\xe9\xa7\'-\xed\r\x00\x00\xd0"\xb2\xd9\xb9\xca\x87\xb5\xa6\xa7\x12\x89\xa1\xc7\x1f\x7f\xbc\xa7\xa7GJ\xc0\xf6\xf2\x947\xd0\x12\x0e\x1cHMM}\xa7\xae\xdd^^^\xb6\xb47\x00\x00@+X]\xbc{\xad\xbe{x\xf8\xab\x93\x93\x93\xfan\xa0\x15\xa8\xbc\x81V188855eio\x00\x00\x80V\xb3\xfe\xe2\xddG\x8e\xbf83\xd3|\xfb\x14\x00\x00\x00\xaeM\x14Ea\x18\xce\xcd\xcd5=;00\xf0\xc3\x1f\xfe`\xe7\xce\x9d\x82\x02Z\x99\xca\x1bh\x03\x07\x0e\xa4\xa6\xa6\xbeS\xb7\xb4w\xa9T:y\xf2T\xa1P\x90\x0f\x00\x00\xc0\xf5+\x16K33\x99|~\xb1\xe9\xd9\x83\x07\xc7\xa6\xa7\xa7zzz\x04\x05\xb48\x957\xd0\x1e\x06\x07\x07O\x9cx\xb1qi\xef\xd9\xd9W\xb3\xd99\xf9\x00\x00\x00\\\x8f|>\x9f\xc9d\xd6Z\xbc\xfb\xd9g\x9f\x19\x1e\x1e\x96\x12\xd0\x16T\xde@\xdb\x88\xc5b\'N\xbc\x98L\xee\xad\x9b\xe7r\xb9\x99\x99\xcc\xfb\xef\xbf/"\x00\x00\x80k\x90\xcd\xce\x85\xe1\xd9\xa6\x8bw\xc7\xe3\xf1\x17_\xfc\xde\xee\xdd\xbb\xa5\x04\xb4\x0b\x957\xd0f\xd2\x1fz\xa4n\x91\x93\xe5\xe5\xe5\x1f\xff\xf8\xc7o\xbf\xfd\xb6|\x00\x00\x00\xae\\\xb9\\>y\xf2T.\x97kz6\x99\xdc\xfb\xc2\x0b\xcf\xdfy\xe7\x9d\x82\x02\xda\x88\xca\x1bh?\xc9drjj*\x16\x8b\xd5\x0e?\xf8\xe0\x83?\xfd\xd3?\xbdx\xf1\xa2|\x00\x00\x00\xae\xc4\xd2\xd2\xd2\xc9\x93\xa7\x9a.fR111\x91N\xa7-\xde\r\xb4\x1d\x957\xd0\x96\xfa\xfb\xe3\'N\xbc\x98H\x0c\xd5\xcd\xff\xfc\xcf\xff\xfc\xdc\xb9s\x169\x01\x00\x00X\xdf\xfc\xfcB&\xf3\xe3\xa6\x8b\x99\xc4b\xb1\x97^\xfa\xe1\xfe\xfd\xfb\xa4\x04\xb4#\x957\xd0\xae\x82 \x98\x9c\x9c\x1c\x19\x19\xa9\x9b_\xbativv\xb6X,\x89\x08\x00\x00\xa0Q\x14E33\x99\x85\x85\x85\xa6g\x07\x06\x06~\xf0\x83\xef\xf7\xf5\xf5\t\nhS7\x89\x00hk\xa3\xa3#\x83\x83\x03\xb3\xb3\xaf\xd6>\x9b\xf0\xbf\xff\xf7\xff>u\xea\xd4\xa1C\x87\x0e\x1cH\x89\x08\x00\x00\xa0\xea\xaf\xfe\xea\xaf~\xf2\x93\x9f4}\xb8\xbb\xe2\xe0\xc1\xb1\xe1\xe1a)\x01m\xcdS\xde@\xdb\x1b\x1c\x1c\xfc\xd1\x8f^\xf9\xb5_\xfb\xb5\xba\xf9\xdc\xdc\xdc\xec\xec\xecZwr\x00\x00\x00\xdd\xe6\xc2\x85\x0bg\xce\x9ci\xfa))\x08\x82\xe3\xc7\x8f\xe9\xbb\x81\x0e\xa0\xf2\x06:A\xe5\xe6\xec\x07?\xf8\xfe\x17\xbf\xf8\xc5\xbay\xa1p\xf1\xe4\xc9S\x169\x01\x00\x00\xba\xdc\xca\xca\xca\xeb\xaf\xbf~\xe1\xc2\x85\xa6g\xe3\xf1\xf8K/\xfdp\xd7\xae]\x82\x02:\x80\xca\x1b\xe8\x1c\x8f=\xf6h:\x9d\xee\xed\xed\xad\x1d\x96\xcb\xe5S\xa7N\x9d?\x9f\x93\x0f\x00\x00\xd0\x9d\xfe\xea\xaf\xfe\xea\xb5\xd7^{\xe7\x9dw\x9a\x9eM\xa5R\'N\xbcx\xdbm\xb7\t\n\xe8\x0c\xbfr\xe9\xd2_J\x01\xe8$\xc5b\xf1\xdf\xfd\xbb\xff\xebo\xff\xf6o\xeb\xe6w\xdf}w\xe5N\xae\xae\x10\x07\x80\x8dr\xf9\xf2\xe57\xdex\xa3\xe9\xa9\xb1\xb11\xf9\x00\xb0].|\xa4\xe9\xa9\xca\xe7\xa3\x87\x1f~\xf8\xb7~\xeb\x0bR\x02:\x89\xa7\xbc\x81N\xd3\xdf\xdf\xff\xf2\xcb\xbf\xdf\xb8\xc8\xc9\xa5K\x97~\xf2\x93\x9f\\\xbe|YD\x00\x00@7X\x7f1\x93\xbb\xee\xba\xeb\x07?\xf8\xbe\xbe\x1b\xe8<7\x89\x00\xe8H\x8f=\xf6\xe8\xe7?\xff\xf9?\xfe\xe3?\xae\xdc\xe4U\x87\xef\xbd\xf7^6\x9b\xfd\xf2\x97\xbf<44$"\x00\x00\xa0\x83\xbd\xfd\xf6\xdb\xe7\xce\x9d\xab\xfd@Tk\xef\xde\xbd\x8f>\x9a\x96\x12\xd0\x91T\xde@\xc7J&\xf7\xfe\xfa\xaf\xef\xfa\xb7\xff\xf6t\xdd"\'\x7f\xfe\xe7\x7f~\xe9\xd2\xa5\xaf}\xedk\x169\x01\x00\x00:\xd2\x1bo\xbc\xf1\xe6\x9bo6=e1\x13\xa0\xe3Y\xcb\x1b\xe8|\x7f\xfc\xc7\xff\xe1\xbf\xfc\x97\xffR7\xbc\xe5\x96[\x1e{\xec\xd1{\xee\xb9\xa7\x15\xbe\xc3\x9f\xfd\xec\xef/\xc5\xf7\xdc\xf3\xb96\xca\xf6\xe7\x1f\xfa_\xab\xaf\xef\xb8\xe3\xd3w\xdcqG\x1b}\xf3b\x17\xbb\xd8\xc5\xbe\xb1\x8a\xc5b6;\xd7\xf4\xd4\xf4\xf4\x94\xd8\xfd\xb4\x8b]\xecb\x17\xfb\x96%\xfcG\x7ftf\xad\x9d*\xef\xba\xeb\xae\xca\xbb\xd2\xa7?\xfdi\x9f\x13\x81\x0e\xe6)o\xa0\xf3ML<\xb0{\xf7\xe7\xc3\xf0l\x14E\xd5\xe1\xfb\xef\xbf\x7f\xfa\xf4\xec\xc8\xc8\xc8\xe8\xe8HK}\xb7\xb7\xdezk\x1be\xfb\xde{\xbf\xac\xbe\xee\xe9\xe9m\xafo^\xecb\x17\xbb\xd87\xd6-\xb7\x04b\xf7\xd3.v\xb1\x8b]\xec\xdb\xabP(\xd4}\xf0\xa9e1\x13\xa0K\xa8\xbc\x81\xae\x90H$N\x9c\xe8?}z\xb6T*\xd5\xce\x17\x16\x16*7\x85O?=\x19\x8b\xc5\xa4\x04\x00\x00\xb4\xa9(\x8a\xb2\xd9l>\xbf\xd8\xf4\xec\xcd7\xdf\xfc\xd0C\x0fY\xcc\x04\xe8\x12\xff@\x04@\x97\x88\xc5b\'N\xbc\x98J\xa5\xea\xe6\xa5R\xe9\xe4\xc9S\x85BAD\x00\x00@;*\x16K33\x99\xb5\xfa\xee\x81\x81\x81\x97^\xfa\xa1\xbe\x1b\xe8\x1e\x9e\xf2\x06\xba\xcb\xf8\xf8\xa1Dbhv\xf6\xd5\xda\xbf\xf5\xab\xbc\xaeL\x92\xc9\xbd\xe3\xe3\xe3A\x10H\t\x00\x00h\x17\xe7\xcf\xe7\xe6\xe6\xe6\xd6:{\xf0\xe0\xd8\xf0\xf0\xb0\x94\x80\xae\xe2)o\xa0\xeb\x0c\x0e\x0e\xfe\xe8G\xaf\x0c\x0c\x0c\xd4\xcd\xf3\xf9\xc5\x93\'O\x15\x8b%\x11\x01\x00\x00\xad/\x8a\xa2\x99\x99\xccZ}w\x10\x04\xc7\x8f\x1f\xd3w\x03]H\xe5\rt\xa3\xca\xcd\xdf\xf4\xf4\xd4\xc8H\xfd\xc6\x95\xe5r\xf9\xd4\xa9S\xe7\xcf\xe7D\x04\x00\x00\xb4\xb2\xa5\xa5\xa5\x97_~eyy\xb9\xe9\xd9Db\xe8\x0f\xfe\xe0_\xed\xda\xb5KP@\x17\xb2\xb0\t\xd0\xbdFGG\x12\x89\xc4\xec\xecl\xb9\\\xae\x9d\xcf\xcd\xcd\xad\xeeii\x91\x13\x00\x00\xa0\x05e\xb3s\xb9\\n\xad\xb3\x13\x13\x13\xfb\xf7\xef\x93\x12\xd0\xb5<\xe5\rt\xb5\xfe\xfe\xf8\x89\x13/&\x93{\xeb\xe6\xcb\xcb\xcb/\xbf\xfc\x8a=-\x01\x00\x80\x96R,\x96N\x9e<\xb5V\xdf\x1d\x8f\xc7\x7f\xff\xf7_\xd2w\x03]\xceS\xde@\xb7\x0b\x82 \x9dN\x0f\x0e\x0ef\xb3s\xf6\xb4\x04\x00\x00Z\xd6\xfa;UV>\xbc\x1c>|\xb8\xa7\xa7GP@\x97Sy\x03\xac\xde\x1d&\x07\x07\x07O\x9f\x9e-\x95>\xb6}e>\xbf\xb8\xb4\xb4<99\xd9\xdf\x1f\x97\x12\x00\x00\xb0-\xa2(\xaa|ZYk\xe5\xee \x08\x8e\x1e}b\xf7\xee\xdd\x82\x02\xb8\xc1\xc2&\x00U\xb1X\xec\xc4\x89\x17\xd7\xda\xd3r~~AD\x00\x00\xc0\xd6+\x14\n\xeb\xecT900\xf0\xd2K?\xd4w\x03Ty\xca\x1b\xe0cFGG\x06\x07\x07\xc2\xf0l\xdd\x9e\x96\x0b\x0b\x0b\xab{Z\xc6b1)\x01\x00\x00[ \x8a\xa2l6\x9b\xcf/\xae\xf5\x05\x07\x0f\x8e\r\x0f\x0f\x0b\n\xa0\x96\xa7\xbc\x01\xea\r\x0e\x0e\x9e8\xf1b"1T7/\x95>\xdc(\xe6\xfc\xf9\x9c\x88\x00\x00\x80\xcd\xb6\xb4\xb4T\xf9\x00\xb2V\xdf\x1d\x8b\xc5^z\xe9\x87\xfan\x80F\x9e\xf2\x06h"\x08\x82\xc9\xc9\xc9|>\xdf\xb8\xa7\xe5\xdc\xdc\xdc\xf2\xf2R:\x9d\xb6\xa7%\x00\x00\xb0I\xe6\xe7\x17*\xd6:\x9bJ\xa5\x0e\x1e\x1c\xb3S%@S*o\x805\xad\xeeiy\xe6LX\xb7j^\xa1p\xf1\xe5\x97_I\xa7\x1fI$\x12R\x02\x00\x006P\xb1X\n\xc3\xb0T*5=k\xa7J\x80O\xa4\xf2\x06XO,\x16\x9b\x9e\x9ej|\xc2"\x8a\xa2\xd9\xd9W\x93\xc9\xbd\xe3\xe3\xe3\x1e\xf7\x06\x00\x006\xc4\xf9\xf3\xb9\xb9\xb9\xb9\xb5\xce&\x12CG\x8e\x1c\xe9\xed\xed\x15\x14\xc0:T\xde\x00\x9fltt$\x91H4>j\x91\xcf/.--\xa7\xd3\x8f\x0c\x0e\x0eJ\t\x00\x00\xb8f\xe5r\xb9\xf1\x0fL\xab\x82 \x18\x1b\x1b\xdb\xbf\x7f\x9f\xa0\x00>\x91\xca\x1b\xe0\x8a\xf4\xf7\xc7W\x1f\xf7\xce\xe5ru7\xa6\x99\xcc\x8fS\xa9\xd4\xe8\xe8\x88\xc7\xbd\x01\x00\x80kp\xfe|naa\xa1v\x1b\xa1Z\xf1x\xfc\x99g\xbe}\xfb\xed\xb7\x0b\n\xe0J\xa8\xbc\x01\xaeT\x10\x04\xe3\xe3\x87\x12\x89\xa10<[.\x97kO\xe5r\xb9B\xa1\xe0qo\x00\x00\xe0\xaa\xac\xffpw\xc5\xc1\x83c\xc3\xc3\xc3\x82\x02\xb8r\xff@\x04\x00Wepp\xf0\xc4\x89\x17\x13\x89\xa1\xc6[\xd5L\xe6\xc7\xf3\xf3\x0b"\x02\x00\x00\xaeD\xa1P8y\xf2\xd4Z}w<\x1e\x7f\xe9\xa5\x1f\xea\xbb\x01\xae\x96\xa7\xbc\x01\xaeZ\x10\x04\x93\x93\x93\x95\xdb\xd30<[\xf7\xb7\x87\x0b\x0b\x0b\x1f=\xee\x9d\xee\xef\x8f\x0b\n\x00\x00h\xaa\xf29"\x0c\xc3B\xe1\xe2Z_\x90J\xa5\x0e\x1e\x1c\xeb\xe9\xe9\x91\x15\xc0\xd5Ry\x03\\\xa3D"\xf1\xa3\x1f\r6\xde\xa7\x96J\xa5S\xa7N\x8d\x8c\x8c\x8c\x8e\x8eH\t\x00\x00\xa8\xd3\xf4\xe9\x99\xaaX,\xf6\xe4\x93Gw\xed\xda%(\x80k\xa3\xf2\x06\xb8v\xab\x8f{7\xddj\xc6\xe3\xde\x00\x00@\x1d\x0fw\x03l\x01\x957\xc0\xf5:p \xf5O\xfeI\xa2q\xcf\x19\x8f{\x03\x00\x00U\xeb?\xdc\x1d\x04\xc1\xd1\xa3O\xec\xde\xbd[P\x00\xd7I\xe5\r\xb0\x01b\xb1\xd8\xf4\xf4\x94\xc7\xbd\x01\x00\x80F\x9f\xf8pw"1\xf4\xf8\xe3\x8f{\xb8\x1b`C\xa8\xbc\x016\x8c\xc7\xbd\x01\x00\x80:\x1e\xee\x06\xd8b*o\x80\x8d\xe4qo\x00\x00`\x95\x87\xbb\x01\xb6\x85\xca\x1b`\xe3}\xe2\xe3\xde\x95/\x08\x82@P\x00\x00\xd0\xa9\xf2\xf9|6;\xe7\xe1n\x80\xad\xa7\xf2\x06\xd8\x14\xeb?\xee]\xb9\xfdM\xa7\x1f\x19\x1c\x1c\x14\x14\x00\x00t\x98r\xb9\xdc\xf8\xf8K-\x0fw\x03l*\x957\xc0&Z\xebq\xef\xcaMp&\xf3\xe3T*5::\xe2qo\x00\x00\xe8\x18M\x9fz\xa9\xf2p7\xc0\x16Py\x03l\xaeu\x1e\xf7\xce\xe5r\x1f\xad\xee\xfd\x88\x94\x00\x00\xa0\xddy\xb8\x1b\xa0E\xa8\xbc\x01\xb6\xc2\xfa\x8f{\xdf}\xf7\xdd\xa9T\xaa\xb7\xb7WP\x00\x00\xd0\x8e\xe6\xe7\x17*\xd6:\xeb\xe1n\x80\xad\xa4\xf2\x06\xd8"\xeb<\xee}\xe9\xd2\xa5\xd7^{-\x95J\xdd}\xf7\xdd\x82\x02\x00\x806R,\x96\xc20,\x95Jk}A2\xb9\xf7\xf0\xe1\xc3\x1e\xee\x06\xd82*o\x80-\xb5\xd6\xe3\xde+++\xe7\xce\x9d\xfbG\xff\xe8\x1f\xc5\xe3\x9f\x89\xc5b\x82\x02\x00\x80\x16\x17E\xd1\xfc\xfcB.\x97[\xeb\x0b*7\xf6O<\xf1\xb8\xe7Z\x00\xb6\x98\xca\x1b`\xab\xad>\xee](\x14\xc2\xf0l\xdd\xe3\xde\xef\xbc\xf3\xce\xc9\x93\xa7FFF\x0e\x1cH\t\n\x00\x00Z\xd6\xd2\xd2R\xe5~\xbe\\.\xaf\xf5\x05\xa9T\xea\xe0\xc11\x0fw\x03l=\x957\xc0\xf6H$\x12?\xfa\xd1`\x18\x86\x85\xc2\xc5\xday\x14Esss\xf9|>\x9dN\xf7\xf7\xc7\x05\x05\x00\x00-eee%\x97\xcb]\xbati\xad/\x88\xc5bO>yt\xd7\xae]\xb2\x02\xd8\x16*o\x80m\x13\x04\xc1\xe4\xe4d\xa1P\xf8\xf7\xff\xfe\xff\xfe\xc5/~Q{\xaaT*\x9d:u*\x95J\x8d\x8e\x8eT\xbeLV\x00\x00\xd0\n.^\xbcx\xe1\xc2\x85\x95\x95\x95\xb5\xbe`dd\xa4r\x0f/(\x80m\xa4\xf2\x06\xd8f\x89D\xe2\x9e{\xee\x99\x9b\xfb\x93\xff\xf6\xdf\xfe[\xdd\xa9\\.W(\x14\xd2\xe9G\x06\x07\x07\x05\x05\x00\x00\xdb\xa8\\.\xbf\xfe\xfa\xeb\xef\xbc\xf3\xceZ_\x10\x8f\xc7\x9f|\xf2\xe8\xce\x9d;e\x05\xb0\xbdT\xde\x00\xdbo\xc7\x8e\x1d\x8f=\xf6\xe8\x17\xbe\xf0O\xb3\xd9\xb9\xbf\xfd\xdb\xbf\xad\xbb\xb1\xced~\x9cH\x0c\xa5\xd3i\x8f{\x03\x00\xc0\xb6\x98\x9f_\xa8X\xebl\xe5F}lll\xff\xfe}\x82\x02h\x05*o\x80Vq\xefG\x9a\xdeL\x17\n\x17_~\xf9\x15\xdbZ\x02\x00\xc0\x16\xfb\xc4m*\x07\x06\x06\x8e\x1e}\xe2\xb6\xdbn\x93\x15@\x8bPy\x03\xb4\x96\xd1\xd1\x91/})y\xe6L\xb8\xbc\xbc\\;\xb7\xad%\x00\x00l\xa5\xca\x1dx\xe3n\xf3\xb5\x82 8r\xe4\xb1\xdf\xfc\xcd\xdf\x94\x15@KQy\x03\xb4\x9cX,6==u\xfe|naa\xa1r\x9f]{\xca\xb6\x96\x00\x00\xb0\x05\x9a\xde\x8d\xd7\xaa\xdc\x93\x1f<8\xd6\xd3\xd3#+\x80V\xa3\xf2\x06hQ\x07\x0e\xa4\xbe\xf4\xa5d\xd3\xe7Jr\xb9\xdcG\x8f{?\x92H$\x04\x05\x00\x00\x1b\xa8X,Un\xc2K\xa5\xd2Z_p\xd7]w=\xf8\xe0\xe1\xcf\x7f\xfe\xf3\xb2\x02hM*o\x80\xd6\x15\x04\xc1\xe4\xe4d\xd3\xd5\x03\xa3(\x9a\x9d}u``\xe0\xd1G\xd3\xb1XLV\x00\x00p\x9d*\xf7\xd8\xf3\xf3\x0b\xb9\\n\xad/\xe8\xed\xed\xdd\xb7o\xdf7\xbe\xf1;\xb2\x02he*o\x80V788x\xe2\xc4\x8b\xab\x7fYYwjyy\xb9\xba\xad\xa5uN\x00\x00\xe0\x9a\xe5\xf3\xf9lvn\x9d\x95L\x06\x06\x06\xd2\xe9G\xee\xbc\xf3NY\x01\xb48\x957@\x1b\x08\x82`\xadm-+\x16\x16\x16V\xd79\x19\x1c\x1c\x94\x15\x00\x00\\\x95r\xb9\xdc\xf46\xbb\xf6n\xdc6\x95\x00mD\xe5\r\xd06V\xb7\xb5l\xfa\xf8I\xe56=\x93\xf9q"14>>n\x9d\x13\x00\x00\xb8\x12\x95\x9b\xea\xa6\x7fLY\xcb6\x95\x00mG\xe5\r\xd0f\x92\xc9d"\x91h\xba\xc8`\xa1pqii\xb9rS>::"(\x00\x00XG\xa1P\xc8f\xe7\xea\xb6\xcc\xa9500\xf0\xd0C\x0f\xf6\xf5\xf5\xc9\n\xa0\xbd\xa8\xbc\x01\xdaO\x10\x04\xe3\xe3\x87\x12\x89\xa1\xca=z\xddV\xf2Q\x14\xad\xaes\xf2\xd1\x17$d\x05\x00\x00u\x8a\xc5R6\x9b]\x7f%\x93\xb1\xb1\xb1\xfd\xfb\xf7\xc9\n\xa0\x1d\xa9\xbc\x01\xdaU\xed\xb6\x96\x8d\xeb\x9c\xcc\xce\xbe:00\xf0\xe8\xa3i\xeb\x9c\x00\x00\xc0\xaa\xcams\xd3?\x97\xac\x95L\xee\x9d\x98\x98\xe8\xed\xed\x15\x17@\x9bRy\x03\xb4\xb7\x03\x07R_\xfaR2\x9b\xcd\xe6\xf3\x8bu\xa7\x96\x97\x97_~\xf9\x95\x91\x91\x91\xca\xd7\x04A +\x00\x00\xbaY\xd3Mqj\xc5\xe3\xf1\x87\x1f~h\xd7\xae]\xb2\x02hk*o\x80\xb6\x17\x04A:\x9dN&\x93\x8d\xeb\x9cT\xac\xaes2::R\xf9\x02Y\x01\x00\xd0\x85\x96\x96\x96\xfe\xbf\xf6\xee\xf7\xb9\xad\xfa\xce\x17\xb8\xda\x0eN\x04\xf9)\xa7\x10"\x97\xbaT"@b\x85\x90\x10\x05\x87R\x19\x9c\xb6\xf16\xd0!{\x0b;\x9b\xce\xdc\xfe\x03\x9b\x87w\x9f\xb5\xfb\x90\xa7\xf4\x1f\xe8\x0c\xe1Q7\x99\xd9>\xb0\xdb\xce4q\xef\xde\x92\xc8\x0b\x0b\xb5\x03\xddD*q;vBX\xa2,\x93\x14\x15\x97\x0e\xf7X\x87\x08\xe1\x1f\xb2\xfc\xdb:z\xbdFMe\x9fc\xc5|\xecH\xe7\xbc\xf59\x9fo\x7f\xff\x80I&\x00-B\xe4\r\x10\x11\xf5\xe7\x9c\x9c<\xf9\xca\xf9\xf3\xf9c\xc7\x8eut$\xd5\n\x00\x80\x16\x11\x1c\x18\xcfxAd-\x93L\x00"F\xe4\r\x10)\xf5\xe7\x9c\xbc\xf8\xe2\x8b\xc1\x01\xfd\xb1c\xc7\xcc9\x01\x00 \xf2\xc2\xb1\xdd&\x99\x00\xb4\x1a\x917@\xd4\xd4\x9fs\x92\xcf\x0f\r\x0f\x8f\x84\x03\xbe\xd5\n\x00\x80H*\x14\n\'O\xbeR*\x95\xea\x1c3\x9bd\x02\x10U"o\x80h\n\xe7\x9c\xcc\xb8DO\xf0\xe1\xe9\xd3\xa7\x07\x07\x07\x8f\x1f\xff\xc7`7\xb5\x02\x00 2J\xa5\xd2\xcb/\x9f\xac3\xb6;f\x92\t@\xd4\x89\xbc\x01\xa2,\x9b\xcdf2\x99\xf0\x8a\xce\xe9\'\x03/\xbd\xf4\x93T*\xf5\x83\x1f\x1cO$\x12j\x05\x00@S+\x97\xcb3\x1e\xf7\xd6\n\x8e~\xff\xe1\x1f^\xb8\xfb\xee\xbb\x95\x0b \xc2D\xde\x00\x11\x17\x8f\xc7\x8f\x1d{n\xff\xfe}\xff\xfa\xaf\xa7FGG\xa7l-\x16\x8b?\xfa\xd1\x8f\x0f\x1c8\xf0\xe4\x93O\xae_\xbf~\xbe\x0f\xfe\xe7?\xff\xb9\xf6\xfe\xb5k\xef5i\x95\x9a\xeb;WveW\xf6\xb5\xe9\xc6\x8d\x1b\xca\xee\xb7]\xd9\x95]\xd9W\xab\xecCCC\xbf\xf9\xcdo>\xfa\xe8\xa3\xd9v\xd8\xbcy\xf3\xdf\xfd]\xdf\xe3\x8f?\xee\x04\x01 \xf2\xbe0:zY\x15\x00Z\xc4\xf9\xf3\xf9\x9f\xff\xfc\xe77o\xde\x9c\xbe\xa9\xad\xadm\xdf\xbe}]]]\xaa\x04\xb00\xd7\xaf_\x7f\xf5\xd5Wg\xdct\xf4\xe8Q\xf5\x01X&W\xae\\\x19\x1c\x1c\xbcu\xebV\x9d}\x9e|\xf2\xc9\xa3G\xbf\xbb\x80\x0e\x0f\x00\x9a\x91.o\x80\x16r\xf0`v\xf7\xee\xdd\xbf\xf8\xc5/\xce\x9d;711Q\xbb)\xf80\xf8\xe4\xc8\xc8H.\x97\xdb\xb1c\x87Z\x01\x00\xb0\xc6\xdd\xbcyspp\xf0\xea\xd5\xabu\xf61\xc7\x0f\xa0\x05\xe9\xf2\x06hE\xef\xbe\xfb\xee\xbf\xfd\xdb\xcf/\\\xb80\xe3\xd6{\xef\xbd\xb7\xbb\xbb\xbb\xbd\xbd]\xa1\x00\x1a\xa7\xcb\x1b`\xc5LLL\x04O\xb9\x97.]\xaa\xb3\xcf\xb6m\xdb\xbe\xff\xfd\xff\xf5\xd0C\x0f)\x17@\xab\x11y\x03\xb4\xae\xb7\xdez\xab\xbf\x7f\xe0O\x7f\xfa\xd3\x8c[\x1f~\xf8\xe1\\.\xb7n\xdd\xba\xfa\'\x1b\x7f\xfd\xeb_\xc3\xfbw\xdcqGs\xadz_;G\xf2\xae\xbb\xeej\xaes\xdb\x81k\xad#G\x8e\xf4\xf6>\xdd\\o`\x00\xb0\xb4D\xde\x00\xad.\x9b\xcdf2\x99\xb3g\x07\x03\xe5r\xb9vS\xf0\xe1\xc0\xc0@pj\xd1\xd7w$\xd8M\xad\x00\x00X\x15\x85B\xa1\xbf\x7f\xa0X,\xd6\xd9\'\x93\xe9z\xfe\xf9\xe77m\xda\xa4\\\x00-N\xe4\r@,\x1e\x8f\xf7\xf5\x1d9x0\xdb\xdf\xdf\x9f\xcf\x0fM\xd9Z*\x95N\x9e|%8\xc78~\xfc\x1f\xd3\xe9\xb4r\x01\x00\xb0b\x82c\xd1\x97_>Y?\xecN&\x93/\xbc\xf0|gg\xa7r\x01\x10\x13y\x03P\x95H$\x8e\x1f?\x9e\xcb\xf5\x9c:uj\xfaIEp\xb2\xf1\xd2K?I\xa5R\xc7\x8e\x1d\xeb\xe8H*\x17\x00\x00\xcb\xaa\\.\x07\xc7\xa5\xd3\x1b2\xa6\x1c\xc1\x1e=\xfa\xdd\xfd\xfb\xf7+\x17\x00U"o\x00>\xa7\xa3#y\xe2\xc4?\r\x0f\x0f\x9f:uz\xfa\x9c\xc4b\xb1\xf8\xe2\x8b/f\xb3\x07\xfa\xfa\xfa\x82\x13\x0c\xe5\x02\x00`\xc9\x95\xcb\xe5\x19\xc7\xee\xd5\x8a\xc7\xe3\xb9\\\xee\xf0\xe1\xde;\xee\xb8C\xc5\x00\xa8%\xf2\x06`\x06\x99\x8a\xe0Lc```\xfa\x99F>?\x14\xdc\x82s\x0c\r5\x00\x00,\xad\xd9\x0eAke\xb3\x07\xbe\xff\xfd\xef[\xa3\x12\x80\x19\x89\xbc\x01\x98UOO\xee\xe0\xc1lx\xd61}\xeb\xe0\xe0\xe0\xb9s\xe7v\xef\xde\xdd\xd5\xd5\xe5|\x03\x00\x80E\xca\xe7\xf3\xfd\xfd\x03\xd3/4\xac\x95J\xa5~\xf8\xc3\xffm\x8dJ\x00\xea\x10y\x03PO\xfd\x95-?\xfa\xe8\xa3\xd7_\x7f\xfd\xe2\xc5\x8b\xfb\xf7\xef\xbf\xfb\xee\xbb\x95\x0b\x00\x80\x05(\x14\n\xfd\xfd\x03\xd6\xa8\x04`I\x88\xbc\x01\x98[\xfd\x95-o\xdd\xba588\xf8\xc6\x1bo\x1c=\xfa\xddl6\xab\\\x00\x004\xa8\x91\xb0\xdb\x1a\x95\x00\xcc\x8b\xc8\x1b\x80F\x85+[\x06\xa7%\xa7N\x9d\x1e\x1f\x1f\x9f\xb2\xf5\x83\x0f>8y\xf2\x95\xf3\xe7\xf3}}G\xd2\xe9\xb4r\x01\x00P\xc7\xcd\x9b7\xcf\x9f??<<\\g\x9fx<~\xf8p\xef\xe1\xc3\x87\x95\x0b\x80\xc6\x89\xbc\x01\x98\x9ft:\xfd\xcf\xff\xfc\x7ff\x9b\xb4X,\x16_z\xe9\'\xa9TJ\xf0\r\x00\xc0\x8cn\xde\xbc\xf9\xfa\xeb\xaf_\xbat\xa9\xfenG\x8e\x1c\xe9\xed}\xda\x9a1\x00\xcc\x97\xc8\x1b\x80\x85\xc8V\xfc\xeaW\xbf\xfa\xe5/\x7f5111ek5\xf8\xfe\xc1\x0f\x8e\'\x12\t\xe5\x02\x00 P.\x97\x83\x03\xc8\xa1\xa1\xa1\xb9\x0e5\x0f<\xf3\xcc3\xd6\xa8\x04`aD\xde\x00,\xdc\xb7\xbe\xf5\xad\xee\xee\xee_\xfc\xe2\x97\xe7\xce\x9d\x9b1\xf8\xfe\xd1\x8f~\x1c\x9c\xb1\xf4\xf5\xf5\t\xbe\x01\x00ZY\xb9\\>{v0\x10\xdc\xa9\xb3[&\xd3\xf5\xfc\xf3\xcf\x0b\xbb\x01X\x0c\x917\x00\x8b\xb2a\xc3\x86\xbf\xff\xfbc\xdf\xf9\xce\xb7\x7f\xf6\xb3\x9f\xfd\xe7\x7f\xbe1}\x87|~(\xb8\t\xbe\x01\x00ZS\x83aw*\x95z\xf6\xd9g:;;U\x0c\x80E\x12y\x03\xb0\x046l\xd8\xf0\xc3\x1f\xfe\xf0\xd9g\x9f\xed\xef\xef\xcf\xe7g\xb8RU\xf0\r\x00\xd0j\x1a\x0c\xbb\x93\xc9\xe4\x0b/q"]\xe7\xdc\xacT*\x9d<\xf9\xca\xa9S\xa7\x83\xb3\xb2\x9e\x9e\\pz\xa6h\x00\x00\xd3\xd5\xb9\x84\xaeV"\x918z\xf4\xbb\xfb\xf7\xefW1\x00\x9a\x88\xc8\x1b\x80&S\r\xbeg\xbb\x02\xb7\\.\x0f\x0c\x0c\x04[\xb3\xd9lOO.8US4\x00\x80\xf00\xe9\xfc\xf9|p\x98$\xec\x06 \xc2D\xde\x004\xa5tE\x9du\x96\x823\xba\xc1\x8al\xf6@__\x9f\xe0\x1b\x00he\xc1\xa1\xd1\xd9\xb3\x93\x87F\xc1\x9d\xfa{\xa6R\xa9C\x87\xba\x85\xdd\x004/\x917\x00M,\x91H\x1c?~\xbc\xaf\xaf\xaf\xbf\xbf\x7fxxd\xc6S\xb8|~(\xb8\x05\'o}}G\xd2\xe9\xb4\xa2\x01\x00-\xa5N\x8b\xc0\x14\xc1\xf1\xd2\xb3\xcf>\xd3\xd9\xd9\xa9h\x0045\x917\x00M/\x0c\xbe\xeb\xf7.\x15\x8b\xc5\x97^\xfaI2\x99\xec\xe9\xc9Y\xdf\x12\x00h\x05u\x06\xc1M\x91\xcd\x1e\xe8\xed\xed\xdd\xbe}\xbb\xa2\x01\x10\x01"o\x00""\x1e\x8f\xf7\xf5\x1d\xe9\xe9\xc9\xd5\x99P9>>~\xf2\xe4+\xfd\xfd\x03\xd9l\xf6\x9e{\xeeikkS7\x00 z\xf2\xf9\xfc\xd9\xb3\x83\xc1\x91\xcf\x9c{f\xb3\x07\x9ey\xe6\x99M\x9b6)\x1a\x00\x91!\xf2\x06 R\xe2\xf1xOO.\xb8\x05gz\xfd\xfd\x033\x06\xdf\xc1\'\x07\x06\x06\xda\xda\xda:;;\xf7\xed\xdb\xb7q\xe3Fu\x03\x00" \xbc\xe8-8\n\x9asu\xca\xe0\x90)\x97\xcb\xf5\xf6>\xad\x03\x00\x80\xe8\x11y\x03\x10M\xd9\x8aB\xa1\xd0\xdf?P,\x16\xa7\xef011q\xa9\xa2\xb3\xb3s\xfd\xfau\xc6|\x03\x00\xcd+\x1c\xd8=\xdb\xd2&\xb5\x12\x89D.\x97;t\xa8[\xd8\r@T\x89\xbc\x01\x88\xb2t:}\xe2Dzll|p\xf0\xecl\xab6\x8d\x8e\x8e\x1a\xf3\r\x004\xa9+W\xae\x9c?\x7f\xae\x91\x81\xdd\xc1\xd1No\xef\xd3\xfb\xf7\xefW4\x00\xa2M\xe4\r@\xf4ut$\x8f\x1f?\xde\xd7\xd7\x17^\xea;c\xf7S8\xe6\xfb\xd4\xa9\xd3\xb9\xdc\xe4\\\x94x<\xaen\x00\xc0Zv\xe9\xd2\xa5\xd7^{\xed\xd6\xad[s\xee\x99\xc9t\x1d>|\xb8\xb3\xb3S\xd1\x00h\x05"o\x00ZE"\x918v\xec\xb9\xbe\xbe#u\xd6\xb7,\x97\xcb\x03\x15\xd9\xec\x81\\\xae\xa7\xa3#\xa9n\x00\xc0\x9a\x12\x1c\xc3\x04\x073\xbf\xfe\xf5\xaf\'&&\xe6\xdc\xd9\xea\x94\x00\xb4 \x917\x00\xad\xa5\xba\xbe\xe5\x993g\xfe\xe3?^\x1b\x1b\x1b\x9bq\xb7|~(\xb8\xa5R\xa9\x83\x07\xb3\xa6\x9d\x00\x00kA\xa1P\xc8O\x1aj\xe4\x80\xc7\xea\x94\x00\xb4,\x917\x00-\xea\xa9\x8a\x0b\x17.\xfc\xf6\xb7\xaf\x06\x7f\xce\xb8O\xb1\xa2\xbf\x7f \x9b\xcd\x9av\x02\x00\xac\x96|>\x7f\xf6\xec\xe0\xf8\xf8\xf8\x9c{\x1a\xd8\r\x00"o\x00Z\xda\xee\x8aR\xa9Tg\xccw\xb0\xb5:\xed$\x9b\xcd\xa6\xd3iu\x03\x00V@\xfdC\x94)\x0c\xec\x06\x80\x90\xc8\x1b\x00>\x1b\xf3=<<\xdc\xdf?0\xe3\x98\xef\xd8\xedi\'\xc9d\xb2\xa7\'g\xda\t\x00\xb0|\n\x85\xc2\xe0\xe0\xe0\xf0\xf0\xc8\x9c{\xb6\xb5\xb5uww\x1f>\xdck`7\x00\x84D\xde\x00\xf0\xa9x<\x9e\xad\x08N2\xfb\xfb\x07\x8a\xc5\xe2\x8c\xbb\x8d\x8f\x8f\x9f<\xf9\xca\xa9S\xa7\xc3i\'\x89DB\xe9\x00\x80%Q.\x97\xeb\xac\xb3=\xc5\xc6\x8d\x1b\x0f\x1d:\xf4\xd4S=f\xaf\x01@-\x917\x00L\x95N\xa7O\x9cH\x07\xa7\x9a\xfd\xfd\xfd\xc3\xc3#3^J\x1c|r\xb0"\x95J\xf5\xf4\xe42\x99\x8c\xba\x01\x00\x0b666>8x\xb6\x91\xa5)\x03\xc1\xe1Gw\xf7\xe3\x8f=\xf6\x98\xba\x01\xc0t"o\x00\x98Y"\x918~\xfc\xf8\x9c\xcdV\xe1\x12\x97\xc1\xce\xd9l\xf6\xe0\xc1\xac\xa6o\x00\xa0q\xc1\x91\xc6\xf0\xf0p\x83KS\x86W\xa4\xf5\xf6>\xbdy\xf3f\xa5\x03\x80\xd9\x88\xbc\x01`\x8es\xcb\x9e\x9e\\p\xab?R\xb3\xba\xc4e&\xd3\x95\xcb\xe5,q\t\x00\xd4W\xffz\xb2)\x12\x89D_\xdf\x91\xbd{\xf7\xb6\xb5\xb5)\x1d\x00\xd4\'\xf2\x06\x80\x86\xa4+\x82\xb3\xd3\xb3g\x07\xf3\xf9\xfclg\xa7\xc1\x89kp\x0b\xceKs\xb9\xdc\xc1\x83Y\xb35\x01\x80)\x82\x03\x89\xf3\xe7\xf3\xb3\xad\x1a2E&\xd3u\xf8\xf0\xe1\xce\xceNu\x03\x80\x06\x89\xbc\x01`\x1e\x12\x89\xc4\xb1c\xcf\x05\xb7\xe0d\xb5\xce5\xc8\xa5R\xe9tE6{ \x9b\xcdj\xfa\x06\x00\xe6|\xe3|\xca!Gp\x08\xf1\xc4\x13\x876m\xda\xa4t\x000/"o\x00X\x88lE\xb8\xd2T\x9dK\x92\xf3\xf9\xa1\xe0\x166}\xef\xd9\x931\xe9\x1b\x00ZM8\xad\xbb\xf1\xb6\xeeT*u\xe8P\xf7\xfe\xfd\xfb\x95\x0e\x00\x16F\xe4\r\x00\x0b\xd7\xd1\x91ld\x89\xcbj\xd3w&\xd3\x95\xcdf3\x99\x8c\xd2\x01@\xe4\xcd\xf9\xd6x-KS\x02\xc0R\x11y\x03\xc0b\xd5.q\x99\x9f44\xdb\x9e\xd5I\xdf\xc19\xed\xc1\x83YM\xdf\x00\x10=a[w\x9d\x01hS$\x93\xc9\xe0(\xc2\xd2\x94\x00\xb0TD\xde\x00\xb0d\xc2%.\x8f\x1d;6g\xd3\xf7@E*\x95:xpr@\x8a\xd2\x01@\x04\xcc\xf9\xe6w\xadx<\x9e\xc9t\xf5\xf6\xf6n\xdf\xbe]\xe9\x00`\t\x89\xbc\x01`\x895\xde\xf4]\xac8ujr\xe0I.\xd7\xd3\xd1\x91T=\x00h:\xa5R\xe9\xfc\xf9\xc9\x97\xfc\xd9\xde\xed\x9eB[7\x00,+\x917\x00,\x97\x06\x9b\xbe\xcb\xe5r\xed*\x97\x07\x0ff\xe3\xf1\xb8\xea\x01\xc0\xda\x97\xcf\xe7\x1b_\x97R[7\x00\xac\x8c/\x8c\x8e^V\x05\x00X\x01###\xaf\xbez\xee\xc2\x85\x0bs\xee\xd9\xd9\xd9\xf9\xc0\x03\x0f\x04\x7f*\x1a4\x91\xeb\xd7\xaf\xbf\xfa\xea\xab3n:z\xf4\xa8\xfa@\xc4\xfe\xbd\x07/\xeb\xa3\xa3\xa3\x13\x13\x13\x8d\xec\xdf\xd1\xd1\xf1\xd8c\xfb\x1f\x7f\xfcq\xefj\x03\xc0\n\xd0\xe5\r\x00+\xa4\xab\xe2\xd6\xad[CCC\xff\xfe\xef\xff\xef\xfd\xf7\xdf\x9fm\xcf\xd1\x8a\xb6\xb6\xb6\xce\xce\xce\xe0K\xda\xdb\xdbU\x0f\x00V\xdd\xcd\x9b7/]\xbat\xf1\xe2\xc5\xe0\xd5\xbc\x91\xfd\x83\x97\xf2={\xf6\xf4\xf5\x1d\xd9\xb6m\x9b\xea\x01\xc0\x8a\xd1\xe5\r\x00\xab\xe3\x9dw.\xff\xf6\xb7\xbf}\xf3\xcd7\xe7l\x10\xdb\xb0aCWWWgg\xe7\xc6\x8d\x1b\xd5\r\xd6,]\xde\x10U\xc1+\xf5\xe8\xe8\xe8\xc5\x8b\x17\xaf^\xbd\xda\xe0\x97\xa4R\xa9C\x87\x0e\xed\xdf\xbfO\xf5\x00`\xe5\x89\xbc\x01`\x95\x9d9sfd\xe4B#c@\xef\xbd\xf7\xde\x9d;wvvvZ\xed\n\xd6 \x917DOx\xdd\xd5\xa5K\x97\x1a\xdc\x7f\xe3\xc6\x8d\xdd\xdd\xdd\x8f?~\xd0\x15Z\x00\xb0\x8a\x0c6\x01\x80U\xf6T\xc5\xf5\xeb\xd7\xdf|\xf3\xcd\xdf\xfc\xe6\xff\xde\xb8qc\xb6=\xafV\x04w\xc2I\xdf\x81\xad[\xb7l\xdd\xba\xb5\x89\xfec\xdfy\xe7\xb3\xf7\xda\xef\xbf\xffkM\xf4\x9d\xdf\x98\xf4?\xe1}eW\xf6\x19\xb5\xb5\xdd1\xdb&e\xf7\xdb\xae\xec\xcdU\xf6+W\xae\xbe^\xf1\x97\xbf\xfc\xa5\x91\xc7Y\xbf~\xfd\xee\xdd\xbb\x0f\x1f\xee\xdd\xb1c\x87\x03\x1b\x00Xu"o\x00X\x13\xda\xdb\xdb\x9f\xae(\x14\n\xf9|~xx\xa4\\.\xcf\xb6\xf3\xa5\x8a\xb6\xb6\xb6G\x1ey\xa4\xa7\xa7\xa7\xa3#\xd9\x8c\xff\xc9w\xdduW\x13}\xb7\xb7n\xfd\xb9z\xff\x8e;\xda\x9a\xeb\x9bW\xf6\x95\xb1~}\\\xd9\xfd\xb6+{S\x97\xfd\xa3\x8f>\xfa\xdd\xef\x86\x07\x07\x07K\xa5R\x83\x8f\x90\xc9te2\x99\xbd{\xf7\xba\x00\x0b\x00\xd6\x0e\x917\x00\xac-\xe9\x8a\xe0N%\xf8\x0e\x8c\xcc\xb6\xe7\xc4\xc4\xc4PE"\x91\x08\xce\xb7{zr\xc1\x1d\x05\x04\x80y\t^O/^\xbc\xf8\xce;\xef\\\xbbv\xad\xc1/\t^ps\xb9\xdc\xa3\x8f\xee\xdd\xbcy\xb3\x02\x02\xc0Z#\xf2\x06\x805*[Q*\x95\xe6\xec8\x0b6\rV$\x93\xc9\xe0K\xf6\xec\xc9\xc8\xbe\x01\xa0\xber\xb9\xfc\xbb\xdf\xfdndddtt\xb4\xc1/\x89\xc7\xe3\x99LWoo\xef\xf6\xed\xdb\x15\x10\x00\xd6,\x917\x00\xaci\x89D\xa2\xa7\'\x17\xdc\xc6\xc6\xc6\xf3\x15u\x06\x9e\x8c\x8f\x8f\x9f\xae\x08\xb3\xef\x83\x07\xb3\xc1\xc9\xb9\x1a\x02@\xad9\xaf\xa3\x9a.\x93\xe9\xea\xee\xee\xde\xb5k\x97\xea\x01\xc0\xda\'\xf2\x06\x80\xe6\xd0\xd1\x91\xec\xe8x\xee\xd8\xb1\xe7^\x7f\xfd\xf5\xd7^{\xfd\xd2\xa5K\x13\x13\x13\xb3\xed\\\xcd\xbe\xc3\x19\xa3\x01\xd97\x00-n\xf8S\xf5V\xcb\x98"\x99L\xf6\xf4\xe4\x8c\xea\x06\x80\xe6"\xf2\x06\x80&\xb3\xaf\xe2\xd6\xad?\x0f\r\xe5\xff\xeb\xbf.\xfe\xfe\xf7\xbf\xaf{z?R\xe9b{E\xf6\r@kZ@\xd2mT7\x0045\x917\x004\xa5\r\x1b\xeez\xaa"8\x81?\x7f~r\xe0\xc9\xf8\xf8x\xdd\x13~\xd97\x00-daIw\xf0\xfax\xe8P\xb7Q\xdd\x00\xd0\xd4D\xde\x00\xd0\xdc\xe2\xf1x8\xec\xbb\x91\x85.c\xb2o\x00"m\x01Iw[[\xdb\x03\x0f<\x90\xcb}s\xe7\xce\x9d\n\x08\x00\x11 \xf2\x06\x80\x88\x98\xb2\xd0ep\xba/\xfb\x06\xa0E, \xe9\x0e^\xf5\x1ez\xe8\xc1\xdd\xbbw?\xf6\xd8c\n\x08\x00Q"\xf2\x06\x80\xa8\xa9.t\xb9\xb0\xec;\x9dN\'\x12\te\x04`\x8d+\x97\xcb\x85Ba\xbeIw x\xbd\xeb\xee\xee\xde\xb5k\x97\x1a\x02@$\x89\xbc\x01 \xb2\xa6d\xdf\x81\xfa\x89\xc0\xed\xec;\x96L&\xb3\xd9\xec\x9e=\x19\xd97\x00kM\xf0ZV\xed\xe9\x9e\xd7\x17\x86\xef\xec\xee\xdd\xbb\xb7\xad\xadM\x19\x01 \xc2D\xde\x00\x10}\xd5\xec\xbb\xc1\xeb\xbe\xc7\xc7\xc7OW$\x93\xc9p\xe6I\xf0\x08\xca\x08\xc0*\n\x97\xac(\x16\x0b\x92n\x00\xa0>\x917\x00\xb4\x900\xbf\x8e5<\xf3t\xbcb`` \x91HT\xbe\xb4+\x9dN+#\x00+fll\xbcP(\xe4\xf3\xf9\xe0\xf5h\x9e/y\x92n\x00hQ"o\x00hE\xd5\xec\xbb\xc1y\xdf\xc1\xd6\xc1\x8ax<^\x1d\xf9m\xb9K\x00\x96IeH\xf7\xc8\x9c/O3\xbd\xc0I\xba\x01\xa0\xd5\x89\xbc\x01\xa0\xa5\xcdw\xad\xcbr\xb9\x9c\xcf\x0f\x05\xb7\xd8\xedX\xc1r\x97\x00,\x89\x05/GY};\xf6\xc1\x07\x1f\x94t\x03\x00"o\x00`\xd2\x94\xec\xbbP(\xccy\ty\xedr\x97F~\x03\xb00\x0b\x1e\xd2\x1d&\xdd{\xf7\xee\xdd\xb5k\x972\x02\x00U"o\x00\xe0s\xc2\xec;v;\x83hd|ju\xe4\xb7\xb1\'\x004h\xc1\xa3K\xc2\xe5%\x1ey\xe4\x91\xaf\x7f\xfd~e\x04\x00\xa6\x13y\x03\x003K$\x12==\xb9\xe0V*\x95\xaaW\x9a\xd7\xff\x92\xda\xb1\'\xa9T*\x93\xc9\xec\xd9\x931\xf6\x04\x80\xea\xcbD\xb8zr\xa1P\x9c\xd7\xe8\x92X\xe5\x8a\xa2t:}\xe8P\xf7\xf6\xed\xdbU\x12\x00\xa8C\xe4\r\x00\xcc!\x91Hd+\xc2\xa8"\xec\xcb\x9b3\xaa(V\x9c>}:l\xc7K\xa7S\xe1\x82\x99\x00\xb4\x9a\xb1\xb1\xf10\xe9\x9e\xf3\xb2\xa1\xe9\xc27P\x1f}t\xef\xe6\xcd\x9bU\x12\x00h\x84\xc8\x1b\x00hT<\x1e\x0f\xb3\xef\xd8|.H\x0fv\x18\xac\x08\xeewvv\xde{\xef\xbd;v\xechooWO\x80\x08\x0b\xaf\x10j\xf0]\xd2\xe9/7\x99LW:\x9d~\xe4\x91G\xd6\xad[\xa7\x98\x00\xc0\xbc\x88\xbc\x01\x80\x85HW\x84\xcb]\x16\n\x85FF~\x07F+\x82;\x1b6l\xd8\xb5\xebaS\xbf\x01"&\xcc\xb8\x1bY\x03y\xba\xf0\xaa\xa0\x07\x1f\xdci9J\x00`1D\xde\x00\xc0\xa2T\x96\xbbL\xf6\xf4\xe4\xe65\xf6\xe4\xd6\xad[\xd5\xa9\xdf\xc9d2\x9c|\x92N\xa7\xd5\x13\xa0\xe9\\\xbf~\xfd\xca\x95+W\xaf^\r\xdf\xd4\x9c\xafpt\xc9\xde\xbd\x8fl\xd9\xb2E1\x01\x80\xc5\x13y\x03\x00Kc\xfa\xd8\x93\x06\xbb\xfc\xc6+\x06\x06&\x1f!\x9dN\xa5Ri\x8b^\x02\xacq\xd5\xb79\x0b\x85\xe2\x9c\x13\xaef|\xc9\xc8d\xba2\x99\xcc\xce\x9d;\x8d.\x01\x00\x96\x96\xc8\x1b\x00Xz\xe1\xd8\x93\xd8\xedY\xae\x95X\xa48g\xebw%@\x19\tn\xe1\xa2\x97a\xdfw&\x931\xf9\x04`\x8d\x08\x9f\xcf\x176\xb7$v\xfb\xb2\x9eG\x1f\xdd\xbb}\xfbv\xc5\x04\x00\x96\x89\xc8\x1b\x00XF\x89D\xa2\xb6\xf5\xfb\xdc\xb9\xf3\x97/_~\xff\xfd\xf7\xe7\xfc\xc2R\xa9t{\xf2\xc9+\xc9d\xb2\x12\xa1\xa7\x0c\xfe\x06Xya+\xf7\xe4\xff\x8a\xc5\x05|\xb9\xb5(\x01\x80\x15&\xf2\x06\x00VH\xb5\xf5\xfb\xda\xb5ko\xbd\xf5\xd6\x1f\xfe\xf0\x87FZ\xbfc\xb7\'\x9f\x0c\x0e\x0e\xc6*\x1d\x82a\xfc\x9d\xc9d\x94\x14`\x99\x8c\x8d\x8d\x87sK\x16\x16s\xc7nO\xe8~\xe8\xa1\x075t\x03\x00+L\xe4\r\x00\xac\xb4{*\x9ez\xea\xa9\xd8\xfcS\x95\xda\xf8{r\xec\xf7\xed\xeeoU\x05X\xa4\xe0\t\xb9\xf2l\\h\xf0\xfd\xc8\xe96n\xdc\xb8o\xdf\xbe\xe0i\xd9\x84n\x00`\x15\x89\xbc\x01\x80\xd5\xd4\xd1\x91\x0cn\xb1\xd8\x91r\xb9\x1c^;?<<\xdc\xe0Jh\xc5\x8a\x81\x81\xc9\xfba\xfc\x1d<\x94\xe1\'\x00\x8d\x0b\x9fx\xc7\xc7\xc7\x16\x1cs\x07O\xb9\xc9d\xb2\xabk\xf7\x9e={\xda\xdb\xdb\x95\x14\x00Xu"o\x00`M\xa8\x0c{\x9dt\xec\xd8s\xe1\xa2\x97\x95u/G\x1a\x8c`\xc2\xf8;\xbco\xf67@\x1d\x8b\x9c\xcd\x1d\n\xe7\x96\xec\xdc\xf9\xc0\x8e\x1d;\x94\x14\x00XSD\xde\x00\xc0\x9aS\xbb\xe8\xe5\x02.\xb4\x9f2\xfb;l\xfd\x0e\x04\x0f\xab\xb6@\x0b\xaa^F366\xb6\x98\x98;xF\xad\xc4\xdc;\xbf\xfe\xf5\xfbU\x15\x00X\xb3D\xde\x00\xc0\x9a\x16N>\xe9\xe9\xc9\xc5n\xc7\xdf\xc3\xc3\xc3\x8dG6a\xfc\x9d\xcf\x0f\xc5*Iz\xf0P\xe1\x00\xf0\xca4\x15\x80\xc8\xaa^.\x13?\xff$V\xd3\x00\xde\xd1\xd1a\x028\xb0v\x04Oka\xc6\xbd\xf8V\xee\xf0\xb9.x\x96\x13s\x03\x00\x11#\xf2\x06\x00"%\x8c\xbfkg\x7f\x17\x8b\x93!x\xa9Tj\xfcAj\x1b\xc0\xc3\t\xe0[\xb6l\xdd\xb4i\xd3\x8e\x1d;T\x18Xa\xb7\xe7q\x8f-r*w(|K/\x9dNU\xde)\x04\x00\x88 \x917\x00\x10Y\xb5\xb3\xbf\xc3\x95\xdc\xc2\x10|^\x99Q8\x01\xbc\xfaa{{{2\x99\xac\xb4F&\x05F\xc0r\xb8v\xed\xda\xe8\xe8\xe5\xe0\xf9j\xf1\xe3Jb5+\xf7\xee\xdc\xf9\x80\xf7\xed\x00\x80V \xf2\x06\x00ZB"\x91\xc8N\x9a\xbc_\x9d\x0c0\xdf\xf1\xdf\x81\xeb\x15\xc3\xc3\xc3\xe1\x87\xe1\x10\xf0p\x02\xb8\x04\x1cX\x98\xb1\xb1\xf1\xb7\xdf~\xfb\xf2\xe5\xcb\xc1\xd3\xcb\xd5\xabW\x17\xff\x80\xe1`\xee\xe0yi\xe7\xce\x9d[\xb6lQa\x00\xa0\xa5\x88\xbc\x01\x80\x96\x13\x8f\xc7k\xc7\x7f\xdfn\xfd\x9e\x0c\xc1\xe75\xff$v{\x08x,\xf6\xe9\x10\xf0\xda\x04<\xf8_\xf0\x17\xa960]\xf0\x9cSYyri\xfa\xb8\xc3\xa7\xb5\xea\xfa\x93\xde~\x03\x00Z\x9c\xc8\x1b\x00hu\xe1\xfc\x93\xf0~\xb9\\\xae\x9d\x7f2\xdf\xa5\xe1\xa6$\xe0\xe1<\x81j\x02n%LhM\xd5+KJ\xa5\xebK2\x8f;\xa4\x95\x1b\x00`F"o\x00\x80\xcf\xc4\xe3\xf1LE\xb5\x01<\\2n\xb4b\xbe\x8f\x16\xce\x01\x1f\x1e\x1e\xa9>x\x98\x7fwt$\x13\x89\x84NL\x88\xaa\xca\x92\xb9\xd7\xc37\xcf\xa6\xac\x07\xb0\x18\x95\xe7\x8d\x94IJ\x00\x00\xf5\x89\xbc\x01\x00f\x156\x80\x87\x13\xc0\x03\x17.\\\x18\x1d\xfd\xe3\x7f\xff\xf7{\xd7\xae\xbd\xb7\x80>\xcdr\xb9\\\xac\xa8~\xa6\xb6\r<\x91h\xaf6\x9b\x03M\xa4T*]\xbf~}\xc9\x9b\xb8k\x9f"\xd2\xe9\xd4}\xf7\xdd\xb7n\xdd:\xd5\x06\x00\x98\x93\xc8\x1b\x00\xa0Q\xbb+\xaa\x1f\x86#P\xc26\xf0\x85\x85\\S\xda\xc0c\xb7\xa7\x81\'\x12\xed\xe9t\xaa\xbd\xbd\xdd,\x14Xk\xc2)%\x95>\xee\xd2RM\xe2\xae\xda\xb8q\xe3=\xf7\xdc\xd3\xd9\xf9\xd5\x87\x1f~X\xc6\r\x00\xb00"o\x00\x80\x05\xba\xbd\x06\xe6\xa7\x16\x9f\x80\xc7>\x9b\x06\x1e\x1b\x18\xf8\xf43\xc9d\xb2\xbd=\xa1\x13\x1cVEm\x07\xf7\xf5\xeb\xa5\xa5\r\xb8c5}\xdc_\xfbZ\xe7W\xbf\xfa\xd5;\xef\xbcS\xcd\x01\x00\x16I\xe4\r\x00\xb04\xa6$\xe0\xd5\xf8{\x91}\xa0a\x08>\xa5\x13<\x1e\x8f\x07\x7fW\xa5\x0b<\xd1\xd1\xd1\x11|\xa8\xfe\xb0x\x85B\xa1\xd2\xc4=\xf9\x8f\xf7\xc3\x0f\xcbK\x1ep\xc7>\x7f%\x87>n\x00\x80\xe5 \xf2\x06\x00X\x16S\xe6\x80\x873\x10\xaa9\xf8b\x96\xb3\x0b\xdb\xc0\xa7\x84q\xa9T\xaa\x92\x80O\xb6\x81\x87\x81\xb8\x1f\x01\xd4\x11\xfc3,\x97?,\x14\x8a\xe1\xa0\x92\xe0\x9fUpg\xc9\xff\x96\xdaEk\xc3k5T\x1e\x00`\xb9\x89\xbc\x01\x00VB\xa2"\x93\xc9T?\x13\x0eB\t\xa3\xf0\xc5\xc7m\x9f_\x17sR\x98\xb5\xb5\xb7\'>\xfe\xf8o\xed\xed\xedmmm\xdb\xb6m\xf3\x83\xa0\x05\x05\xff\xd6*\x7f~\x9an\x873\xf4\x97\xe9\xef\xaam\xe2\xfe\xf2\x97\xbf\xbce\xcb\x16\xf5\x07\x00Xa"o\x00\x80\xd51e\x10J\x18\xc6-\xe1\xc8\xe0\xe0\x01\xa7\xe7\xe0?\xfd\xe9OS\xa9\xd4\x9dw\xc6\x93\xc9\xc9q(\x95\x96\xf0;u\x9e\x12\r\xa5R\xe9\xca\x95+\xb7n\xdd\xbaYq\xe6\xcc\x99e\xea\xdd\xae\xaa\x1d\xb5\xbfm\xdb\xb6\x1d;v\xf8)\x00\x00\xac:\x917\x00\xc0\x9a\x10N#\xa9\r\xc1\xa7\xac\x9b\xb7T\xe1]\x98\x82\xd7\x0e\x07\x8f\xddn\t\x17\x85\xd3\x14\xc2\x7f\x1a\x95?\xabw\x97\xb1q\xbb\xcaZ\xb2\x00\x00MA\xe4\r\x00\xb0F\x85\xb3P\xa6w\x82Wf\x10\x97\x0b\x85\xc2\x12\xc6|aKxlZ\x14\x1e\xabL\t\x8fUz\xd2c\x95\x01\xe5\xf1x\xbc\xbd25\xdc\x0f\x88e\x15\xfe\xb6\xc7*\x03Ib\x93#\xec\'\xd7\x93\\\xee\xae\xed\xaa\xea\\\xa0pD\xc9\xb6m\xdb\xb6n\xdd\xea\x87\x02\x00\xd0\x14D\xde\x00\x00M\xe3\xf3\x9d\xe0G\xc2OV\x06\x82_\x0f\xff\\\xc2f\xf0\xaa0\n\x9fq\xd0J\x98\x86wtL6\x86\x87\xbd\xe1\xd5\x0f\xfd\xb0hD8e;\xec\xd7\xae~\xb8b\xb9vU\xb5}\xbb\x92q\'\xee\xbb\xef\xbeu\xeb\xd6\xf9\xe9\x00\x004)\x917\x00@s\xeb\xe8\x98\\.\xafva\xccX%:\xac4\xc9N\xe6\xe0\xe3\xe3W\xde{\xef\xbd\x89\x89\x89%\xff\xab\xeb\xa4\xe1a\x93l\xac&\x01O\xa7S\xe1\xa6\xda\xbeu\xa2\xadrE\xc2\x87\xb7\xef\x94c5\x19\xf7\n\xcc!\x99Q\xf5\xaa\x85\xf0M\x1a\xed\xdb\x00\x00\xd1#\xf2\x06\x00\x88\xa00V\x9e\x92\x83\x8f\x8c\x8c\xac_\xbf\xbeP(\x86##\x82?\xc7\xc7\xc7\x97\xe9\x1b\xa8NJ\xa9\x06\xe2\x03\x03\x9f\xdb\xa1\x9a\x89\x87\x03\xc4o\x7f\xdb\x9f\xc6\xe2Z\xc5\xd7\xbe0\xbc\x8e\xd5\xc4\xd9\xe1u\x06\xb1UM\xb4\xab\xda\xda\xda\xee\xbb\xef\xbep2I\xd8\xbb\xfd\x95\xaf|%\xf8\xfd\xf7\x83\x03\x00\x88<\x917\x00@\xab\xe8\xea\xea\x8aMk\xb2^\xad\x95\x00\xab\x99x\xacf\x80\xf8\x94X\xfcpjt\xfe\xf1\xc7\x1f\xdf\xbcy\xf3\xd3\x83\xec/|\xe1\x93O>\xa9n\xda\xbau\xeb\x82\xbf\xc3p\xec\xf5l[+\xc9\xf5\x0cM\xd6\x96|\x04\x00\xa0e\x89\xbc\x01\x00\x00\x00\x00\x88\x88/*\x01\x00\x00\x00\x00\x00\xd1 \xf2\x06\x00\x00\x00\x00 "D\xde\x00\x00\x00\x00\x00D\x84\xc8\x1b\x00\x00\x00\x00\x80\x88\x10y\x03\x00\x00\x00\x00\x10\x11"o\x00\x00\x00\x00\x00"B\xe4\r\x00\x00\x00\x00@D\x88\xbc\x01\x00\x00\x00\x00\x88\x08\x917\x00\x00\x00\x00\x00\x11!\xf2\x06\x00\x00\x00\x00 "D\xde\x00\x00\x00\x00\x00D\x84\xc8\x1b\x00\x00\x00\x00\x80\x88\x10y\x03\x00\x00\x00\x00\x10\x11"o\x00\x00\x00\x00\x00"B\xe4\r\x00\x00\x00\x00@D\x88\xbc\x01\x00\x00\x00\x00\x88\x08\x917\x00\x00\x00\x00\x00\x11!\xf2\x06\x00\x00\x00\x00 "D\xde\x00\x00\x00\x00\x00D\x84\xc8\x1b\x00\x00\x00\x00\x80\x88\x10y\x03\x00\x00\x00\x00\x10\x11"o\x00\x00\x00\x00\x00"B\xe4\r\x00\x00\x00\x00@D\x88\xbc\x01\x00\x00\x00\x00\x88\x08\x917\x00\x00\x00\x00\x00\x11!\xf2\x06\x00\x00\x00\x00 "D\xde\x00\x00\x00\x00\x00D\x84\xc8\x1b\x00\x00\x00\x00\x80\x88\x10y\x03\x00\x00\x00\x00\x10\x11"o\x00\x00\x00\x00\x00"B\xe4\r\x00\x00\x00\x00@D\x88\xbc\x01\x00\x00\x00\x00\x88\x08\x917\x00\x00\x00\x00\x00\x11!\xf2\x06\x00\x00\x00\x00 "D\xde\x00\x00\x00\x00\x00D\x84\xc8\x1b\x00\x00\x00\x00\x80\x88\x10y\x03\x00\x00\x00\x00\x10\x11"o\x00\x00\x00\x00\x00"B\xe4\r\x00\x00\x00\x00@D\x88\xbc\x01\x00\x00\x00\x00\x88\x88\xff\x0f\xc2\x88\x8f\xa6R\xa7\xe1\xa5\x00\x00\x00\x00IEND\xaeB`\x82' diff --git a/fluxclient/laser/laser_base.py b/fluxclient/laser/laser_base.py index 7e9e5d7..00be77d 100755 --- a/fluxclient/laser/laser_base.py +++ b/fluxclient/laser/laser_base.py @@ -10,7 +10,7 @@ from PIL import Image import numpy as np from fluxclient.fcode.g_to_f import GcodeToFcode -from . import Grid +import pkg_resources class LaserBase(object): @@ -286,10 +286,9 @@ def dump(self, file_name='', mode='save'): dump the image of this laser class """ img = Image.fromarray(self.image_map) - tmp = io.BytesIO() - tmp.write(Grid) # TODO: change file path + grid = pkg_resources.resource_filename("fluxclient", "assets/grid.png") # magic number just for alignment, don't really important - img_background = Image.open(tmp).resize((img.size[0] + 66, img.size[1] + 66)) + img_background = Image.open(grid).resize((img.size[0] + 66, img.size[1] + 66)) img_background.paste(img, (33, 33), img.point(lambda x: 255 if x < 255 else 0)) img = img_background if mode == 'save': diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index bf97528..26ca936 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -139,7 +139,7 @@ def upload_image(self, buf): self.image = image_bytes ######################### fake code ################################### if environ.get("flux_debug") == '1': - with open('_preview.png', 'wb') as f: + with open('preview.png', 'wb') as f: f.write(image_bytes) ############################################################ From 2c383f22313bb310d2bb71d1e730aff3d35692e2 Mon Sep 17 00:00:00 2001 From: Yen Date: Tue, 5 Jan 2016 16:37:40 +0800 Subject: [PATCH 52/53] assets file: grid.png (see 0a8edc00a9b7f5aeb5737a46a60f6f325bfd1cc7) --- fluxclient/assets/grid.png | Bin 0 -> 69551 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fluxclient/assets/grid.png diff --git a/fluxclient/assets/grid.png b/fluxclient/assets/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6474e541be8f41ebe9117138a0439930e6c944 GIT binary patch literal 69551 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 Date: Tue, 5 Jan 2016 16:59:15 +0800 Subject: [PATCH 53/53] increase version minor --- fluxclient/__init__.py | 2 +- fluxclient/printer/stl_slicer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxclient/__init__.py b/fluxclient/__init__.py index dcd94ac..48cd1eb 100644 --- a/fluxclient/__init__.py +++ b/fluxclient/__init__.py @@ -7,5 +7,5 @@ def check_pcl(): return False -__version__ = "0.8b3" +__version__ = "0.8b4" SUPPORT_PCL = check_pcl() diff --git a/fluxclient/printer/stl_slicer.py b/fluxclient/printer/stl_slicer.py index 26ca936..87c6b3a 100644 --- a/fluxclient/printer/stl_slicer.py +++ b/fluxclient/printer/stl_slicer.py @@ -249,7 +249,7 @@ def gcode_generate(self, names, ws, output_type): try: points, faces = self.read_stl(self.models[n]) except: - return False, 'can\'t parse %s, may not ba a stl file' % (n) + return False, 'can\'t parse file, may not ba a stl file' m_mesh = _printer.MeshObj(points, faces) m_mesh.apply_transform(self.parameter[n]) m_mesh_merge.add_on(m_mesh)