From 1db39c3d9ec7ee7d1afc3839b3ca0f2b95243bbb Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 1 Mar 2012 16:41:27 +0100 Subject: [PATCH 001/108] adding files for the skeleton of the classes and test --- deformations/CMakeLists.txt | 3 + deformations/CPointFunctorAdapter.h | 149 +++++++++++++++ deformations/FrontierEvolver.h | 263 ++++++++++++++++++++++++++ deformations/FrontierEvolver.ih | 116 ++++++++++++ deformations/LocalBalloonForce.h | 135 +++++++++++++ deformations/LocalBalloonForce.ih | 87 +++++++++ deformations/deformationFunctions.h | 20 ++ deformations/testLocalDeformation.cpp | 194 +++++++++++++++++++ 8 files changed, 967 insertions(+) create mode 100644 deformations/CPointFunctorAdapter.h create mode 100644 deformations/FrontierEvolver.h create mode 100644 deformations/FrontierEvolver.ih create mode 100644 deformations/LocalBalloonForce.h create mode 100644 deformations/LocalBalloonForce.ih create mode 100644 deformations/testLocalDeformation.cpp diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 8c9fd0b..87c68da 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -25,6 +25,9 @@ LINK_DIRECTORIES(/usr/lib/) ADD_EXECUTABLE(3dVolViewer 3dVolViewer) TARGET_LINK_LIBRARIES(3dVolViewer ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) +ADD_EXECUTABLE(testLocalDeformation testLocalDeformation) +TARGET_LINK_LIBRARIES(testLocalDeformation ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) + ADD_EXECUTABLE(testDisk testDisk) TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) diff --git a/deformations/CPointFunctorAdapter.h b/deformations/CPointFunctorAdapter.h new file mode 100644 index 0000000..a0fa298 --- /dev/null +++ b/deformations/CPointFunctorAdapter.h @@ -0,0 +1,149 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file CPointFunctorAdpter.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/03/01 + * + * Header file for concept CPointFunctorAdpter.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(CPointFunctorAdpter_RECURSES) +#error Recursive header files inclusion detected in CPointFunctorAdpter.h +#else // defined(CPointFunctorAdpter_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define CPointFunctorAdpter_RECURSES + +#if !defined CPointFunctorAdpter_h +/** Prevents repeated inclusion of headers. */ +#define CPointFunctorAdpter_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include +#include "DGtal/base/Common.h" + +#include "DGtal/kernel/CPointFunctor.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // class CPointFunctorAdpter + /** + Description of \b concept '\b CPointFunctorAdpter'

+ @ingroup Concepts + @brief Aim: Defines the concept describing a point functor, + adapted from another one, which can be returned by the base() method + and can be set the attach() method. + +

Refinement : + - \t PointFunctor + +

Nested types : + - \t PointFunctor : a model of CPointFunctor + +

Notation + - \t X : a model of CPointFunctorAdpter + - \t x : object of type X + +

Definitions + +

Valid expressions and semantics
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\b Name \b Expression \b Type requirements \b Return type \b Precondition \b Semantics \b Postcondition \b Complexity
underlying point functor x.base() const PointFunctor& returns the underlying point functor
underlying point functor x.attach(const PointFunctor&) set the underlying point functor
+ +

Invariants
+ +

Models
+ + +

Notes
+ + @tparam X the type that should be a model of CPointFunctorAdpter. + */ + template + struct CPointFunctorAdpter : CPointFunctor + { + // ----------------------- Concept checks ------------------------------ + public: + // Inner types + typedef typename X::PointFunctor PointFunctor; + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + + // Methods + BOOST_CONCEPT_USAGE( CPointFunctorAdpter ) + { + ConceptUtils::sameType( myPF, myX.base() ); + myX.attach( myPF ); + } + // ------------------------- Private Datas -------------------------------- + private: + X myX; + const PointFunctor& myPF; + + // ------------------------- Internals ------------------------------------ + private: + + }; // end of concept CPointFunctorAdpter + +} // namespace DGtal + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined CPointFunctorAdpter_h + +#undef CPointFunctorAdpter_RECURSES +#endif // else defined(CPointFunctorAdpter_RECURSES) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h new file mode 100644 index 0000000..0d0edc6 --- /dev/null +++ b/deformations/FrontierEvolver.h @@ -0,0 +1,263 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file FrontierEvolver.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/03/01 + * + * Header file for module FrontierEvolver.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(FrontierEvolver_RECURSES) +#error Recursive header files inclusion detected in FrontierEvolver.h +#else // defined(FrontierEvolver_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define FrontierEvolver_RECURSES + +#if !defined FrontierEvolver_h +/** Prevents repeated inclusion of headers. */ +#define FrontierEvolver_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include + +#include "DGtal/base/Common.h" +#include "DGtal/images/CImage.h" +#include "DGtal/kernel/CPointFunctor.h" +#include "CPointFunctorAdapter.h" +#include "DGtal/kernel/CPointPredicate.h" + +#include "DGtal/topology/SurfelAdjacency.h" +#include "DGtal/topology/helpers/FrontierPredicate.h" +#include "DGtal/topology/LightExplicitDigitalSurface.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // template class FrontierEvolver + /** + * Description of template class 'FrontierEvolver'

+ * \brief Aim: This class is a way of deforming an image of labels + * around a connected contact surface between two regions, + * according to a velocity field, whose computation is + * delegated to a instance of a model of CLocalVelocity + * + * At each step, a signed distance function is built. + * The points are sorted according to their time of zero-crossing + * (ie. their distance to the interface divided by their velocity) + * so that they are flipped from a region to another one by one and + * in order, until a time greater than a threshold is reached or + * until a point predicate (possibly based on topological properties) + * returns false. + * + * @tparam TKSpace a model of CCellularGridSpaceND + * @tparam TImage a model of CImage + * @tparam TFunctor a model of CPointFunctorAdapter + * @tparam TPredicate a model of CPointPredicate + */ + template + class FrontierEvolver + { + + + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TImage::Point>::value )); + + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TFunctor::Point>::value )); + + BOOST_CONCEPT_ASSERT(( CPointPredicate )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TPredicate::Point>::value )); + + // ----------------------- Types ------------------------------ + public: + + /// Khalimsky space + typedef TKSpace KSpace; + typedef typename TKSpace::Point Point; + + /// Image of labels + typedef TImage Image; + + /// Frontier + typedef FrontierPredicate SurfelPredicate; + typedef LightExplicitDigitalSurface Frontier; + /// Surfel + typedef typename Frontier::Surfel Surfel; + typedef typename Frontier::SurfelConstIterator SurfelIterator; + + + /// Point functor for the mapping velocity-points + typedef TFunctor Functor; + /// Point predicate + typedef TPredicate Predicate; + + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * @param aK khalimsky space where the digital frontier is defined + * @param aI an image of labels + * @param aS a surfel lying between two regions of @a aI + * @param aF a point functor mapping a velocity to points + * @param aP any point predicate + * @param aW maximal width of the deformation band (1.0 by default) + */ + FrontierEvolver(const KSpace& aK, Image& aI, Surfel& aS, + const Functor& aF, const Predicate& aP, const double& aW = 1.0); + + /** + * Destructor. Does nothing. + */ + ~FrontierEvolver(); + + /** + * Deform the image of labels around the digital frontier + * + * @return 'true' if the maximal time is reached, + * 'false' if the deformation stopped because of + * the point predicate. + */ + bool update(); + + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const; + + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + + // ------------------------- Protected Datas ------------------------------ + protected: + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Constant reference on the khalimsky space + */ + const KSpace& myKSpace; + /** + * Reference on the image of labels + */ + Image& myImage; + /** + * Reference on the starting surfel of the digital frontier + */ + Surfel& mySurfel; + /** + * Constant reference on the functor + */ + const Functor& myFunctor; + /** + * Constant reference on the predicate + */ + const Predicate& myPointPred; + /** + * Maximal width of the band whithin which + * the frontier is moving + */ + double myW; + + /** + * Surfel predicate telling whether a given surfel + * belongs to the frontier or not + */ + SurfelPredicate mySurfelPred; + /** + * (implicit) digital frontier + */ + Frontier myFrontier; + + // ------------------------- Hidden services ------------------------------ + protected: + + + /** + * Copy constructor. + * @param other the object to clone. + * Forbidden by default. + */ + FrontierEvolver ( const FrontierEvolver & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + * Forbidden by default. + */ + FrontierEvolver & operator= ( const FrontierEvolver & other ); + + private: + + + + // ------------------------- Internals ------------------------------------ + private: + + }; // end of class FrontierEvolver + + + /** + * Overloads 'operator<<' for displaying objects of class 'FrontierEvolver'. + * @param out the output stream where the object is written. + * @param object the object of class 'FrontierEvolver' to write. + * @return the output stream after the writing. + */ + template + std::ostream& + operator<< ( std::ostream & out, const FrontierEvolver & object ); + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "FrontierEvolver.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined FrontierEvolver_h + +#undef FrontierEvolver_RECURSES +#endif // else defined(FrontierEvolver_RECURSES) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih new file mode 100644 index 0000000..c2d12ec --- /dev/null +++ b/deformations/FrontierEvolver.ih @@ -0,0 +1,116 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file FrontierEvolver.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/03/01 + * + * @brief Implementation of inline methods defined in FrontierEvolver.h + * + * This file is part of the DGtal library. + */ + + + +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Standard services ------------------------------ + + +template +inline +DGtal::FrontierEvolver +::FrontierEvolver(const KSpace& aK, Image& aI, Surfel& aS, + const Functor& aF, const Predicate& aP, const double& aW) + : myKSpace( aK ), myImage( aI ), mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), myW( aW ), + mySurfelPred( myKSpace, myImage, + myImage( myKSpace.sCoords( + myKSpace.sIndirectIncident( mySurfel, *myKSpace.sOrthDirs( mySurfel ) ) ) ), + myImage( myKSpace.sCoords( + myKSpace.sDirectIncident( mySurfel, *myKSpace.sOrthDirs( mySurfel ) ) ) ) ), + myFrontier( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ) +{ + ASSERT( myW > 0 ); ASSERT( myW <= 1.0 ); + //to do internal function so that initialization is more readable +} + +template +inline +DGtal::FrontierEvolver::~FrontierEvolver() +{ +} + + +template +inline +bool +DGtal::FrontierEvolver::update() +{ +/* + init(); + order(); + evolve(); +*/ + return false; +} + + +template +inline +void +DGtal::FrontierEvolver::selfDisplay ( std::ostream & out ) const +{ + out << "[FrontierEvolver]\n"; + out << "\n"; +} + +template +inline +bool +DGtal::FrontierEvolver::isValid() const +{ + return true; +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Implementation of inline functions // + +template +inline +std::ostream& +DGtal::operator<< ( std::ostream & out, + const FrontierEvolver & object ) +{ + object.selfDisplay( out ); + return out; +} + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/LocalBalloonForce.h b/deformations/LocalBalloonForce.h new file mode 100644 index 0000000..484f7aa --- /dev/null +++ b/deformations/LocalBalloonForce.h @@ -0,0 +1,135 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file LocalBalloonForce.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/03/01 + * + * This files contains several basic classes representing Functors + * on points. + * + * This file is part of the DGtal library. + */ + +#if defined(LocalBalloonForce_RECURSES) +#error Recursive header files inclusion detected in LocalBalloonForce.h +#else // defined(LocalBalloonForce_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define LocalBalloonForce_RECURSES + +#if !defined LocalBalloonForce_h +/** Prevents repeated inclusion of headers. */ +#define LocalBalloonForce_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include "DGtal/kernel/CPointFunctor.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // template class LocalBalloonForce + /** + * Description of template class 'LocalBalloonForce'

+ * \brief Aim: Functor that maps a point + * to a velocity computed from an implicit function + * and some extern data (a balloon force and + * an extern scalar field for weighting). + * + * It is a model of CPointFunctorAdapter + * + * @tparam TFunction type of implicit function, + * which a model of point functor + * @tparam TExternField type of the extern field, + * which a model of point functor too + */ + template + struct LocalBalloonForce + { + typedef TFunction PointFunctor; + typedef TExternField ExternField; + + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename PointFunctor::Point, + typename ExternField::Point>::value )); + + typedef typename PointFunctor::Point Point; + typedef typename PointFunctor::Value Value; + + /** + * Constructor + */ + LocalBalloonForce(const ExternField& aF, const double& aK = 0); + + /** + * Get the underlying function + */ + const PointFunctor& base(); + + /** + * Set the underlying function + */ + void attach(const PointFunctor& aF); + + /** + * Main operator + * @param aPoint any point. + * @tparam TInputPoint type of point + * @return the velocity at @a aPoint. + */ + template + double operator()( const TInputPoint& aPoint ) const; + + private: + /** + * Aliasing pointer to the implicit function + */ + const PointFunctor* myFuncPtr; + /** + * Aliasing pointer to the extern field + */ + const ExternField* myFieldPtr; + /** + * Balloon force + */ + double myK; + + }; // end of class LocalBalloonForce + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "LocalBalloonForce.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined LocalBalloonForce_h + +#undef LocalBalloonForce_RECURSES +#endif // else defined(LocalBalloonForce_RECURSES) diff --git a/deformations/LocalBalloonForce.ih b/deformations/LocalBalloonForce.ih new file mode 100644 index 0000000..55ef82c --- /dev/null +++ b/deformations/LocalBalloonForce.ih @@ -0,0 +1,87 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file LocalBalloonForce.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/02/02 + * + * Implementation of inline methods defined in LocalBalloonForce.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + +#include "DGtal/images/DifferentialOperators.h" + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// +template +inline +DGtal::LocalBalloonForce +::LocalBalloonForce(const ExternField& aF, const double& aK) + : myFuncPtr( NULL ), myFieldPtr( &aF ), myK( aK ) +{ +} + +template +inline +const typename DGtal::LocalBalloonForce::PointFunctor& +DGtal::LocalBalloonForce +::base() +{ + ASSERT( myFuncPtr ); + return *myFuncPtr; +} + +template +inline +void +DGtal::LocalBalloonForce +::attach(const PointFunctor& aF) +{ + myFuncPtr = &aF; +} + +template +template +inline +double +DGtal::LocalBalloonForce +::operator()( const TInputPoint& aPoint ) const +{ + ASSERT( myFuncPtr ); + PointFunctor* tmpPtr = const_cast(myFuncPtr); +//ugly until differential operators are updated + GodunovGradient gradient( *tmpPtr, (myK >= 0) ); + GradientModulus > m(gradient); + double res = + static_cast( myK * myFieldPtr->operator()(aPoint) * m(aPoint) ); + return res; +} +//------------------------------------------------------------------------------ + + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 72032d1..0029236 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -23,6 +23,26 @@ int setSize(TImage& img, const double& threshold = 0) return c; } +template< typename TImage > +void inv(TImage& img, const double& threshold = 0) +{ + + typename TImage::Domain d = img.domain(); + typename TImage::Domain::ConstIterator cIt = d.begin(); + typename TImage::Domain::ConstIterator cItEnd = d.end(); + for ( ; cIt != cItEnd; ++cIt) + { //for each domain point + + typedef typename TImage::Point Point; + Point p( *cIt ); //point p + if (img(p) <= threshold) + img.setValue(p, (typename TImage::Value) 1); + else + img.setValue(p, (typename TImage::Value) 0); + } + +} + template< typename TImage > void initWithBall(TImage& img, const typename TImage::Point& c, const double& r) diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp new file mode 100644 index 0000000..907ee9e --- /dev/null +++ b/deformations/testLocalDeformation.cpp @@ -0,0 +1,194 @@ +#include +#include + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +///////////////////// +#include +#include +#include "DGtal/io/readers/VolReader.h" + +#include "DGtal/images/ImageContainerBySTLVector.h" +#include "DGtal/images/ImageContainerBySTLMap.h" +#include "DGtal/base/BasicFunctors.h" +#include "DGtal/images/ConstImageAdapter.h" + +#include "DGtal/shapes/Shapes.h" + +#include "LocalBalloonForce.h" +#include "FrontierEvolver.h" + + +using namespace Z3i; + +/////////////////////////// useful functions +#include "deformationFunctions.h" +#include "deformationDisplay3d.h" + + + +/////////////////////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + + DGtal::trace.info() << "local evolution "; + DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; + + + + // parse command line ---------------------------------------------- + po::options_description general_opt("Allowed options are"); + general_opt.add_options() + ("help,h", "display this message") + ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) + ("timeStep,t", po::value()->default_value(1.0), "Time step for the evolution" ) + ("displayStep,d", po::value()->default_value(1), "Number of time steps between 2 drawings" ) + ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) + ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) + ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) + ("outputFormat,f", po::value()->default_value("png"), +"Output files format: either (3d to 2d, default) or (3d)" ) + ("withVisu", "Enables interactive 3d visualization before and after evolution" ); + + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help")||argc<=1) + { + trace.info()<< "Local deformation" << std::endl + << "Basic usage: "< --withVisu" << std::endl + << general_opt << "\n"; + return 0; + } + + //Parse options + + //time step + double tstep; + if (!(vm.count("timeStep"))) trace.info() << "time step default value: 1.0" << std::endl; + tstep = vm["timeStep"].as(); + + //iterations + int step; + if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; + step = vm["displayStep"].as(); + int max; + if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; + max = vm["stepsNumber"].as(); + + + //files + std::string outputFiles; + if (!(vm.count("outputFiles"))) + trace.info() << "output files beginning with : interface" << std::endl; + outputFiles = vm["outputFiles"].as(); + + //files format + std::string format; + if (!(vm.count("outputFormat"))) + trace.info() << "output files format is png (3d to 2d) " << std::endl; + format = vm["outputFormat"].as(); + if ((format != "png")&&(format != "vol")) + { + trace.info() << "format is expected to be either png or vol " << std::endl; + return 0; + } + + + //image of labels + typedef ImageContainerBySTLVector LabelImage; + if (!(vm.count("inputImage"))) + { + trace.info() << "you must use --inputImage option" << std::endl; + return 0; + } + string imageFileName = vm["inputImage"].as(); + trace.emphase() << imageFileName <::importVol( imageFileName); + inv(labelImage); + + //3d to 2d display + std::stringstream ss; + ss << outputFiles << "0001"; + writeImage( labelImage, ss.str(), format ); + + //interactive display before the evolution + if (vm.count("withVisu")) displayImage( argc, argv, labelImage ); + + //balloon force + double k; + if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; + k = vm["balloonForce"].as(); + + //algo + //space + KSpace ks; + Domain d( labelImage.domain() ); + ks.init( d.lowerBound(), d.upperBound(), true ); + + //data functions + ImageContainerBySTLVector g( d ); + std::fill(g.begin(),g.end(), 1.0 ); + + //distance map + ImageContainerBySTLMap map( d ); + + //predicate and functor + typedef TruePointPredicate Predicate; + typedef LocalBalloonForce, + ImageContainerBySTLVector > Functor; + Functor f(g, k); + + //getting a bel + Thresholder t( 0 ); + ConstImageAdapter, bool> binaryImage(labelImage, t); + try { + KSpace::SCell bel = Surfaces::findABel( ks, binaryImage, 10000 ); + + trace.info() << "starting bel: " + << bel + << std::endl; + + //frontier evolver + FrontierEvolver e(ks, labelImage, bel, f, Predicate() ); + + for (unsigned int i = 1; i <= max; ++i) + { + std::stringstream s0; + s0 << "iteration # " << i; + DGtal::trace.beginBlock( s0.str() ); + + //update + e.update(); + + if ((i%step)==0) + { + + //3d to 2d display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + writeImage( labelImage, s.str(), format, 1 ); + + } + DGtal::trace.endBlock(); + } + + } catch (DGtal::InputException i) { + trace.emphase() << "starting bel not found" << std::endl; + } + + //interactive display after the evolution + //if (vm.count("withVisu")) displayImage( argc, argv, implicitFunction ); + + + return 0; +} + From 519794f4fb57a87a9a265f5fda7b8ad467728e85 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 1 Mar 2012 17:05:18 +0100 Subject: [PATCH 002/108] adding image of distances as input parameter + little functions for getting points from a surfel --- deformations/FrontierEvolver.h | 52 +++++++++++++++---- deformations/FrontierEvolver.ih | 72 +++++++++++++++++++-------- deformations/testLocalDeformation.cpp | 10 ++-- 3 files changed, 99 insertions(+), 35 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 0d0edc6..226509e 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -74,19 +74,26 @@ namespace DGtal * returns false. * * @tparam TKSpace a model of CCellularGridSpaceND - * @tparam TImage a model of CImage + * @tparam TLabelImage a model of CImage (storing labels) + * @tparam TDistanceImage a model of CImage (storing distance values) * @tparam TFunctor a model of CPointFunctorAdapter * @tparam TPredicate a model of CPointPredicate */ - template + template class FrontierEvolver { - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, - typename TImage::Point>::value )); + typename TLabelImage::Point>::value )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TDistanceImage::Point>::value )); BOOST_CONCEPT_ASSERT(( CPointFunctor )); BOOST_STATIC_ASSERT @@ -106,10 +113,13 @@ namespace DGtal typedef typename TKSpace::Point Point; /// Image of labels - typedef TImage Image; + typedef TLabelImage LImage; + + /// Image of distance values + typedef TDistanceImage DImage; /// Frontier - typedef FrontierPredicate SurfelPredicate; + typedef FrontierPredicate SurfelPredicate; typedef LightExplicitDigitalSurface Frontier; /// Surfel typedef typename Frontier::Surfel Surfel; @@ -129,12 +139,13 @@ namespace DGtal * Constructor. * @param aK khalimsky space where the digital frontier is defined * @param aI an image of labels + * @param aD an image of distance values * @param aS a surfel lying between two regions of @a aI * @param aF a point functor mapping a velocity to points * @param aP any point predicate * @param aW maximal width of the deformation band (1.0 by default) */ - FrontierEvolver(const KSpace& aK, Image& aI, Surfel& aS, + FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, const Functor& aF, const Predicate& aP, const double& aW = 1.0); /** @@ -178,7 +189,11 @@ namespace DGtal /** * Reference on the image of labels */ - Image& myImage; + LImage& myLImage; + /** + * Reference on the image of distance values + */ + DImage& myDImage; /** * Reference on the starting surfel of the digital frontier */ @@ -233,6 +248,20 @@ namespace DGtal // ------------------------- Internals ------------------------------------ private: + /** + * Get inner point. + * @param s a surfel + * @return the inner point + */ + Point getInnerPoint ( const Surfel& s ) const ; + + /** + * Get outer point. + * @param s a surfel + * @return the outer point + */ + Point getOuterPoint ( const Surfel& s ) const ; + }; // end of class FrontierEvolver @@ -242,9 +271,12 @@ namespace DGtal * @param object the object of class 'FrontierEvolver' to write. * @return the output stream after the writing. */ - template + template std::ostream& - operator<< ( std::ostream & out, const FrontierEvolver & object ); + operator<< ( std::ostream & out, + const FrontierEvolver & object ); } // namespace DGtal diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index c2d12ec..902a278 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -38,36 +38,40 @@ // ----------------------- Standard services ------------------------------ -template +template inline -DGtal::FrontierEvolver -::FrontierEvolver(const KSpace& aK, Image& aI, Surfel& aS, +DGtal::FrontierEvolver +::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, const Functor& aF, const Predicate& aP, const double& aW) - : myKSpace( aK ), myImage( aI ), mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), myW( aW ), - mySurfelPred( myKSpace, myImage, - myImage( myKSpace.sCoords( - myKSpace.sIndirectIncident( mySurfel, *myKSpace.sOrthDirs( mySurfel ) ) ) ), - myImage( myKSpace.sCoords( - myKSpace.sDirectIncident( mySurfel, *myKSpace.sOrthDirs( mySurfel ) ) ) ) ), + : myKSpace( aK ), myLImage( aI ), myDImage( aD ), mySurfel( aS ), + myFunctor( aF ), myPointPred( aP ), myW( aW ), + mySurfelPred( myKSpace, myLImage, + myLImage( getInnerPoint( mySurfel ) ), + myLImage( getOuterPoint( mySurfel ) ) ), myFrontier( myKSpace, mySurfelPred, SurfelAdjacency( true ), mySurfel ) { - ASSERT( myW > 0 ); ASSERT( myW <= 1.0 ); - //to do internal function so that initialization is more readable + ASSERT( myW > 0 ); + ASSERT( myW <= 1.0 ); } -template +template inline -DGtal::FrontierEvolver::~FrontierEvolver() +DGtal::FrontierEvolver +::~FrontierEvolver() { } -template +template inline bool -DGtal::FrontierEvolver::update() +DGtal::FrontierEvolver +::update() { /* init(); @@ -78,33 +82,59 @@ DGtal::FrontierEvolver::update() } -template +template inline void -DGtal::FrontierEvolver::selfDisplay ( std::ostream & out ) const +DGtal::FrontierEvolver +::selfDisplay ( std::ostream & out ) const { out << "[FrontierEvolver]\n"; out << "\n"; } -template +template inline bool -DGtal::FrontierEvolver::isValid() const +DGtal::FrontierEvolver +::isValid() const { return true; } +template +inline +typename DGtal::FrontierEvolver::Point +DGtal::FrontierEvolver +::getInnerPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} +template +inline +typename DGtal::FrontierEvolver::Point +DGtal::FrontierEvolver +::getOuterPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} /////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions // -template +template inline std::ostream& DGtal::operator<< ( std::ostream & out, - const FrontierEvolver & object ) + const FrontierEvolver & object ) { object.selfDisplay( out ); return out; diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 907ee9e..586bd26 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -139,11 +139,12 @@ int main(int argc, char** argv) std::fill(g.begin(),g.end(), 1.0 ); //distance map - ImageContainerBySTLMap map( d ); + typedef ImageContainerBySTLMap DistanceImage; + DistanceImage map( d ); //predicate and functor typedef TruePointPredicate Predicate; - typedef LocalBalloonForce, + typedef LocalBalloonForce > Functor; Functor f(g, k); @@ -158,7 +159,8 @@ int main(int argc, char** argv) << std::endl; //frontier evolver - FrontierEvolver e(ks, labelImage, bel, f, Predicate() ); + FrontierEvolver + e(ks, labelImage, map, bel, f, Predicate() ); for (unsigned int i = 1; i <= max; ++i) { @@ -175,7 +177,7 @@ int main(int argc, char** argv) //3d to 2d display std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( labelImage, s.str(), format, 1 ); + writeImage( labelImage, s.str(), format ); } DGtal::trace.endBlock(); From 872a43dbf3fd5f54226873219108e8c6488f51af Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 1 Mar 2012 18:00:11 +0100 Subject: [PATCH 003/108] init point set before FMM from the frontier --- deformations/FrontierEvolver.h | 32 +++++++++--- deformations/FrontierEvolver.ih | 73 ++++++++++++++++++++++++--- deformations/testLocalDeformation.cpp | 2 +- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 226509e..cb5776d 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -48,6 +48,13 @@ #include "CPointFunctorAdapter.h" #include "DGtal/kernel/CPointPredicate.h" +// set +#include "DGtal/kernel/sets/DigitalSetFromMap.h" +#include "DGtal/kernel/sets/DigitalSetBySTLSet.h" +#include "DGtal/kernel/sets/DigitalSetInserter.h" +#include "DGtal/images/ImageHelper.h" + +// frontier #include "DGtal/topology/SurfelAdjacency.h" #include "DGtal/topology/helpers/FrontierPredicate.h" #include "DGtal/topology/LightExplicitDigitalSurface.h" @@ -63,7 +70,7 @@ namespace DGtal * \brief Aim: This class is a way of deforming an image of labels * around a connected contact surface between two regions, * according to a velocity field, whose computation is - * delegated to a instance of a model of CLocalVelocity + * delegated to a instance of a model of CPointFunctorAdapter * * At each step, a signed distance function is built. * The points are sorted according to their time of zero-crossing @@ -114,16 +121,17 @@ namespace DGtal /// Image of labels typedef TLabelImage LImage; + typedef typename LImage::Domain Domain; /// Image of distance values typedef TDistanceImage DImage; /// Frontier - typedef FrontierPredicate SurfelPredicate; - typedef LightExplicitDigitalSurface Frontier; + typedef FrontierPredicate SurfelPredicate; + typedef LightExplicitDigitalSurface Frontier; /// Surfel - typedef typename Frontier::Surfel Surfel; - typedef typename Frontier::SurfelConstIterator SurfelIterator; + typedef typename Frontier::Surfel Surfel; + typedef typename Frontier::SurfelConstIterator SurfelIterator; /// Point functor for the mapping velocity-points @@ -146,7 +154,7 @@ namespace DGtal * @param aW maximal width of the deformation band (1.0 by default) */ FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, - const Functor& aF, const Predicate& aP, const double& aW = 1.0); + const Functor& aF, const Predicate& aP, const double& aW = 1.0); /** * Destructor. Does nothing. @@ -162,6 +170,18 @@ namespace DGtal */ bool update(); + /** + * Return through @a out the points + * for which the distance value has been + * computed and stored in @a myDImage , + * which are candidate to the flip + * + * @tparam TOutputIterator a model of output iterator + * + * @param out an output iterator + */ + template + void init(TOutputIterator& out); /** * Checks the validity/consistency of the object. diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 902a278..11dab6c 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -73,14 +73,73 @@ bool DGtal::FrontierEvolver ::update() { -/* - init(); - order(); - evolve(); -*/ + + /// set of points that are candidate to the flip + typedef DigitalSetBySTLSet CandidatePointSet; + CandidatePointSet candidates( myLImage.domain() ); + + /// initialization of the set + DigitalSetInserter inserter( candidates ); + init( inserter ); + + /// ordering of the points according + /// to their zero-crossing time + //order(); + + /// flip points one by one, in order + /// while possible + //evolve(); + return false; } +template +template +inline +void +DGtal::FrontierEvolver +::init( TOutputIterator& out ) +{ + + /// set of points for which the distance value + /// is computed and stored in myDImage + ///////////////////////get the set type from a traits selector + typedef DigitalSetFromMap PointSet; + PointSet points(myDImage); + + + /// initialization of points from the + /// points adjacent to the frontier + unsigned int nbsurfels = 0; + for ( SurfelIterator it = myFrontier.begin(), + itEnd = myFrontier.end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + Point out( getOuterPoint( *it ) ); + + insertAndAlwaysSetValue( myDImage, points, in, -0.5 ); + insertAndAlwaysSetValue( myDImage, points, out, 0.5 ); + + ++nbsurfels; + } + trace.info() << nbsurfels << " surfels found." << std::endl; + trace.info() << points << std::endl; + trace.info() << myDImage << std::endl; + + /// FMM + // distance thresholds + double t1 = myW + 1.0; + double t2 = t1 * 2.0; + + //first pass + + //copy + + //second pass + +} template @@ -111,7 +170,7 @@ typename DGtal::FrontierEvolver ::getInnerPoint(const Surfel& s) const { - return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); + return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); } template ::getOuterPoint(const Surfel& s) const { - return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); + return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); } /////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 586bd26..a24b8ba 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -188,7 +188,7 @@ int main(int argc, char** argv) } //interactive display after the evolution - //if (vm.count("withVisu")) displayImage( argc, argv, implicitFunction ); + if (vm.count("withVisu")) displayImage( argc, argv, labelImage ); return 0; From 574176df23b69ef371c63d7a34f38ddb64dcaa5a Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 1 Mar 2012 21:18:45 +0100 Subject: [PATCH 004/108] FMM to get a band of points around the frontier --- deformations/FrontierEvolver.h | 6 +++- deformations/FrontierEvolver.ih | 57 +++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index cb5776d..e8c9aba 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -54,6 +54,9 @@ #include "DGtal/kernel/sets/DigitalSetInserter.h" #include "DGtal/images/ImageHelper.h" +// FMM +#include "DGtal/geometry/volumes/distance/FMM.h" + // frontier #include "DGtal/topology/SurfelAdjacency.h" #include "DGtal/topology/helpers/FrontierPredicate.h" @@ -125,6 +128,7 @@ namespace DGtal /// Image of distance values typedef TDistanceImage DImage; + typedef typename DImage::Value Distance; /// Frontier typedef FrontierPredicate SurfelPredicate; @@ -181,7 +185,7 @@ namespace DGtal * @param out an output iterator */ template - void init(TOutputIterator& out); + void init(const TOutputIterator& out); /** * Checks the validity/consistency of the object. diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 11dab6c..32ce244 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -75,16 +75,22 @@ DGtal::FrontierEvolver CandidatePointSet; - CandidatePointSet candidates( myLImage.domain() ); - /// initialization of the set - DigitalSetInserter inserter( candidates ); - init( inserter ); - + // typedef DigitalSetBySTLSet CandidatePointSet; + // CandidatePointSet candidates( myLImage.domain() ); + // DigitalSetInserter inserter( candidates ); + // init( inserter ); + + std::vector points; + init ( std::back_inserter( points ) ); + trace.info() << points.size() << " closest points" << std::endl; + /// ordering of the points according /// to their zero-crossing time - //order(); + //typedef std::pair PointVelocity; + //std::vector candidates; + //prepare ( points.begin(), points.end(), std::back_inserter( candidates ) ); + //std::sort( candidates.begin(), candidates.end(), comparator ? ); /// flip points one by one, in order /// while possible @@ -99,9 +105,11 @@ template inline void DGtal::FrontierEvolver -::init( TOutputIterator& out ) +::init( const TOutputIterator& out ) { + TOutputIterator res = out; + /// set of points for which the distance value /// is computed and stored in myDImage ///////////////////////get the set type from a traits selector @@ -126,18 +134,39 @@ DGtal::FrontierEvolver FMM; + Domain domain = myLImage.domain(); // computation domain + FMM fmm( myDImage, points, domain.predicate() ); //first pass - - //copy + { + double threshold = myW + 1.0; // distance threshold + fmm.computeOneStep( p, d ); + while (std::abs(d) < threshold) + { + *res++ = p; + fmm.computeOneStep( p, d ); + } + } + trace.info() << fmm << std::endl; //second pass + { + double threshold = myW + 2.0; // distance threshold + while (std::abs(d) < threshold) + { + fmm.computeOneStep( p, d ); + } + } + trace.info() << fmm << std::endl; } From c1eaa5a413fd3be3ea9217c33e170956e018a479 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 2 Mar 2012 09:47:56 +0100 Subject: [PATCH 005/108] sorting according to the zero-crossing time --- deformations/FrontierEvolver.h | 40 +++++++++++++++++++++++---- deformations/FrontierEvolver.ih | 36 +++++++++++++++++++++--- deformations/LocalBalloonForce.h | 20 +++----------- deformations/LocalBalloonForce.ih | 27 +++--------------- deformations/testLocalDeformation.cpp | 2 +- 5 files changed, 76 insertions(+), 49 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index e8c9aba..af1c1c1 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -66,6 +66,35 @@ namespace DGtal { + namespace details + { + class VelocityCompare { + public: + template + bool operator()(const T& a, const T& b) + { + return ( std::abs(a.second) < std::abs(b.second) ); + } + }; + + template + class ZeroCrossingTimeCompare { + private: + const I& myI; /// underlying distance map + public: + /* Constructor */ + ZeroCrossingTimeCompare( const I& i ): myI( i ) {}; + /* Destructor */ + ~ZeroCrossingTimeCompare() {}; + /* operator */ + template + bool operator()(const T& a, const T& b) + { + return ( (std::abs(myI( a.first )) * std::abs(b.second)) + < (std::abs(myI( b.first )) * std::abs(a.second)) ); + } + }; + } ///////////////////////////////////////////////////////////////////////////// // template class FrontierEvolver /** @@ -73,20 +102,20 @@ namespace DGtal * \brief Aim: This class is a way of deforming an image of labels * around a connected contact surface between two regions, * according to a velocity field, whose computation is - * delegated to a instance of a model of CPointFunctorAdapter + * delegated to a point functor. * * At each step, a signed distance function is built. * The points are sorted according to their time of zero-crossing * (ie. their distance to the interface divided by their velocity) - * so that they are flipped from a region to another one by one and + * so that they are flipped from a region to another, one by one and * in order, until a time greater than a threshold is reached or * until a point predicate (possibly based on topological properties) - * returns false. + * returns false. * * @tparam TKSpace a model of CCellularGridSpaceND * @tparam TLabelImage a model of CImage (storing labels) * @tparam TDistanceImage a model of CImage (storing distance values) - * @tparam TFunctor a model of CPointFunctorAdapter + * @tparam TFunctor a model of CPointFunctor * @tparam TPredicate a model of CPointPredicate */ template PointVelocity; + std::vector candidates; + typename std::vector::const_iterator + it = points.begin(), + itEnd = points.end(); + for ( ; it != itEnd; ++it) + { + Velocity v = myFunctor( *it ); + candidates.push_back( PointVelocity( *it, v ) ); + } + trace.info() << candidates.size() << " candidates " << std::endl; + + /// time threshold computation + details::VelocityCompare velocityCompare; + typename std::vector::iterator + itmax = std::max_element( candidates.begin(), candidates.end(), velocityCompare ); + Velocity vmax = itmax->second; + double tmax = myW / std::abs(vmax); + trace.info() << "Distance max: " << myW << " / " + << "Velocity max: " << vmax << " = " + << "Time threshold: " << tmax << std::endl; + /// ordering of the points according /// to their zero-crossing time - //typedef std::pair PointVelocity; - //std::vector candidates; - //prepare ( points.begin(), points.end(), std::back_inserter( candidates ) ); - //std::sort( candidates.begin(), candidates.end(), comparator ? ); + details::ZeroCrossingTimeCompare timeCompare( myDImage ); + std::sort( candidates.begin(), candidates.end(), timeCompare ); + trace.info() << "Times ranging from " + << ( std::abs(myDImage( candidates.begin()->first )) + / std::abs(candidates.begin()->second) ) + << " to " + << ( std::abs(myDImage( candidates.rbegin()->first )) + / std::abs(candidates.begin()->second) ) + << std::endl; /// flip points one by one, in order /// while possible diff --git a/deformations/LocalBalloonForce.h b/deformations/LocalBalloonForce.h index 484f7aa..623dae3 100644 --- a/deformations/LocalBalloonForce.h +++ b/deformations/LocalBalloonForce.h @@ -56,8 +56,6 @@ namespace DGtal * and some extern data (a balloon force and * an extern scalar field for weighting). * - * It is a model of CPointFunctorAdapter - * * @tparam TFunction type of implicit function, * which a model of point functor * @tparam TExternField type of the extern field, @@ -76,22 +74,12 @@ namespace DGtal typename ExternField::Point>::value )); typedef typename PointFunctor::Point Point; - typedef typename PointFunctor::Value Value; + typedef double Value; /** * Constructor */ - LocalBalloonForce(const ExternField& aF, const double& aK = 0); - - /** - * Get the underlying function - */ - const PointFunctor& base(); - - /** - * Set the underlying function - */ - void attach(const PointFunctor& aF); + LocalBalloonForce(PointFunctor& aF1, const ExternField& aF2, const double& aK = 0); /** * Main operator @@ -106,9 +94,9 @@ namespace DGtal /** * Aliasing pointer to the implicit function */ - const PointFunctor* myFuncPtr; + PointFunctor* myFuncPtr; /** - * Aliasing pointer to the extern field + * Constant aliasing pointer to the extern field */ const ExternField* myFieldPtr; /** diff --git a/deformations/LocalBalloonForce.ih b/deformations/LocalBalloonForce.ih index 55ef82c..b81b4e5 100644 --- a/deformations/LocalBalloonForce.ih +++ b/deformations/LocalBalloonForce.ih @@ -38,30 +38,11 @@ template inline DGtal::LocalBalloonForce -::LocalBalloonForce(const ExternField& aF, const double& aK) - : myFuncPtr( NULL ), myFieldPtr( &aF ), myK( aK ) +::LocalBalloonForce(PointFunctor& aF1, const ExternField& aF2, const double& aK) + : myFuncPtr( &aF1 ), myFieldPtr( &aF2 ), myK( aK ) { } -template -inline -const typename DGtal::LocalBalloonForce::PointFunctor& -DGtal::LocalBalloonForce -::base() -{ - ASSERT( myFuncPtr ); - return *myFuncPtr; -} - -template -inline -void -DGtal::LocalBalloonForce -::attach(const PointFunctor& aF) -{ - myFuncPtr = &aF; -} - template template inline @@ -74,8 +55,8 @@ DGtal::LocalBalloonForce //ugly until differential operators are updated GodunovGradient gradient( *tmpPtr, (myK >= 0) ); GradientModulus > m(gradient); - double res = - static_cast( myK * myFieldPtr->operator()(aPoint) * m(aPoint) ); + double res = myK * static_cast( myFieldPtr->operator()(aPoint) ) + * static_cast( m(aPoint) ); return res; } //------------------------------------------------------------------------------ diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index a24b8ba..4d5f980 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -146,7 +146,7 @@ int main(int argc, char** argv) typedef TruePointPredicate Predicate; typedef LocalBalloonForce > Functor; - Functor f(g, k); + Functor f(map, g, k); //getting a bel Thresholder t( 0 ); From 6569c99795a7b452058fdbbf682e5f61b04477a0 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 2 Mar 2012 10:05:35 +0100 Subject: [PATCH 006/108] small changes; flip and surfel update remain to do --- deformations/FrontierEvolver.ih | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index d428481..c44c7c4 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -88,12 +88,13 @@ DGtal::FrontierEvolver PointVelocity; std::vector candidates; - typename std::vector::const_iterator - it = points.begin(), - itEnd = points.end(); - for ( ; it != itEnd; ++it) + for (typename std::vector::const_iterator + it = points.begin(), + itEnd = points.end(); + it != itEnd; ++it) { Velocity v = myFunctor( *it ); + //TODO velocity max computation here! and store zero-crossing time instead candidates.push_back( PointVelocity( *it, v ) ); } trace.info() << candidates.size() << " candidates " << std::endl; @@ -120,9 +121,29 @@ DGtal::FrontierEvolversecond) ) << std::endl; - /// flip points one by one, in order + /// flip points one by one, in order, /// while possible - //evolve(); + ASSERT (candidates.begin() != candidates.end()); + Point p; + double t; + bool flag = true; + for (typename std::vector::const_iterator + it = candidates.begin(), + itEnd = candidates.end(); + ( (it != itEnd)&&(flag) ); ++it) + { + p = it->first; + t = ( std::abs(myDImage(p)) / std::abs(it->second) ); + if ( (t <= tmax) && ( myPointPred( p ) ) ) + { + //flip( p ); + } + else + flag = false; + } + + trace.info() << "Lastest flipped point: " << p << std::endl; + return false; } From f5bb78f3c9ac21ab4d2e5993a29edce7254dad4c Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 2 Mar 2012 11:37:10 +0100 Subject: [PATCH 007/108] flip done --- deformations/FrontierEvolver.h | 17 ++++++++- deformations/FrontierEvolver.ih | 68 +++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index af1c1c1..05510d2 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -153,6 +153,7 @@ namespace DGtal /// Image of labels typedef TLabelImage LImage; + typedef typename LImage::Value Label; typedef typename LImage::Domain Domain; /// Image of distance values @@ -265,7 +266,14 @@ namespace DGtal * the frontier is moving */ double myW; - + /** + * Label of the inner region + */ + Label myInnerLabel; + /** + * Label of the outer region + */ + Label myOuterLabel; /** * Surfel predicate telling whether a given surfel * belongs to the frontier or not @@ -316,6 +324,13 @@ namespace DGtal */ Point getOuterPoint ( const Surfel& s ) const ; + /** + * Update the starting surfel @a mySurfel + * of the digital frontier from point @a p + * @param p any (digital) point + */ + void updateSurfel ( const Point& p ); + }; // end of class FrontierEvolver diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index c44c7c4..a08a89c 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -46,15 +46,17 @@ DGtal::FrontierEvolver( true ), mySurfel ) { ASSERT( myW > 0 ); ASSERT( myW <= 1.0 ); + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( myInnerLabel != myOuterLabel ); } template CandidatePointSet; - // CandidatePointSet candidates( myLImage.domain() ); - // DigitalSetInserter inserter( candidates ); - // init( inserter ); - std::vector points; init ( std::back_inserter( points ) ); trace.info() << points.size() << " closest points" << std::endl; @@ -136,14 +132,21 @@ DGtal::FrontierEvolversecond) ); if ( (t <= tmax) && ( myPointPred( p ) ) ) { - //flip( p ); + /// flip( p ); + if ( myLImage(p) == myInnerLabel ) + myLImage.setValue( p, myOuterLabel ); + else if ( myLImage(p) == myOuterLabel ) + myLImage.setValue( p, myInnerLabel ); + else + ASSERT( false && "impossible case" ); } else flag = false; } trace.info() << "Lastest flipped point: " << p << std::endl; - + //updateSurfel( p ); + trace.info() << "new bel: " << mySurfel << std::endl; return false; } @@ -262,6 +265,49 @@ DGtal::FrontierEvolver +inline +void +DGtal::FrontierEvolver +::updateSurfel(const Point& p) +{ + typename KSpace::SCell spel, surfel; + myKSpace.sSetCoords( spel, p ); + + /// for each direction + bool flag = false; + for ( typename KSpace::DirIterator q = myKSpace.sDirs( spel ); + ( (q != 0)&&(!flag) ); ++q ) + { + DGtal::Dimension dir = *q; + + /// for the direct orientation + surfel = myKSpace.sDirectIncident( spel, dir ); + ASSERT( myKSpace.sIsSurfel( surfel ) ); + if ( ( myLImage(getInnerPoint( surfel )) == myInnerLabel ) + && ( myLImage(getOuterPoint( surfel )) == myOuterLabel ) ) + { + mySurfel = surfel; + flag = true; + } + if (!flag) + { + /// for the indirect orientation + surfel = myKSpace.sIndirectIncident( spel, dir ); + ASSERT( myKSpace.sIsSurfel( surfel ) ); + if ( ( myLImage(getInnerPoint( surfel )) == myInnerLabel ) + && ( myLImage(getOuterPoint( surfel )) == myOuterLabel ) ) + { + mySurfel = surfel; + flag = true; + } + } + } + + ASSERT( flag && "impossible case" ); +} + /////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions // From 01969ec2630af1ba3813460dbae53a8b694472e7 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 2 Mar 2012 12:47:35 +0100 Subject: [PATCH 008/108] working on updating bel --- deformations/FrontierEvolver.ih | 35 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index a08a89c..42cc1fe 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -138,15 +138,15 @@ DGtal::FrontierEvolver ::updateSurfel(const Point& p) { - typename KSpace::SCell spel, surfel; - myKSpace.sSetCoords( spel, p ); + /// update mySurfel + + /// spel creation + typename KSpace::SCell spel; + if ( myLImage(p) == myInnerLabel ) + spel = myKSpace.sSpel( p, KSpace::POS ); + else if ( myLImage(p) == myOuterLabel ) + spel = myKSpace.sSpel( p, KSpace::NEG ); + else + ASSERT( false && "impossible label in updateSurfel method" ); /// for each direction bool flag = false; @@ -283,10 +291,10 @@ DGtal::FrontierEvolver( true ), + // mySurfel ) + } /////////////////////////////////////////////////////////////////////////////// From 196ca03b9fb730926bbf7b36b9f7ffbca57931fc Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 2 Mar 2012 17:57:01 +0100 Subject: [PATCH 009/108] vrac: pb in the comparison --- deformations/FrontierEvolver.h | 26 +++- deformations/FrontierEvolver.ih | 207 ++++++++++++++++++-------- deformations/deformationFunctions.h | 18 +-- deformations/testLocalDeformation.cpp | 17 ++- 4 files changed, 179 insertions(+), 89 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 05510d2..78f2b7d 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -80,18 +80,28 @@ namespace DGtal template class ZeroCrossingTimeCompare { private: - const I& myI; /// underlying distance map + const I* myI; /// underlying distance map public: /* Constructor */ - ZeroCrossingTimeCompare( const I& i ): myI( i ) {}; + ZeroCrossingTimeCompare( const I& i ): myI( &i ) + { + trace.info() << myI->domain() << std::endl; + }; /* Destructor */ ~ZeroCrossingTimeCompare() {}; /* operator */ template bool operator()(const T& a, const T& b) { - return ( (std::abs(myI( a.first )) * std::abs(b.second)) - < (std::abs(myI( b.first )) * std::abs(a.second)) ); + if ( !myI->domain().isInside( a.first ) ) + { + std::cerr << a.first << " not in domain (from time comp)" << std::endl; + throw DGtal::InputException(); + } + ASSERT( myI->domain().isInside( a.first ) && "a.first in time comparison"); + ASSERT( myI->domain().isInside( b.first ) && "b.first in time comparison"); + return ( (std::abs((*myI)( a.first )) * std::abs(b.second)) + < (std::abs((*myI)( b.first )) * std::abs(a.second)) ); } }; } @@ -282,7 +292,7 @@ namespace DGtal /** * (implicit) digital frontier */ - Frontier myFrontier; + const Frontier* myFrontier; // ------------------------- Hidden services ------------------------------ protected: @@ -328,8 +338,12 @@ namespace DGtal * Update the starting surfel @a mySurfel * of the digital frontier from point @a p * @param p any (digital) point + * @param isPos bool equal to 'true' if @a p + * belongs to the inner region (and the + * corresponding spel is positive) but 'false' + * otherwise */ - void updateSurfel ( const Point& p ); + void updateFrontier ( const Point& p, bool isPos ); }; // end of class FrontierEvolver diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 42cc1fe..3bca092 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -49,13 +49,14 @@ DGtal::FrontierEvolver( true ), - mySurfel ) + myFrontier( new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ) ) { ASSERT( myW > 0 ); ASSERT( myW <= 1.0 ); ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + trace.info() << "Labels: " << myInnerLabel << " and " << myOuterLabel << std::endl; ASSERT( myInnerLabel != myOuterLabel ); } @@ -65,6 +66,7 @@ inline DGtal::FrontierEvolver ::~FrontierEvolver() { + delete( myFrontier ); } @@ -89,7 +91,13 @@ DGtal::FrontierEvolver::const_iterator + it = candidates.begin(), + itEnd = candidates.end(); + it != itEnd; ++it) + { + if ( !myDImage.domain().isInside( it->first ) ) + { + std::cerr << it->first << " not in domain (verif)" << std::endl; + throw DGtal::InputException(); + } + } + trace.info() << candidates.size() << " candidates " << std::endl; + + trace.info() << "sorting..." << std::endl; details::ZeroCrossingTimeCompare timeCompare( myDImage ); std::sort( candidates.begin(), candidates.end(), timeCompare ); trace.info() << "Times ranging from " @@ -114,41 +136,77 @@ DGtal::FrontierEvolversecond) ) << " to " << ( std::abs(myDImage( candidates.rbegin()->first )) - / std::abs(candidates.begin()->second) ) + / std::abs(candidates.rbegin()->second) ) << std::endl; /// flip points one by one, in order, /// while possible ASSERT (candidates.begin() != candidates.end()); - Point p; - double t; - bool flag = true; + bool go = true; + bool isInner; for (typename std::vector::const_iterator it = candidates.begin(), itEnd = candidates.end(); - ( (it != itEnd)&&(flag) ); ++it) + ( (it != itEnd)&&(go) ); ++it) { - p = it->first; - t = ( std::abs(myDImage(p)) / std::abs(it->second) ); + Point p = it->first; + double t = ( std::abs(myDImage(p)) / std::abs(it->second) ); if ( (t <= tmax) && ( myPointPred( p ) ) ) - { - /// flip( p ); + { /// flip if ( myLImage(p) == myInnerLabel ) - myLImage.setValue( p, myOuterLabel ); + { + isInner = false; + myLImage.setValue( p, myOuterLabel ); + } else if ( myLImage(p) == myOuterLabel ) - myLImage.setValue( p, myInnerLabel ); + { + isInner = true; + myLImage.setValue( p, myInnerLabel ); + } else ASSERT( false && "impossible label in update method" ); } else - flag = false; + go = false; + } + + /// update digital frontier + // moving mySurfel in one direction (but 2 orientation) + DGtal::Dimension q = *myKSpace.sOrthDirs( mySurfel ); + Surfel sIncr = mySurfel; + Surfel sDecr = mySurfel; + bool isIncr = true; + bool stop = mySurfelPred( mySurfel ); + while ( !stop ) + { + if (isIncr) + { + ASSERT( !myKSpace.sIsMax( sIncr, q) ); + sIncr = myKSpace.sGetIncr( sIncr, q ); + stop = mySurfelPred( sIncr ); + isIncr = false; + } + else + { + ASSERT( !myKSpace.sIsMin( sDecr, q) ); + sDecr = myKSpace.sGetDecr( sDecr, q ); + stop = mySurfelPred( sDecr ); + isIncr = true; + } } + if (isIncr) + mySurfel = sDecr; + else + mySurfel = sIncr; + trace.info() << "new bel: " << mySurfel << std::endl; - trace.info() << "Lastest flipped point: " << p << std::endl; - // updateSurfel( p ); - // trace.info() << "new bel: " << mySurfel << std::endl; + /// update frontier + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); - return false; + return true; } template PointSet; PointSet points(myDImage); - + points.clear(); /// initialization of points from the /// points adjacent to the frontier + trace.info() << "starting surfel: " << mySurfel << std::endl; unsigned int nbsurfels = 0; - for ( SurfelIterator it = myFrontier.begin(), - itEnd = myFrontier.end(); + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); it != itEnd; ++it ) { Point in( getInnerPoint( *it ) ); Point out( getOuterPoint( *it ) ); - - insertAndAlwaysSetValue( myDImage, points, in, -0.5 ); - insertAndAlwaysSetValue( myDImage, points, out, 0.5 ); + + if ( myDImage.domain().isInside( in ) ) //TODO using predicate on labels + insertAndAlwaysSetValue( myDImage, points, in, -0.5 ); + if ( myDImage.domain().isInside( out ) ) + insertAndAlwaysSetValue( myDImage, points, out, 0.5 ); ++nbsurfels; } @@ -190,33 +251,37 @@ DGtal::FrontierEvolver FMM; - Domain domain = myLImage.domain(); // computation domain - FMM fmm( myDImage, points, domain.predicate() ); + typedef FMM FMM; + trace.info() << myDImage.domain() << std::endl; + //TODO restreindre a deux labels + FMM fmm( myDImage, points, myDImage.domain().predicate() ); + Point p = Point::diagonal(0); //last point + Distance d = 0; //its distance //first pass { - double threshold = myW + 1.0; // distance threshold - fmm.computeOneStep( p, d ); - while (std::abs(d) < threshold) + double threshold = myW + 1.5; // distance threshold + while ( (fmm.computeOneStep( p, d )) + && (std::abs(d) < threshold) ) { + if ( !myDImage.domain().isInside( p ) ) + { + std::cerr << p << " not in domain (from FMM)" << std::endl; + throw DGtal::InputException(); + } *res++ = p; - fmm.computeOneStep( p, d ); - } + } } trace.info() << fmm << std::endl; //second pass { - double threshold = myW + 2.0; // distance threshold - while (std::abs(d) < threshold) - { - fmm.computeOneStep( p, d ); - } + double threshold = myW + 2.5; // distance threshold + while ( (fmm.computeOneStep( p, d )) + && (std::abs(d) < threshold) ) + { } } trace.info() << fmm << std::endl; @@ -270,54 +335,66 @@ template -::updateSurfel(const Point& p) +::updateFrontier(const Point& p, bool isPos) { /// update mySurfel + //neigbors + Point neighbor = p; + for (Dimension k = 0; k < Point::dimension; ++k) + { + typename Point::Coordinate c = neighbor.at(k); + neighbor.at(k) = (c+1); + std::cout << neighbor << myLImage(neighbor) << " "; + neighbor.at(k) = (c-1); + std::cout << neighbor << myLImage(neighbor) << " "; + neighbor.at(k) = c; + } + std::cout << std::endl; + /// spel creation typename KSpace::SCell spel; - if ( myLImage(p) == myInnerLabel ) + if ( isPos ) spel = myKSpace.sSpel( p, KSpace::POS ); - else if ( myLImage(p) == myOuterLabel ) + else spel = myKSpace.sSpel( p, KSpace::NEG ); - else - ASSERT( false && "impossible label in updateSurfel method" ); /// for each direction bool flag = false; for ( typename KSpace::DirIterator q = myKSpace.sDirs( spel ); - ( (q != 0)&&(!flag) ); ++q ) + ( (q != 0)&&(!flag) ); ++q ) { DGtal::Dimension dir = *q; /// for the direct orientation typename KSpace::SCell surfel - = myKSpace.sDirectIncident( spel, dir ); + = myKSpace.sDirectIncident( spel, dir ); ASSERT( myKSpace.sIsSurfel( surfel ) ); if ( mySurfelPred( surfel ) ) - { - mySurfel = surfel; - flag = true; - } + { + mySurfel = surfel; + flag = true; + } if (!flag) - { - /// for the indirect orientation - surfel = myKSpace.sIndirectIncident( spel, dir ); - ASSERT( myKSpace.sIsSurfel( surfel ) ); - if ( mySurfelPred( surfel ) ) - { - mySurfel = surfel; - flag = true; - } - } + { + /// for the indirect orientation + surfel = myKSpace.sIndirectIncident( spel, dir ); + ASSERT( myKSpace.sIsSurfel( surfel ) ); + if ( mySurfelPred( surfel ) ) + { + mySurfel = surfel; + flag = true; + } + } } - ASSERT( flag && "impossible case in updateSurfel method" ); + ASSERT( flag && "last flipped point must be a border point in updateSurfel method" ); /// update frontier - // myFrontier( myKSpace, mySurfelPred, - // SurfelAdjacency( true ), - // mySurfel ) + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); } diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 0029236..474816d 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -27,18 +27,16 @@ template< typename TImage > void inv(TImage& img, const double& threshold = 0) { - typename TImage::Domain d = img.domain(); - typename TImage::Domain::ConstIterator cIt = d.begin(); - typename TImage::Domain::ConstIterator cItEnd = d.end(); + typename TImage::OutputIterator res = img.outputIterator(); + typename TImage::ConstRange r = img.range(); + typename TImage::ConstRange::ConstIterator cIt = r.begin(); + typename TImage::ConstRange::ConstIterator cItEnd = r.end(); for ( ; cIt != cItEnd; ++cIt) - { //for each domain point - - typedef typename TImage::Point Point; - Point p( *cIt ); //point p - if (img(p) <= threshold) - img.setValue(p, (typename TImage::Value) 1); + { //for each + if (*cIt <= threshold) + *res++ = 1; else - img.setValue(p, (typename TImage::Value) 0); + *res++ = 0; } } diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 4d5f980..41afee1 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -104,7 +104,7 @@ int main(int argc, char** argv) //image of labels - typedef ImageContainerBySTLVector LabelImage; + typedef ImageContainerBySTLVector LabelImage; if (!(vm.count("inputImage"))) { trace.info() << "you must use --inputImage option" << std::endl; @@ -135,22 +135,23 @@ int main(int argc, char** argv) ks.init( d.lowerBound(), d.upperBound(), true ); //data functions - ImageContainerBySTLVector g( d ); - std::fill(g.begin(),g.end(), 1.0 ); + ImageContainerBySTLMap g( d, 1.0 ); //distance map typedef ImageContainerBySTLMap DistanceImage; - DistanceImage map( d ); + DistanceImage map( d, 0.0 ); //predicate and functor typedef TruePointPredicate Predicate; + Predicate predicate; typedef LocalBalloonForce > Functor; - Functor f(map, g, k); + ImageContainerBySTLMap > Functor; + Functor functor(map, g, k); //getting a bel Thresholder t( 0 ); - ConstImageAdapter, bool> binaryImage(labelImage, t); + typedef ConstImageAdapter, bool> BinaryImage; + BinaryImage binaryImage(labelImage, t); try { KSpace::SCell bel = Surfaces::findABel( ks, binaryImage, 10000 ); @@ -160,7 +161,7 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, map, bel, f, Predicate() ); + e(ks, labelImage, map, bel, functor, predicate ); for (unsigned int i = 1; i <= max; ++i) { From 641b5214215e91d59344cec4447d621180421584 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 5 Mar 2012 11:09:38 +0100 Subject: [PATCH 010/108] using zero-crossing time instead of velocity --- deformations/FrontierEvolver.h | 31 +---- deformations/FrontierEvolver.ih | 201 +++++++++++++++--------------- deformations/LocalBalloonForce.ih | 5 +- 3 files changed, 104 insertions(+), 133 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 78f2b7d..f01e3db 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -68,42 +68,15 @@ namespace DGtal namespace details { - class VelocityCompare { + class CompareSecondElement { public: template bool operator()(const T& a, const T& b) { - return ( std::abs(a.second) < std::abs(b.second) ); + return ( a.second < b.second ); } }; - template - class ZeroCrossingTimeCompare { - private: - const I* myI; /// underlying distance map - public: - /* Constructor */ - ZeroCrossingTimeCompare( const I& i ): myI( &i ) - { - trace.info() << myI->domain() << std::endl; - }; - /* Destructor */ - ~ZeroCrossingTimeCompare() {}; - /* operator */ - template - bool operator()(const T& a, const T& b) - { - if ( !myI->domain().isInside( a.first ) ) - { - std::cerr << a.first << " not in domain (from time comp)" << std::endl; - throw DGtal::InputException(); - } - ASSERT( myI->domain().isInside( a.first ) && "a.first in time comparison"); - ASSERT( myI->domain().isInside( b.first ) && "b.first in time comparison"); - return ( (std::abs((*myI)( a.first )) * std::abs(b.second)) - < (std::abs((*myI)( b.first )) * std::abs(a.second)) ); - } - }; } ///////////////////////////////////////////////////////////////////////////// // template class FrontierEvolver diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 3bca092..ff232ca 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -83,130 +83,127 @@ DGtal::FrontierEvolver PointVelocity; - std::vector candidates; + /// velocity and zero-crossing time computation + typedef std::pair PointTime; + std::vector candidates; + double vmax = 0; for (typename std::vector::const_iterator it = points.begin(), itEnd = points.end(); it != itEnd; ++it) { - - Velocity v = myFunctor( *it ); - if ( !myDImage.domain().isInside( *it ) ) - { - std::cerr << *it << " not in domain (after velocity)" << std::endl; - throw DGtal::InputException(); - } - //TODO velocity max computation here! and store zero-crossing time instead - candidates.push_back( PointVelocity( *it, v ) ); + // velocity + Velocity v = myFunctor( *it ); + // maximal velocity + double vabs = std::abs( static_cast( v ) ); + if (vabs > vmax) vmax = vabs; + // new candidate with its zero-crossing time + double d = myDImage( *it ); + if ( ( (d>=0) && (v<0) ) + || ( (d<=0) && (v>0) ) ) + { //if opposite signs (and v != 0) + double t = - d / v; + ASSERT( t >= 0 ); + candidates.push_back( PointTime( *it, t ) ); + } } trace.info() << candidates.size() << " candidates " << std::endl; /// time threshold computation - details::VelocityCompare velocityCompare; - typename std::vector::iterator - itmax = std::max_element( candidates.begin(), candidates.end(), velocityCompare ); - Velocity vmax = itmax->second; - double tmax = myW / std::abs(vmax); + double tmax = myW / vmax; trace.info() << "Distance max: " << myW << " / " << "Velocity max: " << vmax << " = " << "Time threshold: " << tmax << std::endl; - /// ordering of the points according - /// to their zero-crossing time - for (typename std::vector::const_iterator - it = candidates.begin(), - itEnd = candidates.end(); - it != itEnd; ++it) - { - if ( !myDImage.domain().isInside( it->first ) ) - { - std::cerr << it->first << " not in domain (verif)" << std::endl; - throw DGtal::InputException(); - } - } - trace.info() << candidates.size() << " candidates " << std::endl; - - trace.info() << "sorting..." << std::endl; - details::ZeroCrossingTimeCompare timeCompare( myDImage ); - std::sort( candidates.begin(), candidates.end(), timeCompare ); - trace.info() << "Times ranging from " - << ( std::abs(myDImage( candidates.begin()->first )) - / std::abs(candidates.begin()->second) ) - << " to " - << ( std::abs(myDImage( candidates.rbegin()->first )) - / std::abs(candidates.rbegin()->second) ) - << std::endl; - - /// flip points one by one, in order, - /// while possible - ASSERT (candidates.begin() != candidates.end()); - bool go = true; - bool isInner; - for (typename std::vector::const_iterator - it = candidates.begin(), - itEnd = candidates.end(); - ( (it != itEnd)&&(go) ); ++it) - { - Point p = it->first; - double t = ( std::abs(myDImage(p)) / std::abs(it->second) ); - if ( (t <= tmax) && ( myPointPred( p ) ) ) - { /// flip - if ( myLImage(p) == myInnerLabel ) - { - isInner = false; - myLImage.setValue( p, myOuterLabel ); + if (candidates.begin() != candidates.end()) + { //if they are candidates + + /// ordering of the points according + /// to their zero-crossing time + trace.info() << "ordering..." << std::endl; + details::CompareSecondElement timeCompare; + std::sort( candidates.begin(), candidates.end(), timeCompare ); + trace.info() << "Times ranging from " + << candidates.begin()->second + << " to " + << candidates.rbegin()->second + << std::endl; + + /// flip points one by one, in order, + /// while possible + unsigned int nbFlips = 0; + bool go = true; + // bool isInner = true; + for (typename std::vector::const_iterator + it = candidates.begin(), + itEnd = candidates.end(); + ( (it != itEnd)&&(go) ); ++it) + { + const Point p = it->first; + const double t = it->second; + if ( (t <= tmax) && ( myPointPred( p ) ) ) + { /// flip + nbFlips++; + if ( myLImage(p) == myInnerLabel ) + { + // isInner = false; + myLImage.setValue( p, myOuterLabel ); + } + else if ( myLImage(p) == myOuterLabel ) + { + // isInner = true; + myLImage.setValue( p, myInnerLabel ); + } + else + ASSERT( false && "impossible label in update method" ); } - else if ( myLImage(p) == myOuterLabel ) + else + go = false; + } + trace.info() << nbFlips << " flipped points" << std::endl; + + /// update digital frontier + // moving mySurfel in one direction + // (but along 2 orientations) until + // it is a contact surfel + DGtal::Dimension q = *myKSpace.sOrthDirs( mySurfel ); + Surfel sIncr = mySurfel; + Surfel sDecr = mySurfel; + bool isIncr = true; + bool stop = mySurfelPred( mySurfel ); + while ( !stop ) + { + if (isIncr) { - isInner = true; - myLImage.setValue( p, myInnerLabel ); + ASSERT( !myKSpace.sIsMax( sIncr, q) ); + sIncr = myKSpace.sGetIncr( sIncr, q ); + stop = mySurfelPred( sIncr ); + isIncr = false; } else - ASSERT( false && "impossible label in update method" ); + { + ASSERT( !myKSpace.sIsMin( sDecr, q) ); + sDecr = myKSpace.sGetDecr( sDecr, q ); + stop = mySurfelPred( sDecr ); + isIncr = true; + } } - else - go = false; - } - - /// update digital frontier - // moving mySurfel in one direction (but 2 orientation) - DGtal::Dimension q = *myKSpace.sOrthDirs( mySurfel ); - Surfel sIncr = mySurfel; - Surfel sDecr = mySurfel; - bool isIncr = true; - bool stop = mySurfelPred( mySurfel ); - while ( !stop ) - { if (isIncr) - { - ASSERT( !myKSpace.sIsMax( sIncr, q) ); - sIncr = myKSpace.sGetIncr( sIncr, q ); - stop = mySurfelPred( sIncr ); - isIncr = false; - } + mySurfel = sDecr; else - { - ASSERT( !myKSpace.sIsMin( sDecr, q) ); - sDecr = myKSpace.sGetDecr( sDecr, q ); - stop = mySurfelPred( sDecr ); - isIncr = true; - } - } - if (isIncr) - mySurfel = sDecr; - else - mySurfel = sIncr; - trace.info() << "new bel: " << mySurfel << std::endl; + mySurfel = sIncr; + trace.info() << "new bel: " << mySurfel << std::endl; - /// update frontier - delete ( myFrontier ); - myFrontier = new Frontier ( myKSpace, mySurfelPred, - SurfelAdjacency( true ), - mySurfel ); + /// update frontier + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); - return true; + return true; + } + else + return false; } template //ugly until differential operators are updated GodunovGradient gradient( *tmpPtr, (myK >= 0) ); GradientModulus > m(gradient); - double res = myK * static_cast( myFieldPtr->operator()(aPoint) ) - * static_cast( m(aPoint) ); + double res = myK +/** static_cast( myFieldPtr->operator()(aPoint) ) + * static_cast( m(aPoint) )*/; return res; } //------------------------------------------------------------------------------ From 6485a2c8fea71ce1b4526b8d6c9ad5de48fa14f2 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 5 Mar 2012 13:07:26 +0100 Subject: [PATCH 011/108] ok for balloon force (reverse sign for Godunov scheme) --- deformations/FrontierEvolver.ih | 87 ++++++++++++++++--------------- deformations/LocalBalloonForce.ih | 7 ++- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index ff232ca..dfadfc1 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -132,26 +132,28 @@ DGtal::FrontierEvolver::const_iterator it = candidates.begin(), itEnd = candidates.end(); ( (it != itEnd)&&(go) ); ++it) { - const Point p = it->first; - const double t = it->second; + p = it->first; + t = it->second; if ( (t <= tmax) && ( myPointPred( p ) ) ) { /// flip nbFlips++; if ( myLImage(p) == myInnerLabel ) { - // isInner = false; + isInner = false; myLImage.setValue( p, myOuterLabel ); } else if ( myLImage(p) == myOuterLabel ) { - // isInner = true; + isInner = true; myLImage.setValue( p, myInnerLabel ); } else @@ -162,43 +164,44 @@ DGtal::FrontierEvolver( true ), - mySurfel ); + updateFrontier( p, !isInner ); + // /// update digital frontier + // // moving mySurfel in one direction + // // (but along 2 orientations) until + // // it is a contact surfel + // DGtal::Dimension q = *myKSpace.sOrthDirs( mySurfel ); + // Surfel sIncr = mySurfel; + // Surfel sDecr = mySurfel; + // bool isIncr = true; + // bool stop = mySurfelPred( mySurfel ); + // while ( !stop ) + // { + // if (isIncr) + // { + // ASSERT( !myKSpace.sIsMax( sIncr, q) ); + // sIncr = myKSpace.sGetIncr( sIncr, q ); + // stop = mySurfelPred( sIncr ); + // isIncr = false; + // } + // else + // { + // ASSERT( !myKSpace.sIsMin( sDecr, q) ); + // sDecr = myKSpace.sGetDecr( sDecr, q ); + // stop = mySurfelPred( sDecr ); + // isIncr = true; + // } + // } + // if (isIncr) + // mySurfel = sDecr; + // else + // mySurfel = sIncr; + // trace.info() << "new bel: " << mySurfel << std::endl; + + // /// update frontier + // delete ( myFrontier ); + // myFrontier = new Frontier ( myKSpace, mySurfelPred, + // SurfelAdjacency( true ), + // mySurfel ); return true; } diff --git a/deformations/LocalBalloonForce.ih b/deformations/LocalBalloonForce.ih index 402bbe6..61c87da 100644 --- a/deformations/LocalBalloonForce.ih +++ b/deformations/LocalBalloonForce.ih @@ -53,11 +53,10 @@ DGtal::LocalBalloonForce ASSERT( myFuncPtr ); PointFunctor* tmpPtr = const_cast(myFuncPtr); //ugly until differential operators are updated - GodunovGradient gradient( *tmpPtr, (myK >= 0) ); + GodunovGradient gradient( *tmpPtr, (myK <= 0), 1 ); GradientModulus > m(gradient); - double res = myK -/** static_cast( myFieldPtr->operator()(aPoint) ) - * static_cast( m(aPoint) )*/; + double res = myK * static_cast( (*myFieldPtr)(aPoint) ) + * static_cast( m(aPoint) ); return res; } //------------------------------------------------------------------------------ From 9913f4931c343a297cba200b3a2e74053973e816 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 5 Mar 2012 16:14:38 +0100 Subject: [PATCH 012/108] MCM --- deformations/LocalMCM.h | 123 ++++++++++++++++++++++++++ deformations/LocalMCM.ih | 80 +++++++++++++++++ deformations/testLocalDeformation.cpp | 8 +- 3 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 deformations/LocalMCM.h create mode 100644 deformations/LocalMCM.ih diff --git a/deformations/LocalMCM.h b/deformations/LocalMCM.h new file mode 100644 index 0000000..ca32ed9 --- /dev/null +++ b/deformations/LocalMCM.h @@ -0,0 +1,123 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file LocalMCM.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/03/01 + * + * This files contains several basic classes representing Functors + * on points. + * + * This file is part of the DGtal library. + */ + +#if defined(LocalMCM_RECURSES) +#error Recursive header files inclusion detected in LocalMCM.h +#else // defined(LocalMCM_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define LocalMCM_RECURSES + +#if !defined LocalMCM_h +/** Prevents repeated inclusion of headers. */ +#define LocalMCM_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include "DGtal/kernel/CPointFunctor.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // template class LocalMCM + /** + * Description of template class 'LocalMCM'

+ * \brief Aim: Functor that maps a point + * to a velocity computed from an implicit function + * and some extern data (two extern scalar fields + * for weighting). + * + * @tparam TFunction type of implicit function, + * which a model of point functor + * @tparam TExternField type of the extern field, + * which a model of point functor too + */ + template + struct LocalMCM + { + typedef TFunction PointFunctor; + typedef TExternField ExternField; + + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename PointFunctor::Point, + typename ExternField::Point>::value )); + + typedef typename PointFunctor::Point Point; + typedef double Value; + + /** + * Constructor + */ + LocalMCM(PointFunctor& aF1, const ExternField& aA, const ExternField& aB); + + /** + * Main operator + * @param aPoint any point. + * @tparam TInputPoint type of point + * @return the velocity at @a aPoint. + */ + template + double operator()( const TInputPoint& aPoint ) const; + + private: + /** + * Aliasing pointer to the implicit function + */ + const PointFunctor* myFuncPtr; + /** + * Constant aliasing pointer to the extern field A + */ + const ExternField* myAPtr; + /** + * Constant aliasing pointer to the extern field B + */ + const ExternField* myBPtr; + + }; // end of class LocalMCM + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "LocalMCM.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined LocalMCM_h + +#undef LocalMCM_RECURSES +#endif // else defined(LocalMCM_RECURSES) diff --git a/deformations/LocalMCM.ih b/deformations/LocalMCM.ih new file mode 100644 index 0000000..0f3aa7a --- /dev/null +++ b/deformations/LocalMCM.ih @@ -0,0 +1,80 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file LocalMCM.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/02/02 + * + * Implementation of inline methods defined in LocalMCM.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + +#include "DGtal/images/DifferentialOperators.h" + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// +template +inline +DGtal::LocalMCM +::LocalMCM(PointFunctor& aF1, const ExternField& aA, const ExternField& aB) + : myFuncPtr( &aF1 ), myAPtr( &aA ), myBPtr( &aB ) +{ +} + +template +template +inline +double +DGtal::LocalMCM +::operator()( const TInputPoint& aPoint ) const +{ + ASSERT( myFuncPtr ); + PointFunctor* tmpFuncPtr = const_cast(myFuncPtr); + PointFunctor* tmpBPtr = const_cast(myBPtr); +//ugly until differential operators are updated + +//gradient modulus + CentralDifference cdiff( *tmpFuncPtr ); + Gradient > cg( cdiff ); + GradientModulus > > cm(cg); + +//mean curvature + //TODO allow different types for implicit function and extern field + //in weightedDifference + WeightedDifference2 diff2( *tmpFuncPtr, *tmpBPtr ); + Divergence > div(diff2); + double res = static_cast( (*myAPtr)(aPoint) ) + * static_cast( cm(aPoint) ) + * static_cast( div(aPoint) ); + + return res; +} +//------------------------------------------------------------------------------ + + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 41afee1..ae6c5dd 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -21,6 +21,7 @@ namespace po = boost::program_options; #include "DGtal/shapes/Shapes.h" #include "LocalBalloonForce.h" +#include "LocalMCM.h" #include "FrontierEvolver.h" @@ -144,9 +145,12 @@ int main(int argc, char** argv) //predicate and functor typedef TruePointPredicate Predicate; Predicate predicate; - typedef LocalBalloonForce > Functor; + // Functor functor(map, g, k); + typedef LocalMCM > Functor; - Functor functor(map, g, k); + Functor functor(map, g, g); //getting a bel Thresholder t( 0 ); From c9cbe60bd2b4d1af12b98a499aeb412308677e9a Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 7 Mar 2012 11:05:06 +0100 Subject: [PATCH 013/108] new tries with local approach for MCM --- deformations/FrontierEvolver.h | 12 +-- deformations/FrontierEvolver.ih | 103 +++++++++----------------- deformations/testLocalDeformation.cpp | 39 +++++++--- 3 files changed, 66 insertions(+), 88 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index f01e3db..c47aeac 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -182,11 +182,9 @@ namespace DGtal /** * Deform the image of labels around the digital frontier * - * @return 'true' if the maximal time is reached, - * 'false' if the deformation stopped because of - * the point predicate. + * @return time spent during the deformation. */ - bool update(); + double update(); /** * Return through @a out the points @@ -311,12 +309,8 @@ namespace DGtal * Update the starting surfel @a mySurfel * of the digital frontier from point @a p * @param p any (digital) point - * @param isPos bool equal to 'true' if @a p - * belongs to the inner region (and the - * corresponding spel is positive) but 'false' - * otherwise */ - void updateFrontier ( const Point& p, bool isPos ); + void updateFrontier ( const Point& p ); }; // end of class FrontierEvolver diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index dfadfc1..fe0da20 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -56,7 +56,9 @@ DGtal::FrontierEvolver 0 ); ASSERT( myW <= 1.0 ); ASSERT( myKSpace.sIsSurfel( mySurfel ) ); - trace.info() << "Labels: " << myInnerLabel << " and " << myOuterLabel << std::endl; + trace.info() << "Labels: " << myInnerLabel << " (inner region)" + << " and " << myOuterLabel << " (outer region) " + << std::endl; ASSERT( myInnerLabel != myOuterLabel ); } @@ -73,7 +75,7 @@ DGtal::FrontierEvolver inline -bool +double DGtal::FrontierEvolver ::update() { @@ -134,7 +136,6 @@ DGtal::FrontierEvolver::const_iterator it = candidates.begin(), @@ -148,12 +149,12 @@ DGtal::FrontierEvolver( true ), - // mySurfel ); - - return true; + updateFrontier( p ); + + return t; } else - return false; + return 0.0; } template FMM; - trace.info() << myDImage.domain() << std::endl; //TODO restreindre a deux labels FMM fmm( myDImage, points, myDImage.domain().predicate() ); @@ -266,11 +230,6 @@ DGtal::FrontierEvolver -::updateFrontier(const Point& p, bool isPos) +::updateFrontier(const Point& p) { /// update mySurfel //neigbors - Point neighbor = p; - for (Dimension k = 0; k < Point::dimension; ++k) - { - typename Point::Coordinate c = neighbor.at(k); - neighbor.at(k) = (c+1); - std::cout << neighbor << myLImage(neighbor) << " "; - neighbor.at(k) = (c-1); - std::cout << neighbor << myLImage(neighbor) << " "; - neighbor.at(k) = c; - } - std::cout << std::endl; + // std::cout << p << myLImage(p) << " "; + // Point neighbor = p; + // for (Dimension k = 0; k < Point::dimension; ++k) + // { + // typename Point::Coordinate c = neighbor.at(k); + // neighbor.at(k) = (c+1); + // std::cout << neighbor << myLImage(neighbor) << " "; + // neighbor.at(k) = (c-1); + // std::cout << neighbor << myLImage(neighbor) << " "; + // neighbor.at(k) = c; + // } + // std::cout << std::endl; /// spel creation typename KSpace::SCell spel; - if ( isPos ) + const Label pLabel = myLImage(p); + if ( pLabel == myInnerLabel ) spel = myKSpace.sSpel( p, KSpace::POS ); - else + else if ( pLabel == myOuterLabel ) spel = myKSpace.sSpel( p, KSpace::NEG ); + else + ASSERT( false && "impossible label in updateFrontier method" ); /// for each direction bool flag = false; for ( typename KSpace::DirIterator q = myKSpace.sDirs( spel ); ( (q != 0)&&(!flag) ); ++q ) { - DGtal::Dimension dir = *q; + const DGtal::Dimension dir = *q; /// for the direct orientation typename KSpace::SCell surfel = myKSpace.sDirectIncident( spel, dir ); ASSERT( myKSpace.sIsSurfel( surfel ) ); + // std::cerr << getInnerPoint( surfel ) << getOuterPoint( surfel ) << std::endl; if ( mySurfelPred( surfel ) ) { mySurfel = surfel; @@ -380,6 +344,7 @@ DGtal::FrontierEvolver()->default_value(1.0), "Time step for the evolution" ) ("displayStep,d", po::value()->default_value(1), "Number of time steps between 2 drawings" ) ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) + ("bandWidth,w", po::value()->default_value(1.0), "Width of the flipping band" ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) ("outputFormat,f", po::value()->default_value("png"), @@ -79,10 +81,12 @@ int main(int argc, char** argv) //iterations int step; - if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; + if (!(vm.count("displayStep"))) + trace.info() << "number of steps between two drawings: 1 by default" << std::endl; step = vm["displayStep"].as(); int max; - if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; + if (!(vm.count("stepsNumber"))) + trace.info() << "maximal number of steps: 1 by default" << std::endl; max = vm["stepsNumber"].as(); @@ -125,23 +129,32 @@ int main(int argc, char** argv) if (vm.count("withVisu")) displayImage( argc, argv, labelImage ); //balloon force - double k; + double k = 0.0; if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; k = vm["balloonForce"].as(); + //width of the flipping band + double w = 1.0; + if (!(vm.count("bandWidth"))) trace.info() << "band width default value: 1" << std::endl; + w = vm["bandWidth"].as(); + if( (w < 0) || (w > 1) ) + { + trace.info() << "The band width should be between 0 and 1 " << std::endl; + return 0; + } + //algo //space KSpace ks; Domain d( labelImage.domain() ); ks.init( d.lowerBound(), d.upperBound(), true ); - //data functions - ImageContainerBySTLMap g( d, 1.0 ); - //distance map typedef ImageContainerBySTLMap DistanceImage; DistanceImage map( d, 0.0 ); + //data functions + ImageContainerBySTLMap g( d, 1.0 ); //predicate and functor typedef TruePointPredicate Predicate; Predicate predicate; @@ -151,6 +164,8 @@ int main(int argc, char** argv) typedef LocalMCM > Functor; Functor functor(map, g, g); + // typedef LocalMCMforDT Functor; + // Functor functor(map); //getting a bel Thresholder t( 0 ); @@ -165,16 +180,17 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, map, bel, functor, predicate ); + e(ks, labelImage, map, bel, functor, predicate, w ); + double sumt = 0; for (unsigned int i = 1; i <= max; ++i) { std::stringstream s0; s0 << "iteration # " << i; - DGtal::trace.beginBlock( s0.str() ); + trace.beginBlock( s0.str() ); //update - e.update(); + sumt += e.update(); if ((i%step)==0) { @@ -185,9 +201,12 @@ int main(int argc, char** argv) writeImage( labelImage, s.str(), format ); } - DGtal::trace.endBlock(); + + trace.info() << "Total time spent: " << sumt << std::endl; + trace.endBlock(); } + } catch (DGtal::InputException i) { trace.emphase() << "starting bel not found" << std::endl; } From 09a2d7b06a84f63bdfea1b0893bb86bb861466d4 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 7 Mar 2012 18:08:34 +0100 Subject: [PATCH 014/108] MCM again with distance map updated in the course of the computation --- deformations/FrontierEvolver.ih | 199 +++++++++++++++++++++++++------- 1 file changed, 160 insertions(+), 39 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index fe0da20..60ff559 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -79,35 +79,53 @@ double DGtal::FrontierEvolver ::update() { + trace.info() << "starting surfel: " << mySurfel << std::endl; /// set of points that are candidate to the flip - std::vector points; + typedef std::vector Band; + typedef typename Band::const_iterator BandIterator; + Band points; init ( std::back_inserter( points ) ); trace.info() << points.size() << " closest points" << std::endl; /// velocity and zero-crossing time computation typedef std::pair PointTime; - std::vector candidates; + typedef std::vector CandidateVector; + typedef typename CandidateVector::const_iterator CandidateIterator; + CandidateVector candidates; + + typedef std::pair DistanceVelocity; + typedef std::vector DistanceVelocityVector; + typedef typename DistanceVelocityVector::const_iterator DistanceVelocityIterator; + DistanceVelocityVector buffer; + double vmax = 0; - for (typename std::vector::const_iterator + for ( BandIterator it = points.begin(), itEnd = points.end(); it != itEnd; ++it) { + // distance + Distance d = myDImage( *it ); // velocity Velocity v = myFunctor( *it ); // maximal velocity double vabs = std::abs( static_cast( v ) ); - if (vabs > vmax) vmax = vabs; + if (vabs > vmax) vmax = vabs; + // storing distance and velocity + buffer.push_back( DistanceVelocity( d, v ) ); // new candidate with its zero-crossing time - double d = myDImage( *it ); if ( ( (d>=0) && (v<0) ) || ( (d<=0) && (v>0) ) ) { //if opposite signs (and v != 0) - double t = - d / v; + double t = - static_cast( d ) / v; ASSERT( t >= 0 ); candidates.push_back( PointTime( *it, t ) ); } + // std::cout << d << " " << v << " " + // << std::abs(d)/std::abs(v) + // << std::endl; + } trace.info() << candidates.size() << " candidates " << std::endl; @@ -134,28 +152,36 @@ DGtal::FrontierEvolver::const_iterator + for (CandidateIterator it = candidates.begin(), itEnd = candidates.end(); ( (it != itEnd)&&(go) ); ++it) { - p = it->first; + plast = p; + p = it->first; + tlast = t; t = it->second; if ( (t <= tmax) && ( myPointPred( p ) ) ) { /// flip + std::cout << t << " "; nbFlips++; - if ( myLImage(p) == myInnerLabel ) + const Label pLabel = myLImage(p); + if ( pLabel == myInnerLabel ) { - std::cerr << "i" ; + ASSERT(myDImage(p) <= 0); + std::cout << "i" ; myLImage.setValue( p, myOuterLabel ); + ASSERT( (myDImage(p)+tmax*myFunctor(p)) >= 0.0 ); } - else if ( myLImage(p) == myOuterLabel ) + else if ( pLabel == myOuterLabel ) { - std::cerr << "o" ; + ASSERT(myDImage(p) > 0); + std::cout << "o" ; myLImage.setValue( p, myInnerLabel ); + ASSERT( (myDImage(p)+tmax*myFunctor(p)) <= 0.0 ); } else ASSERT( false && "impossible label in update method" ); @@ -163,12 +189,52 @@ DGtal::FrontierEvolver -0.00001) ) + { + if (myLImage( *it ) == myInnerLabel) newDist = 0; + else newDist = 0.00001; + } + // set value + myDImage.setValue( *it, newDist ); + + std::cout << pair.first << " " << newDist << " " + << pair.second << " " + << std::abs(pair.first)/std::abs(pair.second) + << std::endl; + if ( (std::abs(pair.first)/std::abs(pair.second)) <= (tlast + 0.00001) ) + { + ASSERT( ( (pair.first >= -0.00001)&&(myLImage( *it ) == myInnerLabel) ) + || ( (pair.first <= 0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); + } + else + { + ASSERT( ( (pair.first <= 0.00001)&&(myLImage( *it ) == myInnerLabel) ) + || ( (pair.first >= -0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); + } + ASSERT( ( (newDist <= 0.00001)&&(myLImage( *it ) == myInnerLabel) ) + || ( (newDist >= -0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); + } - updateFrontier( p ); - return t; + /// update frontier + updateFrontier( plast ); + + return tlast; } else return 0.0; @@ -187,32 +253,79 @@ DGtal::FrontierEvolver PointSet; PointSet points(myDImage); - points.clear(); + //points.clear(); /// initialization of points from the - /// points adjacent to the frontier - trace.info() << "starting surfel: " << mySurfel << std::endl; + /// points adjacent to the frontier unsigned int nbsurfels = 0; - for ( SurfelIterator it = myFrontier->begin(), - itEnd = myFrontier->end(); - it != itEnd; ++it ) - { - Point in( getInnerPoint( *it ) ); - Point out( getOuterPoint( *it ) ); + if (points.size() == 0) + {//first step + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + ASSERT( myLImage(in) == myInnerLabel ); + Point out( getOuterPoint( *it ) ); + ASSERT( myLImage(out) == myOuterLabel ); + //TODO using predicate on labels + if ( myDImage.domain().isInside( in ) ) + { + insertAndAlwaysSetValue( myDImage, points, in, -0.5 ); + } + if ( myDImage.domain().isInside( out ) ) + { + insertAndAlwaysSetValue( myDImage, points, out, 0.5 ); + } + ++nbsurfels; + } + } + else + {//next steps + typedef std::pair PointDistance; + std::vector firstPoints; - if ( myDImage.domain().isInside( in ) ) //TODO using predicate on labels - insertAndAlwaysSetValue( myDImage, points, in, -0.5 ); - if ( myDImage.domain().isInside( out ) ) - insertAndAlwaysSetValue( myDImage, points, out, 0.5 ); + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + ASSERT( myLImage(in) == myInnerLabel ); + Point out( getOuterPoint( *it ) ); + ASSERT( myLImage(out) == myOuterLabel ); + //TODO using predicate on labels + if ( myDImage.domain().isInside( in ) ) + { + const Distance d = myDImage( in ); + //ASSERT( d <= 0 ); + std::cout << d << " " << (d<=0) << std::endl; + firstPoints.push_back( PointDistance( in, d ) ); + } + if ( myDImage.domain().isInside( out ) ) + { + const Distance d = myDImage( out ); + //ASSERT( d > 0 ); + std::cout << d << " " << (d>0) << std::endl; + firstPoints.push_back( PointDistance( out, d ) ); + } + ++nbsurfels; + } - ++nbsurfels; + points.clear(); + for ( typename std::vector::const_iterator + it = firstPoints.begin(), + itEnd = firstPoints.end(); + it != itEnd; ++it ) + { + insertAndAlwaysSetValue( myDImage, points, it->first, it->second ); + } } - trace.info() << nbsurfels << " surfels found." << std::endl; - trace.info() << points << std::endl; + trace.info() << nbsurfels << " surfels found." << std::endl; std::copy( points.begin(), points.end(), res ); /// FMM @@ -226,10 +339,12 @@ DGtal::FrontierEvolver0)) ); *res++ = p; } } @@ -237,7 +352,7 @@ DGtal::FrontierEvolver -0.00001) ); + spel = myKSpace.sSpel( p, KSpace::NEG ); + } else ASSERT( false && "impossible label in updateFrontier method" ); From 92615258751f655cd36f0ded7bf7b107121f5ec4 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 8 Mar 2012 17:14:56 +0100 Subject: [PATCH 015/108] removing sign error --- deformations/FrontierEvolver.ih | 177 ++++++++++++++++++-------- deformations/testLocalDeformation.cpp | 60 ++++----- 2 files changed, 152 insertions(+), 85 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 60ff559..622090e 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -84,9 +84,9 @@ DGtal::FrontierEvolver Band; typedef typename Band::const_iterator BandIterator; - Band points; - init ( std::back_inserter( points ) ); - trace.info() << points.size() << " closest points" << std::endl; + Band narrowBand; + init ( std::back_inserter( narrowBand ) ); + trace.info() << narrowBand.size() << " closest points" << std::endl; /// velocity and zero-crossing time computation typedef std::pair PointTime; @@ -101,8 +101,8 @@ DGtal::FrontierEvolversecond; if ( (t <= tmax) && ( myPointPred( p ) ) ) { /// flip - std::cout << t << " "; nbFlips++; const Label pLabel = myLImage(p); if ( pLabel == myInnerLabel ) @@ -174,14 +173,12 @@ DGtal::FrontierEvolver= 0.0 ); } else if ( pLabel == myOuterLabel ) { ASSERT(myDImage(p) > 0); std::cout << "o" ; myLImage.setValue( p, myInnerLabel ); - ASSERT( (myDImage(p)+tmax*myFunctor(p)) <= 0.0 ); } else ASSERT( false && "impossible label in update method" ); @@ -194,45 +191,40 @@ DGtal::FrontierEvolver -0.00001) ) + if ( (newDist < 0.0001)&&(newDist > -0.0001) ) { - if (myLImage( *it ) == myInnerLabel) newDist = 0; - else newDist = 0.00001; + if (myLImage( *it ) == myInnerLabel) newDist = -0.0001; + else newDist = 0.0001; } // set value - myDImage.setValue( *it, newDist ); - - std::cout << pair.first << " " << newDist << " " - << pair.second << " " - << std::abs(pair.first)/std::abs(pair.second) - << std::endl; - if ( (std::abs(pair.first)/std::abs(pair.second)) <= (tlast + 0.00001) ) - { - ASSERT( ( (pair.first >= -0.00001)&&(myLImage( *it ) == myInnerLabel) ) - || ( (pair.first <= 0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); - } - else - { - ASSERT( ( (pair.first <= 0.00001)&&(myLImage( *it ) == myInnerLabel) ) - || ( (pair.first >= -0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); - } - ASSERT( ( (newDist <= 0.00001)&&(myLImage( *it ) == myInnerLabel) ) - || ( (newDist >= -0.00001)&&(myLImage( *it ) == myOuterLabel) ) ); - } - + myDImage.setValue( *it, newDist ); + + // debug info + // std::cout << pair.first << " " << newDist << " " + // << pair.second << " " + // << std::abs(pair.first)/std::abs(pair.second) + // << std::endl; + ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) ); + } - /// update frontier - updateFrontier( plast ); + /// update frontier if needed + if (nbFlips > 0) + updateFrontier( plast ); return tlast; } @@ -259,7 +251,7 @@ DGtal::FrontierEvolver PointDistance; - std::vector firstPoints; + std::vector adjacentPoints; for ( SurfelIterator it = myFrontier->begin(), itEnd = myFrontier->end(); @@ -300,40 +292,113 @@ DGtal::FrontierEvolver 0 ); - std::cout << d << " " << (d>0) << std::endl; - firstPoints.push_back( PointDistance( out, d ) ); + Distance d = myDImage( out ); + ASSERT( d > 0 ); + //std::cout << d << " " << (d>0) << std::endl; + adjacentPoints.push_back( PointDistance( out, d ) ); } ++nbsurfels; } points.clear(); for ( typename std::vector::const_iterator - it = firstPoints.begin(), - itEnd = firstPoints.end(); + it = adjacentPoints.begin(), + itEnd = adjacentPoints.end(); it != itEnd; ++it ) { - insertAndAlwaysSetValue( myDImage, points, it->first, it->second ); + PointDistance pair( *it ); + insertAndSetValue( myDImage, points, pair.first, pair.second ); } + trace.info() << adjacentPoints.size() << " adjacent points." << std::endl; + trace.info() << points.size() << " distinct adjacent points." << std::endl; } trace.info() << nbsurfels << " surfels found." << std::endl; std::copy( points.begin(), points.end(), res ); + ///////////// debug + // for (typename PointSet::Iterator it = points.begin(), + // itEnd = points.end(); it != itEnd; ++it) + // { + // Point neighbor = *it; + // for (Dimension k = 0; k < Point::dimension; ++k) + // { + // typename Point::Coordinate c = neighbor.at(k); + // neighbor.at(k) = (c+1); + // if ( points.find(neighbor) == points.end() ) + // { + // unsigned int nb = 0, nbPos = 0; + // Point neighbor2 = neighbor; + // for (Dimension l = 0; l < Point::dimension; ++l) + // { + // typename Point::Coordinate c = neighbor2.at(l); + // neighbor2.at(l) = (c+1); + // if ( points.find(neighbor2) != points.end() ) + // { + // nb++; + // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; + // if ( myDImage( neighbor2 )>=0 ) nbPos++; + // } + // neighbor2.at(l) = (c-1); + // if ( points.find(neighbor2) != points.end() ) + // { + // nb++; + // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; + // if ( myDImage( neighbor2 )>=0 ) nbPos++; + // } + // neighbor2.at(l) = c; + // } + // std::cout << nbPos << " / " << nb << " / 6 " << std::endl; + // ASSERT( (nbPos == nb)||(nbPos == 0) ); + // } + // neighbor.at(k) = (c-1); + // if ( points.find(neighbor) == points.end() ) + // { + // unsigned int nb = 0, nbPos = 0; + // Point neighbor2 = neighbor; + // for (Dimension l = 0; l < Point::dimension; ++l) + // { + // typename Point::Coordinate c = neighbor2.at(l); + // neighbor2.at(l) = (c+1); + // if ( points.find(neighbor2) != points.end() ) + // { + // nb++; + // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; + // if ( myDImage( neighbor2 )>=0 ) nbPos++; + // } + // neighbor2.at(l) = (c-1); + // if ( points.find(neighbor2) != points.end() ) + // { + // nb++; + // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; + // if ( myDImage( neighbor2 )>=0 ) nbPos++; + // } + // neighbor2.at(l) = c; + // } + // std::cout << nbPos << " / " << nb << " / 6 " << std::endl; + // ASSERT( (nbPos == nb)||(nbPos == 0) ); + // } + + // neighbor.at(k) = c; + // } + // } + // trace.info() << "DT..." << std::endl; + ///////// end debug + /// FMM //definition typedef FMM FMM; //TODO restreindre a deux labels FMM fmm( myDImage, points, myDImage.domain().predicate() ); + trace.info() << fmm << std::endl; Point p = Point::diagonal(0); //last point Distance d = 0; //its distance @@ -432,12 +497,12 @@ DGtal::FrontierEvolver -0.00001) ); + ASSERT( (myDImage(p) > 0) ); spel = myKSpace.sSpel( p, KSpace::NEG ); } else diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 50540d0..9f9c3b1 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -168,48 +168,50 @@ int main(int argc, char** argv) // Functor functor(map); //getting a bel - Thresholder t( 0 ); - typedef ConstImageAdapter, bool> BinaryImage; - BinaryImage binaryImage(labelImage, t); + KSpace::SCell bel; try { - KSpace::SCell bel = Surfaces::findABel( ks, binaryImage, 10000 ); + Thresholder t( 0 ); + typedef ConstImageAdapter, bool> BinaryImage; + BinaryImage binaryImage(labelImage, t); + + bel = Surfaces::findABel( ks, binaryImage, 10000 ); trace.info() << "starting bel: " << bel << std::endl; + } catch (DGtal::InputException i) { + trace.emphase() << "starting bel not found" << std::endl; + return 0; + } - //frontier evolver - FrontierEvolver - e(ks, labelImage, map, bel, functor, predicate, w ); - - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) - { - std::stringstream s0; - s0 << "iteration # " << i; - trace.beginBlock( s0.str() ); + //frontier evolver + FrontierEvolver + e(ks, labelImage, map, bel, functor, predicate, w ); - //update - sumt += e.update(); + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + std::stringstream s0; + s0 << "iteration # " << i; + trace.beginBlock( s0.str() ); - if ((i%step)==0) - { + //update + sumt += e.update(); - //3d to 2d display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( labelImage, s.str(), format ); + if ((i%step)==0) + { - } + //3d to 2d display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + writeImage( labelImage, s.str(), format ); - trace.info() << "Total time spent: " << sumt << std::endl; - trace.endBlock(); - } + } + trace.info() << "Total time spent: " << sumt << std::endl; + trace.endBlock(); + } - } catch (DGtal::InputException i) { - trace.emphase() << "starting bel not found" << std::endl; - } //interactive display after the evolution if (vm.count("withVisu")) displayImage( argc, argv, labelImage ); From c61186beb1f8ae39af4ecafe8450fbb5d8d4c476 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 9 Mar 2012 17:41:24 +0100 Subject: [PATCH 016/108] ok, topological pb implies ASSERT inner point with positive distance, works for small w --- deformations/FrontierEvolver.ih | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 622090e..cf9702c 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -294,14 +294,12 @@ DGtal::FrontierEvolver 0 ); - //std::cout << d << " " << (d>0) << std::endl; adjacentPoints.push_back( PointDistance( out, d ) ); } ++nbsurfels; @@ -408,10 +406,12 @@ DGtal::FrontierEvolver0)) ); + ASSERT( myDImage(p) == d ); + ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0)) + || ((myLImage(p) == myOuterLabel)&&(d>0)) ); *res++ = p; } + std::cout << std::endl; } trace.info() << fmm << std::endl; From 94137e47ddd3af42dec2898fb87fb3dca6f856e9 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 13 Mar 2012 19:08:19 +0100 Subject: [PATCH 017/108] small changes for testing --- deformations/deformation2d.cpp | 11 +++++++---- deformations/deformation3d.cpp | 25 ++++++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 79be6b0..d33c2a6 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -214,10 +214,13 @@ int main(int argc, char** argv) std::fill(a.begin(),a.end(), 1 ); typedef ExactDiffusionEvolver > Diffusion; - typedef ExplicitReactionEvolver, - ImageContainerBySTLVector > Reaction; - Diffusion diffusion; - Reaction reaction( epsilon, a, k, flagWithCstVol ); + typedef ExactReactionEvolver > Reaction; + Diffusion diffusion; + Reaction reaction( epsilon ); + // typedef ExplicitReactionEvolver, + // ImageContainerBySTLVector > Reaction; + // Diffusion diffusion; + // Reaction reaction( epsilon, a, k, flagWithCstVol ); LieSplittingEvolver e(diffusion, reaction); for (unsigned int i = step; i <= max; i += step) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index b4b78d5..56d84cf 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -113,20 +113,24 @@ int main(int argc, char** argv) Point q(dsize,dsize,dsize); Point c(dsize/2,dsize/2,dsize/2); ImageContainerBySTLVector implicitFunction( Domain(p,q) ); - //initWithBall( implicitFunction, c, (dsize*3/5)/2); - initWithFlower( implicitFunction, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); if (!(vm.count("inputImage"))) - trace.info() << "starting interface initialized with a flower shape" << std::endl; + { + DGtal::trace.beginBlock("image reading..."); + initWithFlower( implicitFunction, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + trace.info() << "starting interface initialized with a flower shape" << std::endl; + DGtal::trace.endBlock(); + } else { string imageFileName = vm["inputImage"].as(); trace.emphase() << imageFileName < BinaryImage; BinaryImage img = VolReader::importVol( imageFileName); Domain d = img.domain(); - p = d.lowerBound(); q = d.upperBound(); - implicitFunction = ImageContainerBySTLVector( Domain(p,q) ); + implicitFunction = ImageContainerBySTLVector( d ); + DGtal::trace.endBlock(); initWithDT( img, implicitFunction ); } @@ -207,10 +211,13 @@ int main(int argc, char** argv) std::fill(a.begin(),a.end(), 1.0 ); typedef ExactDiffusionEvolver > Diffusion; - typedef ExplicitReactionEvolver, - ImageContainerBySTLVector > Reaction; - Diffusion diffusion; - Reaction reaction( epsilon, a, k ); + typedef ExactReactionEvolver > Reaction; + Diffusion diffusion; + Reaction reaction( epsilon ); + // typedef ExplicitReactionEvolver, + // ImageContainerBySTLVector > Reaction; + // Diffusion diffusion; + // Reaction reaction( epsilon, a, k ); LieSplittingEvolver e(diffusion, reaction); for (unsigned int i = step; i <= max; i += step) From 9f790e49f56bd63641c0642495dbc53b02142cfd Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 21 Mar 2012 19:08:53 +0100 Subject: [PATCH 018/108] changes for the predicate: from one argument (point) to two (point, label) --- deformations/BinaryPredicates.h | 91 +++++++++++++++++++++++++++ deformations/FrontierEvolver.h | 11 ++-- deformations/FrontierEvolver.ih | 39 +++++++----- deformations/testLocalDeformation.cpp | 3 +- 4 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 deformations/BinaryPredicates.h diff --git a/deformations/BinaryPredicates.h b/deformations/BinaryPredicates.h new file mode 100644 index 0000000..b4fe43b --- /dev/null +++ b/deformations/BinaryPredicates.h @@ -0,0 +1,91 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file BinaryPredicates.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/02/02 + * + * This files contains several basic classes representing binary predicates + * + * This file is part of the DGtal library. + */ + +#if defined(BinaryPredicates_RECURSES) +#error Recursive header files inclusion detected in BinaryPredicates.h +#else // defined(BinaryPredicates_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define BinaryPredicates_RECURSES + +#if !defined BinaryPredicates_h +/** Prevents repeated inclusion of headers. */ +#define BinaryPredicates_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include "DGtal/base/Common.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // template class ConstantBinaryPredicate + /** + * Description of template class 'ConstantPointPredicate'

+ * \brief Aim: The predicate that returns always the same value boolCst + * + * @tparam boolCst any boolean value + */ + template + struct ConstantBinaryPredicate + { + /** + * @param t1 first argument + * @param t2 second argument + * @tparam T1 type of the first argument + * @tparam T2 type of the second argument + * @return the value of the predicate + */ + template + bool operator()( const T1& t1, const T2& t2 ) const + { + return boolCst; + } + + }; // end of class ConstantBinaryPredicate + + typedef ConstantBinaryPredicate TrueBinaryPredicate; + typedef ConstantBinaryPredicate FalseBinaryPredicate; + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +//#include "BinaryPredicates.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined BinaryPredicates_h + +#undef BinaryPredicates_RECURSES +#endif // else defined(BinaryPredicates_RECURSES) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index c47aeac..9179704 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -45,9 +45,9 @@ #include "DGtal/base/Common.h" #include "DGtal/images/CImage.h" #include "DGtal/kernel/CPointFunctor.h" -#include "CPointFunctorAdapter.h" #include "DGtal/kernel/CPointPredicate.h" + // set #include "DGtal/kernel/sets/DigitalSetFromMap.h" #include "DGtal/kernel/sets/DigitalSetBySTLSet.h" @@ -122,10 +122,11 @@ namespace DGtal (( ConceptUtils::SameType< typename TKSpace::Point, typename TFunctor::Point>::value )); - BOOST_CONCEPT_ASSERT(( CPointPredicate )); - BOOST_STATIC_ASSERT - (( ConceptUtils::SameType< typename TKSpace::Point, - typename TPredicate::Point>::value )); + // BOOST_CONCEPT_ASSERT(( CPointPredicate )); + // BOOST_STATIC_ASSERT + // (( ConceptUtils::SameType< typename TKSpace::Point, + // typename TPredicate::Point>::value )); + //TODO testing TPredicate as a binary predicate on points and labels // ----------------------- Types ------------------------------ public: diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index cf9702c..71e4423 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -164,24 +164,27 @@ DGtal::FrontierEvolverfirst; tlast = t; t = it->second; - if ( (t <= tmax) && ( myPointPred( p ) ) ) - { /// flip - nbFlips++; + if (t <= tmax) + { const Label pLabel = myLImage(p); - if ( pLabel == myInnerLabel ) - { - ASSERT(myDImage(p) <= 0); - std::cout << "i" ; - myLImage.setValue( p, myOuterLabel ); + if ( myPointPred( p, pLabel ) ) + { /// flip + nbFlips++; + if ( pLabel == myInnerLabel ) + { + ASSERT(myDImage(p) <= 0); + std::cout << "i" ; + myLImage.setValue( p, myOuterLabel ); + } + else if ( pLabel == myOuterLabel ) + { + ASSERT(myDImage(p) > 0); + std::cout << "o" ; + myLImage.setValue( p, myInnerLabel ); + } + else + ASSERT( false && "impossible label in update method" ); } - else if ( pLabel == myOuterLabel ) - { - ASSERT(myDImage(p) > 0); - std::cout << "o" ; - myLImage.setValue( p, myInnerLabel ); - } - else - ASSERT( false && "impossible label in update method" ); } else go = false; @@ -210,6 +213,9 @@ DGtal::FrontierEvolver g( d, 1.0 ); //predicate and functor - typedef TruePointPredicate Predicate; + typedef TrueBinaryPredicate Predicate; Predicate predicate; // typedef LocalBalloonForce > Functor; From 5b5aef63a953b4b90b66defdb3e515e87b3d7b20 Mon Sep 17 00:00:00 2001 From: troussil Date: Thu, 29 Mar 2012 16:47:59 +0200 Subject: [PATCH 019/108] adjusting with-Cairo ifdef --- deformations/deformationDisplay3d.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 0fc80c4..4f7233e 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -2,7 +2,9 @@ //display 3D // static + #ifdef WITH_CAIRO #include "DGtal/io/boards/Board3DTo2D.h" + #endif #include "DGtal/io/Color.h" #include "DGtal/io/colormaps/GradientColorMap.h" @@ -14,6 +16,7 @@ bool writeImage(const TImage& img, string filename, string format, const double& if (format.compare("png")==0) { + #ifdef WITH_CAIRO Board3DTo2D viewer; Domain d = img.domain(); @@ -91,7 +94,6 @@ bool writeImage(const TImage& img, string filename, string format, const double& int size = img.extent().at(0); std::stringstream s; - #ifdef WITH_CAIRO s << filename << ".png"; viewer.saveCairo(s.str().c_str(),Board3DTo2D::CairoPNG,3*size/2,3*size/2 ); return true; From 596335518c3f5b5fc0868fe8fcedf070938a8f00 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 29 Mar 2012 19:28:46 +0200 Subject: [PATCH 020/108] trying renormalize the implicit function --- deformations/FrontierEvolver.ih | 57 +++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 71e4423..54f2966 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -284,8 +284,12 @@ DGtal::FrontierEvolver PointDistance; - std::vector adjacentPoints; + + //TODO think about the best way of dealing adjacentPoints + //and copying it in the band + typedef std::pair PointDistance; + std::map adjacentPoints; + typedef typename std::map::iterator IteratorPointDistance; for ( SurfelIterator it = myFrontier->begin(), itEnd = myFrontier->end(); @@ -295,29 +299,56 @@ DGtal::FrontierEvolver 0 ); + + // //TODO renormalize the distance values + // Distance e = std::abs(din)+std::abs(dout); + // Distance ndin = din/e; + // Distance ndout = dout/e; + Distance ndin = din; + Distance ndout = dout; + + std::pair rin + = adjacentPoints.insert( PointDistance( in, ndin ) ); + if (rin.second == false) + {//if the same point is already stored + //take the minimal distance + if (ndin < rin.first->second) + rin.first->second = ndin; + } + std::pair rout + = adjacentPoints.insert( PointDistance( out, ndout ) ); + if (rout.second == false) + {//if the same point is already stored + //take the minimal distance + if (ndout < rout.first->second) + rout.first->second = ndout; + } } - if ( myDImage.domain().isInside( out ) ) + else { - Distance d = myDImage( out ); - ASSERT( d > 0 ); - adjacentPoints.push_back( PointDistance( out, d ) ); + if (flagIn) + {ASSERT(false && "not implemented yet");} + if (flagOut) + {ASSERT(false && "not implemented yet");} } ++nbsurfels; } points.clear(); - for ( typename std::vector::const_iterator + for ( IteratorPointDistance it = adjacentPoints.begin(), itEnd = adjacentPoints.end(); it != itEnd; ++it ) { - //TODO renormalize the distance values PointDistance pair( *it ); insertAndSetValue( myDImage, points, pair.first, pair.second ); } From a9fcdb3556a5386385484deb277b7392ae4a379f Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 30 Mar 2012 10:33:15 +0200 Subject: [PATCH 021/108] little bug correction in distance renormalization --- deformations/FrontierEvolver.ih | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 54f2966..a2d93b7 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -310,18 +310,18 @@ DGtal::FrontierEvolver 0 ); // //TODO renormalize the distance values - // Distance e = std::abs(din)+std::abs(dout); - // Distance ndin = din/e; - // Distance ndout = dout/e; - Distance ndin = din; - Distance ndout = dout; + Distance e = std::abs(din)+std::abs(dout); + Distance ndin = din/e; + Distance ndout = dout/e; + // Distance ndin = din; + // Distance ndout = dout; std::pair rin = adjacentPoints.insert( PointDistance( in, ndin ) ); if (rin.second == false) {//if the same point is already stored //take the minimal distance - if (ndin < rin.first->second) + if (std::abs(ndin) < std::abs(rin.first->second)) rin.first->second = ndin; } std::pair rout @@ -329,7 +329,7 @@ DGtal::FrontierEvolversecond) + if (std::abs(ndout) < std::abs(rout.first->second)) rout.first->second = ndout; } } From ce3482a3f38efdf342a8097dab77dc88bbff7a10 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 30 Mar 2012 11:00:09 +0200 Subject: [PATCH 022/108] hide trace in local level set method --- deformations/FrontierEvolver.ih | 45 ++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index a2d93b7..664bff9 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -27,6 +27,7 @@ */ +//#define WITHINFO ////////////////////////////////////////////////////////////////////////////// @@ -79,14 +80,18 @@ double DGtal::FrontierEvolver ::update() { + #ifdef WITHINFO trace.info() << "starting surfel: " << mySurfel << std::endl; + #endif /// set of points that are candidate to the flip typedef std::vector Band; typedef typename Band::const_iterator BandIterator; Band narrowBand; init ( std::back_inserter( narrowBand ) ); + #ifdef WITHINFO trace.info() << narrowBand.size() << " closest points" << std::endl; + #endif /// velocity and zero-crossing time computation typedef std::pair PointTime; @@ -127,27 +132,38 @@ DGtal::FrontierEvolversecond << " to " << candidates.rbegin()->second << std::endl; + #endif /// flip points one by one, in order, /// while possible @@ -173,13 +189,13 @@ DGtal::FrontierEvolver 0); - std::cout << "o" ; + //std::cout << "o" ; myLImage.setValue( p, myInnerLabel ); } else @@ -189,11 +205,16 @@ DGtal::FrontierEvolver FMM; //TODO restreindre a deux labels FMM fmm( myDImage, points, myDImage.domain().predicate() ); + #ifdef WITHINFO trace.info() << fmm << std::endl; + #endif Point p = Point::diagonal(0); //last point Distance d = 0; //its distance @@ -451,7 +478,9 @@ DGtal::FrontierEvolver Date: Fri, 30 Mar 2012 18:10:57 +0200 Subject: [PATCH 023/108] topological predicate introduction --- deformations/FrontierEvolver.h | 12 +- deformations/FrontierEvolver.ih | 86 ++++++---- deformations/PointPredicates.h | 225 ++++++++++++++++++++++++++ deformations/testLocalDeformation.cpp | 51 +++--- 4 files changed, 310 insertions(+), 64 deletions(-) create mode 100644 deformations/PointPredicates.h diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 9179704..d2a0298 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -47,6 +47,12 @@ #include "DGtal/kernel/CPointFunctor.h" #include "DGtal/kernel/CPointPredicate.h" +//predicates +#include "DGtal/base/BasicBoolFunctions.h" +#include "DGtal/kernel/BasicPointPredicates.h" +#include "PointPredicates.h" + + // set #include "DGtal/kernel/sets/DigitalSetFromMap.h" @@ -155,9 +161,9 @@ namespace DGtal /// Point functor for the mapping points-velocity typedef TFunctor Functor; typedef typename Functor::Value Velocity; - /// Point predicate - typedef TPredicate Predicate; - + /// Topological predicate + typedef TPredicate Predicate; + // ----------------------- Standard services ------------------------------ public: diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 664bff9..854c584 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -167,6 +167,8 @@ DGtal::FrontierEvolver notSimplePoints; //points not flipped because not simple + unsigned int nbFlips = 0; Point p = Point::diagonal(0), plast = Point::diagonal(0); double t = 0.0, tlast = 0.0; @@ -182,24 +184,34 @@ DGtal::FrontierEvolversecond; if (t <= tmax) { - const Label pLabel = myLImage(p); - if ( myPointPred( p, pLabel ) ) + const Label label = myLImage(p); + const Label oppositeLabel = + (label == myInnerLabel)?myOuterLabel:myInnerLabel; + if ( myPointPred( p, oppositeLabel ) ) { /// flip nbFlips++; - if ( pLabel == myInnerLabel ) - { - ASSERT(myDImage(p) <= 0); - //std::cout << "i" ; - myLImage.setValue( p, myOuterLabel ); - } - else if ( pLabel == myOuterLabel ) - { - ASSERT(myDImage(p) > 0); - //std::cout << "o" ; - myLImage.setValue( p, myInnerLabel ); - } - else - ASSERT( false && "impossible label in update method" ); + myLImage.setValue( p, oppositeLabel ); + // if ( pLabel == myInnerLabel ) + // { + // ASSERT(myDImage(p) <= 0); + // //std::cout << "i" ; + // myLImage.setValue( p, myOuterLabel ); + // } + // else if ( pLabel == myOuterLabel ) + // { + // ASSERT(myDImage(p) > 0); + // //std::cout << "o" ; + // myLImage.setValue( p, myInnerLabel ); + // } + // else + // ASSERT( false && "impossible label in update method" ); + } + else + { + notSimplePoints.insert( p ); + #ifdef WITHINFO + trace.emphase() << p << " is not a simple point!" << std::endl; + #endif } } else @@ -228,14 +240,19 @@ DGtal::FrontierEvolver::epsilon(); // correction due to the approximation error - if ( (newDist < 0.0001)&&(newDist > -0.0001) ) + if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) + //correction due to the non simplicity + || ( notSimplePoints.find( *it ) != notSimplePoints.end() ) ) { - if (myLImage( *it ) == myInnerLabel) newDist = -0.0001; - else newDist = 0.0001; + if (pLabel == myInnerLabel) newDist = -eps; + else newDist = eps; } - //correction due to the non simplicity - //if not simple, .... // set value myDImage.setValue( *it, newDist ); @@ -288,16 +305,15 @@ DGtal::FrontierEvolver 0 ); - // //TODO renormalize the distance values + //renormalize distance values Distance e = std::abs(din)+std::abs(dout); Distance ndin = din/e; Distance ndout = dout/e; @@ -455,10 +472,16 @@ DGtal::FrontierEvolver FMM; + //predicate definition //TODO restreindre a deux labels - FMM fmm( myDImage, points, myDImage.domain().predicate() ); + typedef TwoLabelsPredicate > LabelPredicate; + typedef BinaryPointPredicate FMMPointPredicate; + LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + FMMPointPredicate pred( predOnLabels, myLImage.domain().predicate(), std::logical_and() ); + //FMM definition + typedef FMM FMM; + FMM fmm( myDImage, points, pred ); #ifdef WITHINFO trace.info() << fmm << std::endl; #endif @@ -476,7 +499,6 @@ DGtal::FrontierEvolver0)) ); *res++ = p; } - std::cout << std::endl; } #ifdef WITHINFO trace.info() << fmm << std::endl; diff --git a/deformations/PointPredicates.h b/deformations/PointPredicates.h new file mode 100644 index 0000000..cc1f5e2 --- /dev/null +++ b/deformations/PointPredicates.h @@ -0,0 +1,225 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file PointPredicates.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/02/02 + * + * This files contains several basic classes representing binary predicates + * + * This file is part of the DGtal library. + */ + +#if defined(PointPredicates_RECURSES) +#error Recursive header files inclusion detected in PointPredicates.h +#else // defined(PointPredicates_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define PointPredicates_RECURSES + +#if !defined PointPredicates_h +/** Prevents repeated inclusion of headers. */ +#define PointPredicates_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include "DGtal/base/Common.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + ///////////////////////////////////////////////////////////////////////////// + // template class OneLabelPredicate + /** + * \brief Aim: Predicate returning true or false + * according to the comparison of a label with a reference label. + * + * @tparam TLabel type of labels + (must be default-constructible and equally-comparable) + * @tparam TBinaryPredicate type of binary predicate + (must have a () operator taking two input parameters + and returning a boolean). + * + */ + template + class OneLabelPredicate + { + public: + typedef typename TImage::Value Value; + typedef typename TImage::Point Point; + + public: + /** + * Constructor + * @param aImg any image + * @param aLabel any label + * @param aFunctor any binary functor + */ + OneLabelPredicate(const TImage& aImg, const Value& aLabel, + const TBinaryPredicate& aFunctor = TBinaryPredicate() ) + : myImg(aImg), myLabel(aLabel), myF(aFunctor) + { + } + + private: + /** + * Reference on an image + */ + const TImage& myImg; + /** + * Value to compare with + */ + Value myLabel; + /** + * Comparison method + */ + TBinaryPredicate myF; + + public: + /** + * Compare @a aLabel to @a myLabel with @a myF + * @param aPoint any point of the image domain + * whose label has to be compared to @a myLabel + * @return true or false + */ + bool operator()(const Point& aPoint) const + { + return myF(myLabel, myImg(aPoint) ); + } + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const + { + return true; + } + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const + { + out << "(" << myLabel << ")"; + } + + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class TwoLabelsPredicate + /** + * \brief Aim: Predicate returning true or false + * according to the comparison of a label with + * two reference labels. + * + * @tparam TLabel type of labels + (must be default-constructible and equally-comparable) + * @tparam TBinaryPredicate type of binary predicate + (must have a () operator taking two input parameters + and returning a boolean). + * + */ + template + class TwoLabelsPredicate + { + + public: + typedef typename TImage::Value Value; + typedef typename TImage::Point Point; + + public: + /** + * Constructor + * @param aImg any image + * @param aLabel1 any value + * @param aLabel2 any value + * @param aFunctor any binary functor + */ + TwoLabelsPredicate(const TImage& aImg, + const Value& aLabel1, const Value& aLabel2, + const TBinaryPredicate& aFunctor = TBinaryPredicate() ) + : myImg(aImg), myLabel1(aLabel1), myLabel2(aLabel2), myF(aFunctor) + { + } + + private: + /** + * Reference on an image + */ + const TImage& myImg; + /** + * Value to compare with + */ + Value myLabel1; + /** + * Value to compare with + */ + Value myLabel2; + /** + * Comparison method + */ + TBinaryPredicate myF; + + public: + /** + * Compare the label of @a aPoint to @a myLabel1 and @a myLabel2 + * with @a myF + * @param aPoint any point whose label has to be compared + * @return true or false + */ + bool operator()(const Point& aPoint) const + { + return ( myF(myLabel1, myImg(aPoint)) || myF(myLabel2, myImg(aPoint)) ); + } + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const + { + return true; + } + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const + { + out << "(" << myLabel1 << " U " << myLabel2 << ")"; + } + }; + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +//#include "PointPredicates.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined PointPredicates_h + +#undef PointPredicates_RECURSES +#endif // else defined(PointPredicates_RECURSES) diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 2369717..7dee466 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -18,12 +18,13 @@ namespace po = boost::program_options; #include "DGtal/base/BasicFunctors.h" #include "DGtal/images/ConstImageAdapter.h" #include "BinaryPredicates.h" +//#include "SimplePointHelper.h" +#include "DGtal/topology/helpers/SimplePointHelper.h" #include "DGtal/shapes/Shapes.h" #include "LocalBalloonForce.h" #include "LocalMCM.h" -#include "LocalMCMforDT.h" #include "FrontierEvolver.h" @@ -50,9 +51,8 @@ int main(int argc, char** argv) general_opt.add_options() ("help,h", "display this message") ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) - ("timeStep,t", po::value()->default_value(1.0), "Time step for the evolution" ) - ("displayStep,d", po::value()->default_value(1), "Number of time steps between 2 drawings" ) - ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) + ("timeBound,t", po::value()->default_value(1.0), "Maximum time for the evolution" ) + ("displayStep,d", po::value()->default_value(1), "Number of iterations between 2 drawings" ) ("bandWidth,w", po::value()->default_value(1.0), "Width of the flipping band" ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) @@ -68,7 +68,7 @@ int main(int argc, char** argv) { trace.info()<< "Local deformation" << std::endl << "Basic usage: "< --withVisu" << std::endl + << argv[0] << " [other options] -t

- @ingroup Concepts - @brief Aim: Defines the concept describing a point functor, - adapted from another one, which can be returned by the base() method - and can be set the attach() method. - -

Refinement : - - \t PointFunctor - -

Nested types : - - \t PointFunctor : a model of CPointFunctor - -

Notation - - \t X : a model of CPointFunctorAdpter - - \t x : object of type X - -

Definitions - -

Valid expressions and semantics
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
\b Name \b Expression \b Type requirements \b Return type \b Precondition \b Semantics \b Postcondition \b Complexity
underlying point functor x.base() const PointFunctor& returns the underlying point functor
underlying point functor x.attach(const PointFunctor&) set the underlying point functor
- -

Invariants
- -

Models
- - -

Notes
- - @tparam X the type that should be a model of CPointFunctorAdpter. - */ - template - struct CPointFunctorAdpter : CPointFunctor - { - // ----------------------- Concept checks ------------------------------ - public: - // Inner types - typedef typename X::PointFunctor PointFunctor; - BOOST_CONCEPT_ASSERT(( CPointFunctor )); - - // Methods - BOOST_CONCEPT_USAGE( CPointFunctorAdpter ) - { - ConceptUtils::sameType( myPF, myX.base() ); - myX.attach( myPF ); - } - // ------------------------- Private Datas -------------------------------- - private: - X myX; - const PointFunctor& myPF; - - // ------------------------- Internals ------------------------------------ - private: - - }; // end of concept CPointFunctorAdpter - -} // namespace DGtal - -// // -/////////////////////////////////////////////////////////////////////////////// - -#endif // !defined CPointFunctorAdpter_h - -#undef CPointFunctorAdpter_RECURSES -#endif // else defined(CPointFunctorAdpter_RECURSES) From 175eb276d7150f4a3b0752e33fede36a5c1e64fa Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 2 Apr 2012 16:14:16 +0200 Subject: [PATCH 026/108] test with image by STL Vector instead of image by STL Map --- deformations/FrontierEvolver.h | 62 ++++++++++++++- deformations/FrontierEvolver.ih | 73 ++++++------------ deformations/PointPredicates.h | 107 ++++++++++++++++++++++++++ deformations/testLocalDeformation.cpp | 14 ++-- 4 files changed, 196 insertions(+), 60 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index d2a0298..38b5c30 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -72,6 +72,52 @@ namespace DGtal { + //------------------------------------------------------------------------------ + template +struct SetFromImageDomainValueTraits + { + public: + typedef DigitalSetBySTLSet Set; + public: + public: + static Set get(I& aImage) + { + return Set(aImage.domain()); + } + }; + //Partial specialization + template +struct SetFromImageDomainValueTraits< + ImageContainerBySTLMap, + D, V > + { + public: + typedef DigitalSetFromMap > Set; + public: + static Set get(ImageContainerBySTLMap& aImage) + { + return Set(aImage); + } + }; + //------------------------------------------------------------------------------ + template +struct SetFromImageSelector + { + public: + BOOST_CONCEPT_ASSERT(( CImage )); + typedef typename I::Domain Domain; + typedef typename I::Value Value; + + typedef typename SetFromImageDomainValueTraits::Set Set; + + public: + static Set get(I& i) + { + return SetFromImageDomainValueTraits::get(i); + } + }; + + //------------------------------------------------------------------------------ namespace details { class CompareSecondElement { @@ -137,19 +183,22 @@ namespace DGtal // ----------------------- Types ------------------------------ public: - /// Khalimsky space - typedef TKSpace KSpace; - typedef typename TKSpace::Point Point; - /// Image of labels typedef TLabelImage LImage; typedef typename LImage::Value Label; typedef typename LImage::Domain Domain; + typedef typename Domain::Point Point; /// Image of distance values typedef TDistanceImage DImage; typedef typename DImage::Value Distance; + /// Set of points where the distance values are known + typedef typename SetFromImageSelector::Set PointSet; + + /// Khalimsky space + typedef TKSpace KSpace; + /// Frontier typedef FrontierPredicate SurfelPredicate; typedef LightExplicitDigitalSurface Frontier; @@ -237,6 +286,10 @@ namespace DGtal * Reference on the image of distance values */ DImage& myDImage; + /** + * Set of points where the distance values are known + */ + PointSet myPointSet; /** * Reference on the starting surfel of the digital frontier */ @@ -247,6 +300,7 @@ namespace DGtal const Functor& myFunctor; /** * Constant reference on the predicate + * TODO: rename it into myTopoPred */ const Predicate& myPointPred; /** diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 87a2b52..e8b3653 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -27,7 +27,7 @@ */ -#define WITHINFO +//#define WITHINFO ////////////////////////////////////////////////////////////////////////////// @@ -45,8 +45,9 @@ inline DGtal::FrontierEvolver ::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, const Functor& aF, const Predicate& aP, const double& aW) - : myKSpace( aK ), myLImage( aI ), myDImage( aD ), mySurfel( aS ), - myFunctor( aF ), myPointPred( aP ), myW( aW ), + : myKSpace( aK ), myLImage( aI ), myDImage( aD ), + myPointSet( SetFromImageSelector::get( myDImage ) ), + mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), myW( aW ), myInnerLabel( myLImage( getInnerPoint( mySurfel ) ) ), myOuterLabel( myLImage( getOuterPoint( mySurfel ) ) ), mySurfelPred( myKSpace, myLImage, myInnerLabel, myOuterLabel ), @@ -127,9 +128,6 @@ DGtal::FrontierEvolver= 0 ); candidates.push_back( PointTime( *it, t ) ); } - // std::cout << d << " " << v << " " - // << std::abs(d)/std::abs(v) - // << std::endl; } #ifdef WITHINFO @@ -191,20 +189,6 @@ DGtal::FrontierEvolver 0); - // //std::cout << "o" ; - // myLImage.setValue( p, myInnerLabel ); - // } - // else - // ASSERT( false && "impossible label in update method" ); } else { @@ -217,7 +201,6 @@ DGtal::FrontierEvolver 0)&&(myLImage( *it ) == myOuterLabel) ) ); } @@ -287,18 +265,10 @@ DGtal::FrontierEvolver PointSet; - PointSet points(myDImage); - //points.clear(); - /// initialization of the band from the /// points adjacent to the frontier unsigned int nbsurfels = 0; - if (points.size() == 0) + if (myPointSet.size() == 0) {//first step for ( SurfelIterator it = myFrontier->begin(), itEnd = myFrontier->end(); @@ -309,12 +279,12 @@ DGtal::FrontierEvolver PointDistance; std::map adjacentPoints; @@ -351,8 +321,6 @@ DGtal::FrontierEvolver rin = adjacentPoints.insert( PointDistance( in, ndin ) ); @@ -381,25 +349,26 @@ DGtal::FrontierEvolver > LabelPredicate; - typedef BinaryPointPredicate > FMMPointPredicate; + typedef CascadingPointPredicate< typename Domain::Predicate, + LabelPredicate > FMMPointPredicate; LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - FMMPointPredicate pred( predOnLabels, myLImage.domain().predicate(), std::logical_and() ); + FMMPointPredicate pred( myLImage.domain().predicate(), predOnLabels ); + + // typedef typename Domain::Predicate FMMPointPredicate; + // FMMPointPredicate pred = myLImage.domain().predicate(); + //FMM definition typedef FMM FMM; - FMM fmm( myDImage, points, pred ); + FMM fmm( myDImage, myPointSet, pred ); #ifdef WITHINFO trace.info() << fmm << std::endl; #endif diff --git a/deformations/PointPredicates.h b/deformations/PointPredicates.h index cc1f5e2..0d1af43 100644 --- a/deformations/PointPredicates.h +++ b/deformations/PointPredicates.h @@ -46,6 +46,113 @@ namespace DGtal { + ///////////////////////////////////////////////////////////////////////////// + // template class CascadingPointPredicate + /** + * Description of template class 'CascadingPointPredicate'

\brief + * Aim: The predicate returns true when the given binary functor + * returns true for the two PointPredicates given at construction. + * + * @tparam PointPredicate1 the left predicate type. + * @tparam PointPredicate2 the right predicate type. + */ + template + struct CascadingPointPredicate + { + typedef TPointPredicate1 PointPredicate1; + typedef TPointPredicate2 PointPredicate2; + typedef typename PointPredicate1::Point Point; + // should be the same. + BOOST_STATIC_ASSERT ((boost::is_same< Point, typename PointPredicate2::Point >::value)); + typedef typename PointPredicate2::Point Point2; + + /** + Constructor from predicates + @param pred1 the left predicate. + @param pred2 the right predicate. + */ + CascadingPointPredicate( const PointPredicate1 & pred1, + const PointPredicate2 & pred2 ); + + /** + Copy constructor. + @param other the object to copy + */ + CascadingPointPredicate( const CascadingPointPredicate& other ); + + /** + Assignement + @param other the object to copy + @return reference to the current object + */ + CascadingPointPredicate& operator=( const CascadingPointPredicate& other ); + + /** + Destructor + */ + ~CascadingPointPredicate(); + + /** + * @param p any point. + * @return the value of the predicate at this point. + */ + bool operator()( const Point & p ) const; + + /// aliasing pointer to the left predicate. + const PointPredicate1* myPred1; + /// aliasing pointer to the right predicate. + const PointPredicate2* myPred2; + }; + +//------------------------------------------------------------------------------ +template +inline +DGtal::CascadingPointPredicate +::CascadingPointPredicate( const PointPredicate1 & pred1, + const PointPredicate2 & pred2 ) + : myPred1( &pred1 ), myPred2( &pred2 ) +{ +} +//------------------------------------------------------------------------------ +template +inline +DGtal::CascadingPointPredicate +::CascadingPointPredicate( const CascadingPointPredicate& other ) + : myPred1( other.pred1 ), myPred2( other.pred2 ) +{ +} +//------------------------------------------------------------------------------ +template +inline +DGtal::CascadingPointPredicate& +DGtal::CascadingPointPredicate +::operator=( const CascadingPointPredicate& other ) +{ + if (this != &other) + { + myPred1 = other.myPred1; + myPred2 = other.myPred2; + } +} +//------------------------------------------------------------------------------ +template +inline +DGtal::CascadingPointPredicate +::~CascadingPointPredicate() +{ +} +//------------------------------------------------------------------------------ +template +inline +bool +DGtal::CascadingPointPredicate +::operator()( const Point & p ) const +{ + if ( myPred1->operator()( p ) ) + return myPred2->operator()( p ); +} + + ///////////////////////////////////////////////////////////////////////////// // template class OneLabelPredicate /** diff --git a/deformations/testLocalDeformation.cpp b/deformations/testLocalDeformation.cpp index 7dee466..2bce7f8 100644 --- a/deformations/testLocalDeformation.cpp +++ b/deformations/testLocalDeformation.cpp @@ -145,11 +145,13 @@ int main(int argc, char** argv) ks.init( d.lowerBound(), d.upperBound(), true ); //distance map - typedef ImageContainerBySTLMap DistanceImage; - DistanceImage map( d, 0.0 ); + typedef ImageContainerBySTLVector DistanceImage; + DistanceImage distanceImage( d ); //data functions - ImageContainerBySTLMap g( d, 1.0 ); + DistanceImage g( d ); + std::fill( g.begin(), g.end(), 1.0 ); + //predicate // typedef TrueBinaryPredicate Predicate; // Predicate predicate; @@ -161,8 +163,8 @@ int main(int argc, char** argv) // ImageContainerBySTLMap > Functor; // Functor functor(map, g, k); typedef LocalMCM > Functor; - Functor functor(map, g, g); + DistanceImage > Functor; + Functor functor(distanceImage, g, g); //getting a bel KSpace::SCell bel; @@ -183,7 +185,7 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, map, bel, functor, predicate, w ); + e(ks, labelImage, distanceImage, bel, functor, predicate, w ); trace.beginBlock( "Deformation" ); double sumt = 0; From f845dd14658d01713f5cb2f6b46793b192379eec Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 3 Apr 2012 15:27:25 +0200 Subject: [PATCH 027/108] many tests... (topo pred and diff operators) --- deformations/FrontierEvolver.ih | 2 + deformations/LocalMCM.h | 23 + deformations/LocalMCM.ih | 37 +- deformations/SimplePointHelper.h | 439 +++++++++++ deformations/SimplePointHelper.ih | 950 +++++++++++++++++++++++ deformations/SimplePointHelperDetails.ih | 366 +++++++++ deformations/deformationDisplay3d.h | 83 +- deformations/testLocalDeformation.cpp | 19 +- 8 files changed, 1911 insertions(+), 8 deletions(-) create mode 100644 deformations/SimplePointHelper.h create mode 100644 deformations/SimplePointHelper.ih create mode 100644 deformations/SimplePointHelperDetails.ih diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index e8b3653..f304d09 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -321,6 +321,8 @@ DGtal::FrontierEvolver rin = adjacentPoints.insert( PointDistance( in, ndin ) ); diff --git a/deformations/LocalMCM.h b/deformations/LocalMCM.h index ca32ed9..1429d22 100644 --- a/deformations/LocalMCM.h +++ b/deformations/LocalMCM.h @@ -42,6 +42,8 @@ ////////////////////////////////////////////////////////////////////////////// // Inclusions #include "DGtal/kernel/CPointFunctor.h" + +#include "DGtal/images/DifferentialOperators.h" ////////////////////////////////////////////////////////////////////////////// namespace DGtal @@ -75,6 +77,9 @@ namespace DGtal typedef typename PointFunctor::Point Point; typedef double Value; + + typedef typename Gradient >::OutputValue Normal; + typedef typename Divergence >::OutputValue Curvature; /** * Constructor @@ -90,6 +95,24 @@ namespace DGtal template double operator()( const TInputPoint& aPoint ) const; + /** + * Gradient. + * @param aPoint any point. + * @tparam TInputPoint type of point + * @return the gradient at @a aPoint. + */ + template + Normal getNormal( const TInputPoint& aPoint ) const; + + /** + * Curvature. + * @param aPoint any point. + * @tparam TInputPoint type of point + * @return curvature at @a aPoint. + */ + template + Curvature getCurvature( const TInputPoint& aPoint ) const; + private: /** * Aliasing pointer to the implicit function diff --git a/deformations/LocalMCM.ih b/deformations/LocalMCM.ih index 0f3aa7a..70c03b0 100644 --- a/deformations/LocalMCM.ih +++ b/deformations/LocalMCM.ih @@ -30,7 +30,6 @@ #include ////////////////////////////////////////////////////////////////////////////// -#include "DGtal/images/DifferentialOperators.h" /////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION of inline methods. @@ -72,7 +71,43 @@ DGtal::LocalMCM return res; } //------------------------------------------------------------------------------ +template +template +inline +typename DGtal::LocalMCM::Normal +DGtal::LocalMCM +::getNormal( const TInputPoint& aPoint ) const +{ + ASSERT( myFuncPtr ); + PointFunctor* tmpFuncPtr = const_cast(myFuncPtr); +//ugly until differential operators are updated +//gradient + CentralDifference cdiff( *tmpFuncPtr ); + Gradient > cg( cdiff ); + return cg( aPoint ); +} + +//------------------------------------------------------------------------------ +template +template +inline +typename DGtal::LocalMCM::Curvature +DGtal::LocalMCM +::getCurvature( const TInputPoint& aPoint ) const +{ + ASSERT( myFuncPtr ); + PointFunctor* tmpFuncPtr = const_cast(myFuncPtr); + PointFunctor* tmpBPtr = const_cast(myBPtr); +//ugly until differential operators are updated + +//mean curvature + //TODO allow different types for implicit function and extern field + //in weightedDifference + WeightedDifference2 diff2( *tmpFuncPtr, *tmpBPtr ); + Divergence > div(diff2); + return div( aPoint ); +} // // /////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/SimplePointHelper.h b/deformations/SimplePointHelper.h new file mode 100644 index 0000000..fdf197c --- /dev/null +++ b/deformations/SimplePointHelper.h @@ -0,0 +1,439 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file SimplePointHelper.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en LabelsImage et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2011/11/03 + * + * @brief Header file for module SimplePointHelper.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(SimplePointHelper_RECURSES) +#error Recursive header files inclusion detected in SimplePointHelper.h +#else // defined(SimplePointHelper_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define SimplePointHelper_RECURSES + +#if !defined SimplePointHelper_h +/** Prevents repeated inclusion of headers. */ +#define SimplePointHelper_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions + +#include +#include +#include +#include +#include +#include + +#include "DGtal/base/Common.h" +#include "DGtal/kernel/SpaceND.h" +#include "DGtal/kernel/domains/HyperRectDomain.h" +#include "DGtal/images/ImageContainerBySTLVector.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + #include "SimplePointHelperDetails.ih" + + ///////////////////////////////////////////////////////////////////////////// + // template class SimplePointHelper + /** + * \brief Aim: Tests whether a given voxel v + * is ML-simple with respect to a given region. + * + * Two voxels u and w are r-adjacent (0 <= r <= dim) iff + * exactly (dim-r) coordinates are equal and r differ by one. + * The r-neighborhood of a voxel u is the set of voxels that are r-adjacent to u. + * The h(anImage); + trace.info() << h.isMLsimple(aPoint, aLabel) << endl; + + * @endcode + * + * It is also possible to test if a point is simple: + * + * @code + + DGtal::SimplePointHelper h(anImage); + trace.info() << h.isMLsimple(aPoint) << endl; + + * @endcode + * + * NB: The method isSimple() returns 'true' if the center voxel v + * is simple for the region V it belongs to (and the voxels that + * does not belong to V are assumed to belong to the complementary set). + * + * @tparam TImage type of image. + */ + template + class SimplePointHelper + { + + BOOST_STATIC_ASSERT( (TImage::dimension<=3)&&(TImage::dimension>=1) ); + + // ----------------------- Types ------------------------------ + public: + + + typedef TImage LabelsImage; + typedef typename TImage::Value Label; + + typedef typename TImage::Domain Domain; + typedef typename Domain::Point Point; + typedef typename Domain::Point Vector; + typedef typename Point::Coordinate Coordinate; + + private: + + typedef ImageContainerBySTLVector BinaryImage; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Main constructor. + * + * @param aImg any image + * @param aLabel label of the infinite region + * located outside the image domain + * (default value if not provided) + */ + SimplePointHelper(LabelsImage& aImg, const Label& aLabel); + + /** + * Destructor. Does nothing. + */ + ~SimplePointHelper(); + + + /** + * Checks if @a aPoint is ML-simple with respect + * to the region having label @a aLabel. + * + * @param aPoint any point + * @param aLabel any label + * @return 'true' if ML-simple, 'false' otherwise. + */ + bool isMLSimple(const Point& aPoint, const Label& aLabel) const; + + /** + * Checks if @a aPoint is ML-simple with respect + * to the region having label @a aLabel. + * + * @param aPoint any point + * @param aLabel any label + * @return 'true' if ML-simple, 'false' otherwise. + * + * @see isMLSimple + */ + bool operator()(const Point& aPoint, const Label& aLabel) const; + + + /** + * Checks if @a aPoint is simple with respect + * to the region @a aPoint belongs to. + * + * @param aPoint any point + * @return 'true' if simple, 'false' otherwise. + */ + bool isSimple(const Point& aPoint) const; + + /** + * Checks if the underlying image is labeled, + * ie. sets of voxels of same label are (dim-1)-connected. + * + * @return 'true' if the image is labeled, 'false' otherwise. + * + * NB: trivial algorithm in O(|D|.|L|), + * where |D| is the size of the domain and + * |L| is the number of distinct labels in the image. + */ + bool isLabeled() const; + + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, + * ie. the underlying image is labeled, + * 'false' otherwise. + * + * @see isLabeled + */ + bool isValid() const; + + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + + // ------------------------- Static methods ------------------------------ + + /** + * Read labels from the range [ @a itb , @a ite ) for filling @a aImg. + * + * @param aImg labeled image to fill + * @param itb begin iterator + * @param ite end iterator + * @tparam TIterator type of iterator on labels. + */ + template + static void readConfiguration ( LabelsImage& aImg, + const TIterator& itb, const TIterator& ite ); + + /** + * Randomly fill the image @a aImg with the labels contained in @a labels + * following a region growing strategy from the center voxel. + * + * NB: The number of distinct adjacent regions to the center voxel + * depends of the number of distinct labels, but also depends on + * the probability @a prob of filling the neighbors of a given voxel + * (the less the probability is, the more there are distincts regions). + * + * @param aImg labeled image to fill + * @param labels set of distinct labels + * @param prob probability of growing from a given voxel to its neighbor + * @return 'true' is the computed configuration is valid, + * 'false' otherwise + */ + static bool generateRandomConfiguration ( LabelsImage& aImg, const std::set

+ * \brief Aim: This class is a way of deforming an image of labels + * around all the connected contact surfaces between two adjacent regions, + * according to a speed field, whose computation is delegated to a point functor. + * + * + * @tparam TKSpace a model of CCellularGridSpaceND + * @tparam TLabelImage a model of CImage (storing labels) + * @tparam TDistanceImage a model of CImage (storing distance values) + * @tparam TExternImage a model of CImage (storing an extern scalar field) + * @tparam TTopoPredicate + */ + template + class PartitionEvolver + { + + + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TLabelImage::Point>::value )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TDistanceImage::Point>::value )); + + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TExternImage::Point>::value )); + + // BOOST_CONCEPT_ASSERT(( CPoinTTopoPredicate )); + // BOOST_STATIC_ASSERT + // (( ConceptUtils::SameType< typename TKSpace::Point, + // typename TTopoPredicate::Point>::value )); + //TODO testing TTopoPredicate as a binary TopoPredicate on points and labels + + // ----------------------- Types ------------------------------ + public: + + /// Khalimsky space + typedef TKSpace KSpace; + typedef typename KSpace::Cell Cell; + typedef typename KSpace::SCell SCell; + + /// Image of labels + typedef TLabelImage LabelImage; + typedef typename LabelImage::Value Label; + typedef typename LabelImage::Domain Domain; + typedef typename Domain::Point Point; + + /// Images of distance values + typedef TDistanceImage DistanceImage; + typedef CountedPtr DistanceImagePtr; + + /// Extern image + typedef TExternImage ExternImage; + + /// Point functor for the mapping points-speed + typedef LocalMCM Functor; + typedef CountedPtr FunctorPtr; + + /// Topological predicate + typedef TTopoPredicate TopoPredicate; + + /// Frontier evolver + typedef FrontierEvolver Evolver; + typedef CountedPtr FrontierEvolverPtr; + + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * @param aK khalimsky space where the digital frontiers are defined + * @param aI an image of labels + * @param aF any extern data field + * @param aP any point TopoPredicate + */ + PartitionEvolver(const KSpace& aK, LabelImage& aI, const ExternImage& aF, const TopoPredicate& aP); + + /** + * Destructor. Does nothing. + */ + ~PartitionEvolver(); + + + /** + * Deform the image of labels during @a aT + * + * @param aT time step + * @return time spent during the deformation + * (equal to aT). + */ + double update(const double& aT); + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const; + + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + + // ------------------------- Protected Datas ------------------------------ + protected: + // ------------------------- Private Datas -------------------------------- + private: + + + // ------------------------- References -------------------------------- + /** + * Constant reference on the khalimsky space + */ + const KSpace& myKSpace; + /** + * Reference on the image of labels + */ + LabelImage& myLabelImage; + /** + * Constant reference on the extern image + */ + const ExternImage& myExternImage; + /** + * Constant reference on the topological predicate + */ + const TopoPredicate& myTopoPred; + + + // ------------------------- Data -------------------------------- + /** + * Set of smart owning pointers on images (of distance values) + */ + std::vector myImages; + /** + * Set of smart owning pointers on functors, + * which locally computes the differential estimations + * and displacement speed + */ + std::vector myFunctors; + /** + * Set of smart owning pointers on frontier evolvers + */ + std::vector myEvolvers; + + // ------------------------- Hidden services ------------------------------ + protected: + + + /** + * Copy constructor. + * @param other the object to clone. + * Forbidden by default. + */ + PartitionEvolver ( const PartitionEvolver & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + * Forbidden by default. + */ + PartitionEvolver & operator= ( const PartitionEvolver & other ); + + private: + + + + // ------------------------- Internals ------------------------------------ + private: + + /** + * Insert bels, ie cells lying between two points + * of different labels in @a aImg, + * in @a aSet + * @param aSet (returned) set of bels. + * @param aKSpace khalimsky space. + * @param aImg label image. + * @param aLowerBound. + * @param aUpperBound. + */ + void getBels ( std::set& aSet, + const KSpace & aKSpace, + const LabelImage & aImg, + const Point & aLowerBound, + const Point & aUpperBound ); + + }; // end of class PartitionEvolver + + + /** + * Overloads 'operator<<' for displaying objects of class 'PartitionEvolver'. + * @param out the output stream where the object is written. + * @param object the object of class 'PartitionEvolver' to write. + * @return the output stream after the writing. + */ + template + std::ostream& + operator<< ( std::ostream & out, + const PartitionEvolver & object ); + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "PartitionEvolver.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined PartitionEvolver_h + +#undef PartitionEvolver_RECURSES +#endif // else defined(PartitionEvolver_RECURSES) diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih new file mode 100644 index 0000000..c401fff --- /dev/null +++ b/deformations/PartitionEvolver.ih @@ -0,0 +1,209 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file PartitionEvolver.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/04/06 + * + * @brief Implementation of inline methods defined in PartitionEvolver.h + * + * This file is part of the DGtal library. + */ + + + +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Standard services ------------------------------ + +// frontier +#include "DGtal/topology/SurfelAdjacency.h" +#include "DGtal/topology/helpers/FrontierPredicate.h" +#include "DGtal/topology/LightExplicitDigitalSurface.h" +#include "DGtal/topology/SCellsFunctors.h" + +template +inline +DGtal::PartitionEvolver +::PartitionEvolver(const KSpace& aK, LabelImage& aI, const ExternImage& aF, const TopoPredicate& aP) + : myKSpace( aK ), myLabelImage( aI ), myExternImage( aF ), myTopoPred( aP ) +{ + + /// retrieve bels + std::set bels; + getBels( bels, myKSpace, myLabelImage, myKSpace.lowerBound(), myKSpace.upperBound() ); + + /// retrieve frontiers + while(!bels.empty()){ + + //unsigned bel + Cell ubel = *(bels.begin()); + //signed version (arbitrary choice) + SCell sbel = myKSpace.sCell( myKSpace.uKCoords( ubel ), false ); + //incident points + SCellToIncidentPoints func( myKSpace ); + typename SCellToIncidentPoints::Output points = func( sbel ); + Label iLabel( myLabelImage( points.first ) ); + Label oLabel( myLabelImage( points.second ) ); + + /// frontier from sbel + typedef FrontierPredicate SurfelPredicate; + /// !!!!!! be careful oLabel and iLabel are swaped because func is wrong + SurfelPredicate surfelPred( myKSpace, myLabelImage, oLabel, iLabel ); + typedef LightExplicitDigitalSurface Frontier; + Frontier frontier( myKSpace, + surfelPred, + SurfelAdjacency( true ), + sbel ); + + // tracking (and removing bels belonging to this frontier) + typedef typename Frontier::SurfelConstIterator SurfelIterator; + for ( SurfelIterator it = frontier.begin(), + itEnd = frontier.end(); + it != itEnd; ++it ) + bels.erase( myKSpace.uCell( myKSpace.sKCoords( *it ) ) ); + + /// new frontier evolver (with its image and differential estimators) + myImages.push_back( DistanceImagePtr( new DistanceImage( myLabelImage.domain() ) ) ); + myFunctors.push_back( FunctorPtr( new Functor( *(*myImages.rbegin()), + myExternImage, + myExternImage ) ) ); + myEvolvers.push_back( FrontierEvolverPtr( new Evolver(myKSpace, + myLabelImage, + *(*myImages.rbegin()), + sbel, + *(*myFunctors.rbegin()), + myTopoPred) ) ); + + ASSERT( myImage.size() == myFunctors.size() ); + ASSERT( myImage.size() == myEvolvers.size() ); + } + +} + +template +inline +DGtal::PartitionEvolver +::~PartitionEvolver() +{ + +} + + + +template +inline +double +DGtal::PartitionEvolver +::update(const double& aT) +{ + + /// update all frontiers (in arbitrary order) + for (typename std::vector::const_iterator + it = myEvolvers.begin(), + itEnd = myEvolvers.end(); it != itEnd; ++it) + { + FrontierEvolverPtr e = *it; + e->update( aT ); + } + + return aT; +} + + +template +inline +void +DGtal::PartitionEvolver +::selfDisplay ( std::ostream & out ) const +{ + out << "[PartitionEvolver] "; + out << myEvolvers.size() << " frontier(s) "; +} + +template +inline +bool +DGtal::PartitionEvolver +::isValid() const +{ + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// Internals // + +template +inline +void +DGtal::PartitionEvolver +::getBels( std::set& aSet, + const KSpace & aKSpace, + const LabelImage & aImg, + const Point & aLowerBound, + const Point & aUpperBound ) +{ + for (DGtal::Dimension k = 0; k < KSpace::dimension; ++k ) + { + Cell dir_low_uid = aKSpace.uSpel( aLowerBound ); + Cell dir_up_uid = aKSpace.uGetDecr( aKSpace.uSpel( aUpperBound ), k); + Cell p = dir_low_uid; + do + { + Label here = aImg( aKSpace.uCoords(p) ); + Label next = aImg( aKSpace.uCoords(aKSpace.uGetIncr( p, k )) ); + if ( here != next ) + { // add new bel to the set. + aSet.insert( aKSpace.uIncident( p, k, true )); + } + } + while ( aKSpace.uNext( p, dir_low_uid, dir_up_uid ) ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Implementation of inline functions // + +template +inline +std::ostream& +DGtal::operator<< ( std::ostream & out, + const PartitionEvolver & object ) +{ + object.selfDisplay( out ); + return out; +} + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 407c689..36a6432 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -24,6 +24,10 @@ using namespace Z3i; #include "ExplicitReactionEvolver.h" #include "LieSplittingEvolver.h" +//local level set +#include "SimplePointHelper.h" +#include "PartitionEvolver.h" + /////////////////////////// useful functions #include "deformationFunctions.h" #include "deformationDisplay3d.h" @@ -45,17 +49,17 @@ int main(int argc, char** argv) ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) ("shape,s", po::value()->default_value("ball"), -"Generated shape: either (default) or " ) + "Generated shape: either (default) or " ) ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) ("algo,a", po::value()->default_value("levelSet"), -"can be: \n \n or " ) + "can be: \n \n or " ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) ("outputFormat,f", po::value()->default_value("png"), -"Output files format: either (3d to 2d, default) or (3d)" ) + "Output files format: either (3d to 2d, default) or (3d)" ) ("withVisu", "Enables interactive 3d visualization after evolution" ); @@ -65,9 +69,10 @@ int main(int argc, char** argv) if(vm.count("help")||argc<=1) { trace.info()<< "Evolution of a 3d interface" << std::endl - << "Basic usage: "< -n --withVisu" << std::endl - << general_opt << "\n"; + << "Basic usage: "< -n --withVisu" + << std::endl + << general_opt << "\n"; return 0; } @@ -104,13 +109,13 @@ int main(int argc, char** argv) format = vm["outputFormat"].as(); if ((format != "png")&&(format != "vol")) { - trace.info() << "format is expected to be either png or vol " << std::endl; - return 0; + trace.info() << "format is expected to be either png or vol " << std::endl; + return 0; } //image and implicit function - typedef ImageContainerBySTLVector LabelImage; + typedef ImageContainerBySTLVector LabelImage; LabelImage* labelImage = NULL; if (vm.count("inputImage")) @@ -138,7 +143,8 @@ int main(int argc, char** argv) } else initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - trace.info() << "starting interface initialized with a " << (vm["shape"].as()) << std::endl; + trace.info() << "starting interface initialized with a " + << (vm["shape"].as()) << std::endl; DGtal::trace.endBlock(); } @@ -157,174 +163,165 @@ int main(int argc, char** argv) algo = vm["algo"].as(); if (algo.compare("levelSet")==0) - { + { - //balloon force - double k; - if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; - k = vm["balloonForce"].as(); + //balloon force + double k; + if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; + k = vm["balloonForce"].as(); - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); - //data functions - ImageContainerBySTLVector a( d ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( d ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( d ); - std::fill(g.begin(),g.end(), 1.0 ); + //data functions + ImageContainerBySTLVector a( d ); + std::fill(a.begin(),a.end(), 1.0 ); + ImageContainerBySTLVector b( d ); + std::fill(b.begin(),b.end(), 1.0 ); + ImageContainerBySTLVector g( d ); + std::fill(g.begin(),g.end(), 1.0 ); - //interface evolver - WeickertKuhneEvolver > e(a,b,g,k,1); + //interface evolver + WeickertKuhneEvolver > e(a,b,g,k,1); - DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); + DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; - //update - e.update(implicitFunction,tstep); + //update + e.update(implicitFunction,tstep); - if ((i%step)==0) - { + if ((i%step)==0) + { - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( implicitFunction, s.str(), format ); + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + writeImage( implicitFunction, s.str(), format ); - } - sumt += tstep; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } + } + sumt += tstep; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } - DGtal::trace.endBlock(); + DGtal::trace.endBlock(); - //interactive display after the evolution - if (vm.count("withVisu")) displayImage2( argc, argv, implicitFunction, implicitFunction, a, b ); + //interactive display after the evolution + if (vm.count("withVisu")) displayImage2( argc, argv, implicitFunction, implicitFunction, a, b ); - } else if (algo.compare("phaseField")==0) - { + } else if (algo.compare("phaseField")==0) + { - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } + double epsilon = 3.0; + if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; + epsilon = vm["epsilon"].as(); + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 0; + } - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); - //computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); + //computing the profile from the signed distance + Profile p(epsilon); + std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - typedef ExactDiffusionEvolver > Diffusion; + typedef ExactDiffusionEvolver > Diffusion; typedef ExactReactionEvolver > Reaction; Diffusion diffusion; Reaction reaction( epsilon ); - // typedef ExplicitReactionEvolver, - // ImageContainerBySTLVector > Reaction; - // Diffusion diffusion; - // ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); - // std::fill(a.begin(),a.end(), 1.0 ); - // Reaction reaction( epsilon, a, k ); - LieSplittingEvolver e(diffusion, reaction); - - DGtal::trace.beginBlock( "Deformation (phase field)" ); - - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; + // typedef ExplicitReactionEvolver, + // ImageContainerBySTLVector > Reaction; + // Diffusion diffusion; + // ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); + // std::fill(a.begin(),a.end(), 1.0 ); + // Reaction reaction( epsilon, a, k ); + LieSplittingEvolver e(diffusion, reaction); - //update - e.update(implicitFunction,tstep); + DGtal::trace.beginBlock( "Deformation (phase field)" ); - if ((i%step)==0) - { + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( implicitFunction, s.str(), format, 0.5 ); + //update + e.update(implicitFunction,tstep); - } - sumt += tstep; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } + if ((i%step)==0) + { - DGtal::trace.endBlock(); + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + writeImage( implicitFunction, s.str(), format, 0.5 ); - //interactive display after the evolution - if (vm.count("withVisu")) displayImage( argc, argv, implicitFunction, 0.5 ); + } + sumt += tstep; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } - } else if (algo.compare("localLevelSet")==0) - { - DGtal::trace.info() << "coming soon... " << std::endl; - -/* - //space - KSpace ks; - ks.init( d.lowerBound(), d.upperBound(), true ); - - //distance map - typedef ImageContainerBySTLVector DistanceImage; - DistanceImage distanceImage( d ); + DGtal::trace.endBlock(); - //data functions - DistanceImage g( d ); - std::fill( g.begin(), g.end(), 1.0 ); + //interactive display after the evolution + if (vm.count("withVisu")) displayImage( argc, argv, implicitFunction, 0.5 ); - // local MCM a la Weickert - typedef LocalMCM Functor; - Functor functor(distanceImage, g, g); - - // topological predicate - typedef SimplePointHelper Predicate; - Predicate predicate(*labelImage); - - //frontier evolver - PartitionEvolver - e(ks, *labelImage, functor, predicate); - - DGtal::trace.beginBlock( "Deformation" ); - - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) + } else if (algo.compare("localLevelSet")==0) { - DGtal::trace.info() << "iteration # " << i << std::endl; - - //update - e.update(tstep); - - if ((i%step)==0) - { - - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( *labelImage, s.str(), format ); - + //space + KSpace ks; + ks.init( d.lowerBound(), d.upperBound(), true ); + + //distance image... + typedef ImageContainerBySTLVector DistanceImage; + //and extern data... + DistanceImage g( d ); + std::fill(g.begin(), g.end(), 1.0); + + // topological predicate + typedef SimplePointHelper TopologicalPredicate; + TopologicalPredicate topologicalPredicate(*labelImage); + + //frontier evolver + PartitionEvolver + e(ks, *labelImage, g, topologicalPredicate); + + DGtal::trace.info() << e << std::endl; + + DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); + + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + //update + e.update(tstep); + + if ((i%step)==0) + { + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + writeImage( *labelImage, s.str(), format ); + } + sumt += tstep; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; } - sumt += tstep; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - DGtal::trace.endBlock(); + DGtal::trace.endBlock(); - //interactive display after the evolution - if (vm.count("withVisu")) displayImage2( argc, argv, *labelImage, distanceImage, g, g ); -*/ + //interactive display after the evolution + if (vm.count("withVisu")) displayImage( argc, argv, *labelImage ); + - } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; //free delete( labelImage ); From 427e064073197c64dcaec3d4b70097d929d26105 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 6 Apr 2012 17:21:26 +0200 Subject: [PATCH 044/108] cleaning and improving deformation2d --- deformations/deformation2d.cpp | 126 +++++++++++++++--------- deformations/deformation3d.cpp | 4 +- deformations/deformationFunctions.h | 2 +- deformations/testDisk.cpp | 4 +- deformations/testLocalDeformation2d.cpp | 2 +- 5 files changed, 84 insertions(+), 54 deletions(-) diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index d33c2a6..60dc8ce 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -25,6 +25,9 @@ using namespace Z2i; #include "ExactReactionEvolver.h" #include "LieSplittingEvolver.h" +//local level set +#include "SimplePointHelper.h" +#include "PartitionEvolver.h" /////////////////////////// useful functions #include "deformationFunctions.h" @@ -43,12 +46,14 @@ int main(int argc, char** argv) general_opt.add_options() ("help,h", "display this message") ("inputImage,i", po::value(), "Binary image to initialize the starting interface (.pgm)" ) - ("domainSize,s", po::value()->default_value(64), "Domain size (if default starting interface)" ) - ("timeStep,t", po::value()->default_value(1.0), "Time step for the evolution" ) - ("displayStep,d", po::value()->default_value(1), "Number of time steps between 2 drawings" ) + ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) + ("shape,s", po::value()->default_value("ball"), + "Generated shape: either (default) or " ) + ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) + ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) ("algo,a", po::value()->default_value("levelSet"), -"can be: \n \n or " ) + "can be: \n \n or \n or " ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) ("withCstVol", "with volume conservation (only for phase fields)" ) @@ -106,35 +111,43 @@ int main(int argc, char** argv) return 0; } - //balloon force - double k; - if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; - k = vm["balloonForce"].as(); - - //image and implicit function - Point p(0,0); - Point q(dsize,dsize); - Point c(dsize/2,dsize/2); - ImageContainerBySTLVector implicitFunction( Domain(p,q) ); - //initWithBall( implicitFunction, c, (dsize*3/5)/2 ); - initWithFlower( implicitFunction, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); - if (!(vm.count("inputImage"))) - trace.info() << "starting interface initialized with a flower shape" << std::endl; - else + typedef ImageContainerBySTLVector LabelImage; + LabelImage* labelImage = NULL; + + if (vm.count("inputImage")) { string imageFileName = vm["inputImage"].as(); trace.emphase() << imageFileName < BinaryImage; - BinaryImage img = PNMReader::importPGM( imageFileName ); - Domain d = img.domain(); - implicitFunction = ImageContainerBySTLVector( d ); - initWithDT( img, implicitFunction ); + DGtal::trace.beginBlock("image reading..."); + LabelImage tmp = PNMReader::importPGM( imageFileName ); + labelImage = new LabelImage( tmp ); + DGtal::trace.endBlock(); + } + else + { + DGtal::trace.beginBlock("image reading..."); + Point p(0,0); + Point q(dsize,dsize); + Point c(dsize/2,dsize/2); + labelImage = new LabelImage( Domain(p,q) ); + if (vm.count("shape")) + { + if ( (vm["shape"].as()) == "flower" ) + initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + } + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + trace.info() << "starting interface initialized with a " + << (vm["shape"].as()) << std::endl; + DGtal::trace.endBlock(); } - //area - double area = (double) setSize( implicitFunction ); - trace.info() << "# area: " << area << std::endl; + //domain + Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); + //algo std::string algo; @@ -144,6 +157,14 @@ int main(int argc, char** argv) if (algo.compare("levelSet")==0) { + //balloon force + double k; + if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; + k = vm["balloonForce"].as(); + + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + if (vm.count("withFunction")) drawFunction( implicitFunction, vm["withFunction"].as() ); @@ -152,21 +173,22 @@ int main(int argc, char** argv) drawContour(implicitFunction, ss.str(), format); //data functions - ImageContainerBySTLVector a( Domain(p,q) ); + ImageContainerBySTLVector a( d ); std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( Domain(p,q) ); + ImageContainerBySTLVector b( d ); std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( Domain(p,q) ); + ImageContainerBySTLVector g( d ); std::fill(g.begin(),g.end(), 1.0 ); //evolution WeickertKuhneEvolver > e(a,b,g,k,1); + + DGtal::trace.beginBlock( "Deformation (Weickert level set method)" ); + for (unsigned int i = 1; i <= max; ++i) { - std::stringstream s0; - s0 << "iteration # " << i; - DGtal::trace.beginBlock( s0.str() ); + DGtal::trace.info() << "iteration # " << i << std::endl; e.update( implicitFunction, tstep); @@ -177,12 +199,12 @@ int main(int argc, char** argv) drawContour(implicitFunction, s.str(), format); } - DGtal::trace.endBlock(); - //area - trace.info() << "# area: " << setSize( implicitFunction ) << std::endl; + trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; } + DGtal::trace.endBlock(); + } else if (algo.compare("phaseField")==0) { @@ -199,6 +221,9 @@ int main(int argc, char** argv) if (vm.count("withCstVol")) flagWithCstVol = true; + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + //computing the profile from the signed distance Profile p(epsilon); std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); @@ -210,8 +235,7 @@ int main(int argc, char** argv) ss << outputFiles << "0001"; drawContour(implicitFunction, ss.str(), format, 0.5); - ImageContainerBySTLVector a( implicitFunction.domain() ); - std::fill(a.begin(),a.end(), 1 ); + typedef ExactDiffusionEvolver > Diffusion; typedef ExactReactionEvolver > Reaction; @@ -219,32 +243,38 @@ int main(int argc, char** argv) Reaction reaction( epsilon ); // typedef ExplicitReactionEvolver, // ImageContainerBySTLVector > Reaction; + // ImageContainerBySTLVector a( implicitFunction.domain() ); + // std::fill(a.begin(),a.end(), 1 ); // Diffusion diffusion; // Reaction reaction( epsilon, a, k, flagWithCstVol ); LieSplittingEvolver e(diffusion, reaction); + DGtal::trace.beginBlock( "Deformation (phase field)" ); + for (unsigned int i = step; i <= max; i += step) { - std::stringstream s0; - s0 << "iteration # " << i; - DGtal::trace.beginBlock( s0.str() ); - - e.update( implicitFunction, (tstep*step) ); + DGtal::trace.info() << "iteration # " << i << std::endl; - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format, 0.5); + e.update( implicitFunction, tstep); - DGtal::trace.endBlock(); + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format, 0.5); + } //area - trace.info() << "# area: " << setSize( implicitFunction, 0.5 ) << std::endl; + trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; } + DGtal::trace.endBlock(); } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + //free + delete( labelImage ); return 1; } diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 36a6432..e141a24 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -54,7 +54,7 @@ int main(int argc, char** argv) ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) ("algo,a", po::value()->default_value("levelSet"), - "can be: \n \n or " ) + "can be: \n \n or \n or " ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) @@ -326,6 +326,6 @@ int main(int argc, char** argv) //free delete( labelImage ); - return 0; + return 1; } diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 8e519b6..b9cd5b6 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -3,7 +3,7 @@ /////////////////////////// useful functions template< typename TImage > -int setSize(TImage& img, const double& threshold = 0) +int getSize(TImage& img, const double& threshold = 0) { int c = 0; //counter diff --git a/deformations/testDisk.cpp b/deformations/testDisk.cpp index f3e74cf..bc1a6f4 100644 --- a/deformations/testDisk.cpp +++ b/deformations/testDisk.cpp @@ -36,7 +36,7 @@ void evolution (TEvolver& e, TImage& img, { int i = 0; - int area = setSize( img, threshold ); + int area = getSize( img, threshold ); while ( area > 0 && (i < n) ) { ++i; @@ -48,7 +48,7 @@ void evolution (TEvolver& e, TImage& img, DGtal::trace.endBlock(); - area = setSize( img, threshold ); + area = getSize( img, threshold ); std::cout << "# time expected area computed area" << std::endl; double t = i*tstep; double Rt = std::sqrt(R0*R0 - (2*t)); diff --git a/deformations/testLocalDeformation2d.cpp b/deformations/testLocalDeformation2d.cpp index 6724621..66991f6 100644 --- a/deformations/testLocalDeformation2d.cpp +++ b/deformations/testLocalDeformation2d.cpp @@ -237,7 +237,7 @@ int main(int argc, char** argv) } std::cout << "# time computed area " << std::endl; - std::cout << sumt << " " << setSize(labelImage, 0) << std::endl; + std::cout << sumt << " " << getSize(labelImage, 0) << std::endl; } trace.endBlock(); From 9946ab219abcb14b295687b95734e8d1ffd3e5d6 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 6 Apr 2012 18:04:35 +0200 Subject: [PATCH 045/108] partition 2d (only tested on binary images) --- deformations/FrontierEvolver.h | 4 +- deformations/PartitionEvolver.ih | 5 +- deformations/deformation2d.cpp | 212 +++++++++++++++++----------- deformations/deformationDisplay2d.h | 2 +- 4 files changed, 137 insertions(+), 86 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 6556409..cb54414 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -300,9 +300,9 @@ struct SetFromImageSelector */ PointSet myPointSet; /** - * Reference on the starting surfel of the digital frontier + * Starting surfel of the digital frontier */ - Surfel& mySurfel; + Surfel mySurfel; /** * Constant reference on the functor */ diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index c401fff..32d47e1 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -61,7 +61,7 @@ DGtal::PartitionEvolver func( myKSpace ); typename SCellToIncidentPoints::Output points = func( sbel ); @@ -127,8 +127,7 @@ DGtal::PartitionEvolverupdate( aT ); + (*it)->update( aT ); } return aT; diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 60dc8ce..9f3902e 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) ("withFunction", po::value(), "Output pgm file basename, where the starting implicit function is stored" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) ("outputFormat,f", po::value()->default_value("raster"), -"Output files format: either (image, default) or (domain representation)" ); + "Output files format: either (image, default) or (domain representation)" ); po::variables_map vm; @@ -69,9 +69,9 @@ int main(int argc, char** argv) if(vm.count("help")||argc<=1) { trace.info()<< "Evolution of a 2d interface" << std::endl - << "Basic usage: "< -n " << std::endl - << general_opt << "\n"; + << "Basic usage: "< -n " << std::endl + << general_opt << "\n"; return 0; } @@ -107,8 +107,8 @@ int main(int argc, char** argv) format = vm["outputFormat"].as(); if ((format != "vector")&&(format != "raster")) { - trace.info() << "format is expected to be either vector, or raster " << std::endl; - return 0; + trace.info() << "format is expected to be either vector, or raster " << std::endl; + return 0; } //image and implicit function @@ -155,123 +155,175 @@ int main(int argc, char** argv) algo = vm["algo"].as(); if (algo.compare("levelSet")==0) - { + { - //balloon force - double k; - if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; - k = vm["balloonForce"].as(); + //balloon force + double k; + if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; + k = vm["balloonForce"].as(); ImageContainerBySTLVector implicitFunction( d ); initWithDT( *labelImage, implicitFunction ); - if (vm.count("withFunction")) - drawFunction( implicitFunction, vm["withFunction"].as() ); + if (vm.count("withFunction")) + drawFunction( implicitFunction, vm["withFunction"].as() ); - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format); + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(implicitFunction, ss.str(), format); - //data functions - ImageContainerBySTLVector a( d ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( d ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( d ); - std::fill(g.begin(),g.end(), 1.0 ); + //data functions + ImageContainerBySTLVector a( d ); + std::fill(a.begin(),a.end(), 1.0 ); + ImageContainerBySTLVector b( d ); + std::fill(b.begin(),b.end(), 1.0 ); + ImageContainerBySTLVector g( d ); + std::fill(g.begin(),g.end(), 1.0 ); - //evolution - WeickertKuhneEvolver > e(a,b,g,k,1); + //evolution + WeickertKuhneEvolver > e(a,b,g,k,1); DGtal::trace.beginBlock( "Deformation (Weickert level set method)" ); - for (unsigned int i = 1; i <= max; ++i) - { + for (unsigned int i = 1; i <= max; ++i) + { - DGtal::trace.info() << "iteration # " << i << std::endl; + DGtal::trace.info() << "iteration # " << i << std::endl; - e.update( implicitFunction, tstep); + e.update( implicitFunction, tstep); - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format); - } + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format); + } - //area - trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; - } + //area + trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; + } DGtal::trace.endBlock(); - } else if (algo.compare("phaseField")==0) - { + } else if (algo.compare("phaseField")==0) + { - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } + double epsilon = 3.0; + if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; + epsilon = vm["epsilon"].as(); + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 0; + } - bool flagWithCstVol = false; - if (vm.count("withCstVol")) - flagWithCstVol = true; + bool flagWithCstVol = false; + if (vm.count("withCstVol")) + flagWithCstVol = true; ImageContainerBySTLVector implicitFunction( d ); initWithDT( *labelImage, implicitFunction ); - //computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); + //computing the profile from the signed distance + Profile p(epsilon); + std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - if (vm.count("withFunction")) + if (vm.count("withFunction")) drawFunction( implicitFunction, vm["withFunction"].as() ); - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format, 0.5); + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(implicitFunction, ss.str(), format, 0.5); - typedef ExactDiffusionEvolver > Diffusion; + typedef ExactDiffusionEvolver > Diffusion; typedef ExactReactionEvolver > Reaction; Diffusion diffusion; Reaction reaction( epsilon ); - // typedef ExplicitReactionEvolver, - // ImageContainerBySTLVector > Reaction; - // ImageContainerBySTLVector a( implicitFunction.domain() ); - // std::fill(a.begin(),a.end(), 1 ); - // Diffusion diffusion; - // Reaction reaction( epsilon, a, k, flagWithCstVol ); - LieSplittingEvolver e(diffusion, reaction); + // typedef ExplicitReactionEvolver, + // ImageContainerBySTLVector > Reaction; + // ImageContainerBySTLVector a( implicitFunction.domain() ); + // std::fill(a.begin(),a.end(), 1 ); + // Diffusion diffusion; + // Reaction reaction( epsilon, a, k, flagWithCstVol ); + LieSplittingEvolver e(diffusion, reaction); DGtal::trace.beginBlock( "Deformation (phase field)" ); - for (unsigned int i = step; i <= max; i += step) - { + for (unsigned int i = step; i <= max; i += step) + { - DGtal::trace.info() << "iteration # " << i << std::endl; + DGtal::trace.info() << "iteration # " << i << std::endl; - e.update( implicitFunction, tstep); + e.update( implicitFunction, tstep); - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format, 0.5); - } + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format, 0.5); + } - //area - trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; + //area + trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; - } + } DGtal::trace.endBlock(); - } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + } else if (algo.compare("localLevelSet")==0) + { + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(*labelImage, ss.str(), format); + + //space + KSpace ks; + ks.init( d.lowerBound(), d.upperBound(), true ); + + //distance image... + typedef ImageContainerBySTLVector DistanceImage; + //and extern data... + DistanceImage g( d ); + std::fill(g.begin(), g.end(), 1.0); + + // topological predicate + typedef SimplePointHelper TopologicalPredicate; + TopologicalPredicate topologicalPredicate(*labelImage); + + //frontier evolver + DGtal::trace.beginBlock( "Partition construction" ); + PartitionEvolver + e(ks, *labelImage, g, topologicalPredicate); + + DGtal::trace.info() << e << std::endl; + DGtal::trace.endBlock(); + + DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); + + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + //update + e.update(tstep); + + if ((i%step)==0) + { + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(*labelImage, s.str(), format); + } + sumt += tstep; + } + + DGtal::trace.endBlock(); + + } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; //free delete( labelImage ); diff --git a/deformations/deformationDisplay2d.h b/deformations/deformationDisplay2d.h index f7ee517..12473eb 100644 --- a/deformations/deformationDisplay2d.h +++ b/deformations/deformationDisplay2d.h @@ -46,7 +46,7 @@ bool drawContour(const TImage& img, std::string filename, std::string format, co //create a label image from the implicit function typedef ImageContainerBySTLVector LabelImage; - LabelImage labelImage( img.domain() ); + LabelImage labelImage( Domain( img.domain() ) ); Domain d = labelImage.domain(); Domain::ConstIterator cIt = d.begin(); Domain::ConstIterator cItEnd = d.end(); From 3d5db9bced9b8e07b381add8c5d5033533637ad3 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 9 Apr 2012 09:45:32 +0200 Subject: [PATCH 046/108] test partition 2d --- deformations/deformation2d.cpp | 4 +- deformations/deformationDisplay2d.h | 48 +- deformations/images/partition.pgm | 16388 ++++++++++++++++++++++++++ 3 files changed, 16437 insertions(+), 3 deletions(-) create mode 100644 deformations/images/partition.pgm diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 9f3902e..cc1b417 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -276,7 +276,7 @@ int main(int argc, char** argv) std::stringstream ss; ss << outputFiles << "0001"; - drawContour(*labelImage, ss.str(), format); + drawContours(*labelImage, ss.str(), format); //space KSpace ks; @@ -316,7 +316,7 @@ int main(int argc, char** argv) //display std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(*labelImage, s.str(), format); + drawContours(*labelImage, s.str(), format); } sumt += tstep; } diff --git a/deformations/deformationDisplay2d.h b/deformations/deformationDisplay2d.h index 12473eb..35de141 100644 --- a/deformations/deformationDisplay2d.h +++ b/deformations/deformationDisplay2d.h @@ -7,7 +7,8 @@ template< typename TImage > -bool drawContour(const TImage& img, std::string filename, std::string format, const double& threshold = 0) +bool drawContour(const TImage& img, std::string filename, std::string format, + const double& threshold = 0) { if (format.compare("vector")==0) @@ -67,6 +68,51 @@ bool drawContour(const TImage& img, std::string filename, std::string format, co } else return false; } +template< typename TImage > +bool drawContours(const TImage& img, std::string filename, std::string format, + const double& threshold = 0) +{ + + if (format.compare("vector")==0) + { + + typedef GradientColorMap ColorMap; + ColorMap colormap(0,255); + + Board2D b; + Z2i::Domain d(img.domain()); + Z2i::Domain::ConstIterator cIt = d.begin(); + Z2i::Domain::ConstIterator cItEnd = d.end(); + for ( ; cIt != cItEnd; ++cIt) + { + b << CustomStyle( (*cIt).className(), new CustomFillColor( colormap( img(*cIt) ) ) ); + } + +#ifdef WITH_CAIRO + std::stringstream s; + s << filename << ".png"; + b.saveCairo(s.str().c_str(),Board2D::CairoPNG); +#else + std::stringstream s; + s << filename << ".eps"; + b.saveEPS(s.str().c_str()); +#endif + return true; + + } else if (format.compare("raster")==0) + { + + //write it into a pgm file + std::stringstream s; + s << filename << ".pgm"; + typedef GradientColorMap ColorMap; + PNMWriter::exportPGM( s.str(), img, 0, 255, true ); + + return true; + } else return false; +} + + template< typename TImage > void drawFunction( const TImage& img, std::string basename) { diff --git a/deformations/images/partition.pgm b/deformations/images/partition.pgm new file mode 100644 index 0000000..1560080 --- /dev/null +++ b/deformations/images/partition.pgm @@ -0,0 +1,16388 @@ +P2 +# CREATOR: GIMP PNM Filter Version 1.1 +128 128 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +255 +255 +255 +255 +255 +255 +255 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +137 +137 +137 +137 +137 +137 +137 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 From 1462b682a19648672e9b4a9a3093ae0d6932d413 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 9 Apr 2012 17:21:59 +0200 Subject: [PATCH 047/108] test partition 2d --- deformations/FrontierEvolver.ih | 24 +- deformations/PartitionEvolver.ih | 4 +- deformations/deformation2d.cpp | 5 + deformations/deformationDisplay2d.h | 2 +- deformations/images/glasses.pgm | 16388 ++++++++++++++++++++++++++ deformations/images/glasses2.pgm | 16388 ++++++++++++++++++++++++++ deformations/images/glasses3.pgm | 16388 ++++++++++++++++++++++++++ 7 files changed, 49185 insertions(+), 14 deletions(-) create mode 100644 deformations/images/glasses.pgm create mode 100644 deformations/images/glasses2.pgm create mode 100644 deformations/images/glasses3.pgm diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 1101a32..92b0357 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -505,20 +505,20 @@ DGtal::FrontierEvolver rin = adjacentPoints.insert( PointDistance( in, ndin ) ); - if (rin.second == false) - {//if the same point is already stored - //take the minimal distance - if (std::abs(ndin) < std::abs(rin.first->second)) - rin.first->second = ndin; - } + // if (rin.second == false) + // {//if the same point is already stored + // //take the minimal distance + // if (std::abs(ndin) < std::abs(rin.first->second)) + // rin.first->second = ndin; + // } std::pair rout = adjacentPoints.insert( PointDistance( out, ndout ) ); - if (rout.second == false) - {//if the same point is already stored - //take the minimal distance - if (std::abs(ndout) < std::abs(rout.first->second)) - rout.first->second = ndout; - } + // if (rout.second == false) + // {//if the same point is already stored + // //take the minimal distance + // if (std::abs(ndout) < std::abs(rout.first->second)) + // rout.first->second = ndout; + // } } else { diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index 32d47e1..e8c8cf1 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -123,10 +123,12 @@ DGtal::PartitionEvolver::const_iterator it = myEvolvers.begin(), - itEnd = myEvolvers.end(); it != itEnd; ++it) + itEnd = myEvolvers.end(); it != itEnd; ++it, ++i) { + //trace.info() << "Frontier #" << i << std::endl; (*it)->update( aT ); } diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index cc1b417..37be184 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -123,6 +123,11 @@ int main(int argc, char** argv) LabelImage tmp = PNMReader::importPGM( imageFileName ); labelImage = new LabelImage( tmp ); DGtal::trace.endBlock(); + + std::stringstream ss; + ss << outputFiles << "0000"; + drawContours(*labelImage, ss.str(), format); + } else { diff --git a/deformations/deformationDisplay2d.h b/deformations/deformationDisplay2d.h index 35de141..a2071f6 100644 --- a/deformations/deformationDisplay2d.h +++ b/deformations/deformationDisplay2d.h @@ -76,7 +76,7 @@ bool drawContours(const TImage& img, std::string filename, std::string format, if (format.compare("vector")==0) { - typedef GradientColorMap ColorMap; + typedef GradientColorMap ColorMap; ColorMap colormap(0,255); Board2D b; diff --git a/deformations/images/glasses.pgm b/deformations/images/glasses.pgm new file mode 100644 index 0000000..09deabe --- /dev/null +++ b/deformations/images/glasses.pgm @@ -0,0 +1,16388 @@ +P2 +# CREATOR: GIMP PNM Filter Version 1.1 +128 128 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/deformations/images/glasses2.pgm b/deformations/images/glasses2.pgm new file mode 100644 index 0000000..ac7c418 --- /dev/null +++ b/deformations/images/glasses2.pgm @@ -0,0 +1,16388 @@ +P2 +# CREATOR: GIMP PNM Filter Version 1.1 +128 128 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/deformations/images/glasses3.pgm b/deformations/images/glasses3.pgm new file mode 100644 index 0000000..ca972fb --- /dev/null +++ b/deformations/images/glasses3.pgm @@ -0,0 +1,16388 @@ +P2 +# CREATOR: GIMP PNM Filter Version 1.1 +128 128 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 From 009f8446a9bff8e167ba5ac97a7b7546809dd1c4 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 16 Apr 2012 12:31:51 +0200 Subject: [PATCH 048/108] small bug --- deformations/CMakeLists.txt | 13 ++++++++++--- deformations/PartitionEvolver.ih | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index b52bae1..9cf37f8 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -11,11 +11,18 @@ LINK_DIRECTORIES(${DGTAL_LIBRARY_DIRS}) #Inclusion de Boost -include(FindBoost) -find_package(Boost 1.36.0 REQUIRED program_options) +SET(Boost_ADDITIONAL_VERSIONS "1.49" "1.49.0") +SET(Boost_DEBUG True) +SET(Boost_USE_STATIC_LIBS ON) +SET(Boost_USE_MULTITHREADED OFF) +SET(BOOST_ROOT /usr/local/) +SET(BOOST_INCLUDEDIR /usr/local/include/boost) +SET(BOOST_LIBRARYDIR /usr/local/lib) +find_package(Boost 1.49.0 COMPONENTS program_options) message(STATUS "Found Boost: ${Boost_LIBRARIES} ") -link_directories(${Boost_LIBRARY_DIRS}) +message(STATUS "More precisely: ${Boost_PROGRAM_OPTIONS_LIBRARY} ") include_directories(${Boost_INCLUDE_DIRS}) +link_directories(${Boost_LIBRARY_DIRS}) #fftw INCLUDE_DIRECTORIES(/usr/include/) diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index e8c8cf1..be61cdd 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -97,8 +97,8 @@ DGtal::PartitionEvolver Date: Mon, 16 Apr 2012 20:10:21 +0200 Subject: [PATCH 049/108] providing FMM and differential operators source files for an easier use --- deformations/DifferentialOperators.h | 999 ++++++++++++++++++++++++ deformations/DifferentialOperators.ih | 459 +++++++++++ deformations/FMM.h | 497 ++++++++++++ deformations/FMM.ih | 507 +++++++++++++ deformations/FMMPointFunctors.h | 809 ++++++++++++++++++++ deformations/FMMPointFunctors.ih | 1011 +++++++++++++++++++++++++ deformations/FrontierEvolver.h | 2 +- deformations/FrontierEvolver.ih | 219 ++---- deformations/LocalMCM.h | 2 +- 9 files changed, 4338 insertions(+), 167 deletions(-) create mode 100644 deformations/DifferentialOperators.h create mode 100644 deformations/DifferentialOperators.ih create mode 100644 deformations/FMM.h create mode 100644 deformations/FMM.ih create mode 100644 deformations/FMMPointFunctors.h create mode 100644 deformations/FMMPointFunctors.ih diff --git a/deformations/DifferentialOperators.h b/deformations/DifferentialOperators.h new file mode 100644 index 0000000..4804f64 --- /dev/null +++ b/deformations/DifferentialOperators.h @@ -0,0 +1,999 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file DifferentialOperators.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 201/12/19 + * + * Header file for module DifferentialOperators.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(DifferentialOperators_RECURSES) +#error Recursive header files inclusion detected in DifferentialOperators.h +#else // defined(DifferentialOperators_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define DifferentialOperators_RECURSES + +#if !defined DifferentialOperators_h +/** Prevents repeated inclusion of headers. */ +#define DifferentialOperators_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include +#include "DGtal/images/CConstImage.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + + ///////////////////////////////////////////////////////////////////////////// + // template class ForwardDifference + /** + * Description of template class 'ForwardDifference'

+ * \brief Aim: Computes the forward difference at a point. + * + * + * @tparam TFonctor model of CPointFunctor + * @tparam TPointPredicate model of CPointPredicate + * @tparam TOutputValue type of returned value (default TFunctor::Value) + */ + template + class ForwardDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + ForwardDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~ForwardDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class BackwardDifference + /** + * Description of template class 'BackwardDifference'

+ * \brief Aim: Computes the backward difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class BackwardDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + BackwardDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~BackwardDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class CentralDifference + /** + * Description of template class 'CentralDifference'

+ * \brief Aim: Computes the backward difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class CentralDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + CentralDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~CentralDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class Difference2 + /** + * Description of template class 'Difference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class Difference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Difference2( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Difference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class NormalizedDifference2 + /** + * Description of template class 'NormalizedDifference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class NormalizedDifference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + NormalizedDifference2( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~NormalizedDifference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward difference + * normalized by the inverse of the gradient modulus + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + // ------------------------- Internals -------------------------------- + private: + + /** + * Return the harmonic average of the inverse of @a aV1 and @a aV2 + * + * @param aV1 a first value + * @param aV2 a second value + * @return the average + */ + double average ( const Value& aV1, const Value& aN2 ) const; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class WeightedDifference2 + /** + * Description of template class 'WeightedDifference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class WeightedDifference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aImage any image + * @param aWImage any image of weights + * @param aGridStep any length (=1 by default) + */ + WeightedDifference2( Image& aImage, Image& aWImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~WeightedDifference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward differences on @a aImage + * weighted by @a aWImage and normalized + * by the inverse of the gradient modulus + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return second derivative of @a aImage along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myImage; + /** + * Reference on the weights image + */ + Image& myWImage; + + /** + * Grid step + */ + OutputValue myH; + + // ------------------------- Internals -------------------------------- + private: + + /** + * Return the harmonic average of @a aV1 and @a aV2, + * @a aV1 and @a aV2 being normalized by @a aN1 and @a aN2. + * + * @param aV1 a first value + * @param aN1 any value dividing @a aV1 + * @param aV2 a second value + * @param aN2 any value dividing @a aV2 + * @return the normalized harmonic average of @a aV1 and @a aV2 + */ + double average ( const Value& aV1, const double& aN1, + const Value& aV2, const double& aN2 ) const; + + }; + + /////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // template class Gradient + /** + * Description of template class 'Gradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class Gradient + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TDifference FiniteDifference; + typedef typename FiniteDifference::Dimension Dimension; + static const typename FiniteDifference::Dimension dimension = FiniteDifference::dimension; + typedef typename FiniteDifference::Image Image; + typedef typename FiniteDifference::Point Point; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aD a finite difference operator + */ + Gradient( const FiniteDifference& aD): myD(aD) {} + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Gradient( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Gradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Finite difference + */ + FiniteDifference myD; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class UpwindGradient + /** + * Description of template class 'UpwindGradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class UpwindGradient + { + + + // ----------------------- Types ------------------------------ + public: + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + UpwindGradient( Image& aStartingImage, + const TOutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~UpwindGradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @param aVector displacement vector of the interface + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Vector& aVector ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Forward difference + */ + ForwardDifference myF; + /** + * Backward difference + */ + BackwardDifference myB; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class GodunovGradient + /** + * Description of template class 'GodunovGradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class GodunovGradient + { + + + // ----------------------- Types ------------------------------ + public: + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aStartingImage any image + * @param isPositive flag equal to 'true' if the + * interface moves in the direction of the normal + * and 'false' if it moves in the opposite direction + * (='true' by default) + * @param aGridStep any length (=1 by default) + */ + GodunovGradient( Image& aStartingImage, bool isPositive = true, + const TOutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~GodunovGradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @param isPositive flag equal to 'true' if the + * interface moves in the direction of the normal + * and 'false' if it moves in the opposite direction + * (='true' by default) + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, bool isPositive ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Forward difference + */ + ForwardDifference myF; + /** + * Backward difference + */ + BackwardDifference myB; + /** + * Flag + */ + bool myIsPositive; + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class Divergence + /** + * Description of template class 'Divergence'

+ * \brief Aim: Computes the divergence at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class Divergence + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TDifference FiniteDifference; + typedef typename FiniteDifference::Dimension Dimension; + static const typename FiniteDifference::Dimension dimension = FiniteDifference::dimension; + typedef typename FiniteDifference::Image Image; + typedef typename FiniteDifference::Point Point; + typedef typename FiniteDifference::OutputValue OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aD a finite difference operator + */ + Divergence( const FiniteDifference& aD ): myD(aD) {} + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Divergence( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Divergence() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Divergence + * + * @param aPoint the point where the divergence is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Finite difference + */ + FiniteDifference myD; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class GradientModulus + /** + * Description of template class 'GradientModulus'

+ * \brief Aim: Computes the gradient modulus at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TGradient type of gradient + */ + template + class GradientModulus + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TGradient Gradient; + typedef typename Gradient::Dimension Dimension; + static const typename Gradient::Dimension dimension = Gradient::dimension; + typedef typename Gradient::Point Point; + + typedef double OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aG any gradient operator + */ + GradientModulus( const Gradient& aG) : myG(aG) {} + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + GradientModulus( typename Gradient::Image& aStartingImage, + const typename Gradient::OutputValue::Component& aGridStep = 1); + + + /** + * Destructor. Does nothing. + */ + ~GradientModulus() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient modulus + * + * @param aPoint the point where the gradient modulus is computed + * @return gradient modulus of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Gradient + */ + Gradient myG; + + }; + + + /////////////////////////////////////////////////////////////////// + + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "DifferentialOperators.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined DifferentialOperators_h + +#undef DifferentialOperators_RECURSES +#endif // else defined(DifferentialOperators_RECURSES) diff --git a/deformations/DifferentialOperators.ih b/deformations/DifferentialOperators.ih new file mode 100644 index 0000000..789300c --- /dev/null +++ b/deformations/DifferentialOperators.ih @@ -0,0 +1,459 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file DifferentialOperators.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2011/12/19 + * + * @brief Implementation of inline methods defined in DifferentialOperators.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// --------------------One-dimensional differential operators ----------------- + +template +inline +DGtal::ForwardDifference +::ForwardDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::ForwardDifference::OutputValue +DGtal::ForwardDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Point next = aPoint; + next.at(aDim) += 1; + if ( myU.domain().isInside(next) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else + { + Point prev = aPoint; + prev.at(aDim) -= 1; + if ( myU.domain().isInside(prev) ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + ASSERT( false && "too small image" ) ; + } +} + +template +inline +DGtal::BackwardDifference +::BackwardDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::BackwardDifference::OutputValue +DGtal::BackwardDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Point prev = aPoint; + prev.at(aDim) -= 1; + + if ( myU.domain().isInside(prev) ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + { + Point next = aPoint; + next.at(aDim) += 1; + if ( myU.domain().isInside(next) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else + ASSERT( false && "too small image" ) ; + } +} + +template +inline +DGtal::CentralDifference +::CentralDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::CentralDifference::OutputValue +DGtal::CentralDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next.at(aDim) += 1; + bool nextInside = d.isInside(next); + Point prev = aPoint; + prev.at(aDim) -= 1; + bool prevInside = d.isInside(prev); + + if (nextInside && prevInside ) + return ( (myU(next) - myU(prev)) / (2*myH) ); + else if ( nextInside && (!prevInside) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else if ( (!nextInside) && prevInside ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + ASSERT( false && "too small image" ) ; +} + +template +inline +DGtal::Difference2 +::Difference2( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::Difference2::OutputValue +DGtal::Difference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next.at(aDim) += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous.at(aDim) -= 1; + bool previousInside = d.isInside(previous); + + if (nextInside && previousInside ) + return ( (myU(next) - 2*myU(aPoint) + myU(previous) ) / (myH*myH) ); + else + return 0; +} + +template +inline +DGtal::NormalizedDifference2 +::NormalizedDifference2( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::NormalizedDifference2::OutputValue +DGtal::NormalizedDifference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next.at(aDim) += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous.at(aDim) -= 1; + bool previousInside = d.isInside(previous); + + typedef Gradient > Gradient; + GradientModulus m( myU ); + double mod = m(aPoint); + + if (nextInside && previousInside ) + { + double nMod = m(next); + double pMod = m(previous); + return ( ( average(nMod,mod)*(myU(next) - myU(aPoint)) ) + - ( average(mod,pMod)*(myU(aPoint) - myU(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!nextInside) && previousInside ) + { + double pMod = m(previous); + return ( ( ( 1 - average(pMod,mod) ) + *(myU(aPoint) - myU(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!previousInside) && nextInside ) + { + double nMod = m(next); + return ( ( ( average(nMod,mod) - 1 ) + *(myU(next) - myU(aPoint)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else + ASSERT( false && "too small image" ) ; +} + +template +inline +double +DGtal::NormalizedDifference2:: +average( const Value& aV1, const Value& aV2 ) const +{ + double som = NumberTraits::castToDouble(aV1 + aV2); + if (som == 0) return 0; + else return 2/som; +} + +template +inline +DGtal::WeightedDifference2 +::WeightedDifference2( Image& aImage, Image& aWImage, const OutputValue& aGridStep ) + : myImage( aImage ), myWImage( aWImage), myH( aGridStep ) +{ + ASSERT(aWImage.domain().lowerBound() == aImage.domain().lowerBound()); + ASSERT(aWImage.domain().upperBound() == aImage.domain().upperBound()); +} + +template +inline +typename DGtal::WeightedDifference2::OutputValue +DGtal::WeightedDifference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myImage.domain(); + Point next = aPoint; + next.at(aDim) += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous.at(aDim) -= 1; + bool previousInside = d.isInside(previous); + + typedef Gradient > Gradient; + GradientModulus m( myImage ); + double mod = m(aPoint); + + if (nextInside && previousInside ) + { + double nMod = m(next); + double pMod = m(previous); + return ( ( average(myWImage(next),nMod,myWImage(aPoint),mod) + *(myImage(next) - myImage(aPoint)) ) + - ( average(myWImage(aPoint),mod,myWImage(previous),pMod) + *(myImage(aPoint) - myImage(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!nextInside) && previousInside ) + { + double pMod = m(previous); + return ( ( ( myWImage(aPoint) + - average(myWImage(previous),pMod,myWImage(aPoint),mod) ) + *(myImage(aPoint) - myImage(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!previousInside) && nextInside ) + { + double nMod = m(next); + return ( ( ( average(myWImage(next),nMod,myWImage(aPoint),mod) + - myWImage(aPoint) ) + *(myImage(next) - myImage(aPoint)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else + ASSERT( false && "too small image" ) ; + +} + +template +inline +double +DGtal::WeightedDifference2:: +average( const Value& aV1, const double& aN1, + const Value& aV2, const double& aN2 ) const +{ + ASSERT(aV1 != 0); + ASSERT(aV2 != 0); + double q1 = aN1 / NumberTraits::castToDouble(aV1); + double q2 = aN2 / NumberTraits::castToDouble(aV2); + double sum = q1 + q2; + if (sum == 0) return 0; + else return 2/sum; +} + +/////////////////////////////////////////////////////////////////////////////// +// -------------------- Gradient operators ----------------- + + +template +inline +DGtal::Gradient +::Gradient( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep ) + : myD( FiniteDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::Gradient::OutputValue +DGtal::Gradient:: +operator() (const Point& aPoint) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + g.at(k) = myD(aPoint,k); + } + return g; +} + + +template +inline +DGtal::UpwindGradient +::UpwindGradient( Image& aStartingImage, const TOutputValue& aGridStep ) + : myF( ForwardDifference( aStartingImage, aGridStep ) ), + myB( BackwardDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::UpwindGradient::OutputValue +DGtal::UpwindGradient:: + operator() (const Point& aPoint, const Vector& aVector) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + if (aVector.at(k) > 0) + g.at(k) = myB(aPoint,k); + else if (aVector.at(k) < 0) + g.at(k) = myF(aPoint,k); + else //== 0 + g.at(k) = 0; + } + return g; +} + +template +inline +DGtal::GodunovGradient +::GodunovGradient( Image& aStartingImage, bool isPositive, const TOutputValue& aGridStep ) + : myF( ForwardDifference( aStartingImage, aGridStep ) ), + myB( BackwardDifference( aStartingImage, aGridStep ) ), + myIsPositive( isPositive ) +{ +} + +template +inline +typename DGtal::GodunovGradient::OutputValue +DGtal::GodunovGradient:: + operator() (const Point& aPoint) const +{ + return operator() (aPoint,myIsPositive); +} + +template +inline +typename DGtal::GodunovGradient::OutputValue +DGtal::GodunovGradient:: +operator() (const Point& aPoint, bool isPositive) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + if (isPositive) + { + typename OutputValue::Coordinate a = myB(aPoint,k); + if (a < 0) a = 0; + typename OutputValue::Coordinate b = myF(aPoint,k); + if (b > 0) b = 0; + g.at(k) = std::sqrt( std::max(a*a,b*b) ); + } + else + { + typename OutputValue::Coordinate a = myB(aPoint,k); + if (a > 0) a = 0; + typename OutputValue::Coordinate b = myF(aPoint,k); + if (b < 0) b = 0; + g.at(k) = std::sqrt( std::max(a*a,b*b) ); + } + } + return g; +} + + +template +inline +DGtal::GradientModulus +::GradientModulus( typename Gradient::Image& aStartingImage, + const typename Gradient::OutputValue::Component& aGridStep ) + : myG( Gradient( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::GradientModulus::OutputValue +DGtal::GradientModulus:: +operator() (const Point& aPoint) const +{ + typename Gradient::OutputValue g = myG( aPoint ); + return g.norm( Gradient::OutputValue::L_2 ); +} + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Divergence Operator ------------------------------ + + +template +inline +DGtal::Divergence +::Divergence( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep ) + : myD( FiniteDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::Divergence::OutputValue +DGtal::Divergence:: +operator() (const Point& aPoint) const +{ + OutputValue sum = 0; + for (Dimension k = 0; k < dimension; ++k ) + { + sum += myD(aPoint,k); + } + return sum; +} diff --git a/deformations/FMM.h b/deformations/FMM.h new file mode 100644 index 0000000..581ad91 --- /dev/null +++ b/deformations/FMM.h @@ -0,0 +1,497 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file FMM.h + * + * @author Tristan Roussillon (\c + * tristan.roussillon@liris.cnrs.fr ) Laboratoire d'InfoRmatique en + * Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, + * France + * + * @date 2012/01/17 + * + * @brief Fast Marching Method for incremental distance transform + * + * This file is part of the DGtal library. + * + */ + +#if defined(FMM_RECURSES) +#error Recursive header files inclusion detected in FMM.h +#else // defined(FMM_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define FMM_RECURSES + +#if !defined FMM_h +/** Prevents repeated inclusion of headers. */ +#define FMM_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include +#include +#include +#include +#include "DGtal/base/Common.h" +#include "DGtal/images/CImage.h" +#include "DGtal/images/ImageHelper.h" +#include "DGtal/kernel/sets/CDigitalSet.h" +#include "DGtal/kernel/sets/SetPredicate.h" +#include "DGtal/kernel/CPointPredicate.h" +#include "DGtal/kernel/CPointFunctor.h" +#include "DGtal/geometry/volumes/distance/FMMPointFunctors.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + namespace details + { + template + class PointValueCompare { + public: + bool operator()(const T& a, const T& b) + { + if ( std::abs(a.second) == std::abs(b.second) ) + { //point comparison + return (a.first < b.first); + } + else //distance comparison + //(in absolute value in order to deal with + //signed distance values) + return ( std::abs(a.second) < std::abs(b.second) ); + } + }; + } + + ///////////////////////////////////////////////////////////////////////////// + // template class FMM + /** + * Description of template class 'FMM'

+ * \brief Aim: Fast Marching Method (FMM) for nd distance transforms. + * + * In this approach, a signed distance function is computing at + * each digital point by marching out from an initial set of points, + * for which the values of the signed distance are known. This set + * is an initialization of the so-called @e accepted @e point @e set. + * Each digital point adjacent to one of the accepted points is + * put into the so-called @e candidate @e point @e set. + * A tentative value is computed for its signed distance, using + * only the values of the accepted points lying in its neighborhood. + * This task is delegated to an instance of a point functor, + * which is defined as L2FirstOrderLocalDistance by default. + * However, you are free to use L2SecondOrderLocalDistance, which provides + * more accurate distance values, L1FirstOrderLocalDistance and + * LInfFirstOrderLocalDistance for other norms. + * + * Then the point of smallest tentative value is added to the set of + * accepted points. The tentative values of the candidates adjacent + * to the newly added point are updated using the the distance value + * of the newly added point. The search of the point of smallest + * tentative value is accelerated using a STL set of pairs (point, + * tentative value). + * + * @tparam TImage any model of CImage + * @tparam TSet any model of CDigitalSet + * @tparam TPointPredicate any model of CPointPredicate, + * used to bound the computation within a domain + * @tparam TPointFunctor any model of CPointFunctor, + * used to compute the new distance value + * + * You can define the FMM type as follows: + @snippet geometry/volumes/distance/exampleFMM3D.cpp FMMDef + * + * You can run the algorithm as follows (d is a domain): + @snippet geometry/volumes/distance/exampleFMM3D.cpp FMMUsage + * + * @see exampleFMM2D.cpp + * @see exampleFMM3D.cpp + * @see testFMM.cpp + */ + template > + class FMM + { + + // ----------------------- Types ------------------------------ + public: + + + //concept assert + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( CPointPredicate )); + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + + typedef TImage Image; + typedef TSet AcceptedPointSet; + typedef TPointPredicate PointPredicate; + + //points + typedef typename Image::Point Vector; + typedef typename Image::Point Point; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename AcceptedPointSet::Point >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename PointPredicate::Point >::value )); + + //dimension + typedef typename Point::Dimension Dimension; + static const Dimension dimension = Point::dimension; + + //distance + typedef TPointFunctor PointFunctor; + typedef typename PointFunctor::Value Value; + + + private: + + //intern data types + typedef std::pair PointValue; + typedef std::set > CandidatePointSet; + typedef unsigned long Area; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on the image + */ + Image& myImage; + + /** + * Reference on the set of accepted points + */ + AcceptedPointSet& myAcceptedPoints; + + /** + * Set of candidate points + */ + CandidatePointSet myCandidatePoints; + + /** + * Point functor used to deduce + * the distance of a new point + * from the distance of its neighbors + */ + PointFunctor myPF; + + /** + * Constant reference on a point predicate that returns + * 'true' inside the domain + * where the distance transform is performed + */ + const PointPredicate& myPointPredicate; + + /** + * Area threshold (in number of accepted points) + * above which the propagation stops + */ + Area myAreaThreshold; + + /** + * Value threshold above which the propagation stops + */ + Value myValueThreshold; + + /** + * Min value + */ + Value myMinValue; + + /** + * Max value + */ + Value myMaxValue; + + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @see init + */ + FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate); + + /** + * Constructor. + * + * @see init + */ + FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const Area& aAreaThreshold, const Value& aValueThreshold); + + /** + * Constructor. + * + * @see init + */ + FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const PointFunctor& aPointFunctor ); + + /** + * Constructor. + * + * @see init + */ + FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const Area& aAreaThreshold, const Value& aValueThreshold, + const PointFunctor& aPointFunctor ); + + /** + * Destructor. + */ + ~FMM(); + + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Computes the distance map + */ + void compute(); + + /** + * Insert the candidate of min distance into the set + * of accepted points if it is possible and then + * update the set of candidate points. + * + * @param aPoint inserted point (if inserted) + * @param aValue its distance value (if inserted) + * + * @return 'true' if the point of min distance is accepted + * 'false' otherwise. + * + * @see addNewAcceptedPoint + */ + bool computeOneStep(Point& aPoint, Value& aValue); + + /** + * Minimal distance value in the set of accepted points. + * + * @return minimal distance value. + */ + Value min() const; + + /** + * Maximal distance value in the set of accepted points. + * + */ + Value max() const; + + /** + * Computes the minimal distance value in the set of accepted points. + * + * NB: in O(n log n) where n is the size of the set + * + * @return minimal distance value. + */ + Value getMin() const; + + /** + * Computes the maximal distance value in the set of accepted points. + * + * NB: in O(n log n) where n is the size of the set + * + * @return maximal distance value. + */ + Value getMax() const; + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const; + + // ------------------------- static functions for init -------------------- + + + /** + * Initialize @a aImg and @a aSet from the points of the range [@a itb , @a ite ) + * Assign a distance equal to @a aValue + * + * @param itb begin iterator (on points) + * @param ite end iterator (on points) + * @param aImg the distance image + * @param aSet the set of points for which the distance has been assigned + * @param aValue distance default value + */ + template + static void initFromPointsRange(const TIteratorOnPoints& itb, const TIteratorOnPoints& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue); + + /** + * Initialize @a aImg and @a aSet from the points + * incident to the signed cells of the range [@a itb , @a ite ) + * Assign to the inner points a distance equal to - @a aValue + * if @a aFlagIsPositive is 'false' (default) but @a aValue otherwise, + * and conversely for the outer points. + * + * @param itb begin iterator (on signed cells) + * @param ite end iterator (on signed cells) + * @param aImg the distance image + * @param aSet the set of points for which the distance has been assigned + * @param aValue distance default value + */ + template + static void initFromBelsRange(const KSpace& aK, + const TIteratorOnBels& itb, const TIteratorOnBels& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue, + bool aFlagIsPositive = false); + /** + * Initialize @a aImg and @a aSet from the points + * incident to the signed cells of the range [@a itb , @a ite ) + * Assign to the inner points a distance equal to - @a aValue + * if @a aFlagIsPositive is 'false' (default) but @a aValue otherwise, + * and conversely for the outer points. + * + * @param itb begin iterator (on signed cells) + * @param ite end iterator (on signed cells) + * @param aF any implicit function + * @param aImg the distance image + * @param aSet the set of points for which the distance has been assigned + */ + template + static void initFromBelsRange(const KSpace& aK, + const TIteratorOnBels& itb, const TIteratorOnBels& ite, + const TImplicitFunction& aF, + Image& aImg, AcceptedPointSet& aSet, + bool aFlagIsPositive = false); + + + /** + * Initialize @a aImg and @a aSet from the inner and outer points + * of the range [@a itb , @a ite ) of pairs of points. + * Assign to the inner points a distance equal to - @a aValue + * if @a aFlagIsPositive is 'false' (default) but @a aValue otherwise, + * and conversely for the outer points. + * + * @param itb begin iterator (on points) + * @param ite end iterator (on points) + * @param aImg the distance image + * @param aSet the set of points for which the distance has been assigned + * @param aValue distance default value + */ + template + static void initFromIncidentPointsRange(const TIteratorOnPairs& itb, const TIteratorOnPairs& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue, + bool aFlagIsPositive = false); + + private: + + /** + * Copy constructor. + * @param other the object to clone. + * Forbidden by default. + */ + FMM ( const FMM & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + * Forbidden by default. + */ + FMM & operator= ( const FMM & other ); + + // ------------------------- Internals ------------------------------------ + private: + + /** + * Initialize the set of candidate points + */ + void init(); + + /** + * Insert the candidate of min distance into the set + * of accepted points and update the set of candidate points. + * + * @param aPoint inserted point (if true) + * @param aValue distance value of the inserted point (if true) + * + * @return 'true' if the point of min distance is accepted + * 'false' otherwise. + */ + bool addNewAcceptedPoint(Point& aPoint, Value& aValue); + + /** + * Update the set of candidate points with the neigbors of @a aPoint. + * + * @param aPoint any point + */ + void update(const Point& aPoint); + + /** + * Test a new point as a candidate. + * If it is not yet accepted + * and if the point predicate return 'true', + * compute its distance and insert it + * into the set candidate points. + * + * @param aPoint any point + * + * @return 'true' if inserted, + * 'false' otherwise. + */ + bool addNewCandidate(const Point& aPoint); + + + }; // end of class FMM + + + /** + * Overloads 'operator<<' for displaying objects of class 'FMM'. + * @param out the output stream where the object is written. + * @param object the object of class 'FMM' to write. + * @return the output stream after the writing. + */ + template + std::ostream& + operator<< ( std::ostream & out, const FMM & object ); + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "FMM.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined FMM_h + +#undef FMM_RECURSES +#endif // else defined(FMM_RECURSES) diff --git a/deformations/FMM.ih b/deformations/FMM.ih new file mode 100644 index 0000000..ad47272 --- /dev/null +++ b/deformations/FMM.ih @@ -0,0 +1,507 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file FMM.ih + * @author Tristan Roussillon (\c + * tristan.roussillon@liris.cnrs.fr ) Laboratoire d'InfoRmatique en + * Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, + * France + * + * + * @date 2012/01/17 + * + * @brief Implementation of inline methods defined in FMM.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + +#include "DGtal/topology/SCellsFunctors.h" + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Standard services ------------------------------ + +template +inline +DGtal::FMM +::FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate) + : myImage( aImg ), myAcceptedPoints( aSet ), myPF( PointFunctor(aImg, aSet) ), + myPointPredicate( aPointPredicate ), + myAreaThreshold( std::numeric_limits::max() ), + myValueThreshold( std::numeric_limits::max() ) +{ + if (myAcceptedPoints.size() == 0) throw InputException(); + init(); +} + + +template +inline +DGtal::FMM +::FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const Area& aAreaThreshold, + const Value& aValueThreshold) + : myImage( aImg ), myAcceptedPoints( aSet ), myPF( PointFunctor(aImg, aSet) ), + myPointPredicate( aPointPredicate ), + myAreaThreshold( aAreaThreshold ), + myValueThreshold( aValueThreshold ) +{ + if (myAcceptedPoints.size() == 0) throw InputException(); + init(); +} + + +template +inline +DGtal::FMM +::FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const PointFunctor& aPointFunctor) + : myImage( aImg ), myAcceptedPoints( aSet ), myPF( aPointFunctor ), + myPointPredicate( aPointPredicate ), + myAreaThreshold( std::numeric_limits::max() ), + myValueThreshold( std::numeric_limits::max() ) +{ + if (myAcceptedPoints.size() == 0) throw InputException(); + init(); +} + + +template +inline +DGtal::FMM +::FMM(Image& aImg, AcceptedPointSet& aSet, + const PointPredicate& aPointPredicate, + const Area& aAreaThreshold, + const Value& aValueThreshold, + const PointFunctor& aPointFunctor) + : myImage( aImg ), myAcceptedPoints( aSet ), myPF( aPointFunctor ), + myPointPredicate( aPointPredicate ), + myAreaThreshold( aAreaThreshold ), + myValueThreshold( aValueThreshold ) +{ + if (myAcceptedPoints.size() == 0) throw InputException(); + init(); +} + + +template +inline +DGtal::FMM::~FMM() +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// Static functions : + + +template +template +void +DGtal::FMM +::initFromPointsRange(const TIteratorOnPoints& itb, const TIteratorOnPoints& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue) +{ + + aSet.clear(); + for (TIteratorOnPoints it = itb; it != ite; ++it) + { + insertAndAlwaysSetValue( aImg, aSet, *it, aValue ); + } +} + +template +template +void +DGtal::FMM +::initFromBelsRange(const KSpace& aK, + const TIteratorOnBels& itb, const TIteratorOnBels& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue, + bool aFlagIsPositive) +{ + Value k = -1; + if (aFlagIsPositive) k = 1; + + aSet.clear(); + for (TIteratorOnBels it = itb; it != ite; ++it) + { + //getting incident points + SCellToIncidentPoints func( aK ); + typename SCellToIncidentPoints::Output points = func( *it ); + //assignement + insertAndAlwaysSetValue( aImg, aSet, points.first, k*aValue ); + insertAndAlwaysSetValue( aImg, aSet, points.second, -k*aValue ); + } +} + +template +template +void +DGtal::FMM +::initFromBelsRange(const KSpace& aK, + const TIteratorOnBels& itb, const TIteratorOnBels& ite, + const TImplicitFunction& aF, + Image& aImg, AcceptedPointSet& aSet, + bool aFlagIsPositive) +{ + Value k = -1; + if (aFlagIsPositive) k = 1; + + /// types + typedef typename KSpace::Cell Bel; + typedef typename TImplicitFunction::Value Value; + typedef std::pair BelValue; + typedef std::map Buffer; + + typedef typename SCellToIncidentPoints::Output Pair; + typedef std::vector IncidentPoints; + SCellToIncidentPoints getIncidentPoints( aK ); + + /// 1) store a value for each bel + /// (== distance of the inner point to the interface) + IncidentPoints incidentPoints; + Buffer buffer; + for (TIteratorOnBels it = itb; it != ite; ++it) + { + //getting incident points + Pair points = getIncidentPoints( *it ); + incidentPoints.push_back( points ); + + //getting values + Value vin = aF( points.first ); + Value vout = aF( points.second ); + + //computing/storing the new value + Value e = std::max(vin, vout) - std::min(vin, vout); + Value v = (std::abs(vin)/e); + // std::cout << points.first << " " << vin << ", " << points.second << " " << vout; + // std::cout << " : " << e << ", " << v << std::endl; + + ASSERT( v >= 0 ); + buffer.insert( BelValue( aK.unsigns( *it ), v ) ); + } + + aSet.clear(); + /// 2) for each inner/outer point + /// computes its distance from the values of its incident bels + typedef L2FirstOrderLocalDistanceFromCells Computer4InnerPts; + typedef L2FirstOrderLocalDistanceFromCells Computer4OuterPts; + Computer4InnerPts computerIn(aK, buffer); + Computer4OuterPts computerOut(aK, buffer); + for (typename IncidentPoints::const_iterator it = incidentPoints.begin(); + it != incidentPoints.end(); ++it) + { + //computing the values + Value vin = computerIn( it->first ); + Value vout = computerOut( it->second ); + // std::cout << points.first << " " << vin << ", " + // << points.second << " " << vout << std::endl; + + //assignement + insertAndAlwaysSetValue( aImg, aSet, it->first, k*vin ); + insertAndAlwaysSetValue( aImg, aSet, it->second, -k*vout ); + } +} + +template +template +void +DGtal::FMM +::initFromIncidentPointsRange(const TIteratorOnPairs& itb, const TIteratorOnPairs& ite, + Image& aImg, AcceptedPointSet& aSet, + const Value& aValue, + bool aFlagIsPositive) +{ + Value k = -1; + if (aFlagIsPositive) k = 1; + + aSet.clear(); + for (TIteratorOnPairs it = itb; it != ite; ++it) + { + insertAndAlwaysSetValue( aImg, aSet, it->first, k*aValue ); + insertAndAlwaysSetValue( aImg, aSet, it->second, -k*aValue ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Interface - public : + + +template +inline +void +DGtal::FMM::compute() +{ + Point p = Point::diagonal(0); + Value d = 0; + while ( addNewAcceptedPoint( p, d ) ) + { } +} + +template +inline +bool +DGtal::FMM +::computeOneStep(Point& aPoint, Value& aValue) +{ + return addNewAcceptedPoint(aPoint, aValue); +} + +template +inline +typename DGtal::FMM::Value +DGtal::FMM::min() const +{ + return myMinValue; +} + +template +inline +typename DGtal::FMM::Value +DGtal::FMM::max() const +{ + return myMaxValue; +} + +template +inline +typename DGtal::FMM::Value +DGtal::FMM::getMin() const +{ + const AcceptedPointSet& set = myAcceptedPoints; + ASSERT( set.size() >= 1 ); + + typename AcceptedPointSet::ConstIterator it = set.begin(); + typename AcceptedPointSet::ConstIterator itEnd = set.end(); + Value vmin = myImage( *it ); + for (++it; it != itEnd; ++it) + { + Value v = myImage( *it ); + if (v < vmin) vmin = v; + } + return vmin; +} + +template +inline +typename DGtal::FMM::Value +DGtal::FMM::getMax() const +{ + const AcceptedPointSet& set = myAcceptedPoints; + ASSERT( set.size() >= 1 ); + + typename AcceptedPointSet::ConstIterator it = set.begin(); + typename AcceptedPointSet::ConstIterator itEnd = set.end(); + Value vmax = myImage( *it ); + for (++it; it != itEnd; ++it) + { + Value v = myImage( *it ); + if (v > vmax) vmax = v; + } + return vmax; +} + +template +inline +bool +DGtal::FMM::isValid() const +{ + //area threshold + if ( (myAcceptedPoints.size() <= 0) + || (myAcceptedPoints.size() >= myAreaThreshold) ) return false; + + //distance threshold + if ( ( getMin() != min() ) || ( getMax() != max() ) ) return false; + if ( (std::abs(getMin()) >= myValueThreshold) + || (getMax() >= myValueThreshold) ) return false; + + //point predicate + bool flagIsOk = true; + const AcceptedPointSet& set = myAcceptedPoints; + typename AcceptedPointSet::ConstIterator it = set.begin(); + typename AcceptedPointSet::ConstIterator itEnd = set.end(); + for ( ; ( (it != itEnd)&&(flagIsOk == true) ); ++it) + { + if (myPointPredicate( *it ) == false) flagIsOk = false; + } + if (!flagIsOk) return false; + + return true; +} + +template +inline +void +DGtal::FMM::selfDisplay ( std::ostream & out ) const +{ + out << "[FMM " << dimension << "d] "; + out << myAcceptedPoints.size() << " accepted points (< " << myAreaThreshold << ")"; + out << " and " << myCandidatePoints.size() << " candidates. "; + myPF.selfDisplay(out); + out << " "; + out << "dmin: " << min() << ", dmax: " << max(); + out << " (abs < " << myValueThreshold << ")" << std::endl; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Internals + +template +inline +void +DGtal::FMM::init() +{ + + myCandidatePoints.clear(); + + typename AcceptedPointSet::Iterator it = myAcceptedPoints.begin(); + typename AcceptedPointSet::Iterator itEnd = myAcceptedPoints.end(); + for ( ; it != itEnd; ++it) + { + update( *it ); + } + + myMinValue = getMin(); + myMaxValue = getMax(); + +} + +template +inline +bool +DGtal::FMM +::addNewAcceptedPoint(Point& aPoint, Value& aValue) +{ + + if ( (myAcceptedPoints.size()+1) < myAreaThreshold ) + {//if a new point can be accepted + + bool flagStop = false; + typename CandidatePointSet::iterator it = myCandidatePoints.begin(); + typename CandidatePointSet::iterator itEnd = myCandidatePoints.end(); + while ( (it != itEnd) && (!flagStop) ) + { //while there are candidates and no point has been accepted + + //pair of min distance + PointValue minPair = *it; + + if ( std::abs(minPair.second) < myValueThreshold ) + { //if distance below a given threshold + + //the point of min distance is removed from the set of candidates + myCandidatePoints.erase(*it); + //it can be inserted into the set of accepted points + if ( insertAndSetValue( myImage, myAcceptedPoints, + minPair.first, minPair.second ) ) + { //if it does not belong to the set + //the set of candidates is updated with + //the neighbors of the new accepted point + aPoint = minPair.first; + aValue = minPair.second; + if (aValue > myMaxValue) myMaxValue = aValue; + if (aValue < myMinValue) myMinValue = aValue; + update( aPoint ); + flagStop = true; + } + else + { //otherwise it has already been accepted + //with a smaller distance and the next candidate + //should be considered + it = myCandidatePoints.begin(); + } + + }//end if distance below a given threshold + else return false; + + } //end while there are candidates + + return flagStop; //true if a point has been accepted + + } //end if a new point can be accepted + else return false; +} + +template +inline +void +DGtal::FMM::update(const Point& aPoint) +{ + + //neigbors + Point neighbor = aPoint; + for (Dimension k = 0; k < dimension; ++k) + { + typename Point::Coordinate c = neighbor.at(k); + neighbor.at(k) = (c+1); + addNewCandidate(neighbor); + neighbor.at(k) = (c-1); + addNewCandidate(neighbor); + neighbor.at(k) = c; + } +} + +template +inline +bool +DGtal::FMM::addNewCandidate(const Point& aPoint) +{ + + //if it lies within the computation domain + //and if it is not already accepted + if ( (myPointPredicate(aPoint) ) + && ( myAcceptedPoints.find(aPoint) == myAcceptedPoints.end() ) ) + { + Value d = myPF( aPoint ); + PointValue newPair( aPoint, d ); + //insert the new candidate with its distance + myCandidatePoints.insert(newPair); + return true; + } + else return false; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Implementation of inline functions // + +template +inline +std::ostream& +DGtal::operator<< ( std::ostream & out, + const FMM & object ) +{ + object.selfDisplay( out ); + return out; +} + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/FMMPointFunctors.h b/deformations/FMMPointFunctors.h new file mode 100644 index 0000000..ae2c0f1 --- /dev/null +++ b/deformations/FMMPointFunctors.h @@ -0,0 +1,809 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file FMMPointFunctors.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, + * France + * + * @date 2012/02/21 + * + * @brief Distance computation within a small neighborhood around a point + * + * This file is part of the DGtal library. + * + */ + +#if defined(FMMPointFunctors_RECURSES) +#error Recursive header files inclusion detected in FMMPointFunctors.h +#else // defined(FMMPointFunctors_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define FMMPointFunctors_RECURSES + +#if !defined FMMPointFunctors_h +/** Prevents repeated inclusion of headers. */ +#define FMMPointFunctors_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include +#include +#include +#include +#include "DGtal/base/Common.h" + +#include "DGtal/kernel/sets/CDigitalSet.h" +#include "DGtal/kernel/CPointFunctor.h" +#include "DGtal/images/CImage.h" +#include "DGtal/images/ImageHelper.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + /////////////////////////////////////////////////////////////////////////////// + //--------------- small helpers ---------------------------------------------- + namespace details + { + //@TODO put it in a file of the base directory ? + + //comparator in absolute value + template + bool absComparator(const Value& i, const Value& j) + { + return ( std::abs(static_cast(i)) < std::abs(static_cast(j)) ); + } + + //pair second member comparator in absolute value + template + bool secondAbsComparator(const Pair& i, const Pair& j) + { + return absComparator( i.second, j.second ); + } + } + + + ///////////////////////////////////////////////////////////////////////////// + // template class L2FirstOrderLocalDistance + /** + * Description of template class 'L2FirstOrderLocalDistance'

+ * \brief Aim: Class for the computation of the Euclidean distance + * at some point p, from the available distance values of some points + * lying in the 1-neighborhood of p (ie. points at a L1-distance to p + * equal to 1). + * + * The computed value is such that the upwind gradient of the + * distance map is one, ie. it the minimum solution \f$ \Phi \f$ + * over all quadrants, verifying the following quadratic equation: + * \f$ \sum_{i = 1 \ldots d } ( \Phi - \Phi_i )^2 \f$ + * where \f$ \Phi_i \f$ is the distance value of the point preceding + * or following p along the \f$ i \f$ axis. + * + * It is a model of CPointFunctor. + * + * @tparam TImage model of CImage used for the mapping point-distance value + * @tparam TSet model of CDigitalSet for storing points whose distance value is known + * + * @see FMM + */ + template + class L2FirstOrderLocalDistance + { + + // ----------------------- Types ------------------------------ + public: + + + /// image + BOOST_CONCEPT_ASSERT(( CImage )); + typedef TImage Image; + typedef typename Image::Point Point; + typedef typename Image::Value Value; + + /// set + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + typedef TSet Set; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); + + private: + + typedef std::vector Values; + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying image + Image* myImgPtr; + /// Aliasing pointer on the underlying set + Set* mySetPtr; + + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from an image and a set. + * NB: only pointers are stored + * + * @param aImg any distance map + * @param aSet any digital set + */ + L2FirstOrderLocalDistance(Image& aImg, TSet& aSet); + + /** + * Copy constructor. + * @param other the object to clone. + */ + L2FirstOrderLocalDistance ( const L2FirstOrderLocalDistance & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + L2FirstOrderLocalDistance & operator= ( const L2FirstOrderLocalDistance & other); + + /** + * Destructor. + * Does nothing. + */ + ~L2FirstOrderLocalDistance(); + + /** + * Euclidean distance computation at @a aPoint , + * from the available distance values + * of the 1-neighbors of @a aPoint . + * + * @param aPoint the point for which the distance is computed + * + * @return the distance value at @a aPoint. + * + */ + Value operator() (const Point& aPoint); + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + // ----------------------- Internals ------------------------------------- + + private: + + /** + * Returns an approximation of the Euclidean distance + * at some point, knowing the distance of its neighbors + * + * @param aValueList the distance of (some of) the neighbors + * @return the computed distance. + */ + Value compute(Values& aValueList) const; + + + /** + * Returns the squared euclidean norm of the gradient + * of the distance map + * + * @param aValue the distance value of the point where the gradient is computed + * @param aValueList the distance value of (some of) the neighbors + * + * @return the computed gradient norm. + */ + Value gradientNorm(const Value& aValue, const Values& aValueList) const; + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class L2SecondOrderLocalDistance + /** + * Description of template class 'L2SecondOrderLocalDistance'

+ * \brief Aim: Class for the computation of the Euclidean distance + * at some point p, from the available distance values of some points + * lying in the neighborhood of p, such that only one of their + * coordinate differ from the coordinates of p by at most two. + * + * Like L2FirstOrderLocalDistance, the computed value is such that + * the upwind gradient of the distance map is one, but instead of + * using first-order accurate forward and backward differences, + * L2SecondOrderLocalDistance uses second-order accurate forward + * and backward difference whenever there are enough points whose + * distance values are known in order to evaluate these differences. + * + * It is a model of CPointFunctor. + * + * @tparam TImage model of CImage used for the mapping point-distance value + * @tparam TSet model of CDigitalSet for storing points whose distance value is known + * + * @see FMM + */ + template + class L2SecondOrderLocalDistance + { + + // ----------------------- Types ------------------------------ + public: + + + /// image + BOOST_CONCEPT_ASSERT(( CImage )); + typedef TImage Image; + typedef typename Image::Point Point; + typedef typename Image::Value Value; + + /// set + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + typedef TSet Set; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); + + private: + + typedef std::pair CoeffValue; + typedef std::vector List; + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying image + Image* myImgPtr; + /// Aliasing pointer on the underlying set + Set* mySetPtr; + + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from an image and a set. + * NB: only pointers are stored + * + * @param aImg any distance map + * @param aSet any digital set + */ + L2SecondOrderLocalDistance(Image& aImg, TSet& aSet); + + /** + * Copy constructor. + * @param other the object to clone. + */ + L2SecondOrderLocalDistance ( const L2SecondOrderLocalDistance & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + L2SecondOrderLocalDistance & operator= ( const L2SecondOrderLocalDistance & other); + + /** + * Destructor. + * Does nothing. + */ + ~L2SecondOrderLocalDistance(); + + /** + * Euclidean distance computation at @a aPoint , + * from the available distance values + * of the 1-neighbors of @a aPoint . + * + * @param aPoint the point for which the distance is computed + * + * @return the distance value at @a aPoint. + * + */ + Value operator() (const Point& aPoint); + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + // ----------------------- Internals ------------------------------------- + + private: + + /** + * Returns an approximation of the Euclidean distance + * at some point, knowing the distance of its neighbors + * + * @param aList the distance of (some of) the neighbors + * @return the computed distance. + */ + Value compute(List& aList) const; + + + /** + * Returns the squared euclidean norm of the gradient + * of the distance map + * + * @param aValue the distance value of the point where the gradient is computed + * @param aList the distance value of (some of) the neighbors + * + * @return the computed gradient norm. + */ + Value gradientNorm(const Value& aValue, const List& aList) const; + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class LInfFirstOrderLocalDistance + /** + * Description of template class 'LInfFirstOrderLocalDistance'

+ * \brief Aim: Class for the computation of the LInf-distance + * at some point p, from the available distance values of some points + * lying in the 1-neighborhood of p (ie. points at a L1-distance to p + * equal to 1). + * + * If there is only one available distance value v in the 1-neighborhood of p, + * the computed value is merely incremented or decremented. + * Otherwise, it is the maximum over all + * the available distance value in the 1-neighborhood of p. + * + * It is a model of CPointFunctor. + * + * @tparam TImage model of CImage used for the mapping point-distance value + * @tparam TSet model of CDigitalSet for storing points whose distance value is known + * + * @see FMM + */ + template + class LInfFirstOrderLocalDistance + { + // ----------------------- Types ------------------------------ + public: + + + /// image + BOOST_CONCEPT_ASSERT(( CImage )); + typedef TImage Image; + typedef typename Image::Point Point; + typedef typename Image::Value Value; + + /// set + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + typedef TSet Set; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); + + private: + + typedef std::vector Values; + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying image + Image* myImgPtr; + /// Aliasing pointer on the underlying set + Set* mySetPtr; + + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from an image and a set. + * NB: only pointers are stored + * + * @param aImg any distance map + * @param aSet any digital set + */ + LInfFirstOrderLocalDistance(Image& aImg, TSet& aSet); + + /** + * Copy constructor. + * @param other the object to clone. + */ + LInfFirstOrderLocalDistance ( const LInfFirstOrderLocalDistance & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + LInfFirstOrderLocalDistance & operator= ( const LInfFirstOrderLocalDistance & other); + + /** + * Destructor. + * Does nothing. + */ + ~LInfFirstOrderLocalDistance(); + + + /** + * LInf-distance computation at @a aPoint , + * from the available distance values + * of the 1-neighbors of @a aPoint . + * + * @param aPoint the point for which the distance is computed + * + * @return the distance value at @a aPoint. + * + */ + Value operator() (const Point& aPoint); + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + // ----------------------- Internals ------------------------------------- + + private: + + /** + * Returns the LInf-distance at some point, + * knowing the distance of its neighbors + * + * @param aValueList the distance of (some of) the neighbors + * @return the computed distance. + */ + Value compute(Values& aValueList) const; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class L1FirstOrderLocalDistance + /** + * Description of template class 'L1FirstOrderLocalDistance'

+ * \brief Aim: Class for the computation of the L1-distance + * at some point p, from the available distance values of some points + * lying in the 1-neighborhood of p (ie. points at a L1-distance to p + * equal to 1). + * + * The computed value is merely the minimum over all + * the available distance values in the 1-neighborhood of p, + * plus one. + * + * It is a model of CPointFunctor. + * + * @tparam TImage model of CImage used for the mapping point-distance value + * @tparam TSet model of CDigitalSet for storing points whose distance value is known + * + * @see FMM + */ + template + class L1FirstOrderLocalDistance + { + // ----------------------- Types ------------------------------ + public: + + + /// image + BOOST_CONCEPT_ASSERT(( CImage )); + typedef TImage Image; + typedef typename Image::Point Point; + typedef typename Image::Value Value; + + /// set + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + typedef TSet Set; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); + + private: + + typedef std::vector Values; + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying image + Image* myImgPtr; + /// Aliasing pointer on the underlying set + Set* mySetPtr; + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from an image and a set. + * NB: only pointers are stored + * + * @param aImg any distance map + * @param aSet any digital set + */ + L1FirstOrderLocalDistance(Image& aImg, TSet& aSet); + + /** + * Copy constructor. + * @param other the object to clone. + */ + L1FirstOrderLocalDistance ( const L1FirstOrderLocalDistance & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + L1FirstOrderLocalDistance & operator= ( const L1FirstOrderLocalDistance & other); + + /** + * Destructor. + * Does nothing. + */ + ~L1FirstOrderLocalDistance(); + + /** + * L1-distance computation at @a aPoint , + * from the available distance values + * of the 1-neighbors of @a aPoint . + * + * @param aPoint the point for which the distance is computed + * + * @return the distance value at @a aPoint. + */ + Value operator() (const Point& aPoint); + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + // ----------------------- Internals ------------------------------------- + + private: + + /** + * Returns the L1-distance at some point, + * knowing the distance of its neighbors + * + * @param aValueList the distance of (some of) the neighbors + * @return the computed distance. + */ + Value compute(Values& aValueList) const; + + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class L2FirstOrderLocalDistanceFromCells + /** + * Description of template class 'L2FirstOrderLocalDistanceFromCells'

+ * \brief Aim: Class for the computation of the Euclidean distance + * at some point p, from the available distance values in the neighborhood of p. + * Contrary to L2FirstOrderLocalDistance, the distance values are not available + * from the points adjacent to p but instead from the (d-1)-cells lying between p + * and these points. + * + * @note The stored values are expected to be the distance of the interface + * to the points directly incident to the cells and must be between 0 and 1. + * + * @tparam TKSpace a model of cellular grid + * @tparam TMap a model of associative container used for the mapping cells-value + * @tparam isIndirect a bool equal to 'false' if the tested points are expected to be + * directly incident to the cells (default) and 'true' otherwise + * + * @see initFromBelsRange FMM + */ + template + class L2FirstOrderLocalDistanceFromCells + { + + // ----------------------- Types ------------------------------ + public: + + + /// map + typedef TMap Map; + typedef typename Map::mapped_type Value; + + /// cellular grid + typedef TKSpace KSpace; + typedef typename KSpace::Point Point; + typedef typename KSpace::Cell Cell; + + private: + + typedef std::vector Values; + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying cellular grid + const KSpace* myKSpace; + /// Aliasing pointer on the underlying mapping + Map* myMap; + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from a space and a map. + * NB: only pointers are stored + * + * @param aMap any distance map + */ + L2FirstOrderLocalDistanceFromCells(const KSpace& aK, Map& aMap); + + /** + * Copy constructor. + * @param other the object to clone. + */ + L2FirstOrderLocalDistanceFromCells ( const L2FirstOrderLocalDistanceFromCells & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + L2FirstOrderLocalDistanceFromCells & operator= ( const L2FirstOrderLocalDistanceFromCells & other); + + /** + * Destructor. + * Does nothing. + */ + ~L2FirstOrderLocalDistanceFromCells(); + + /** + * Euclidean distance computation at @a aPoint , + * from the available distance values + * of the adjacent cells. + * + * @param aPoint the point for which the distance is computed + * + * @return the distance value at @a aPoint. + * + */ + Value operator() (const Point& aPoint); + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + // ----------------------- Internals ------------------------------------- + + private: + + /** + * Returns an approximation of the Euclidean distance + * at some point, knowing the distance of its adjacent cells + * contained in @a aValueList + * + * @param aValueList the distance of (some of) the neighbors + * @return the computed distance. + */ + Value compute(Values& aValueList) const; + + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class SpeedExtrapolator + /** + * Description of template class 'SpeedExtrapolator'

+ * \brief Aim: Class for the computation of the a speed value + * at some point p, from the available distance values and speed + * values of some points lying in the 1-neighborhood of p + * (ie. points at a L1-distance to p equal to 1) in order to + * extrapolate a speed field in the normal direction to the interface. + * + * The computed value is such that the dot product of the gradients + * of the speed function and of the distance function is zero, ie. + * \f$ \nabla S . \nabla \Phi = 0 \f$. + * + * [Adalsteinsson and Sethian, Fast Construction of Extension Velocities + * in Level Set Methods, J. Comput. Phys. 148, 2-22, 1999] + * + * It is a model of CPointFunctor. + * + * @tparam TDistanceImage model of CImage used for the mapping point-distance value + * @tparam TSet model of CDigitalSet for storing points whose distance value is known + * @tparam TSpeedFunctor model of CImage used for the mapping point-speed value + * + * @see FMM + */ + template + class SpeedExtrapolator + { + + // ----------------------- Types ------------------------------ + public: + + + /// image + BOOST_CONCEPT_ASSERT(( CImage )); + typedef TDistanceImage DistanceImage; + typedef typename DistanceImage::Point Point; + typedef typename DistanceImage::Value DistanceValue; + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + typedef TSpeedFunctor SpeedFunctor; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename SpeedFunctor::Point >::value )); + typedef typename SpeedFunctor::Value Value; + + /// set + BOOST_CONCEPT_ASSERT(( CDigitalSet )); + typedef TSet Set; + BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); + + // ----------------------- Data ------------------------------------- + public: + /// Aliasing pointer on the underlying image of distance values + const DistanceImage* myDistImgPtr; + /// Aliasing pointer on the underlying set of points + /// whose distance value is known + const Set* mySetPtr; + /// Aliasing pointer on the underlying image of speed values + DistanceImage* mySpeedFuncPtr; + + + // ----------------------- Interface -------------------------------------- + public: + + /** + * Constructor from images and set. + * NB: only pointers are stored + * + * @param aDistImg any distance map + * @param aSet any digital set + * @param aSpeedFunc any speed map + */ + SpeedExtrapolator(const DistanceImage& aDistImg, const TSet& aSet, SpeedFunctor& aSpeedFunc); + + /** + * Copy constructor. + * @param other the object to clone. + */ + SpeedExtrapolator ( const SpeedExtrapolator & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + */ + SpeedExtrapolator & operator= ( const SpeedExtrapolator & other); + + /** + * Destructor. + * Does nothing. + */ + ~SpeedExtrapolator(); + + /** + * Speed value computation at @a aPoint , + * from the available distance/speed values + * of the 1-neighbors of @a aPoint . + * + * @param aPoint the point for which the speed is computed + * + * @return the speed value at @a aPoint. + * + */ + Value operator() (const Point& aPoint); + + + // ----------------------- Internals ------------------------------------- + + private: + + }; + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "DGtal/geometry/volumes/distance/FMMPointFunctors.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined FMMPointFunctors_h + +#undef FMMPointFunctors_RECURSES +#endif // else defined(FMMPointFunctors_RECURSES) diff --git a/deformations/FMMPointFunctors.ih b/deformations/FMMPointFunctors.ih new file mode 100644 index 0000000..b9371dc --- /dev/null +++ b/deformations/FMMPointFunctors.ih @@ -0,0 +1,1011 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file FMMPointFunctors.ih + * @author Tristan Roussillon (\c + * tristan.roussillon@liris.cnrs.fr ) Laboratoire d'InfoRmatique en + * Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, + * France + * + * + * @date 2012/02/21 + * + * @brief Implementation of inline methods defined in FMMPointFunctors.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistance::L2FirstOrderLocalDistance + (Image& aImg, TSet& aSet): myImgPtr(&aImg), mySetPtr(&aSet) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistance::L2FirstOrderLocalDistance + (const L2FirstOrderLocalDistance& other): myImgPtr(other.myImgPtr), mySetPtr(other.mySetPtr) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistance& +DGtal::L2FirstOrderLocalDistance::operator= + (const L2FirstOrderLocalDistance& other) +{ + if( this != &other) + { + myImgPtr = other.myImgPtr; + mySetPtr = other.mySetPtr; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistance::~L2FirstOrderLocalDistance + () +{ +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2FirstOrderLocalDistance::Value +DGtal::L2FirstOrderLocalDistance::operator() + (const Point& aPoint) +{ + + //distance values + Values v; + v.reserve(Point::dimension); + + //two 1-neighbors + Point neighbor1 = aPoint; + Point neighbor2 = aPoint; + + typename Point::Iterator it1 = neighbor1.begin(); + typename Point::Iterator it2 = neighbor2.begin(); + typename Point::ConstIterator it = aPoint.begin(); + typename Point::ConstIterator itEnd = aPoint.end(); + for ( ; it != itEnd; ++it, ++it1, ++it2) + {//for each dimension + + typename Point::Coordinate c = *it; + *it1 = (c+1); + *it2 = (c-1); + + //neighboring values + Value d, d1, d2 = 0; + bool flag1 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor1, d1 ); + bool flag2 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor2, d2 ); + if ( flag1 || flag2 ) + { + if ( flag1 && flag2 ) + { //take the minimal value + if (std::abs(d1) < std::abs(d2)) + d = d1; + else + d = d2; + } else + { + if (flag1) d = d1; + if (flag2) d = d2; + } + + v.push_back(d); + } + + *it1 = c; + *it2 = c; + } //end for each dimension + + //computation of the new value + return this->compute(v); +} + + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2FirstOrderLocalDistance::Value +DGtal::L2FirstOrderLocalDistance::compute +(Values& aValueList) const +{ + ASSERT(aValueList.size() > 0); + + unsigned int nb = aValueList.size(); + if ( nb == 1 ) + { + Value d = aValueList.back(); + if (d >= 0) return d + 1.0; + else return d - 1.0; + } + else + { + //function computation + typename Values::iterator itMax = + std::max_element( aValueList.begin(), aValueList.end(), details::absComparator ); + if ( gradientNorm( *itMax, aValueList ) > 1 ) + { + aValueList.erase( itMax ); + return this->compute(aValueList); + } + else + { //resolution + double a = 0; + double b = 0; + double c = -1; + + for (typename Values::iterator it = aValueList.begin(); + it != aValueList.end(); ++it) + { + Value d = *it; + + a += 1; + b -= static_cast(2*d); + c += static_cast(d*d); + } + + //discriminant + double disc = b*b - 4*a*c; + ASSERT(disc >= 0); + + double dres1 = ( ( -b + std::sqrt(disc) ) / (2*a) ); + double dres2 = ( ( -b - std::sqrt(disc) ) / (2*a) ); + if ( std::abs(dres1) > std::abs(dres2) ) + return static_cast(dres1); + else + return static_cast(dres2); + } + } + +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2FirstOrderLocalDistance::Value +DGtal::L2FirstOrderLocalDistance +::gradientNorm(const Value& aValue, const Values& aValueList) const +{ + double sum = 0; + for (typename Values::const_iterator it = aValueList.begin(); + it != aValueList.end(); ++it) + { + Value d = std::abs(aValue - *it); + sum += (d*d); + } + return sum; +} + +//----------------------------------------------------------------------------- +template +inline +void +DGtal::L2FirstOrderLocalDistance +::selfDisplay ( std::ostream & out ) const +{ + out << "L2"; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::L2SecondOrderLocalDistance::L2SecondOrderLocalDistance + (Image& aImg, TSet& aSet): myImgPtr(&aImg), mySetPtr(&aSet) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2SecondOrderLocalDistance::L2SecondOrderLocalDistance + (const L2SecondOrderLocalDistance& other): myImgPtr(other.myImgPtr), mySetPtr(other.mySetPtr) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2SecondOrderLocalDistance& +DGtal::L2SecondOrderLocalDistance::operator= + (const L2SecondOrderLocalDistance& other) +{ + if( this != &other) + { + myImgPtr = other.myImgPtr; + mySetPtr = other.mySetPtr; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2SecondOrderLocalDistance::~L2SecondOrderLocalDistance + () +{ +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2SecondOrderLocalDistance::Value +DGtal::L2SecondOrderLocalDistance::operator() + (const Point& aPoint) +{ + + //distance values + List l; + l.reserve(Point::dimension); + + //two 1-neighbors + Point neighbor1 = aPoint; + Point neighbor2 = aPoint; + + typename Point::Iterator it1 = neighbor1.begin(); + typename Point::Iterator it2 = neighbor2.begin(); + typename Point::ConstIterator it = aPoint.begin(); + typename Point::ConstIterator itEnd = aPoint.end(); + for ( ; it != itEnd; ++it, ++it1, ++it2) + {//for each dimension + + typename Point::Coordinate c = *it; + + /// first-order + double coeff = 1.0; + ++(*it1); + --(*it2); + Value d, d1, d2 = 0; + bool flag1 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor1, d1 ); + bool flag2 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor2, d2 ); + if ( flag1 || flag2 ) + { + /// second-order + ++(*it1); + --(*it2); + Value d12, d22 = 0; + bool flag12 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor1, d12 ); + bool flag22 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor2, d22 ); + + if ( flag1 && flag2 ) + { + + if ( flag12 && flag22 ) + { //take the minimal value + d1 = 2.0*d1 - d12/2.0; + d2 = 2.0*d2 - d22/2.0; + if (std::abs(d1) < std::abs(d2)) + d = d1; + else + d = d2; + coeff = 1.5; + } + else + { //like first-order accurate case + //take the minimal value + if (std::abs(d1) < std::abs(d2)) + d = d1; + else + d = d2; + } + + } + else //if not flag1 AND flag2 both true + { + if (flag1) + { + + if ( flag12 ) + { + d1 = 2.0*d1 - d12/2.0; + coeff = 1.5; + } + d = d1; + + } + + if (flag2) + { + + if ( flag22 ) + { + d2 = 2.0*d2 - d22/2.0; + coeff = 1.5; + } + d = d2; + } + } + + l.push_back( CoeffValue( coeff, d ) ); + + } //end if flag1 or flag2 + + *it1 = c; + *it2 = c; + } //end for each dimension + + //computation of the new value + return this->compute(l); +} + + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2SecondOrderLocalDistance::Value +DGtal::L2SecondOrderLocalDistance::compute +(List& aList) const +{ + ASSERT(aList.size() > 0); + + unsigned int nb = aList.size(); + if ( nb == 1 ) + { + CoeffValue pair = aList.back(); + if (pair.second >= 0) + return ( (pair.second + 1.0)/(pair.first) ); + else + return ( (pair.second - 1.0)/(pair.first) ); + } + else + { + //function computation + // typename List::iterator itMax = + // std::max_element( aList.begin(), aList.end(), details::secondAbsComparator ); + // if ( gradientNorm( itMax->second, aList ) > 1 ) + // { + // trace.info() << "NB. numerical error in L2SecondOrderLocalDistance " << std::endl; + // aList.erase( itMax ); + // return this->compute(aList); + // } + // else + { //resolution + double a = 0; + double b = 0; + double c = -1; + + for (typename List::iterator it = aList.begin(); + it != aList.end(); ++it) + { + double coeff = it->first; + Value v = it->second; + + a += (coeff*coeff); + b -= 2 * coeff * static_cast(v); + c += static_cast(v*v); + } + + //discriminant + double disc = b*b - 4*a*c; + ASSERT(disc >= 0); + + double dres1 = ( ( -b + std::sqrt(disc) ) / (2*a) ); + double dres2 = ( ( -b - std::sqrt(disc) ) / (2*a) ); + if ( std::abs(dres1) > std::abs(dres2) ) + return static_cast(dres1); + else + return static_cast(dres2); + } + } +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2SecondOrderLocalDistance::Value +DGtal::L2SecondOrderLocalDistance +::gradientNorm(const Value& aValue, const List& aList) const +{ + double sum = 0; + for (typename List::const_iterator it = aList.begin(); + it != aList.end(); ++it) + { + Value v = std::abs( it->first*aValue - it->second ); + sum += (v*v); + } + return sum; +} + +//----------------------------------------------------------------------------- +template +inline +void +DGtal::L2SecondOrderLocalDistance +::selfDisplay ( std::ostream & out ) const +{ + out << "L2"; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::LInfFirstOrderLocalDistance::LInfFirstOrderLocalDistance + (Image& aImg, TSet& aSet): myImgPtr(&aImg), mySetPtr(&aSet) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::LInfFirstOrderLocalDistance::LInfFirstOrderLocalDistance + (const LInfFirstOrderLocalDistance& other): myImgPtr(other.myImgPtr), mySetPtr(other.mySetPtr) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::LInfFirstOrderLocalDistance& +DGtal::LInfFirstOrderLocalDistance::operator= + (const LInfFirstOrderLocalDistance& other) +{ + if( this != &other) + { + myImgPtr = other.myImgPtr; + mySetPtr = other.mySetPtr; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::LInfFirstOrderLocalDistance::~LInfFirstOrderLocalDistance + () +{ +} +//----------------------------------------------------------------------------- +template +inline +typename DGtal::LInfFirstOrderLocalDistance::Value +DGtal::LInfFirstOrderLocalDistance::operator() + (const Point& aPoint) +{ + + //distance values + Values v; + v.reserve(Point::dimension); + + //two 1-neighbors + Point neighbor1 = aPoint; + Point neighbor2 = aPoint; + + typename Point::Iterator it1 = neighbor1.begin(); + typename Point::Iterator it2 = neighbor2.begin(); + typename Point::ConstIterator it = aPoint.begin(); + typename Point::ConstIterator itEnd = aPoint.end(); + for ( ; it != itEnd; ++it, ++it1, ++it2) + {//for each dimension + + typename Point::Coordinate c = *it; + *it1 = (c+1); + *it2 = (c-1); + + //neighboring values + Value d, d1, d2 = 0; + bool flag1 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor1, d1 ); + bool flag2 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor2, d2 ); + if ( flag1 || flag2 ) + { + if ( flag1 && flag2 ) + { //take the minimal value + if (std::abs(d1) < std::abs(d2)) + d = d1; + else + d = d2; + } else + { + if (flag1) d = d1; + if (flag2) d = d2; + } + + v.push_back(d); + + } + + *it1 = c; + *it2 = c; + } //end for each dimension + + //computation of the new value + return this->compute(v); + +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::LInfFirstOrderLocalDistance::Value +DGtal::LInfFirstOrderLocalDistance::compute +(Values& aValueList) const +{ + + ASSERT(aValueList.size() > 0); + + unsigned int nb = aValueList.size(); + if ( nb == 1 ) + { + Value d = aValueList.back(); + if (d >= 0) ++d; + else --d; + return d; + } + else + { //max element + typename Values::iterator it = + std::max_element( aValueList.begin(), aValueList.end(), details::absComparator ); + return *it; + } +} + +//----------------------------------------------------------------------------- +template +inline +void +DGtal::LInfFirstOrderLocalDistance +::selfDisplay ( std::ostream & out ) const +{ + out << "LInf"; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::L1FirstOrderLocalDistance::L1FirstOrderLocalDistance + (Image& aImg, TSet& aSet): myImgPtr(&aImg), mySetPtr(&aSet) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L1FirstOrderLocalDistance::L1FirstOrderLocalDistance + (const L1FirstOrderLocalDistance& other): myImgPtr(other.myImgPtr), mySetPtr(other.mySetPtr) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L1FirstOrderLocalDistance& +DGtal::L1FirstOrderLocalDistance::operator= + (const L1FirstOrderLocalDistance& other) +{ + if( this != &other) + { + myImgPtr = other.myImgPtr; + mySetPtr = other.mySetPtr; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L1FirstOrderLocalDistance::~L1FirstOrderLocalDistance + () +{ +} +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L1FirstOrderLocalDistance::Value +DGtal::L1FirstOrderLocalDistance::operator() + (const Point& aPoint) +{ + + //distance values + Values v; + v.reserve(2*Point::dimension); + + //two 1-neighbors + Point neighbor1 = aPoint; + Point neighbor2 = aPoint; + + typename Point::Iterator it1 = neighbor1.begin(); + typename Point::Iterator it2 = neighbor2.begin(); + typename Point::ConstIterator it = aPoint.begin(); + typename Point::ConstIterator itEnd = aPoint.end(); + for ( ; it != itEnd; ++it, ++it1, ++it2) + {//for each dimension + + typename Point::Coordinate c = *it; + *it1 = (c+1); + *it2 = (c-1); + + //neighboring values + Value d1, d2 = 0; + bool flag1 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor1, d1 ); + bool flag2 = findAndGetValue( *myImgPtr, *mySetPtr, neighbor2, d2 ); + if (flag1) v.push_back( d1 ); + if (flag2) v.push_back( d2 ); + + *it1 = c; + *it2 = c; + } //end for each dimension + + //computation of the new value + return this->compute(v); + +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L1FirstOrderLocalDistance::Value +DGtal::L1FirstOrderLocalDistance::compute +(Values& aValueList) const +{ + ASSERT(aValueList.size() > 0); + + //min (in absolute values) + typename Values::iterator it = + std::min_element( aValueList.begin(), aValueList.end(), details::absComparator ); + Value vmin = *it; + + //sign + if (vmin >= 0) + return vmin + 1; + else + return vmin - 1; +} + +//----------------------------------------------------------------------------- +template +inline +void +DGtal::L1FirstOrderLocalDistance +::selfDisplay ( std::ostream & out ) const +{ + out << "L1"; +} +// // +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Helper classes defined in the compilation unit (anonymous namespace) +// see operator() below +namespace +{ + // + template + struct ValueBetween0And1 + { + template + static Value get(const Value& v) + { + ASSERT( (v>=0)&&(v<=1) ); + return v; + } + }; + //specialization + template< > + struct ValueBetween0And1 + { + template + static Value get(const Value& v) + { + ASSERT( (v>=0)&&(v<=1) ); + return (1 - v); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistanceFromCells +::L2FirstOrderLocalDistanceFromCells + (const KSpace& aK, Map& aMap): myKSpace(&aK), myMap(&aMap) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistanceFromCells +::L2FirstOrderLocalDistanceFromCells + (const L2FirstOrderLocalDistanceFromCells& other) +: myKSpace(other.myKSpace), myMap(other.myMap) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistanceFromCells& +DGtal::L2FirstOrderLocalDistanceFromCells +::operator= + (const L2FirstOrderLocalDistanceFromCells& other) +{ + if( this != &other) + { + myMap = other.myMap; + myKSpace = other.myKSpace; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::L2FirstOrderLocalDistanceFromCells +::~L2FirstOrderLocalDistanceFromCells + () +{ +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2FirstOrderLocalDistanceFromCells::Value +DGtal::L2FirstOrderLocalDistanceFromCells::operator() + (const Point& aPoint) +{ + + //distance values + Values v; + v.reserve(Point::dimension); + + Cell spel = myKSpace->uSpel( aPoint ); + for ( typename KSpace::DirIterator q = myKSpace->uDirs( spel ); + (q != 0); ++q ) + { //for each dimension + const DGtal::Dimension dir = *q; + + /// for the direct orientation + Cell surfel1 = myKSpace->uIncident( spel, dir, true ); + //ASSERT( myKSpace->uIsSurfel( surfel1 ) ); + ASSERT( myKSpace->uDim( surfel1 ) == (KSpace::dimension - 1) ); + + /// for the indirect orientation + Cell surfel2 = myKSpace->uIncident( spel, dir, false ); + //ASSERT( myKSpace->uIsSurfel( surfel2 ) ); + ASSERT( myKSpace->uDim( surfel2 ) == (KSpace::dimension - 1) ); + + //neighboring values + Value d = 0; + typename Map::iterator it1 = myMap->find( surfel1 ); + typename Map::iterator it2 = myMap->find( surfel2 ); + bool flag1 = ( it1 != myMap->end() ); + bool flag2 = ( it2 != myMap->end() ); + if ( flag1 || flag2 ) + { + if ( flag1 && flag2 ) + { //take the minimal value + ASSERT( (it1->second >= 0)&&(it1->second <= 1) ); + ASSERT( (it2->second >= 0)&&(it2->second <= 1) ); + if (it1->second < it2->second) + d = ValueBetween0And1 + ::get( it1->second ); + else + d = ValueBetween0And1 + ::get( it2->second ); + } else + { + if (flag1) + { + ASSERT( (it1->second >= 0)&&(it1->second <= 1) ); + d = ValueBetween0And1 + ::get( it1->second ); + } + if (flag2) + { + ASSERT( (it2->second >= 0)&&(it2->second <= 1) ); + d = ValueBetween0And1 + ::get( it2->second ); + } + } + + if (d == 0) return 0; + + v.push_back(d); + } + + } //end for each dimension + + //computation of the new value + return this->compute(v); +} + + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::L2FirstOrderLocalDistanceFromCells::Value +DGtal::L2FirstOrderLocalDistanceFromCells::compute +(Values& aValueList) const +{ + ASSERT(aValueList.size() > 0); + + unsigned int nb = aValueList.size(); + if ( nb == 1 ) + { + return aValueList.back(); + } + else + { //resolution + double a = 0; + + for (typename Values::iterator it = aValueList.begin(); + it != aValueList.end(); ++it) + { + Value d = *it; + a += ( 1.0 / static_cast( d*d ) ); + } + + return static_cast( std::sqrt(a) / a ); + } +} + +//----------------------------------------------------------------------------- +template +inline +void +DGtal::L2FirstOrderLocalDistanceFromCells +::selfDisplay ( std::ostream & out ) const +{ + out << "L2"; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +template +inline +DGtal::SpeedExtrapolator::SpeedExtrapolator +(const DistanceImage& aDistImg, const Set& aSet, SpeedFunctor& aSpeedFunc) + : myDistImgPtr(&aDistImg), mySetPtr(&aSet), mySpeedFuncPtr(&aSpeedFunc) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::SpeedExtrapolator::SpeedExtrapolator + (const SpeedExtrapolator& other) + : myDistImgPtr(other.myDistImgPtr), mySetPtr(other.mySetPtr), mySpeedFuncPtr(other.mySpeedFuncPtr) +{ +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::SpeedExtrapolator& +DGtal::SpeedExtrapolator::operator= + (const SpeedExtrapolator& other) +{ + if( this != &other) + { + myDistImgPtr = other.myDistImgPtr; + mySetPtr = other.mySetPtr; + mySpeedFuncPtr = other.mySpeedFuncPtr; + } + return *this; +} + +//----------------------------------------------------------------------------- +template +inline +DGtal::SpeedExtrapolator::~SpeedExtrapolator + () +{ +} + +//----------------------------------------------------------------------------- +template +inline +typename DGtal::SpeedExtrapolator::Value +DGtal::SpeedExtrapolator::operator() + (const Point& aPoint) +{ + + //speed values + Value num, den = 0; + + //two 1-neighbors for one dimension + Point neighbor1 = aPoint; + Point neighbor2 = aPoint; + + typename Point::Iterator it1 = neighbor1.begin(); + typename Point::Iterator it2 = neighbor2.begin(); + typename Point::ConstIterator it = aPoint.begin(); + typename Point::ConstIterator itEnd = aPoint.end(); + for ( ; it != itEnd; ++it, ++it1, ++it2) + {//for each dimension + + typename Point::Coordinate c = *it; + + //distance value + DistanceValue d = 0; + bool flag = findAndGetValue( *myDistImgPtr, *mySetPtr, aPoint, d ); + ASSERT( flag ); + + //neighbors + *it1 = (c+1); + *it2 = (c-1); + //neighboring speed value + Value s = 0; + //neighboring distance values + DistanceValue d0, d1, d2 = 0; + bool flag1 = findAndGetValue( *myDistImgPtr, *mySetPtr, neighbor1, d1 ); + bool flag2 = findAndGetValue( *myDistImgPtr, *mySetPtr, neighbor2, d2 ); + if ( flag1 || flag2 ) + { + if ( flag1 && flag2 ) + { //take the minimal value + if (std::abs(d1) < std::abs(d2)) + { + d0 = d1; + s = (*mySpeedFuncPtr)( neighbor1 ); + } + else + { + d0 = d2; + s = (*mySpeedFuncPtr)( neighbor2 ); + } + } else + { + if (flag1) + { + d0 = d1; + s = (*mySpeedFuncPtr)( neighbor1 ); + } + if (flag2) + { + d0 = d2; + s = (*mySpeedFuncPtr)( neighbor2 ); + } + } + + Value diff = static_cast(d - d0); + num += ( s * diff ); + den += diff; + } + + *it1 = c; + *it2 = c; + } //end for each dimension + + //computation of the new value + ASSERT(den != 0); + return (num/den); +} diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index cb54414..f935516 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -61,7 +61,7 @@ #include "DGtal/images/ImageHelper.h" // FMM -#include "DGtal/geometry/volumes/distance/FMM.h" +#include "FMM.h" // frontier #include "DGtal/topology/SurfelAdjacency.h" diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 92b0357..d5b3d63 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -444,33 +444,27 @@ DGtal::FrontierEvolver > LabelPredicate; + typedef CascadingPointPredicate< typename Domain::Predicate, + LabelPredicate > PointPredicate4FMM; + LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + PointPredicate4FMM pred( myLImage.domain().predicate(), predOnLabels ); + typedef FMM FMM; + /// initialization of the band from the /// points adjacent to the frontier - unsigned int nbsurfels = 0; if (myPointSet.size() == 0) {//first step - for ( SurfelIterator it = myFrontier->begin(), - itEnd = myFrontier->end(); - it != itEnd; ++it ) - { - Point in( getInnerPoint( *it ) ); - Point out( getOuterPoint( *it ) ); - if ( myDImage.domain().isInside( in ) ) - { - ASSERT( myLImage(in) == myInnerLabel ); - insertAndAlwaysSetValue( myDImage, myPointSet, in, -0.5 ); - } - if ( myDImage.domain().isInside( out ) ) - { - ASSERT( myLImage(out) == myOuterLabel ); - insertAndAlwaysSetValue( myDImage, myPointSet, out, 0.5 ); - } - ++nbsurfels; - } + FMM::initFromBelsRange(myKSpace, myFrontier->begin(), myFrontier->end(), + myDImage, myPointSet, 0.5, true); } else {//next steps + //this renormalization doesn ot work at all + // FMM::initFromBelsRange(myKSpace, myFrontier->begin(), myFrontier->end(), + // myDImage, myDImage, myPointSet, true); //TODO think about the best way of dealing with adjacentPoints //and copying it in the band typedef std::pair PointDistance; @@ -478,72 +472,47 @@ DGtal::FrontierEvolver::iterator IteratorPointDistance; for ( SurfelIterator it = myFrontier->begin(), - itEnd = myFrontier->end(); - it != itEnd; ++it ) - { - Point in( getInnerPoint( *it ) ); - Point out( getOuterPoint( *it ) ); - - bool flagIn = ( myDImage.domain().isInside( in ) ); - bool flagOut = ( myDImage.domain().isInside( out ) ); - if (flagIn && flagOut) - { - ASSERT( myLImage(in) == myInnerLabel ); - Distance din = myDImage( in ); - ASSERT( din <= 0 ); - - ASSERT( myLImage(out) == myOuterLabel ); - Distance dout = myDImage( out ); - ASSERT( dout > 0 ); - - //renormalize distance values - // Distance e = std::abs(din)+std::abs(dout); - // Distance ndin = din/e; - // Distance ndout = dout/e; - Distance ndin = din; - Distance ndout = dout; - - std::pair rin - = adjacentPoints.insert( PointDistance( in, ndin ) ); - // if (rin.second == false) - // {//if the same point is already stored - // //take the minimal distance - // if (std::abs(ndin) < std::abs(rin.first->second)) - // rin.first->second = ndin; - // } - std::pair rout - = adjacentPoints.insert( PointDistance( out, ndout ) ); - // if (rout.second == false) - // {//if the same point is already stored - // //take the minimal distance - // if (std::abs(ndout) < std::abs(rout.first->second)) - // rout.first->second = ndout; - // } - } - else - { - if (flagIn) - {ASSERT(false && "not implemented yet");} - if (flagOut) - {ASSERT(false && "not implemented yet");} - } - ++nbsurfels; - } + itEnd = myFrontier->end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + Point out( getOuterPoint( *it ) ); + + bool flagIn = ( myDImage.domain().isInside( in ) ); + bool flagOut = ( myDImage.domain().isInside( out ) ); + if (flagIn && flagOut) + { + ASSERT( myLImage(in) == myInnerLabel ); + Distance din = myDImage( in ); + ASSERT( din <= 0 ); + + ASSERT( myLImage(out) == myOuterLabel ); + Distance dout = myDImage( out ); + ASSERT( dout > 0 ); + + std::pair rin + = adjacentPoints.insert( PointDistance( in, din ) ); + + std::pair rout + = adjacentPoints.insert( PointDistance( out, dout ) ); + } + else + { + ASSERT(false && "impossible"); + } + } myPointSet.clear(); for ( IteratorPointDistance - it = adjacentPoints.begin(), - itEnd = adjacentPoints.end(); - it != itEnd; ++it ) - { - PointDistance pair( *it ); - insertAndSetValue( myDImage, myPointSet, pair.first, pair.second ); - } + it = adjacentPoints.begin(), + itEnd = adjacentPoints.end(); + it != itEnd; ++it ) + { + PointDistance pair( *it ); + insertAndSetValue( myDImage, myPointSet, pair.first, pair.second ); + } } - #ifdef WITHINFO - trace.info() << nbsurfels << " surfels found." << std::endl; - #endif std::copy( myPointSet.begin(), myPointSet.end(), res ); @@ -551,90 +520,8 @@ DGtal::FrontierEvolver=0 ) nbPos++; - // } - // neighbor2.at(l) = (c-1); - // if ( points.find(neighbor2) != points.end() ) - // { - // nb++; - // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; - // if ( myDImage( neighbor2 )>=0 ) nbPos++; - // } - // neighbor2.at(l) = c; - // } - // std::cout << nbPos << " / " << nb << " / 6 " << std::endl; - // ASSERT( (nbPos == nb)||(nbPos == 0) ); - // } - // neighbor.at(k) = (c-1); - // if ( points.find(neighbor) == points.end() ) - // { - // unsigned int nb = 0, nbPos = 0; - // Point neighbor2 = neighbor; - // for (Dimension l = 0; l < Point::dimension; ++l) - // { - // typename Point::Coordinate c = neighbor2.at(l); - // neighbor2.at(l) = (c+1); - // if ( points.find(neighbor2) != points.end() ) - // { - // nb++; - // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; - // if ( myDImage( neighbor2 )>=0 ) nbPos++; - // } - // neighbor2.at(l) = (c-1); - // if ( points.find(neighbor2) != points.end() ) - // { - // nb++; - // std::cout << neighbor2 << myDImage( neighbor2 ) << std::endl; - // if ( myDImage( neighbor2 )>=0 ) nbPos++; - // } - // neighbor2.at(l) = c; - // } - // std::cout << nbPos << " / " << nb << " / 6 " << std::endl; - // ASSERT( (nbPos == nb)||(nbPos == 0) ); - // } - - // neighbor.at(k) = c; - // } - // } - // trace.info() << "DT..." << std::endl; - ///////// end debug - - /// FMM - - //predicate definition - typedef TwoLabelsPredicate > LabelPredicate; - typedef CascadingPointPredicate< typename Domain::Predicate, - LabelPredicate > FMMPointPredicate; - LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - FMMPointPredicate pred( myLImage.domain().predicate(), predOnLabels ); - - // typedef typename Domain::Predicate FMMPointPredicate; - // FMMPointPredicate pred = myLImage.domain().predicate(); - - //FMM definition - typedef FMM FMM; + /// FMM computation FMM fmm( myDImage, myPointSet, pred ); #ifdef WITHINFO trace.info() << fmm << std::endl; @@ -645,7 +532,8 @@ DGtal::FrontierEvolver Date: Tue, 17 Apr 2012 11:58:33 +0200 Subject: [PATCH 050/108] in FrontierEvolver, FMM is now not limited to the 2 adjacent regions (but candidates to flip yes) and evolution is better near contact points. However, there is still a bug when the reference surfel of a given frontier is lost after the evolution of an other frontier --- deformations/FrontierEvolver.h | 12 +- deformations/FrontierEvolver.ih | 424 +- deformations/PartitionEvolver.ih | 2 +- deformations/deformation2d.cpp | 3 + deformations/images/glasses3.pgm | 1800 +-- deformations/images/glasses3bis.pgm | 16388 ++++++++++++++++++++++ deformations/testLocalDeformation3d.cpp | 2 +- 7 files changed, 17518 insertions(+), 1113 deletions(-) create mode 100644 deformations/images/glasses3bis.pgm diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index f935516..581ad96 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -235,12 +235,12 @@ struct SetFromImageSelector */ ~FrontierEvolver(); - /** - * Deform the image of labels around the digital frontier - * - * @return time spent during the deformation. - */ - double update(); + // /** + // * Deform the image of labels around the digital frontier + // * + // * @return time spent during the deformation. + // */ + // double update(); /** * Deform the image of labels during @a aT diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index d5b3d63..d9740e9 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -27,7 +27,7 @@ */ -//#define WITHINFO +#define WITHINFO ////////////////////////////////////////////////////////////////////////////// @@ -76,185 +76,189 @@ DGtal::FrontierEvolver -inline -double -DGtal::FrontierEvolver -::update() -{ - #ifdef WITHINFO - trace.info() << "starting surfel: " << mySurfel << std::endl; - #endif - - /// set of points that are candidate to the flip - typedef std::vector Band; - typedef typename Band::const_iterator BandIterator; - Band narrowBand; - init ( std::back_inserter( narrowBand ) ); - #ifdef WITHINFO - trace.info() << narrowBand.size() << " closest points" << std::endl; - #endif - - /// velocity and zero-crossing time computation - typedef std::pair PointTime; - typedef std::vector CandidateVector; - typedef typename CandidateVector::const_iterator CandidateIterator; - CandidateVector candidates; +// template +// inline +// double +// DGtal::FrontierEvolver +// ::update() +// { +// #ifdef WITHINFO +// trace.info() << std::endl; +// trace.info() << "starting surfel: " << mySurfel << std::endl; +// trace.info() << "between: " << myInnerLabel << " (inner region)" +// << " and " << myOuterLabel << " (outer region) " +// << std::endl; +// #endif + +// /// set of points that are candidate to the flip +// typedef std::vector Band; +// typedef typename Band::const_iterator BandIterator; +// Band narrowBand; +// init ( std::back_inserter( narrowBand ) ); +// #ifdef WITHINFO +// trace.info() << narrowBand.size() << " closest points" << std::endl; +// #endif + +// /// velocity and zero-crossing time computation +// typedef std::pair PointTime; +// typedef std::vector CandidateVector; +// typedef typename CandidateVector::const_iterator CandidateIterator; +// CandidateVector candidates; - typedef std::pair DistanceVelocity; - typedef std::vector DistanceVelocityVector; - typedef typename DistanceVelocityVector::const_iterator DistanceVelocityIterator; - DistanceVelocityVector buffer; - - double vmax = 0; - for ( BandIterator - it = narrowBand.begin(), - itEnd = narrowBand.end(); - it != itEnd; ++it) - { - // distance - Distance d = myDImage( *it ); - // velocity - Velocity v = myFunctor( *it ); - // maximal velocity - double vabs = std::abs( static_cast( v ) ); - if (vabs > vmax) vmax = vabs; - // storing distance and velocity - buffer.push_back( DistanceVelocity( d, v ) ); - // new candidate with its zero-crossing time - if ( ( (d>=0) && (v<0) ) - || ( (d<=0) && (v>0) ) ) - { //if opposite signs (and v != 0) - double t = - static_cast( d ) / v; - ASSERT( t >= 0 ); - candidates.push_back( PointTime( *it, t ) ); - } - - } - #ifdef WITHINFO - trace.info() << candidates.size() << " candidates " << std::endl; - #endif - - /// time threshold computation - double tmax = myW / vmax; - - #ifdef WITHINFO - trace.info() << "Distance max: " << myW << " / " - << "Velocity max: " << vmax << " = " - << "Time threshold: " << tmax << std::endl; - #endif - - if (candidates.begin() != candidates.end()) - { //if they are candidates - - /// ordering of the points according - /// to their zero-crossing time - #ifdef WITHINFO - trace.info() << "ordering..." << std::endl; - #endif +// typedef std::pair DistanceVelocity; +// typedef std::vector DistanceVelocityVector; +// typedef typename DistanceVelocityVector::const_iterator DistanceVelocityIterator; +// DistanceVelocityVector buffer; + +// double vmax = 0; +// for ( BandIterator +// it = narrowBand.begin(), +// itEnd = narrowBand.end(); +// it != itEnd; ++it) +// { +// // distance +// Distance d = myDImage( *it ); +// // velocity +// Velocity v = myFunctor( *it ); +// // maximal velocity +// double vabs = std::abs( static_cast( v ) ); +// if (vabs > vmax) vmax = vabs; +// // storing distance and velocity +// buffer.push_back( DistanceVelocity( d, v ) ); +// // new candidate with its zero-crossing time +// if ( ( (d>=0) && (v<0) ) +// || ( (d<=0) && (v>0) ) ) +// { //if opposite signs (and v != 0) +// double t = - static_cast( d ) / v; +// ASSERT( t >= 0 ); +// candidates.push_back( PointTime( *it, t ) ); +// } + +// } +// #ifdef WITHINFO +// trace.info() << candidates.size() << " candidates " << std::endl; +// #endif + +// /// time threshold computation +// double tmax = myW / vmax; + +// #ifdef WITHINFO +// trace.info() << "Distance max: " << myW << " / " +// << "Velocity max: " << vmax << " = " +// << "Time threshold: " << tmax << std::endl; +// #endif + +// if (candidates.begin() != candidates.end()) +// { //if they are candidates + +// /// ordering of the points according +// /// to their zero-crossing time +// #ifdef WITHINFO +// trace.info() << "ordering..." << std::endl; +// #endif - details::CompareSecondElement timeCompare; - std::sort( candidates.begin(), candidates.end(), timeCompare ); - - #ifdef WITHINFO - trace.info() << "Times ranging from " - << candidates.begin()->second - << " to " - << candidates.rbegin()->second - << std::endl; - #endif - - /// flip points one by one, in order, - /// while possible - std::set notSimplePoints; //points not flipped because not simple - - unsigned int nbFlips = 0; - Point p = Point::diagonal(0), plast = Point::diagonal(0); - double t = 0.0, tlast = 0.0; - bool go = true; - for (CandidateIterator - it = candidates.begin(), - itEnd = candidates.end(); - ( (it != itEnd)&&(go) ); ++it) - { - plast = p; - p = it->first; - tlast = t; - t = it->second; - if (t <= tmax) - { - const Label label = myLImage(p); - const Label oppositeLabel = - (label == myInnerLabel)?myOuterLabel:myInnerLabel; - if ( myPointPred( p, oppositeLabel ) ) - { /// flip - nbFlips++; - myLImage.setValue( p, oppositeLabel ); - } - else - { - notSimplePoints.insert( p ); - #ifdef WITHINFO - trace.emphase() << p << " is not a simple point!" << std::endl; - #endif - } - } - else - go = false; - } - - #ifdef WITHINFO - trace.info() << nbFlips << " flipped points in " << tlast << " unit time" << std::endl; - #endif - - /// update distance map - #ifdef WITHINFO - trace.info() << "updating signed distance function..." << std::endl; - #endif - - if (tlast == 0.0) - tlast = tmax; - - DistanceVelocityIterator itBuffer = buffer.begin(); - for (BandIterator - it = narrowBand.begin(), - itEnd = narrowBand.end(); - it != itEnd; ++it, ++itBuffer) - { - // velocity - DistanceVelocity pair( *itBuffer ); - Distance newDist = pair.first + tlast*pair.second; - - //label - const Label pLabel = myLImage( *it ); - - const Distance eps = std::numeric_limits::epsilon(); - // correction due to the approximation error - if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) - //correction due to the non simplicity - || ( notSimplePoints.find( *it ) != notSimplePoints.end() ) ) - { - if (pLabel == myInnerLabel) newDist = -eps; - else newDist = eps; - } - - // set value - myDImage.setValue( *it, newDist ); - - ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) - || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) ); - } - - /// update frontier if needed - if (nbFlips > 0) - updateFrontier( plast ); - - return tlast; - } - else - return 0.0; -} +// details::CompareSecondElement timeCompare; +// std::sort( candidates.begin(), candidates.end(), timeCompare ); + +// #ifdef WITHINFO +// trace.info() << "Times ranging from " +// << candidates.begin()->second +// << " to " +// << candidates.rbegin()->second +// << std::endl; +// #endif + +// /// flip points one by one, in order, +// /// while possible +// std::set notSimplePoints; //points not flipped because not simple + +// unsigned int nbFlips = 0; +// Point p = Point::diagonal(0), plast = Point::diagonal(0); +// double t = 0.0, tlast = 0.0; +// bool go = true; +// for (CandidateIterator +// it = candidates.begin(), +// itEnd = candidates.end(); +// ( (it != itEnd)&&(go) ); ++it) +// { +// plast = p; +// p = it->first; +// tlast = t; +// t = it->second; +// if (t <= tmax) +// { +// const Label label = myLImage(p); +// const Label oppositeLabel = +// (label == myInnerLabel)?myOuterLabel:myInnerLabel; +// if ( myPointPred( p, oppositeLabel ) ) +// { /// flip +// nbFlips++; +// myLImage.setValue( p, oppositeLabel ); +// } +// else +// { +// notSimplePoints.insert( p ); +// #ifdef WITHINFO +// trace.emphase() << p << " is not a simple point!" << std::endl; +// #endif +// } +// } +// else +// go = false; +// } + +// #ifdef WITHINFO +// trace.info() << nbFlips << " flipped points in " << tlast << " unit time" << std::endl; +// #endif + +// /// update distance map +// #ifdef WITHINFO +// trace.info() << "updating signed distance function..." << std::endl; +// #endif + +// if (tlast == 0.0) +// tlast = tmax; + +// DistanceVelocityIterator itBuffer = buffer.begin(); +// for (BandIterator +// it = narrowBand.begin(), +// itEnd = narrowBand.end(); +// it != itEnd; ++it, ++itBuffer) +// { +// // velocity +// DistanceVelocity pair( *itBuffer ); +// Distance newDist = pair.first + tlast*pair.second; + +// //label +// const Label pLabel = myLImage( *it ); + +// const Distance eps = std::numeric_limits::epsilon(); +// // correction due to the approximation error +// if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) +// //correction due to the non simplicity +// || ( notSimplePoints.find( *it ) != notSimplePoints.end() ) ) +// { +// if (pLabel == myInnerLabel) newDist = -eps; +// else newDist = eps; +// } + +// // set value +// myDImage.setValue( *it, newDist ); + +// ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) +// || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) ); +// } + +// /// update frontier if needed +// if (nbFlips > 0) +// updateFrontier( plast ); + +// return tlast; +// } +// else +// return 0.0; +// } template @@ -263,8 +267,15 @@ double DGtal::FrontierEvolver ::update(const double& aT) { + ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); + ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); + #ifdef WITHINFO + trace.info() << std::endl; trace.info() << "starting surfel: " << mySurfel << std::endl; + trace.info() << "between: " << myInnerLabel << " (inner region)" + << " and " << myOuterLabel << " (outer region) " + << std::endl; #endif /// set of points that are candidate to the flip @@ -287,27 +298,31 @@ DGtal::FrontierEvolver=0) && (v<0) ) - || ( (d<=0) && (v>0) ) ) - { //if opposite signs (and v != 0) - double t = - static_cast( d ) / v; - ASSERT( t >= 0 ); - candidates.push_back( PointTime( *it, t ) ); + if ( ( myLImage( p ) == myInnerLabel ) + || (myLImage( p ) == myOuterLabel ) ) + { + if ( ( (d>=0) && (v<0) ) + || ( (d<=0) && (v>0) ) ) + { //if opposite signs (and v != 0) + double t = - static_cast( d ) / v; + ASSERT( t >= 0 ); + candidates.push_back( PointTime( p, t ) ); + } } - } #ifdef WITHINFO trace.info() << candidates.size() << " candidates " << std::endl; @@ -315,11 +330,8 @@ DGtal::FrontierEvolver 0)&&(myLImage( *it ) == myOuterLabel) ) ); + || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) + || ( (myLImage( *it ) != myInnerLabel)&&(myLImage( *it ) != myOuterLabel) ) ); } /// update frontier if needed @@ -445,12 +458,14 @@ DGtal::FrontierEvolver > LabelPredicate; - typedef CascadingPointPredicate< typename Domain::Predicate, - LabelPredicate > PointPredicate4FMM; - LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - PointPredicate4FMM pred( myLImage.domain().predicate(), predOnLabels ); - typedef FMM FMM; + // typedef TwoLabelsPredicate > LabelPredicate; + // typedef CascadingPointPredicate< typename Domain::Predicate, + // LabelPredicate > PointPredicate4FMM; + // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + // PointPredicate4FMM pred( myLImage.domain().predicate(), predOnLabels ); + // typedef FMM FMM; + typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); + typedef FMM FMM; /// initialization of the band from the /// points adjacent to the frontier @@ -522,7 +537,7 @@ DGtal::FrontierEvolver0)) ); + || ((myLImage(p) == myOuterLabel)&&(d>0)) + || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); *res++ = p; } } @@ -549,9 +564,8 @@ DGtal::FrontierEvolver TopologicalPredicate; TopologicalPredicate topologicalPredicate(*labelImage); diff --git a/deformations/images/glasses3.pgm b/deformations/images/glasses3.pgm index ca972fb..812b3d5 100644 --- a/deformations/images/glasses3.pgm +++ b/deformations/images/glasses3.pgm @@ -10822,36 +10822,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -10950,36 +10950,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11078,36 +11078,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11206,36 +11206,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11334,36 +11334,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11462,36 +11462,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11590,36 +11590,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11718,36 +11718,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11846,36 +11846,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -11974,36 +11974,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12102,36 +12102,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12230,36 +12230,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12358,36 +12358,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12486,36 +12486,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12614,36 +12614,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12742,36 +12742,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12870,36 +12870,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -12998,36 +12998,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13126,36 +13126,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13254,36 +13254,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13382,36 +13382,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13510,36 +13510,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13638,36 +13638,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13766,36 +13766,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -13894,36 +13894,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -14022,36 +14022,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -14150,36 +14150,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -14278,36 +14278,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -14406,36 +14406,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 @@ -14534,36 +14534,36 @@ P2 0 0 0 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 -104 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 +103 0 0 0 diff --git a/deformations/images/glasses3bis.pgm b/deformations/images/glasses3bis.pgm new file mode 100644 index 0000000..07757e2 --- /dev/null +++ b/deformations/images/glasses3bis.pgm @@ -0,0 +1,16388 @@ +P2 +# CREATOR: GIMP PNM Filter Version 1.1 +128 128 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +205 +205 +205 +205 +205 +205 +205 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +104 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/deformations/testLocalDeformation3d.cpp b/deformations/testLocalDeformation3d.cpp index ff2e1a2..32dbd7f 100644 --- a/deformations/testLocalDeformation3d.cpp +++ b/deformations/testLocalDeformation3d.cpp @@ -206,7 +206,7 @@ int main(int argc, char** argv) trace.info() << "iteration # " << i << std::endl; //update - deltat = e.update(); + deltat = e.update(w); sumt += deltat; if ((i%step)==0) From 8af2e27d724bd229d88592358f7ff1938fd3602e Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 17 Apr 2012 18:09:27 +0200 Subject: [PATCH 051/108] checking surfels for all frontiers of the partition during the flips --- deformations/FrontierEvolver.h | 82 +++++++++++---- deformations/FrontierEvolver.ih | 130 +++++++++++++++++------- deformations/PartitionEvolver.h | 19 +++- deformations/PartitionEvolver.ih | 52 +++++++++- deformations/testLocalDeformation2d.cpp | 2 +- deformations/testLocalDeformation3d.cpp | 2 +- 6 files changed, 223 insertions(+), 64 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 581ad96..1c2a6ab 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -67,6 +67,10 @@ #include "DGtal/topology/SurfelAdjacency.h" #include "DGtal/topology/helpers/FrontierPredicate.h" #include "DGtal/topology/LightExplicitDigitalSurface.h" + +//partition +#include "PartitionEvolver.h" + ////////////////////////////////////////////////////////////////////////////// namespace DGtal @@ -130,6 +134,8 @@ struct SetFromImageSelector }; } + + ///////////////////////////////////////////////////////////////////////////// // template class FrontierEvolver /** @@ -214,6 +220,11 @@ struct SetFromImageSelector typedef TPredicate Predicate; + /// Partition + typedef PartitionEvolver Partition; + // ----------------------- Standard services ------------------------------ public: @@ -228,7 +239,8 @@ struct SetFromImageSelector * @param aW maximal width of the deformation band (1.0 by default) */ FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, - const Functor& aF, const Predicate& aP, const double& aW = 1.0); + const Functor& aF, const Predicate& aP, + Partition* aPartitionPtr = NULL, const double& aW = 1.0); /** * Destructor. Does nothing. @@ -251,18 +263,26 @@ struct SetFromImageSelector */ double update(const double& aT); - /** - * Return through @a out the points - * for which the distance value has been - * computed and stored in @a myDImage , - * which are candidate to the flip - * - * @tparam TOutputIterator a model of output iterator - * - * @param out an output iterator + + /** + * @return starting surfel of the digital frontier. */ - template - void init(const TOutputIterator& out); + Surfel surfel() const; + + /** + * @param aSurfel new starting surfel of the digital frontier. + */ + void setSurfel(const Surfel& aSurfel); + + /** + * @return begin iterator on the surfels of the digital frontier. + */ + SurfelIterator begin() const; + + /** + * @return end iterator on the surfels of the digital frontier. + */ + SurfelIterator end() const; /** * Checks the validity/consistency of the object. @@ -270,7 +290,6 @@ struct SetFromImageSelector */ bool isValid() const; - /** * Writes/Displays the object on an output stream. * @param out the output stream where the object is written. @@ -334,6 +353,10 @@ struct SetFromImageSelector * (implicit) digital frontier */ const Frontier* myFrontier; + /** + * Aliasing pointer on the partition the frontier belongs to + */ + Partition* myPartitionPtr; // ------------------------- Hidden services ------------------------------ protected: @@ -361,6 +384,33 @@ struct SetFromImageSelector // ------------------------- Internals ------------------------------------ private: + /** + * Return through @a out the points + * of the narrow band + * for which the distance value has been + * computed and stored in @a myDImage + * + * @tparam TOutputIterator a model of output iterator + * + * @param out an output iterator + */ + template + void init(const TOutputIterator& out); + + /** + * Checks whether the other frontiers (if any) + * can be modified by the flip of @a aPoint + * @param aPoint any (digital) point + */ + void checkPartition ( const Point& aPoint ); + + /** + * Update the starting surfel @a mySurfel + * of the digital frontier from point @a p + * @param p any (digital) point + */ + void updateFrontier ( const Point& p ); + /** * Get inner point. * @param s a surfel @@ -375,12 +425,6 @@ struct SetFromImageSelector */ Point getOuterPoint ( const Surfel& s ) const ; - /** - * Update the starting surfel @a mySurfel - * of the digital frontier from point @a p - * @param p any (digital) point - */ - void updateFrontier ( const Point& p ); }; // end of class FrontierEvolver diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index d9740e9..2f2c0e5 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -44,10 +44,12 @@ template ::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, - const Functor& aF, const Predicate& aP, const double& aW) + const Functor& aF, const Predicate& aP, Partition* aPartitionPtr, + const double& aW) : myKSpace( aK ), myLImage( aI ), myDImage( aD ), myPointSet( SetFromImageSelector::get( myDImage ) ), - mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), myW( aW ), + mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), + myPartitionPtr( aPartitionPtr), myW( aW ), myInnerLabel( myLImage( getInnerPoint( mySurfel ) ) ), myOuterLabel( myLImage( getOuterPoint( mySurfel ) ) ), mySurfelPred( myKSpace, myLImage, myInnerLabel, myOuterLabel ), @@ -267,6 +269,8 @@ double DGtal::FrontierEvolver ::update(const double& aT) { + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); @@ -378,7 +382,8 @@ DGtal::FrontierEvolver::epsilon(); + const Distance eps = std::numeric_limits::epsilon(); + //const Distance eps = 0.00001; // correction due to the approximation error if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) //correction due to the non simplicity @@ -552,8 +558,8 @@ DGtal::FrontierEvolver0)) + ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) + || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); *res++ = p; } @@ -577,14 +583,58 @@ DGtal::FrontierEvolver + typename TFunctor, typename TPredicate> +inline +typename DGtal::FrontierEvolver::Surfel +DGtal::FrontierEvolver +::surfel() const +{ + return mySurfel; +} + +template inline void DGtal::FrontierEvolver -::selfDisplay ( std::ostream & out ) const +::setSurfel(const Surfel& aSurfel) { - out << "[FrontierEvolver]\n"; - out << "\n"; + /// update surfel + mySurfel = aSurfel; + + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); + ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); + ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); + + /// update frontier + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); + +} + +template +inline +typename DGtal::FrontierEvolver +::SurfelIterator +DGtal::FrontierEvolver +::begin() const +{ + return myFrontier->begin(); +} + +template +inline +typename DGtal::FrontierEvolver +::SurfelIterator +DGtal::FrontierEvolver +::end() const +{ + return myFrontier->end(); } template ::isValid() const { - return true; + return ( ( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ) + && ( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ) ); } + +template +inline +void +DGtal::FrontierEvolver +::selfDisplay ( std::ostream & out ) const +{ + out << "[FrontierEvolver]\n"; + out << "\n"; +} + + template inline @@ -624,24 +688,21 @@ template -::updateFrontier(const Point& p) +::checkPartition(const Point& aPoint) { - /// update mySurfel - //neigbors - // std::cout << p << myLImage(p) << " "; - // Point neighbor = p; - // for (Dimension k = 0; k < Point::dimension; ++k) - // { - // typename Point::Coordinate c = neighbor.at(k); - // neighbor.at(k) = (c+1); - // std::cout << neighbor << myLImage(neighbor) << " "; - // neighbor.at(k) = (c-1); - // std::cout << neighbor << myLImage(neighbor) << " "; - // neighbor.at(k) = c; - // } - // std::cout << std::endl; - + if (myPartitionPtr != NULL) + { + myPartitionPtr->checkFrontiers( this, aPoint ); + } +} +template +inline +void +DGtal::FrontierEvolver +::updateFrontier(const Point& p) +{ /// spel creation typename KSpace::SCell spel; const Label pLabel = myLImage(p); @@ -659,6 +720,7 @@ DGtal::FrontierEvolver( true ), - mySurfel ); + this->setSurfel( newSurfel ); } diff --git a/deformations/PartitionEvolver.h b/deformations/PartitionEvolver.h index 7b13b7c..0271d00 100644 --- a/deformations/PartitionEvolver.h +++ b/deformations/PartitionEvolver.h @@ -51,13 +51,18 @@ #include "DGtal/base/CountedPtr.h" #include "LocalMCM.h" -#include "FrontierEvolver.h" ////////////////////////////////////////////////////////////////////////////// namespace DGtal { + //Forward declaration + template + class FrontierEvolver; + ///////////////////////////////////////////////////////////////////////////// // template class PartitionEvolver /** @@ -160,6 +165,17 @@ namespace DGtal */ double update(const double& aT); + /** + * Check the validity of the different frontiers + * of the partition + * + * @param aPtrToCaller pointer on the frontier evolver + * that called the checking procedure + * @param aPoint any point + * @pre must lie in the domain of the image of labels + */ + void checkFrontiers(const Evolver* aPtrToCaller, const Point& aPoint); + /** * Checks the validity/consistency of the object. * @return 'true' if the object is valid, 'false' otherwise. @@ -279,6 +295,7 @@ namespace DGtal /////////////////////////////////////////////////////////////////////////////// // Includes inline functions. +#include "FrontierEvolver.h" #include "PartitionEvolver.ih" // // diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index 252a833..1befa6d 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -95,7 +95,7 @@ DGtal::PartitionEvolver::const_iterator it = myEvolvers.begin(), - itEnd = myEvolvers.end(); it != itEnd; ++it, ++i) + itEnd = myEvolvers.end(); it != itEnd; ++it) { - //trace.info() << "Frontier #" << i << std::endl; (*it)->update( aT ); } return aT; } +template +inline +void +DGtal::PartitionEvolver +::checkFrontiers(const Evolver* aPtrToCaller, const Point& aPoint) +{ + trace.info() << " checking frontiers... " << std::endl; + + for (typename std::vector::const_iterator + it = myEvolvers.begin(), + itEnd = myEvolvers.end(); it != itEnd; ++it) + { /// for each frontier (except aPtrToCaller) + if ( it->get() != aPtrToCaller ) + { + SCell s = (*it)->surfel(); + + SCellToIncidentPoints func( myKSpace ); + typename SCellToIncidentPoints::Output points = func( s ); + + if ( (points.first == aPoint)||(points.second == aPoint) ) + { /// if s is adjacent to aPoint + + /// tracking until a new surfel is found + bool flag = true; + typedef typename Evolver::SurfelIterator SurfelIterator; + for ( SurfelIterator sit = (*it)->begin(), + sitEnd = (*it)->end(); + ( (sit != sitEnd)&&(flag) ); ++sit ) + { + SCell newS = *sit; + typename SCellToIncidentPoints::Output newPoints = func( newS ); + if ( (newPoints.first != aPoint) && (newPoints.second != aPoint) ) + {/// if newS is not adjacent to aPoint + + /// update + (*it)->setSurfel( newS ); + flag = false; + trace.info() << s << " moved to " << newS << std::endl; + } + } + ASSERT( flag == false ); + } + } + } +} template diff --git a/deformations/testLocalDeformation2d.cpp b/deformations/testLocalDeformation2d.cpp index 66991f6..ba081f0 100644 --- a/deformations/testLocalDeformation2d.cpp +++ b/deformations/testLocalDeformation2d.cpp @@ -216,7 +216,7 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, distanceImage, bel, functor, predicate, 0.5 ); + e(ks, labelImage, distanceImage, bel, functor, predicate, NULL, 0.5 ); trace.beginBlock( "Deformation" ); double sumt = 0.0; diff --git a/deformations/testLocalDeformation3d.cpp b/deformations/testLocalDeformation3d.cpp index 32dbd7f..e5fd65e 100644 --- a/deformations/testLocalDeformation3d.cpp +++ b/deformations/testLocalDeformation3d.cpp @@ -196,7 +196,7 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, distanceImage, bel, functor, predicate, w ); + e(ks, labelImage, distanceImage, bel, functor, predicate, NULL, w ); trace.beginBlock( "Deformation" ); double deltat = 1.0; From 71deb1e8754717c10aa2b90de99ed7e9b8a0ecca Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 18 Apr 2012 20:25:30 +0200 Subject: [PATCH 052/108] nothing better + bug double free --- deformations/FMM.h | 3 +- deformations/FMMPointFunctors.h | 2 +- deformations/FMMPointFunctors.ih | 22 +-- deformations/FrontierEvolver.h | 7 - deformations/FrontierEvolver.ih | 277 +++++++------------------------ deformations/LocalMCM.h | 8 + deformations/PartitionEvolver.h | 6 +- deformations/PartitionEvolver.ih | 56 +++++-- deformations/deformation2d.cpp | 10 +- 9 files changed, 133 insertions(+), 258 deletions(-) diff --git a/deformations/FMM.h b/deformations/FMM.h index 581ad91..5c201ba 100644 --- a/deformations/FMM.h +++ b/deformations/FMM.h @@ -55,7 +55,8 @@ #include "DGtal/kernel/sets/SetPredicate.h" #include "DGtal/kernel/CPointPredicate.h" #include "DGtal/kernel/CPointFunctor.h" -#include "DGtal/geometry/volumes/distance/FMMPointFunctors.h" + +#include "FMMPointFunctors.h" ////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/FMMPointFunctors.h b/deformations/FMMPointFunctors.h index ae2c0f1..2029052 100644 --- a/deformations/FMMPointFunctors.h +++ b/deformations/FMMPointFunctors.h @@ -798,7 +798,7 @@ namespace DGtal /////////////////////////////////////////////////////////////////////////////// // Includes inline functions. -#include "DGtal/geometry/volumes/distance/FMMPointFunctors.ih" +#include "FMMPointFunctors.ih" // // /////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/FMMPointFunctors.ih b/deformations/FMMPointFunctors.ih index b9371dc..b488f00 100644 --- a/deformations/FMMPointFunctors.ih +++ b/deformations/FMMPointFunctors.ih @@ -150,7 +150,7 @@ DGtal::L2FirstOrderLocalDistance::compute if ( nb == 1 ) { Value d = aValueList.back(); - if (d >= 0) return d + 1.0; + if (d > 0) return d + 1.0; else return d - 1.0; } else @@ -183,12 +183,10 @@ DGtal::L2FirstOrderLocalDistance::compute double disc = b*b - 4*a*c; ASSERT(disc >= 0); - double dres1 = ( ( -b + std::sqrt(disc) ) / (2*a) ); - double dres2 = ( ( -b - std::sqrt(disc) ) / (2*a) ); - if ( std::abs(dres1) > std::abs(dres2) ) - return static_cast(dres1); + if ( b < 0 ) + return static_cast( ( -b + std::sqrt(disc) ) / (2*a) ); else - return static_cast(dres2); + return static_cast( ( -b - std::sqrt(disc) ) / (2*a) ); } } @@ -205,7 +203,7 @@ DGtal::L2FirstOrderLocalDistance for (typename Values::const_iterator it = aValueList.begin(); it != aValueList.end(); ++it) { - Value d = std::abs(aValue - *it); + Value d = (aValue - *it); sum += (d*d); } return sum; @@ -377,7 +375,7 @@ DGtal::L2SecondOrderLocalDistance::compute if ( nb == 1 ) { CoeffValue pair = aList.back(); - if (pair.second >= 0) + if (pair.second > 0) return ( (pair.second + 1.0)/(pair.first) ); else return ( (pair.second - 1.0)/(pair.first) ); @@ -414,12 +412,10 @@ DGtal::L2SecondOrderLocalDistance::compute double disc = b*b - 4*a*c; ASSERT(disc >= 0); - double dres1 = ( ( -b + std::sqrt(disc) ) / (2*a) ); - double dres2 = ( ( -b - std::sqrt(disc) ) / (2*a) ); - if ( std::abs(dres1) > std::abs(dres2) ) - return static_cast(dres1); + if ( b < 0 ) + return static_cast( ( -b + std::sqrt(disc) ) / (2*a) ); else - return static_cast(dres2); + return static_cast( ( -b - std::sqrt(disc) ) / (2*a) ); } } } diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 1c2a6ab..88606b3 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -247,13 +247,6 @@ struct SetFromImageSelector */ ~FrontierEvolver(); - // /** - // * Deform the image of labels around the digital frontier - // * - // * @return time spent during the deformation. - // */ - // double update(); - /** * Deform the image of labels during @a aT * diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 2f2c0e5..f2ba189 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -57,15 +57,19 @@ DGtal::FrontierEvolver( true ), mySurfel ) ) { + ASSERT( myFrontier ); + ASSERT( myW > 0 ); ASSERT( myW <= 1.0 ); - ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + #ifdef WITHINFO trace.info() << "Labels: " << myInnerLabel << " (inner region)" << " and " << myOuterLabel << " (outer region) " << std::endl; #endif ASSERT( myInnerLabel != myOuterLabel ); + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); } template ::~FrontierEvolver() { + #ifdef WITHINFO + trace.info() << "FrontierEvolver " << this << std::endl; + #endif delete( myFrontier ); } -// template -// inline -// double -// DGtal::FrontierEvolver -// ::update() -// { -// #ifdef WITHINFO -// trace.info() << std::endl; -// trace.info() << "starting surfel: " << mySurfel << std::endl; -// trace.info() << "between: " << myInnerLabel << " (inner region)" -// << " and " << myOuterLabel << " (outer region) " -// << std::endl; -// #endif - -// /// set of points that are candidate to the flip -// typedef std::vector Band; -// typedef typename Band::const_iterator BandIterator; -// Band narrowBand; -// init ( std::back_inserter( narrowBand ) ); -// #ifdef WITHINFO -// trace.info() << narrowBand.size() << " closest points" << std::endl; -// #endif - -// /// velocity and zero-crossing time computation -// typedef std::pair PointTime; -// typedef std::vector CandidateVector; -// typedef typename CandidateVector::const_iterator CandidateIterator; -// CandidateVector candidates; - -// typedef std::pair DistanceVelocity; -// typedef std::vector DistanceVelocityVector; -// typedef typename DistanceVelocityVector::const_iterator DistanceVelocityIterator; -// DistanceVelocityVector buffer; - -// double vmax = 0; -// for ( BandIterator -// it = narrowBand.begin(), -// itEnd = narrowBand.end(); -// it != itEnd; ++it) -// { -// // distance -// Distance d = myDImage( *it ); -// // velocity -// Velocity v = myFunctor( *it ); -// // maximal velocity -// double vabs = std::abs( static_cast( v ) ); -// if (vabs > vmax) vmax = vabs; -// // storing distance and velocity -// buffer.push_back( DistanceVelocity( d, v ) ); -// // new candidate with its zero-crossing time -// if ( ( (d>=0) && (v<0) ) -// || ( (d<=0) && (v>0) ) ) -// { //if opposite signs (and v != 0) -// double t = - static_cast( d ) / v; -// ASSERT( t >= 0 ); -// candidates.push_back( PointTime( *it, t ) ); -// } - -// } -// #ifdef WITHINFO -// trace.info() << candidates.size() << " candidates " << std::endl; -// #endif - -// /// time threshold computation -// double tmax = myW / vmax; - -// #ifdef WITHINFO -// trace.info() << "Distance max: " << myW << " / " -// << "Velocity max: " << vmax << " = " -// << "Time threshold: " << tmax << std::endl; -// #endif - -// if (candidates.begin() != candidates.end()) -// { //if they are candidates - -// /// ordering of the points according -// /// to their zero-crossing time -// #ifdef WITHINFO -// trace.info() << "ordering..." << std::endl; -// #endif - -// details::CompareSecondElement timeCompare; -// std::sort( candidates.begin(), candidates.end(), timeCompare ); - -// #ifdef WITHINFO -// trace.info() << "Times ranging from " -// << candidates.begin()->second -// << " to " -// << candidates.rbegin()->second -// << std::endl; -// #endif - -// /// flip points one by one, in order, -// /// while possible -// std::set notSimplePoints; //points not flipped because not simple - -// unsigned int nbFlips = 0; -// Point p = Point::diagonal(0), plast = Point::diagonal(0); -// double t = 0.0, tlast = 0.0; -// bool go = true; -// for (CandidateIterator -// it = candidates.begin(), -// itEnd = candidates.end(); -// ( (it != itEnd)&&(go) ); ++it) -// { -// plast = p; -// p = it->first; -// tlast = t; -// t = it->second; -// if (t <= tmax) -// { -// const Label label = myLImage(p); -// const Label oppositeLabel = -// (label == myInnerLabel)?myOuterLabel:myInnerLabel; -// if ( myPointPred( p, oppositeLabel ) ) -// { /// flip -// nbFlips++; -// myLImage.setValue( p, oppositeLabel ); -// } -// else -// { -// notSimplePoints.insert( p ); -// #ifdef WITHINFO -// trace.emphase() << p << " is not a simple point!" << std::endl; -// #endif -// } -// } -// else -// go = false; -// } - -// #ifdef WITHINFO -// trace.info() << nbFlips << " flipped points in " << tlast << " unit time" << std::endl; -// #endif - -// /// update distance map -// #ifdef WITHINFO -// trace.info() << "updating signed distance function..." << std::endl; -// #endif - -// if (tlast == 0.0) -// tlast = tmax; - -// DistanceVelocityIterator itBuffer = buffer.begin(); -// for (BandIterator -// it = narrowBand.begin(), -// itEnd = narrowBand.end(); -// it != itEnd; ++it, ++itBuffer) -// { -// // velocity -// DistanceVelocity pair( *itBuffer ); -// Distance newDist = pair.first + tlast*pair.second; - -// //label -// const Label pLabel = myLImage( *it ); - -// const Distance eps = std::numeric_limits::epsilon(); -// // correction due to the approximation error -// if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) -// //correction due to the non simplicity -// || ( notSimplePoints.find( *it ) != notSimplePoints.end() ) ) -// { -// if (pLabel == myInnerLabel) newDist = -eps; -// else newDist = eps; -// } - -// // set value -// myDImage.setValue( *it, newDist ); - -// ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) -// || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) ); -// } - -// /// update frontier if needed -// if (nbFlips > 0) -// updateFrontier( plast ); - -// return tlast; -// } -// else -// return 0.0; -// } - template inline @@ -319,7 +142,7 @@ DGtal::FrontierEvolver=0) && (v<0) ) + if ( ( (d>0) && (v<0) ) || ( (d<=0) && (v>0) ) ) { //if opposite signs (and v != 0) double t = - static_cast( d ) / v; @@ -384,6 +207,10 @@ DGtal::FrontierEvolver 0)&&(myLImage( *it ) == myOuterLabel) ) + || ( (myLImage( *it ) != myInnerLabel)&&(myLImage( *it ) != myOuterLabel) ) ) ) + { + trace.info() << *it << " in " << myLImage( *it ) + << " at " << newDist << std::endl; + } + #endif ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) || ( (myLImage( *it ) != myInnerLabel)&&(myLImage( *it ) != myOuterLabel) ) ); + + // set value + myDImage.setValue( *it, newDist ); + } /// update frontier if needed @@ -464,14 +301,14 @@ DGtal::FrontierEvolver > LabelPredicate; - // typedef CascadingPointPredicate< typename Domain::Predicate, - // LabelPredicate > PointPredicate4FMM; - // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - // PointPredicate4FMM pred( myLImage.domain().predicate(), predOnLabels ); - // typedef FMM FMM; - typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); - typedef FMM FMM; + typedef TwoLabelsPredicate > LabelPredicate; + typedef CascadingPointPredicate< typename Domain::Predicate, + LabelPredicate > PointPredicate4FMM; + LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); + typedef FMM FMM; + // typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); + // typedef FMM FMM; /// initialization of the band from the /// points adjacent to the frontier @@ -499,28 +336,19 @@ DGtal::FrontierEvolver 0 ); - - std::pair rin - = adjacentPoints.insert( PointDistance( in, din ) ); - - std::pair rout - = adjacentPoints.insert( PointDistance( out, dout ) ); - } - else - { - ASSERT(false && "impossible"); - } + ASSERT( myLImage(in) == myInnerLabel ); + Distance din = myDImage( in ); + ASSERT( din <= 0 ); + + ASSERT( myLImage(out) == myOuterLabel ); + Distance dout = myDImage( out ); + ASSERT( dout > 0 ); + + std::pair rin + = adjacentPoints.insert( PointDistance( in, din ) ); + + std::pair rout + = adjacentPoints.insert( PointDistance( out, dout ) ); } myPointSet.clear(); @@ -558,6 +386,15 @@ DGtal::FrontierEvolver-0.0001)) + || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ) ) + { + trace.info() << p << " in " << myLImage(p) << " at " << d << std::endl; + } + #endif + ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); @@ -612,7 +449,7 @@ DGtal::FrontierEvolver( true ), mySurfel ); - + ASSERT( myFrontier ); } template DistanceImagePtr; + typedef CountedPtr DistanceImagePtr; /// Extern image typedef TExternImage ExternImage; @@ -135,7 +135,7 @@ namespace DGtal /// Frontier evolver typedef FrontierEvolver Evolver; - typedef CountedPtr FrontierEvolverPtr; + typedef CountedPtr EvolverPtr; // ----------------------- Standard services ------------------------------ @@ -229,7 +229,7 @@ namespace DGtal /** * Set of smart owning pointers on frontier evolvers */ - std::vector myEvolvers; + std::vector myEvolvers; // ------------------------- Hidden services ------------------------------ protected: diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index 1befa6d..1811f86 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -50,6 +50,15 @@ DGtal::PartitionEvolver bels; @@ -86,21 +95,21 @@ DGtal::PartitionEvolver ::~PartitionEvolver() { + /// images + for (typename std::vector::const_iterator + it = myImages.begin(), + itEnd = myImages.end(); it != itEnd; ++it) + { + trace.info() << "distance image " << it->get() << std::endl; + } + + /// functors + for (typename std::vector::const_iterator + it = myFunctors.begin(), + itEnd = myFunctors.end(); it != itEnd; ++it) + { + trace.info() << "moving functor " << it->get() << std::endl; + } + /// frontiers + for (typename std::vector::const_iterator + it = myEvolvers.begin(), + itEnd = myEvolvers.end(); it != itEnd; ++it) + { + trace.info() << "frontier evolver " << it->get() << std::endl; + } + } @@ -123,7 +155,7 @@ DGtal::PartitionEvolver::const_iterator + for (typename std::vector::const_iterator it = myEvolvers.begin(), itEnd = myEvolvers.end(); it != itEnd; ++it) { @@ -142,7 +174,7 @@ DGtal::PartitionEvolver::const_iterator + for (typename std::vector::const_iterator it = myEvolvers.begin(), itEnd = myEvolvers.end(); it != itEnd; ++it) { /// for each frontier (except aPtrToCaller) diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 6810661..383e5ca 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -13,6 +13,10 @@ namespace po = boost::program_options; #include #include "DGtal/io/readers/PNMReader.h" + + +#include "ImageContainer.h" + using namespace Z2i; //evolvers @@ -30,6 +34,8 @@ using namespace Z2i; #include "SimplePointHelper.h" #include "PartitionEvolver.h" + + /////////////////////////// useful functions #include "deformationFunctions.h" #include "deformationDisplay2d.h" @@ -289,7 +295,7 @@ int main(int argc, char** argv) ks.init( d.lowerBound(), d.upperBound(), true ); //distance image... - typedef ImageContainerBySTLVector DistanceImage; + typedef ImageContainer DistanceImage; //and extern data... DistanceImage g( d ); std::fill(g.begin(), g.end(), 1.0); @@ -333,6 +339,8 @@ int main(int argc, char** argv) } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + + DGtal::trace.info() << "end" << std::endl; //free delete( labelImage ); From bb24374d1a260847c1614a933fd648601498cb57 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 10:41:50 +0200 Subject: [PATCH 053/108] cleaning (bug may come from DGtal - SurfelNeigborhood - to correct later) --- deformations/FrontierEvolver.h | 2 +- deformations/FrontierEvolver.ih | 5 +---- deformations/LocalMCM.h | 1 - deformations/PartitionEvolver.ih | 30 +++--------------------------- deformations/deformation2d.cpp | 6 +----- 5 files changed, 6 insertions(+), 38 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 88606b3..461f603 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -238,7 +238,7 @@ struct SetFromImageSelector * @param aP any point predicate * @param aW maximal width of the deformation band (1.0 by default) */ - FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, + FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, const Functor& aF, const Predicate& aP, Partition* aPartitionPtr = NULL, const double& aW = 1.0); diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index f2ba189..de06d4a 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -43,7 +43,7 @@ template inline DGtal::FrontierEvolver -::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, Surfel& aS, +::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, const Functor& aF, const Predicate& aP, Partition* aPartitionPtr, const double& aW) : myKSpace( aK ), myLImage( aI ), myDImage( aD ), @@ -78,9 +78,6 @@ inline DGtal::FrontierEvolver ::~FrontierEvolver() { - #ifdef WITHINFO - trace.info() << "FrontierEvolver " << this << std::endl; - #endif delete( myFrontier ); } diff --git a/deformations/LocalMCM.h b/deformations/LocalMCM.h index ec187f2..c3b94a4 100644 --- a/deformations/LocalMCM.h +++ b/deformations/LocalMCM.h @@ -91,7 +91,6 @@ namespace DGtal */ ~LocalMCM() { - trace.info() << "LocalMCM" << this << std::endl; } /** diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index 1811f86..26c5f7b 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -58,7 +58,7 @@ DGtal::PartitionEvolver bels; @@ -70,7 +70,7 @@ DGtal::PartitionEvolver func( myKSpace ); typename SCellToIncidentPoints::Output points = func( sbel ); @@ -117,31 +117,7 @@ template ::~PartitionEvolver() -{ - /// images - for (typename std::vector::const_iterator - it = myImages.begin(), - itEnd = myImages.end(); it != itEnd; ++it) - { - trace.info() << "distance image " << it->get() << std::endl; - } - - /// functors - for (typename std::vector::const_iterator - it = myFunctors.begin(), - itEnd = myFunctors.end(); it != itEnd; ++it) - { - trace.info() << "moving functor " << it->get() << std::endl; - } - - /// frontiers - for (typename std::vector::const_iterator - it = myEvolvers.begin(), - itEnd = myEvolvers.end(); it != itEnd; ++it) - { - trace.info() << "frontier evolver " << it->get() << std::endl; - } - +{ } diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 383e5ca..7db96c7 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -13,10 +13,6 @@ namespace po = boost::program_options; #include #include "DGtal/io/readers/PNMReader.h" - - -#include "ImageContainer.h" - using namespace Z2i; //evolvers @@ -295,7 +291,7 @@ int main(int argc, char** argv) ks.init( d.lowerBound(), d.upperBound(), true ); //distance image... - typedef ImageContainer DistanceImage; + typedef ImageContainerBySTLVector DistanceImage; //and extern data... DistanceImage g( d ); std::fill(g.begin(), g.end(), 1.0); From 6799754ce2d56eddd9054e05d54931a49196da36 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 10:47:10 +0200 Subject: [PATCH 054/108] FMM in domain instead of bounded within two adjacent regions --- deformations/FrontierEvolver.ih | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index de06d4a..bd80fdd 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -298,14 +298,14 @@ DGtal::FrontierEvolver > LabelPredicate; - typedef CascadingPointPredicate< typename Domain::Predicate, - LabelPredicate > PointPredicate4FMM; - LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); - typedef FMM FMM; - // typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); - // typedef FMM FMM; + // typedef TwoLabelsPredicate > LabelPredicate; + // typedef CascadingPointPredicate< typename Domain::Predicate, + // LabelPredicate > PointPredicate4FMM; + // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + // PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); + // typedef FMM FMM; + typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); + typedef FMM FMM; /// initialization of the band from the /// points adjacent to the frontier From 52cc594c315e6d1f40a71d64ea9a3a11cd7a5c97 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 11:07:08 +0200 Subject: [PATCH 055/108] removing parameter 'maximal width' in FrontierEvolver --- deformations/FrontierEvolver.h | 8 +-- deformations/FrontierEvolver.ih | 8 +-- deformations/testLocalDeformation2d.cpp | 2 +- deformations/testLocalDeformation3d.cpp | 93 +++++++++++++++++-------- 4 files changed, 67 insertions(+), 44 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 461f603..3a087ae 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -236,11 +236,10 @@ struct SetFromImageSelector * @param aS a surfel lying between two regions of @a aI * @param aF a point functor mapping a velocity to points * @param aP any point predicate - * @param aW maximal width of the deformation band (1.0 by default) */ FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, const Functor& aF, const Predicate& aP, - Partition* aPartitionPtr = NULL, const double& aW = 1.0); + Partition* aPartitionPtr = NULL); /** * Destructor. Does nothing. @@ -324,11 +323,6 @@ struct SetFromImageSelector * TODO: rename it into myTopoPred */ const Predicate& myPointPred; - /** - * Maximal width of the band whithin which - * the frontier is moving - */ - double myW; /** * Label of the inner region */ diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index bd80fdd..b494daf 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -44,12 +44,11 @@ template ::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, - const Functor& aF, const Predicate& aP, Partition* aPartitionPtr, - const double& aW) + const Functor& aF, const Predicate& aP, Partition* aPartitionPtr ) : myKSpace( aK ), myLImage( aI ), myDImage( aD ), myPointSet( SetFromImageSelector::get( myDImage ) ), mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), - myPartitionPtr( aPartitionPtr), myW( aW ), + myPartitionPtr( aPartitionPtr), myInnerLabel( myLImage( getInnerPoint( mySurfel ) ) ), myOuterLabel( myLImage( getOuterPoint( mySurfel ) ) ), mySurfelPred( myKSpace, myLImage, myInnerLabel, myOuterLabel ), @@ -59,9 +58,6 @@ DGtal::FrontierEvolver 0 ); - ASSERT( myW <= 1.0 ); - #ifdef WITHINFO trace.info() << "Labels: " << myInnerLabel << " (inner region)" << " and " << myOuterLabel << " (outer region) " diff --git a/deformations/testLocalDeformation2d.cpp b/deformations/testLocalDeformation2d.cpp index ba081f0..a16fa93 100644 --- a/deformations/testLocalDeformation2d.cpp +++ b/deformations/testLocalDeformation2d.cpp @@ -216,7 +216,7 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, distanceImage, bel, functor, predicate, NULL, 0.5 ); + e(ks, labelImage, distanceImage, bel, functor, predicate, NULL); trace.beginBlock( "Deformation" ); double sumt = 0.0; diff --git a/deformations/testLocalDeformation3d.cpp b/deformations/testLocalDeformation3d.cpp index e5fd65e..34675fd 100644 --- a/deformations/testLocalDeformation3d.cpp +++ b/deformations/testLocalDeformation3d.cpp @@ -50,10 +50,13 @@ int main(int argc, char** argv) po::options_description general_opt("Allowed options are"); general_opt.add_options() ("help,h", "display this message") - ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) - ("timeBound,t", po::value()->default_value(1.0), "Maximum time for the evolution" ) - ("displayStep,d", po::value()->default_value(1), "Number of iterations between 2 drawings" ) - ("bandWidth,w", po::value()->default_value(1.0), "Width of the flipping band" ) + ("inputImage,i", po::value(), "Binary image to initialize the starting interface (pgm format)" ) + ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) + ("shape,s", po::value()->default_value("disk"), +"Generated shape: either (default) or " ) + ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) + ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) + ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) ("outputFormat,f", po::value()->default_value("png"), @@ -74,17 +77,23 @@ int main(int argc, char** argv) } //Parse options + //domain size + int dsize; + if (!(vm.count("domainSize"))) trace.info() << "Domain size default value: 64" << std::endl; + dsize = vm["domainSize"].as(); //time step - double tmax; - if (!(vm.count("timeBound"))) trace.info() << "stopping time default value: 1.0" << std::endl; - tmax = vm["timeBound"].as(); + double tstep; + if (!(vm.count("timeStep"))) trace.info() << "time step default value: 1.0" << std::endl; + tstep = vm["timeStep"].as(); //iterations int step; - if (!(vm.count("displayStep"))) - trace.info() << "number of iterations between two drawings: 1 by default" << std::endl; + if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; step = vm["displayStep"].as(); + int max; + if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; + max = vm["stepsNumber"].as(); //files std::string outputFiles; @@ -107,15 +116,48 @@ int main(int argc, char** argv) //image of labels typedef short int Label; typedef ImageContainerBySTLVector LabelImage; + + + typedef ImageContainerBySTLVector Image; + Point p = Point::diagonal(0); + Point q = Point::diagonal(dsize); + Point c = Point::diagonal(dsize/2); + Domain dom(p,q); + Image img( dom ); + + //generated shape + if (vm.count("shape")) + { + if ( (vm["shape"].as()) == "flower" ) + initWithFlower( img, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + else + initWithBall( img, c, (dsize*3/5)/2 ); + } + else + initWithBall( img, c, (dsize*3/5)/2 ); + + LabelImage labelImage( dom ); + Domain::ConstIterator cIt = dom.begin(), cItEnd = dom.end(); + for ( ; cIt != cItEnd; ++cIt) + { //for each domain point + if (img(*cIt) <= 0) labelImage.setValue(*cIt, 0); + else labelImage.setValue(*cIt, 1); + } + + if (!(vm.count("inputImage"))) { - trace.info() << "you must use --inputImage option" << std::endl; - return 0; - } + trace.info() << "starting interface initialized with a ball shape" << std::endl; + } + else + { string imageFileName = vm["inputImage"].as(); trace.emphase() << imageFileName <::importVol( imageFileName); inv(labelImage); + } + + ///////////////////////////////////////// //3d to 2d display std::stringstream ss; @@ -127,16 +169,6 @@ int main(int argc, char** argv) if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; k = vm["balloonForce"].as(); - //width of the flipping band - double w = 1.0; - if (!(vm.count("bandWidth"))) trace.info() << "band width default value: 1" << std::endl; - w = vm["bandWidth"].as(); - if( (w < 0) || (w > 1) ) - { - trace.info() << "The band width should be between 0 and 1 " << std::endl; - return 0; - } - //space KSpace ks; Domain d( labelImage.domain() ); @@ -196,18 +228,17 @@ int main(int argc, char** argv) //frontier evolver FrontierEvolver - e(ks, labelImage, distanceImage, bel, functor, predicate, NULL, w ); + e(ks, labelImage, distanceImage, bel, functor, predicate, NULL); trace.beginBlock( "Deformation" ); - double deltat = 1.0; - double sumt = 0.0; - for (unsigned int i = 1; ( (sumt <= tmax)&&(deltat > 0.001) ); ++i) + double sumt = 0.0; + for (unsigned int i = 1; i <= max; ++i) { - trace.info() << "iteration # " << i << std::endl; + trace.info() << "# iteration # " << i << " " << std::endl; //update - deltat = e.update(w); - sumt += deltat; + e.update(tstep); + sumt += tstep; if ((i%step)==0) { @@ -217,7 +248,9 @@ int main(int argc, char** argv) writeImage( labelImage, s.str(), format ); } - trace.info() << "time spent: " << sumt << std::endl; + std::cout << "# time " << std::endl; + std::cout << sumt << std::endl; + } trace.endBlock(); From 03eb5d94bac3128a8581aeefb7fff85fbbf10049 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 11:40:11 +0200 Subject: [PATCH 056/108] private method for retreiving candidate to flip --- deformations/FrontierEvolver.h | 44 ++++++++--- deformations/FrontierEvolver.ih | 125 ++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 57 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 3a087ae..4fa7850 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -199,6 +199,15 @@ struct SetFromImageSelector typedef TDistanceImage DImage; typedef typename DImage::Value Distance; + /// Point functor for the mapping points-speed + typedef TFunctor Functor; + typedef typename Functor::Value Speed; + typedef std::pair DistanceSpeed; + typedef std::pair PointTime; + + /// Topological predicate + typedef TPredicate Predicate; + /// Set of points where the distance values are known typedef typename SetFromImageSelector::Set PointSet; @@ -213,13 +222,6 @@ struct SetFromImageSelector typedef typename Frontier::SurfelConstIterator SurfelIterator; - /// Point functor for the mapping points-velocity - typedef TFunctor Functor; - typedef typename Functor::Value Velocity; - /// Topological predicate - typedef TPredicate Predicate; - - /// Partition typedef PartitionEvolver - void init(const TOutputIterator& out); + void initNarrowBand(TOutputIterator res); + + /** + * Return through @a res the points + * that can be flipped into the + * adjacent region + * + * @param itb begin iterator on points + * @param ite end iterator on points + * @param aDistanceSpeedIto an output iterator on DistanceSpeed pairs + * @param aCandidateIto an output iterator on candidates + * + * @tparam TInputIterator a model of input iterator on points + * @tparam TOutputIterator1 a model of output iterator on DistanceSpeed pairs + * @tparam TOutputIterator2 a model of output iterator on candidates + * + */ + template + void initCandidates( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ); /** * Checks whether the other frontiers (if any) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index b494daf..8814bb8 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -98,52 +98,51 @@ DGtal::FrontierEvolver Band; - typedef typename Band::const_iterator BandIterator; Band narrowBand; - init ( std::back_inserter( narrowBand ) ); + initNarrowBand ( std::back_inserter( narrowBand ) ); #ifdef WITHINFO trace.info() << narrowBand.size() << " closest points" << std::endl; #endif - /// velocity and zero-crossing time computation - typedef std::pair PointTime; + /// speed and zero-crossing time computation + typedef std::vector DistanceSpeedVector; + DistanceSpeedVector buffer; + + /// candidates to flip typedef std::vector CandidateVector; - typedef typename CandidateVector::const_iterator CandidateIterator; CandidateVector candidates; - - typedef std::pair DistanceVelocity; - typedef std::vector DistanceVelocityVector; - typedef typename DistanceVelocityVector::const_iterator DistanceVelocityIterator; - DistanceVelocityVector buffer; - - for ( BandIterator - it = narrowBand.begin(), - itEnd = narrowBand.end(); - it != itEnd; ++it) - { - //point - Point p = *it; - // distance - Distance d = myDImage( p ); - // velocity - Velocity v = myFunctor( p ); - // storing distance and velocity - buffer.push_back( DistanceVelocity( d, v ) ); - // new candidate with its zero-crossing time - if ( ( myLImage( p ) == myInnerLabel ) - || (myLImage( p ) == myOuterLabel ) ) - { - if ( ( (d>0) && (v<0) ) - || ( (d<=0) && (v>0) ) ) - { //if opposite signs (and v != 0) - double t = - static_cast( d ) / v; - ASSERT( t >= 0 ); - candidates.push_back( PointTime( p, t ) ); - } - } - } + initCandidates( narrowBand.begin(), narrowBand.end(), + std::back_inserter( buffer ), + std::back_inserter( candidates ) ); + + // for ( BandIterator + // it = narrowBand.begin(), + // itEnd = narrowBand.end(); + // it != itEnd; ++it) + // { + // //point + // Point p = *it; + // // distance + // Distance d = myDImage( p ); + // // speed + // Speed v = myFunctor( p ); + // // storing distance and speed + // buffer.push_back( DistanceSpeed( d, v ) ); + // // new candidate with its zero-crossing time + // if ( ( myLImage( p ) == myInnerLabel ) + // || (myLImage( p ) == myOuterLabel ) ) + // { + // if ( ( (d>0) && (v<0) ) + // || ( (d<=0) && (v>0) ) ) + // { //if opposite signs (and v != 0) + // double t = - static_cast( d ) / v; + // ASSERT( t >= 0 ); + // candidates.push_back( PointTime( p, t ) ); + // } + // } + // } #ifdef WITHINFO trace.info() << candidates.size() << " candidates " << std::endl; #endif @@ -182,7 +181,7 @@ DGtal::FrontierEvolver -template +template inline void DGtal::FrontierEvolver -::init( const TOutputIterator& out ) +::initCandidates( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ) { + for ( TInputIterator it = itb; + it != ite; ++it) + { + // point + Point p = *it; + // distance + Distance d = myDImage( p ); + // speed + Speed v = myFunctor( p ); + // storing distance and speed + *aDistanceSpeedIto++ = DistanceSpeed( d, v ); + // new candidate with its zero-crossing time + if ( ( myLImage( p ) == myInnerLabel ) + || (myLImage( p ) == myOuterLabel ) ) + { + if ( ( (d>0) && (v<0) ) + || ( (d<=0) && (v>0) ) ) + { // if opposite signs (and v != 0) + double t = - static_cast( d ) / v; + ASSERT( t >= 0 ); + // storing candidate + *aCandidateIto++ = PointTime( p, t ); + } + } + } +} - TOutputIterator res = out; +template +template +inline +void +DGtal::FrontierEvolver +::initNarrowBand( TOutputIterator res ) +{ //predicate and FMM definitions // typedef TwoLabelsPredicate > LabelPredicate; From e539bc88daa7e79e425e1b9e1f0e1c34793854b3 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 12:23:48 +0200 Subject: [PATCH 057/108] private method for updating the distance function --- deformations/FrontierEvolver.h | 25 ++++++ deformations/FrontierEvolver.ih | 139 +++++++++++++------------------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 4fa7850..2da96a2 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -406,6 +406,7 @@ struct SetFromImageSelector void initCandidates( const TInputIterator& itb, const TInputIterator& ite, TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ); + /** * Checks whether the other frontiers (if any) * can be modified by the flip of @a aPoint @@ -413,6 +414,30 @@ struct SetFromImageSelector */ void checkPartition ( const Point& aPoint ); + /** + * Update @a myDImage at each point of the + * range [@a itb , @a ite ) knowing their + * distance and speed returning by @a aDistanceSpeedIt + * + * The points that belongs to @a aSet are not allowed to flip. + * + * @param itb begin iterator on points + * @param ite end iterator on points + * @param aDistanceSpeedIt an input iterator on DistanceSpeed pairs + * @param aSet any set of points + * @param t evolution time step + * + * @tparam TInputIterator1 a model of input iterator on points + * @tparam TInputIterator2 a model of input iterator on DistanceSpeed pairs + * @tparam TSet STL set like type + * + */ + template + void updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, + TInputIterator2 aDistanceSpeedIt, + const TSet& aSet, const double& t ); + + /** * Update the starting surfel @a mySurfel * of the digital frontier from point @a p diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 8814bb8..cd85e42 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -109,52 +109,18 @@ DGtal::FrontierEvolver DistanceSpeedVector; DistanceSpeedVector buffer; - /// candidates to flip typedef std::vector CandidateVector; CandidateVector candidates; initCandidates( narrowBand.begin(), narrowBand.end(), std::back_inserter( buffer ), std::back_inserter( candidates ) ); - - // for ( BandIterator - // it = narrowBand.begin(), - // itEnd = narrowBand.end(); - // it != itEnd; ++it) - // { - // //point - // Point p = *it; - // // distance - // Distance d = myDImage( p ); - // // speed - // Speed v = myFunctor( p ); - // // storing distance and speed - // buffer.push_back( DistanceSpeed( d, v ) ); - // // new candidate with its zero-crossing time - // if ( ( myLImage( p ) == myInnerLabel ) - // || (myLImage( p ) == myOuterLabel ) ) - // { - // if ( ( (d>0) && (v<0) ) - // || ( (d<=0) && (v>0) ) ) - // { //if opposite signs (and v != 0) - // double t = - static_cast( d ) / v; - // ASSERT( t >= 0 ); - // candidates.push_back( PointTime( p, t ) ); - // } - // } - // } #ifdef WITHINFO trace.info() << candidates.size() << " candidates " << std::endl; #endif - /// time threshold - double tmax = aT; - #ifdef WITHINFO - trace.info() << "Time threshold: " << tmax << std::endl; - #endif - if (candidates.begin() != candidates.end()) - { //if they are candidates + { //if there are candidates /// ordering of the points according /// to their zero-crossing time @@ -190,7 +156,7 @@ DGtal::FrontierEvolverfirst; tlast = t; t = it->second; - if (t <= tmax) + if (t <= aT) { const Label label = myLImage(p); const Label oppositeLabel = @@ -225,60 +191,71 @@ DGtal::FrontierEvolver 0) + updateFrontier( plast ); - typename DistanceSpeedVector::const_iterator itBuffer = buffer.begin(); - for (typename Band::const_iterator - it = narrowBand.begin(), - itEnd = narrowBand.end(); - it != itEnd; ++it, ++itBuffer) + return aT; + } + else + return 0.0; +} + +template + template +inline +void +DGtal::FrontierEvolver +::updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, + TInputIterator2 aDistanceSpeedIt, + const TSet& aSet, const double& t ) +{ + for (TInputIterator1 it = itb; + it != ite; ++it, ++aDistanceSpeedIt) + { + // point + const Point p = *it; + // distance and speed + const DistanceSpeed pair( *aDistanceSpeedIt ); + Distance newDist = pair.first + t * pair.second; + + //label + const Label pLabel = myLImage( p ); + + const Distance eps = std::numeric_limits::epsilon(); + // correction due to the approximation error + if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) + //correction due to the non simplicity + || ( aSet.find( p ) != aSet.end() ) ) { - // speed - DistanceSpeed pair( *itBuffer ); - Distance newDist = pair.first + tlast*pair.second; - - //label - const Label pLabel = myLImage( *it ); - - const Distance eps = std::numeric_limits::epsilon(); - //const Distance eps = 0.00001; - // correction due to the approximation error - if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) - //correction due to the non simplicity - || ( notSimplePoints.find( *it ) != notSimplePoints.end() ) ) - { - if (pLabel == myInnerLabel) newDist = -eps; - else newDist = eps; - } + if (pLabel == myInnerLabel) newDist = -eps; + else newDist = eps; + } - #ifdef WITHINFO - if ( !( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) - || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) - || ( (myLImage( *it ) != myInnerLabel)&&(myLImage( *it ) != myOuterLabel) ) ) ) - { - trace.info() << *it << " in " << myLImage( *it ) - << " at " << newDist << std::endl; - } - #endif - ASSERT( ( (newDist <= 0)&&(myLImage( *it ) == myInnerLabel) ) - || ( (newDist > 0)&&(myLImage( *it ) == myOuterLabel) ) - || ( (myLImage( *it ) != myInnerLabel)&&(myLImage( *it ) != myOuterLabel) ) ); + #ifdef WITHINFO + if ( !( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ) ) + { + trace.info() << p << " in " << myLImage( p ) + << " at " << newDist << std::endl; + } + #endif - // set value - myDImage.setValue( *it, newDist ); + ASSERT( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); - } - /// update frontier if needed - if (nbFlips > 0) - updateFrontier( plast ); + // set value + myDImage.setValue( p, newDist ); - return tmax; } - else - return 0.0; + } template Date: Thu, 19 Apr 2012 13:47:47 +0200 Subject: [PATCH 058/108] private method for updating the label image --- deformations/FrontierEvolver.h | 25 ++ deformations/FrontierEvolver.ih | 484 +++++++++++++++++--------------- 2 files changed, 277 insertions(+), 232 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 2da96a2..6e4f0d1 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -414,6 +414,31 @@ struct SetFromImageSelector */ void checkPartition ( const Point& aPoint ); + /** + * Update @a myLImage for each candidates of the + * range [@a itb , @a ite ) + * + * The points that are not allowed to flip + * (because of the topological predicate) + * are stored through @a ito into a container + * + * @param itb begin iterator on candidates + * @param ite end iterator on candidates + * @param ito output iterator on points + * @param aP (returned) last point + * @param aT (returned) zero-crossing time of the last point + * @param aTMax maximal accepted time (equal to the evolution time step) + * + * @tparam TInputIterator a model of input iterator on candidates + * @tparam TOutputIterator a model of input iterator on points + * + * @return number of flipped points + */ + template + int updateLabelImage( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator ito, + Point& aP, double &aT, const double& aTMax ); + /** * Update @a myDImage at each point of the * range [@a itb , @a ite ) knowing their diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index cd85e42..bd79259 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -77,6 +77,88 @@ DGtal::FrontierEvolver +inline +typename DGtal::FrontierEvolver::Surfel +DGtal::FrontierEvolver +::surfel() const +{ + return mySurfel; +} + +template +inline +void +DGtal::FrontierEvolver +::setSurfel(const Surfel& aSurfel) +{ + /// update surfel + mySurfel = aSurfel; + + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); + ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); + ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); + + /// update frontier + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); + ASSERT( myFrontier ); +} + +template +inline +typename DGtal::FrontierEvolver +::SurfelIterator +DGtal::FrontierEvolver +::begin() const +{ + return myFrontier->begin(); +} + +template +inline +typename DGtal::FrontierEvolver +::SurfelIterator +DGtal::FrontierEvolver +::end() const +{ + return myFrontier->end(); +} + +template +inline +bool +DGtal::FrontierEvolver +::isValid() const +{ + return ( ( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ) + && ( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ) ); +} + + +template +inline +void +DGtal::FrontierEvolver +::selfDisplay ( std::ostream & out ) const +{ + out << "[FrontierEvolver]\n"; + out << "\n"; +} + + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Main methods ------------------------------ + template @@ -139,64 +221,30 @@ DGtal::FrontierEvolver notSimplePoints; //points not flipped because not simple - - unsigned int nbFlips = 0; - Point p = Point::diagonal(0), plast = Point::diagonal(0); - double t = 0.0, tlast = 0.0; - bool go = true; - for (typename CandidateVector::const_iterator - it = candidates.begin(), - itEnd = candidates.end(); - ( (it != itEnd)&&(go) ); ++it) - { - plast = p; - p = it->first; - tlast = t; - t = it->second; - if (t <= aT) - { - const Label label = myLImage(p); - const Label oppositeLabel = - (label == myInnerLabel)?myOuterLabel:myInnerLabel; - if ( myPointPred( p, oppositeLabel ) ) - { /// flip - nbFlips++; - checkPartition( p ); - #ifdef WITHINFO - trace.emphase() << p << " flipped into region " - << oppositeLabel << std::endl; - #endif - myLImage.setValue( p, oppositeLabel ); - } - else - { - notSimplePoints.insert( p ); - #ifdef WITHINFO - trace.emphase() << p << " is not a simple point!" << std::endl; - #endif - } - } - else - go = false; - } - + /// flip points one by one, in order, while it is possible + //points not allowed to flip because not simple + std::set forbiddenPoints; + // last point and its zero-crossing time + Point lastP = Point::diagonal(0); + double lastT = 0.0; + int nbFlips = updateLabelImage( candidates.begin(), candidates.end(), + std::inserter( forbiddenPoints, forbiddenPoints.begin() ), + lastP, lastT, aT ); + ASSERT( lastT <= aT ); #ifdef WITHINFO - trace.info() << nbFlips << " flipped points in " << tlast << " unit time" << std::endl; + trace.info() << nbFlips << " flipped points in " << lastT << " unit time" << std::endl; #endif - /// update distance map + /// update distance map anyway #ifdef WITHINFO trace.info() << "updating signed distance function..." << std::endl; #endif updateDistanceImage( narrowBand.begin(), narrowBand.end(), - buffer.begin(), notSimplePoints, aT ); - + buffer.begin(), forbiddenPoints, aT ); + /// update frontier if needed if (nbFlips > 0) - updateFrontier( plast ); + updateFrontier( lastP ); return aT; } @@ -204,96 +252,6 @@ DGtal::FrontierEvolver - template -inline -void -DGtal::FrontierEvolver -::updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, - TInputIterator2 aDistanceSpeedIt, - const TSet& aSet, const double& t ) -{ - for (TInputIterator1 it = itb; - it != ite; ++it, ++aDistanceSpeedIt) - { - // point - const Point p = *it; - // distance and speed - const DistanceSpeed pair( *aDistanceSpeedIt ); - Distance newDist = pair.first + t * pair.second; - - //label - const Label pLabel = myLImage( p ); - - const Distance eps = std::numeric_limits::epsilon(); - // correction due to the approximation error - if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) - //correction due to the non simplicity - || ( aSet.find( p ) != aSet.end() ) ) - { - if (pLabel == myInnerLabel) newDist = -eps; - else newDist = eps; - } - - #ifdef WITHINFO - if ( !( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) - || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) - || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ) ) - { - trace.info() << p << " in " << myLImage( p ) - << " at " << newDist << std::endl; - } - #endif - - ASSERT( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) - || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) - || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); - - - // set value - myDImage.setValue( p, newDist ); - - } - -} - -template -template -inline -void -DGtal::FrontierEvolver -::initCandidates( const TInputIterator& itb, const TInputIterator& ite, - TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ) -{ - for ( TInputIterator it = itb; - it != ite; ++it) - { - // point - Point p = *it; - // distance - Distance d = myDImage( p ); - // speed - Speed v = myFunctor( p ); - // storing distance and speed - *aDistanceSpeedIto++ = DistanceSpeed( d, v ); - // new candidate with its zero-crossing time - if ( ( myLImage( p ) == myInnerLabel ) - || (myLImage( p ) == myOuterLabel ) ) - { - if ( ( (d>0) && (v<0) ) - || ( (d<=0) && (v>0) ) ) - { // if opposite signs (and v != 0) - double t = - static_cast( d ) / v; - ASSERT( t >= 0 ); - // storing candidate - *aCandidateIto++ = PointTime( p, t ); - } - } - } -} - template template @@ -422,118 +380,85 @@ DGtal::FrontierEvolver -inline -typename DGtal::FrontierEvolver::Surfel -DGtal::FrontierEvolver -::surfel() const -{ - return mySurfel; -} template +template inline void DGtal::FrontierEvolver -::setSurfel(const Surfel& aSurfel) -{ - /// update surfel - mySurfel = aSurfel; - - ASSERT( myKSpace.sIsSurfel( mySurfel ) ); - ASSERT( mySurfelPred( mySurfel ) ); - ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); - ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); - - /// update frontier - delete ( myFrontier ); - myFrontier = new Frontier ( myKSpace, mySurfelPred, - SurfelAdjacency( true ), - mySurfel ); - ASSERT( myFrontier ); -} - -template -inline -typename DGtal::FrontierEvolver -::SurfelIterator -DGtal::FrontierEvolver -::begin() const -{ - return myFrontier->begin(); -} - -template -inline -typename DGtal::FrontierEvolver -::SurfelIterator -DGtal::FrontierEvolver -::end() const -{ - return myFrontier->end(); -} - -template -inline -bool -DGtal::FrontierEvolver -::isValid() const -{ - return ( ( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ) - && ( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ) ); -} - - -template -inline -void -DGtal::FrontierEvolver -::selfDisplay ( std::ostream & out ) const +::initCandidates( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ) { - out << "[FrontierEvolver]\n"; - out << "\n"; + for ( TInputIterator it = itb; + it != ite; ++it) + { + // point + Point p = *it; + // distance + Distance d = myDImage( p ); + // speed + Speed v = myFunctor( p ); + // storing distance and speed + *aDistanceSpeedIto++ = DistanceSpeed( d, v ); + // new candidate with its zero-crossing time + if ( ( myLImage( p ) == myInnerLabel ) + || (myLImage( p ) == myOuterLabel ) ) + { + if ( ( (d>0) && (v<0) ) + || ( (d<=0) && (v>0) ) ) + { // if opposite signs (and v != 0) + double t = - static_cast( d ) / v; + ASSERT( t >= 0 ); + // storing candidate + *aCandidateIto++ = PointTime( p, t ); + } + } + } } template +template inline -typename DGtal::FrontierEvolver::Point +int DGtal::FrontierEvolver -::getInnerPoint(const Surfel& s) const +::updateLabelImage( const TInputIterator& itb, const TInputIterator& ite, TOutputIterator ito, + Point& aP, double& aT, const double& aTMax ) { - return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); -} -template -inline -typename DGtal::FrontierEvolver::Point -DGtal::FrontierEvolver -::getOuterPoint(const Surfel& s) const -{ - return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); -} + unsigned int nbFlips = 0; -template -inline -void -DGtal::FrontierEvolver -::checkPartition(const Point& aPoint) -{ - if (myPartitionPtr != NULL) + for (TInputIterator it = itb; + ( (it != ite)&&(it->second <= aTMax) ); ++it) { - myPartitionPtr->checkFrontiers( this, aPoint ); + aP = it->first; + aT = it->second; + const Label label = myLImage( aP ); + const Label oppositeLabel = + (label == myInnerLabel)?myOuterLabel:myInnerLabel; + + if ( myPointPred( aP, oppositeLabel ) ) + { /// flip + checkPartition( aP ); + #ifdef WITHINFO + trace.emphase() << aP << " flipped into region " + << oppositeLabel << std::endl; + #endif + myLImage.setValue( aP, oppositeLabel ); + ++nbFlips; + } + else + { + *ito++ = aP; + #ifdef WITHINFO + trace.emphase() << aP << " is not a simple point!" << std::endl; + #endif + } } + + return nbFlips; } template +template +inline +void +DGtal::FrontierEvolver +::updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, + TInputIterator2 aDistanceSpeedIt, + const TSet& aSet, const double& t ) +{ + for (TInputIterator1 it = itb; + it != ite; ++it, ++aDistanceSpeedIt) + { + // point + const Point p = *it; + // distance and speed + const DistanceSpeed pair( *aDistanceSpeedIt ); + Distance newDist = pair.first + t * pair.second; + + //label + const Label pLabel = myLImage( p ); + + const Distance eps = std::numeric_limits::epsilon(); + // correction due to the approximation error + if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) + //correction due to the non simplicity + || ( aSet.find( p ) != aSet.end() ) ) + { + if (pLabel == myInnerLabel) newDist = -eps; + else newDist = eps; + } + + #ifdef WITHINFO + if ( !( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ) ) + { + trace.info() << p << " in " << myLImage( p ) + << " at " << newDist << std::endl; + } + #endif + + ASSERT( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); + + + // set value + myDImage.setValue( p, newDist ); + + } + +} + + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Small Helpers ------------------------------ +template +inline +void +DGtal::FrontierEvolver +::checkPartition(const Point& aPoint) +{ + if (myPartitionPtr != NULL) + { + myPartitionPtr->checkFrontiers( this, aPoint ); + } +} + + +template +inline +typename DGtal::FrontierEvolver::Point +DGtal::FrontierEvolver +::getInnerPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} + +template +inline +typename DGtal::FrontierEvolver::Point +DGtal::FrontierEvolver +::getOuterPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} + + /////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions // From 7374d1d6c20d44146c6dea03f58dbc1f6bec9419 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 14:46:13 +0200 Subject: [PATCH 059/108] cleaning topological predicate in FrontierEvolver --- deformations/FrontierEvolver.h | 45 ++++++++-------- deformations/FrontierEvolver.ih | 94 +++++++++++++++------------------ 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index 6e4f0d1..af30226 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -76,6 +76,7 @@ namespace DGtal { + //------------------------------------------------------------------------------ template struct SetFromImageDomainValueTraits @@ -142,26 +143,27 @@ struct SetFromImageSelector * Description of template class 'FrontierEvolver'

* \brief Aim: This class is a way of deforming an image of labels * around a connected contact surface between two regions, - * according to a velocity field, whose computation is + * according to a speed field, whose computation is * delegated to a point functor. * - * At each step, a signed distance function is built. - * The points are sorted according to their time of zero-crossing - * (ie. their distance to the interface divided by their velocity) - * so that they are flipped from a region to another, one by one and - * in order, until a time greater than a threshold is reached or - * until a point predicate (possibly based on topological properties) - * returns false. + * At each step, a implicit function is extended from the known + * values at the boundary points adjacent to the contact surface. + * The points lying around the interface are sorted according to + * their time of zero-crossing (ie. their distance to the interface + * divided by their speed) so that they are flipped from one region + * to another, one by one and in order, until a time greater than + * a given threshold is reached, but only if a given predicate + * based on topological properties returns true. * * @tparam TKSpace a model of CCellularGridSpaceND * @tparam TLabelImage a model of CImage (storing labels) * @tparam TDistanceImage a model of CImage (storing distance values) * @tparam TFunctor a model of CPointFunctor - * @tparam TPredicate a model of CPointPredicate + * @tparam TTopoPredicate a model of topological predicate */ template + typename TFunctor, typename TTopoPredicate> class FrontierEvolver { @@ -180,11 +182,11 @@ struct SetFromImageSelector (( ConceptUtils::SameType< typename TKSpace::Point, typename TFunctor::Point>::value )); - // BOOST_CONCEPT_ASSERT(( CPointPredicate )); + // BOOST_CONCEPT_ASSERT(( CPointPredicate )); // BOOST_STATIC_ASSERT // (( ConceptUtils::SameType< typename TKSpace::Point, - // typename TPredicate::Point>::value )); - //TODO testing TPredicate as a binary predicate on points and labels + // typename TTopoPredicate::Point>::value )); + //TODO testing TTopoPredicate as a binary predicate on points and labels // ----------------------- Types ------------------------------ public: @@ -206,7 +208,7 @@ struct SetFromImageSelector typedef std::pair PointTime; /// Topological predicate - typedef TPredicate Predicate; + typedef TTopoPredicate TopoPredicate; /// Set of points where the distance values are known typedef typename SetFromImageSelector::Set PointSet; @@ -225,7 +227,7 @@ struct SetFromImageSelector /// Partition typedef PartitionEvolver Partition; + TopoPredicate> Partition; // ----------------------- Standard services ------------------------------ public: @@ -237,10 +239,10 @@ struct SetFromImageSelector * @param aD an image of distance values * @param aS a surfel lying between two regions of @a aI * @param aF a point functor mapping a speed to points - * @param aP any point predicate + * @param aP any topological predicate */ FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, - const Functor& aF, const Predicate& aP, + const Functor& aF, const TopoPredicate& aP, Partition* aPartitionPtr = NULL); /** @@ -321,10 +323,9 @@ struct SetFromImageSelector */ const Functor& myFunctor; /** - * Constant reference on the predicate - * TODO: rename it into myTopoPred + * Constant reference on the topological predicate */ - const Predicate& myPointPred; + const TopoPredicate& myTopoPred; /** * Label of the inner region */ @@ -495,11 +496,11 @@ struct SetFromImageSelector * @return the output stream after the writing. */ template + typename TFunctor, typename TTopoPredicate> std::ostream& operator<< ( std::ostream & out, const FrontierEvolver & object ); + TFunctor, TTopoPredicate> & object ); } // namespace DGtal diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index bd79259..6b5660d 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -40,14 +40,14 @@ template + typename TFunctor, typename TTopoPredicate> inline -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::FrontierEvolver(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, - const Functor& aF, const Predicate& aP, Partition* aPartitionPtr ) + const Functor& aF, const TopoPredicate& aP, Partition* aPartitionPtr ) : myKSpace( aK ), myLImage( aI ), myDImage( aD ), myPointSet( SetFromImageSelector::get( myDImage ) ), - mySurfel( aS ), myFunctor( aF ), myPointPred( aP ), + mySurfel( aS ), myFunctor( aF ), myTopoPred( aP ), myPartitionPtr( aPartitionPtr), myInnerLabel( myLImage( getInnerPoint( mySurfel ) ) ), myOuterLabel( myLImage( getOuterPoint( mySurfel ) ) ), @@ -69,29 +69,29 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::~FrontierEvolver() { delete( myFrontier ); } template + typename TFunctor, typename TTopoPredicate> inline -typename DGtal::FrontierEvolver::Surfel -DGtal::FrontierEvolver +typename DGtal::FrontierEvolver::Surfel +DGtal::FrontierEvolver ::surfel() const { return mySurfel; } template + typename TFunctor, typename TTopoPredicate> inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::setSurfel(const Surfel& aSurfel) { /// update surfel @@ -111,32 +111,32 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline -typename DGtal::FrontierEvolver +typename DGtal::FrontierEvolver ::SurfelIterator -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::begin() const { return myFrontier->begin(); } template + typename TFunctor, typename TTopoPredicate> inline -typename DGtal::FrontierEvolver +typename DGtal::FrontierEvolver ::SurfelIterator -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::end() const { return myFrontier->end(); } template + typename TFunctor, typename TTopoPredicate> inline bool -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::isValid() const { return ( ( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ) @@ -145,10 +145,10 @@ DGtal::FrontierEvolver +typename TFunctor, typename TTopoPredicate> inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::selfDisplay ( std::ostream & out ) const { out << "[FrontierEvolver]\n"; @@ -161,10 +161,10 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline double -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::update(const double& aT) { ASSERT( myKSpace.sIsSurfel( mySurfel ) ); @@ -253,21 +253,15 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> template inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::initNarrowBand( TOutputIterator res ) { //predicate and FMM definitions - // typedef TwoLabelsPredicate > LabelPredicate; - // typedef CascadingPointPredicate< typename Domain::Predicate, - // LabelPredicate > PointPredicate4FMM; - // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - // PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); - // typedef FMM FMM; typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); typedef FMM FMM; @@ -382,11 +376,11 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> template inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::initCandidates( const TInputIterator& itb, const TInputIterator& ite, TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ) { @@ -419,11 +413,11 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> template inline int -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::updateLabelImage( const TInputIterator& itb, const TInputIterator& ite, TOutputIterator ito, Point& aP, double& aT, const double& aTMax ) { @@ -439,7 +433,7 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::updateFrontier(const Point& p) { /// spel creation @@ -520,11 +514,11 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> template inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, TInputIterator2 aDistanceSpeedIt, const TSet& aSet, const double& t ) @@ -577,10 +571,10 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline void -DGtal::FrontierEvolver +DGtal::FrontierEvolver ::checkPartition(const Point& aPoint) { if (myPartitionPtr != NULL) @@ -591,22 +585,22 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline typename DGtal::FrontierEvolver::Point -DGtal::FrontierEvolver + TFunctor, TTopoPredicate>::Point +DGtal::FrontierEvolver ::getInnerPoint(const Surfel& s) const { return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); } template + typename TFunctor, typename TTopoPredicate> inline typename DGtal::FrontierEvolver::Point -DGtal::FrontierEvolver + TFunctor, TTopoPredicate>::Point +DGtal::FrontierEvolver ::getOuterPoint(const Surfel& s) const { return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); @@ -617,12 +611,12 @@ DGtal::FrontierEvolver + typename TFunctor, typename TTopoPredicate> inline std::ostream& DGtal::operator<< ( std::ostream & out, const FrontierEvolver & object ) + TFunctor, TTopoPredicate> & object ) { object.selfDisplay( out ); return out; From e8aebb5216bfa24e5136d2893010302f6ae77ca6 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 17:52:37 +0200 Subject: [PATCH 060/108] extension speed --- deformations/CMakeLists.txt | 8 +- deformations/FMMPointFunctors.ih | 2 +- deformations/FrontierEvolver.h | 62 +-- deformations/FrontierEvolver2.h | 463 ++++++++++++++++++ deformations/FrontierEvolver2.ih | 664 ++++++++++++++++++++++++++ deformations/FrontierEvolverHelpers.h | 120 +++++ deformations/PartitionEvolver.h | 5 +- 7 files changed, 1256 insertions(+), 68 deletions(-) create mode 100644 deformations/FrontierEvolver2.h create mode 100644 deformations/FrontierEvolver2.ih create mode 100644 deformations/FrontierEvolverHelpers.h diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 9cf37f8..1a4d39a 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -32,11 +32,11 @@ LINK_DIRECTORIES(/usr/lib/) ADD_EXECUTABLE(3dVolViewer 3dVolViewer) TARGET_LINK_LIBRARIES(3dVolViewer ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) -ADD_EXECUTABLE(testLocalDeformation3d testLocalDeformation3d) -TARGET_LINK_LIBRARIES(testLocalDeformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) +#ADD_EXECUTABLE(testLocalDeformation3d testLocalDeformation3d) +#TARGET_LINK_LIBRARIES(testLocalDeformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) -ADD_EXECUTABLE(testLocalDeformation2d testLocalDeformation2d) -TARGET_LINK_LIBRARIES(testLocalDeformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) +#ADD_EXECUTABLE(testLocalDeformation2d testLocalDeformation2d) +#TARGET_LINK_LIBRARIES(testLocalDeformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) ADD_EXECUTABLE(testDisk testDisk) TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) diff --git a/deformations/FMMPointFunctors.ih b/deformations/FMMPointFunctors.ih index b488f00..9dabf45 100644 --- a/deformations/FMMPointFunctors.ih +++ b/deformations/FMMPointFunctors.ih @@ -178,7 +178,7 @@ DGtal::L2FirstOrderLocalDistance::compute b -= static_cast(2*d); c += static_cast(d*d); } - + //discriminant double disc = b*b - 4*a*c; ASSERT(disc >= 0); diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index af30226..fd238ed 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -70,73 +70,13 @@ //partition #include "PartitionEvolver.h" - +#include "FrontierEvolverHelpers.h" ////////////////////////////////////////////////////////////////////////////// namespace DGtal { - //------------------------------------------------------------------------------ - template -struct SetFromImageDomainValueTraits - { - public: - typedef DigitalSetBySTLSet Set; - public: - public: - static Set get(I& aImage) - { - return Set(aImage.domain()); - } - }; - //Partial specialization - template -struct SetFromImageDomainValueTraits< - ImageContainerBySTLMap, - D, V > - { - public: - typedef DigitalSetFromMap > Set; - public: - static Set get(ImageContainerBySTLMap& aImage) - { - return Set(aImage); - } - }; - //------------------------------------------------------------------------------ - template -struct SetFromImageSelector - { - public: - BOOST_CONCEPT_ASSERT(( CImage )); - typedef typename I::Domain Domain; - typedef typename I::Value Value; - - typedef typename SetFromImageDomainValueTraits::Set Set; - - public: - static Set get(I& i) - { - return SetFromImageDomainValueTraits::get(i); - } - }; - - //------------------------------------------------------------------------------ - namespace details - { - class CompareSecondElement { - public: - template - bool operator()(const T& a, const T& b) - { - return ( a.second < b.second ); - } - }; - - } - - ///////////////////////////////////////////////////////////////////////////// // template class FrontierEvolver /** diff --git a/deformations/FrontierEvolver2.h b/deformations/FrontierEvolver2.h new file mode 100644 index 0000000..a80f47c --- /dev/null +++ b/deformations/FrontierEvolver2.h @@ -0,0 +1,463 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file FrontierEvolver2.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/03/01 + * + * Header file for module FrontierEvolver2.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(FrontierEvolver2_RECURSES) +#error Recursive header files inclusion detected in FrontierEvolver2.h +#else // defined(FrontierEvolver2_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define FrontierEvolver2_RECURSES + +#if !defined FrontierEvolver2_h +/** Prevents repeated inclusion of headers. */ +#define FrontierEvolver2_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include + +#include "DGtal/base/Common.h" +#include "DGtal/images/CImage.h" +#include "DGtal/kernel/CPointFunctor.h" +#include "DGtal/kernel/CPointPredicate.h" + +//predicates +#include "DGtal/base/BasicBoolFunctions.h" +#include "DGtal/kernel/BasicPointPredicates.h" +#include "PointPredicates.h" + + + +// set +#include "DGtal/images/ImageContainerBySTLMap.h" +#include "DGtal/kernel/sets/DigitalSetFromMap.h" +#include "DGtal/kernel/sets/DigitalSetBySTLSet.h" +#include "DGtal/kernel/sets/DigitalSetInserter.h" +#include "DGtal/images/ImageHelper.h" + +// FMM +#include "FMM.h" + +// frontier +#include "DGtal/topology/SurfelAdjacency.h" +#include "DGtal/topology/helpers/FrontierPredicate.h" +#include "DGtal/topology/LightExplicitDigitalSurface.h" + +//partition +#include "PartitionEvolver.h" +#include "FrontierEvolverHelpers.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + + ///////////////////////////////////////////////////////////////////////////// + // template class FrontierEvolver2 + /** + * Description of template class 'FrontierEvolver2'

+ * \brief Aim: This class is a way of deforming an image of labels + * around a digital frontier (ie. connected contact surface) + * between two adjacent regions according to a speed field. + * The speed field is only computed around the interface + * (this task is delegated to a point functor) and is then + * extended outward the interface in the normal direction. + * + * At each step, a signed distance function is updated and extended + * within a narrow band of width 4 (2 on each side) + * from the values known at the points adjacent to the digital frontier. + * The points lying in the narrow band are sorted according to + * their time of zero-crossing (ie. their distance to the interface + * divided by their speed) so that they are flipped from one region + * to another, one by one and in order, until a time greater than + * a given threshold is reached, but only if a given predicate + * based on topological properties returns true. + * + * @tparam TKSpace a model of CCellularGridSpaceND + * @tparam TLabelImage a model of CImage (storing labels) + * @tparam TDistanceImage a model of CImage (storing distance values) + * @tparam TFunctor a model of CPointFunctor + * @tparam TTopoPredicate a model of topological predicate + */ + template + class FrontierEvolver2 + { + + + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TLabelImage::Point>::value )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TDistanceImage::Point>::value )); + + BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TKSpace::Point, + typename TFunctor::Point>::value )); + + // BOOST_CONCEPT_ASSERT(( CPointPredicate )); + // BOOST_STATIC_ASSERT + // (( ConceptUtils::SameType< typename TKSpace::Point, + // typename TTopoPredicate::Point>::value )); + //TODO testing TTopoPredicate as a binary predicate on points and labels + + // ----------------------- Types ------------------------------ + public: + + /// Image of labels + typedef TLabelImage LImage; + typedef typename LImage::Value Label; + typedef typename LImage::Domain Domain; + typedef typename Domain::Point Point; + + /// Image of distance values + typedef TDistanceImage DImage; + typedef typename DImage::Value Distance; + + /// Point functor for the mapping points-speed + typedef TFunctor Functor; + typedef typename Functor::Value Speed; + typedef std::pair DistanceSpeed; + typedef std::pair PointTime; + + /// Topological predicate + typedef TTopoPredicate TopoPredicate; + + /// Set of points where the distance values are known + typedef typename SetFromImageSelector::Set PointSet; + + /// Khalimsky space + typedef TKSpace KSpace; + + /// Frontier + typedef FrontierPredicate SurfelPredicate; + typedef LightExplicitDigitalSurface Frontier; + /// Surfel + typedef typename Frontier::Surfel Surfel; + typedef typename Frontier::SurfelConstIterator SurfelIterator; + + + /// Partition + typedef PartitionEvolver Partition; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * @param aK khalimsky space where the digital frontier is defined + * @param aI an image of labels + * @param aD an image of distance values + * @param aS a surfel lying between two regions of @a aI + * @param aF a point functor mapping a speed to points + * @param aP any topological predicate + */ + FrontierEvolver2(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, + const Functor& aF, const TopoPredicate& aP, + Partition* aPartitionPtr = NULL); + + /** + * Destructor. Does nothing. + */ + ~FrontierEvolver2(); + + /** + * Deform the image of labels during @a aT + * + * @param aT time step + * @return time spent during the deformation + * (equal to aT). + */ + double update(const double& aT); + + + /** + * @return starting surfel of the digital frontier. + */ + Surfel surfel() const; + + /** + * @param aSurfel new starting surfel of the digital frontier. + */ + void setSurfel(const Surfel& aSurfel); + + /** + * @return begin iterator on the surfels of the digital frontier. + */ + SurfelIterator begin() const; + + /** + * @return end iterator on the surfels of the digital frontier. + */ + SurfelIterator end() const; + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const; + + /** + * Writes/Displays the object on an output stream. + * @param out the output stream where the object is written. + */ + void selfDisplay ( std::ostream & out ) const; + + + // ------------------------- Protected Datas ------------------------------ + protected: + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Constant reference on the khalimsky space + */ + const KSpace& myKSpace; + /** + * Reference on the image of labels + */ + LImage& myLImage; + /** + * Reference on the image of distance values + */ + DImage& myDImage; + /** + * Set of points where the distance values are known + */ + PointSet myPointSet; + /** + * Starting surfel of the digital frontier + */ + Surfel mySurfel; + /** + * Constant reference on the functor + */ + const Functor& myFunctor; + /** + * Constant reference on the topological predicate + */ + const TopoPredicate& myTopoPred; + /** + * Label of the inner region + */ + Label myInnerLabel; + /** + * Label of the outer region + */ + Label myOuterLabel; + /** + * Surfel predicate telling whether a given surfel + * belongs to the frontier or not + */ + SurfelPredicate mySurfelPred; + /** + * (implicit) digital frontier + */ + const Frontier* myFrontier; + /** + * Aliasing pointer on the partition the frontier belongs to + */ + Partition* myPartitionPtr; + + // ------------------------- Hidden services ------------------------------ + protected: + + + /** + * Copy constructor. + * @param other the object to clone. + * Forbidden by default. + */ + FrontierEvolver2 ( const FrontierEvolver2 & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + * Forbidden by default. + */ + FrontierEvolver2 & operator= ( const FrontierEvolver2 & other ); + + private: + + + + // ------------------------- Internals ------------------------------------ + private: + + /** + * Return through @a res the points + * of the narrow band + * for which the distance value has been + * computed and stored in @a myDImage + * + * @tparam TOutputIterator a model of output iterator + * + * @param res an output iterator + */ + template + void initNarrowBand(TOutputIterator res); + + /** + * Return through @a res the points + * that can be flipped into the + * adjacent region + * + * @param itb begin iterator on points + * @param ite end iterator on points + * @param aDistanceSpeedIto an output iterator on DistanceSpeed pairs + * @param aCandidateIto an output iterator on candidates + * + * @tparam TInputIterator a model of input iterator on points + * @tparam TOutputIterator1 a model of output iterator on DistanceSpeed pairs + * @tparam TOutputIterator2 a model of output iterator on candidates + * + */ + template + void initCandidates( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ); + + + /** + * Checks whether the other frontiers (if any) + * can be modified by the flip of @a aPoint + * @param aPoint any (digital) point + */ + void checkPartition ( const Point& aPoint ); + + /** + * Update @a myLImage for each candidates of the + * range [@a itb , @a ite ) + * + * The points that are not allowed to flip + * (because of the topological predicate) + * are stored through @a ito into a container + * + * @param itb begin iterator on candidates + * @param ite end iterator on candidates + * @param ito output iterator on points + * @param aP (returned) last point + * @param aT (returned) zero-crossing time of the last point + * @param aTMax maximal accepted time (equal to the evolution time step) + * + * @tparam TInputIterator a model of input iterator on candidates + * @tparam TOutputIterator a model of input iterator on points + * + * @return number of flipped points + */ + template + int updateLabelImage( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator ito, + Point& aP, double &aT, const double& aTMax ); + + /** + * Update @a myDImage at each point of the + * range [@a itb , @a ite ) knowing their + * distance and speed returning by @a aDistanceSpeedIt + * + * The points that belongs to @a aSet are not allowed to flip. + * + * @param itb begin iterator on points + * @param ite end iterator on points + * @param aDistanceSpeedIt an input iterator on DistanceSpeed pairs + * @param aSet any set of points + * @param t evolution time step + * + * @tparam TInputIterator1 a model of input iterator on points + * @tparam TInputIterator2 a model of input iterator on DistanceSpeed pairs + * @tparam TSet STL set like type + * + */ + template + void updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, + TInputIterator2 aDistanceSpeedIt, + const TSet& aSet, const double& t ); + + + /** + * Update the starting surfel @a mySurfel + * of the digital frontier from point @a p + * @param p any (digital) point + */ + void updateFrontier ( const Point& p ); + + /** + * Get inner point. + * @param s a surfel + * @return the inner point + */ + Point getInnerPoint ( const Surfel& s ) const ; + + /** + * Get outer point. + * @param s a surfel + * @return the outer point + */ + Point getOuterPoint ( const Surfel& s ) const ; + + + }; // end of class FrontierEvolver2 + + + /** + * Overloads 'operator<<' for displaying objects of class 'FrontierEvolver2'. + * @param out the output stream where the object is written. + * @param object the object of class 'FrontierEvolver2' to write. + * @return the output stream after the writing. + */ + template + std::ostream& + operator<< ( std::ostream & out, + const FrontierEvolver2 & object ); + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "FrontierEvolver2.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined FrontierEvolver2_h + +#undef FrontierEvolver2_RECURSES +#endif // else defined(FrontierEvolver2_RECURSES) diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih new file mode 100644 index 0000000..ec6d041 --- /dev/null +++ b/deformations/FrontierEvolver2.ih @@ -0,0 +1,664 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file FrontierEvolver2.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/03/01 + * + * @brief Implementation of inline methods defined in FrontierEvolver2.h + * + * This file is part of the DGtal library. + */ + + +#define WITHINFO + +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Standard services ------------------------------ + + +template +inline +DGtal::FrontierEvolver2 +::FrontierEvolver2(const KSpace& aK, LImage& aI, DImage& aD, const Surfel& aS, + const Functor& aF, const TopoPredicate& aP, Partition* aPartitionPtr ) + : myKSpace( aK ), myLImage( aI ), myDImage( aD ), + myPointSet( SetFromImageSelector::get( myDImage ) ), + mySurfel( aS ), myFunctor( aF ), myTopoPred( aP ), + myPartitionPtr( aPartitionPtr), + myInnerLabel( myLImage( getInnerPoint( mySurfel ) ) ), + myOuterLabel( myLImage( getOuterPoint( mySurfel ) ) ), + mySurfelPred( myKSpace, myLImage, myInnerLabel, myOuterLabel ), + myFrontier( new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ) ) +{ + ASSERT( myFrontier ); + + #ifdef WITHINFO + trace.info() << "Labels: " << myInnerLabel << " (inner region)" + << " and " << myOuterLabel << " (outer region) " + << std::endl; + #endif + ASSERT( myInnerLabel != myOuterLabel ); + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); +} + +template +inline +DGtal::FrontierEvolver2 +::~FrontierEvolver2() +{ + delete( myFrontier ); +} + +template +inline +typename DGtal::FrontierEvolver2::Surfel +DGtal::FrontierEvolver2 +::surfel() const +{ + return mySurfel; +} + +template +inline +void +DGtal::FrontierEvolver2 +::setSurfel(const Surfel& aSurfel) +{ + /// update surfel + mySurfel = aSurfel; + + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); + ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); + ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); + + /// update frontier + delete ( myFrontier ); + myFrontier = new Frontier ( myKSpace, mySurfelPred, + SurfelAdjacency( true ), + mySurfel ); + ASSERT( myFrontier ); +} + +template +inline +typename DGtal::FrontierEvolver2 +::SurfelIterator +DGtal::FrontierEvolver2 +::begin() const +{ + return myFrontier->begin(); +} + +template +inline +typename DGtal::FrontierEvolver2 +::SurfelIterator +DGtal::FrontierEvolver2 +::end() const +{ + return myFrontier->end(); +} + +template +inline +bool +DGtal::FrontierEvolver2 +::isValid() const +{ + return ( ( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ) + && ( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ) ); +} + + +template +inline +void +DGtal::FrontierEvolver2 +::selfDisplay ( std::ostream & out ) const +{ + out << "[FrontierEvolver2]\n"; + out << "\n"; +} + + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Main methods ------------------------------ + + +template +inline +double +DGtal::FrontierEvolver2 +::update(const double& aT) +{ + ASSERT( myKSpace.sIsSurfel( mySurfel ) ); + ASSERT( mySurfelPred( mySurfel ) ); + ASSERT( myInnerLabel == myLImage( getInnerPoint( mySurfel ) ) ); + ASSERT( myOuterLabel == myLImage( getOuterPoint( mySurfel ) ) ); + + #ifdef WITHINFO + trace.info() << std::endl; + trace.info() << "starting surfel: " << mySurfel << std::endl; + trace.info() << "between: " << myInnerLabel << " (inner region)" + << " and " << myOuterLabel << " (outer region) " + << std::endl; + #endif + + /// narrow band + typedef std::vector Band; + Band narrowBand; + initNarrowBand ( std::back_inserter( narrowBand ) ); + #ifdef WITHINFO + trace.info() << narrowBand.size() << " closest points" << std::endl; + #endif + + /// speed and zero-crossing time computation + typedef std::vector DistanceSpeedVector; + DistanceSpeedVector buffer; + /// candidates to flip + typedef std::vector CandidateVector; + CandidateVector candidates; + initCandidates( narrowBand.begin(), narrowBand.end(), + std::back_inserter( buffer ), + std::back_inserter( candidates ) ); + #ifdef WITHINFO + trace.info() << candidates.size() << " candidates " << std::endl; + #endif + + if (candidates.begin() != candidates.end()) + { //if there are candidates + + /// ordering of the points according + /// to their zero-crossing time + #ifdef WITHINFO + trace.info() << "ordering..." << std::endl; + #endif + + details::CompareSecondElement timeCompare; + std::sort( candidates.begin(), candidates.end(), timeCompare ); + + #ifdef WITHINFO + trace.info() << "Times ranging from " + << candidates.begin()->second + << " to " + << candidates.rbegin()->second + << std::endl; + #endif + + /// flip points one by one, in order, while it is possible + //points not allowed to flip because not simple + std::set forbiddenPoints; + // last point and its zero-crossing time + Point lastP = Point::diagonal(0); + double lastT = 0.0; + int nbFlips = updateLabelImage( candidates.begin(), candidates.end(), + std::inserter( forbiddenPoints, forbiddenPoints.begin() ), + lastP, lastT, aT ); + ASSERT( lastT <= aT ); + #ifdef WITHINFO + trace.info() << nbFlips << " flipped points in " << lastT << " unit time" << std::endl; + #endif + + /// update distance map anyway + #ifdef WITHINFO + trace.info() << "updating signed distance function..." << std::endl; + #endif + updateDistanceImage( narrowBand.begin(), narrowBand.end(), + buffer.begin(), forbiddenPoints, aT ); + + /// update frontier if needed + if (nbFlips > 0) + updateFrontier( lastP ); + + return aT; + } + else + return 0.0; +} + +template +template +inline +void +DGtal::FrontierEvolver2 +::initNarrowBand( TOutputIterator res ) +{ + + //predicate and FMM definitions + typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); + typedef FMM FMM; + + /// initialization of the band from the + /// points adjacent to the digital frontier + if (myPointSet.size() == 0) + {//first step + FMM::initFromBelsRange(myKSpace, myFrontier->begin(), myFrontier->end(), + myDImage, myPointSet, 0.5, true); + } + else + {//next steps + + //TODO think about the best way of dealing with adjacentPoints + //and copying it in the band + typedef std::pair PointDistance; + std::map adjacentPoints; + typedef typename std::map::iterator IteratorPointDistance; + + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + Point out( getOuterPoint( *it ) ); + + ASSERT( myLImage(in) == myInnerLabel ); + Distance din = myDImage( in ); + ASSERT( din <= 0 ); + + ASSERT( myLImage(out) == myOuterLabel ); + Distance dout = myDImage( out ); + ASSERT( dout > 0 ); + + std::pair rin + = adjacentPoints.insert( PointDistance( in, din ) ); + + std::pair rout + = adjacentPoints.insert( PointDistance( out, dout ) ); + } + + myPointSet.clear(); + for ( IteratorPointDistance + it = adjacentPoints.begin(), + itEnd = adjacentPoints.end(); + it != itEnd; ++it ) + { + PointDistance pair( *it ); + insertAndSetValue( myDImage, myPointSet, pair.first, pair.second ); + } + } + + + std::copy( myPointSet.begin(), myPointSet.end(), res ); + + #ifdef WITHINFO + trace.info() << myPointSet.size() << " distinct adjacent points." << std::endl; + #endif + + + /// FMM computation + FMM fmm( myDImage, myPointSet, pointPredicate ); + #ifdef WITHINFO + trace.info() << fmm << std::endl; + #endif + + Point p = Point::diagonal(0); //last point + Distance d = 0; //its distance + //first pass + { + double threshold = std::max( std::abs(fmm.max()),std::abs(fmm.min()) ) + + 2.0; // distance threshold + while ( (fmm.computeOneStep( p, d )) + && (std::abs(d) < threshold) ) + { + ASSERT( myDImage(p) == d ); + #ifdef WITHINFO + if (! ( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) + || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) + || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ) ) + { + trace.info() << p << " in " << myLImage(p) << " at " << d << std::endl; + } + #endif + + ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) + || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) + || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); + *res++ = p; + } + } + #ifdef WITHINFO + trace.info() << fmm << std::endl; + #endif + +} + + +template +template +inline +void +DGtal::FrontierEvolver2 +::initCandidates( const TInputIterator& itb, const TInputIterator& ite, + TOutputIterator1 aDistanceSpeedIto, TOutputIterator2 aCandidateIto ) +{ + + /// computing speed + typedef ImageContainerBySTLMap SpeedImage; + SpeedImage speedImage( myDImage.domain(), 0.0 ); + + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); + it != itEnd; ++it ) + { + Point in( getInnerPoint( *it ) ); + ASSERT( myLImage(in) == myInnerLabel ); + speedImage.setValue( in, myFunctor( in ) ); + + Point out( getOuterPoint( *it ) ); + ASSERT( myLImage(out) == myOuterLabel ); + speedImage.setValue( out, myFunctor( out ) ); + } + #ifdef WITHINFO + trace.info() << " speed of the adjacent points... " << std::endl; + #endif + + + {/// extension speed + typedef ImageContainerBySTLMap TmpDImage; + TmpDImage tmpDImage( myDImage.domain(), 0.0 ); + typedef DigitalSetFromMap< ImageContainerBySTLMap > TmpSet; + TmpSet tmpSet( tmpDImage ); + + SpeedExtrapolator + speedFunctor( tmpDImage, tmpSet, speedImage ); + + typedef FMM FMM; + FMM::initFromBelsRange( myKSpace, + myFrontier->begin(), myFrontier->end(), + myDImage, tmpDImage, tmpSet ); + + const double maxWidth = 2.0; + FMM fmm( tmpDImage, tmpSet, myDImage.domain().predicate() ); + Point lastPt = Point::diagonal(0); //last point + double lastDist = 0.0; //its distance + while ( (fmm.computeOneStep( lastPt, lastDist )) + && (std::abs( lastDist ) < 2.0) ) + { //new speed value + speedImage.setValue( lastPt, speedFunctor( lastPt ) ); + } + #ifdef WITHINFO + trace.info() << " extension... " << std::endl; + #endif + } + + /// candidates + for ( TInputIterator it = itb; + it != ite; ++it) + { + // point + Point p = *it; + // distance + Distance d = myDImage( p ); + // speed + Speed v = speedImage( p ); + // storing distance and speed + *aDistanceSpeedIto++ = DistanceSpeed( d, v ); + // new candidate with its zero-crossing time + if ( ( myLImage( p ) == myInnerLabel ) + || (myLImage( p ) == myOuterLabel ) ) + { + if ( ( (d>0) && (v<0) ) + || ( (d<=0) && (v>0) ) ) + { // if opposite signs (and v != 0) + double t = - static_cast( d ) / v; + ASSERT( t >= 0 ); + // storing candidate + *aCandidateIto++ = PointTime( p, t ); + } + } + } +} + + +template +template +inline +int +DGtal::FrontierEvolver2 +::updateLabelImage( const TInputIterator& itb, const TInputIterator& ite, TOutputIterator ito, + Point& aP, double& aT, const double& aTMax ) +{ + + unsigned int nbFlips = 0; + + for (TInputIterator it = itb; + ( (it != ite)&&(it->second <= aTMax) ); ++it) + { + aP = it->first; + aT = it->second; + const Label label = myLImage( aP ); + const Label oppositeLabel = + (label == myInnerLabel)?myOuterLabel:myInnerLabel; + + if ( myTopoPred( aP, oppositeLabel ) ) + { /// flip + checkPartition( aP ); + #ifdef WITHINFO + trace.emphase() << aP << " flipped into region " + << oppositeLabel << std::endl; + #endif + myLImage.setValue( aP, oppositeLabel ); + ++nbFlips; + } + else + { + *ito++ = aP; + #ifdef WITHINFO + trace.emphase() << aP << " is not a simple point!" << std::endl; + #endif + } + } + + return nbFlips; +} + +template +inline +void +DGtal::FrontierEvolver2 +::updateFrontier(const Point& p) +{ + /// spel creation + typename KSpace::SCell spel; + const Label pLabel = myLImage(p); + if ( pLabel == myInnerLabel ) + { + ASSERT( (myDImage(p) <= 0) ); + spel = myKSpace.sSpel( p, KSpace::POS ); + } + else if ( pLabel == myOuterLabel ) + { + ASSERT( (myDImage(p) > 0) ); + spel = myKSpace.sSpel( p, KSpace::NEG ); + } + else + ASSERT( false && "impossible label in updateFrontier method" ); + + /// for each direction + Surfel newSurfel; + bool flag = false; + for ( typename KSpace::DirIterator q = myKSpace.sDirs( spel ); + ( (q != 0)&&(!flag) ); ++q ) + { + const DGtal::Dimension dir = *q; + + /// for the direct orientation + typename KSpace::SCell surfel + = myKSpace.sDirectIncident( spel, dir ); + ASSERT( myKSpace.sIsSurfel( surfel ) ); + if ( mySurfelPred( surfel ) ) + { + newSurfel = surfel; + flag = true; + } + if (!flag) + { + surfel = myKSpace.sIndirectIncident( spel, dir ); + ASSERT( myKSpace.sIsSurfel( surfel ) ); + if ( mySurfelPred( surfel ) ) + { + newSurfel = surfel; + flag = true; + } + } + } + ASSERT( flag && "last flipped point must be a border point in updateFrontier method" ); + + this->setSurfel( newSurfel ); + +} + + +template +template +inline +void +DGtal::FrontierEvolver2 +::updateDistanceImage( const TInputIterator1& itb, const TInputIterator1& ite, + TInputIterator2 aDistanceSpeedIt, + const TSet& aSet, const double& t ) +{ + for (TInputIterator1 it = itb; + it != ite; ++it, ++aDistanceSpeedIt) + { + // point + const Point p = *it; + // distance and speed + const DistanceSpeed pair( *aDistanceSpeedIt ); + Distance newDist = pair.first + t * pair.second; + + //label + const Label pLabel = myLImage( p ); + + const Distance eps = std::numeric_limits::epsilon(); + // correction due to the approximation error + if ( ( (newDist < 0.0001)&&(newDist > -0.0001) ) + //correction due to the non simplicity + || ( aSet.find( p ) != aSet.end() ) ) + { + if (pLabel == myInnerLabel) newDist = -eps; + else newDist = eps; + } + + #ifdef WITHINFO + if ( !( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ) ) + { + trace.info() << p << " in " << myLImage( p ) + << " at " << newDist << std::endl; + } + #endif + + ASSERT( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); + + + // set value + myDImage.setValue( p, newDist ); + + } + +} + + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Small Helpers ------------------------------ +template +inline +void +DGtal::FrontierEvolver2 +::checkPartition(const Point& aPoint) +{ + if (myPartitionPtr != NULL) + { + myPartitionPtr->checkFrontiers( this, aPoint ); + } +} + + +template +inline +typename DGtal::FrontierEvolver2::Point +DGtal::FrontierEvolver2 +::getInnerPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sDirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} + +template +inline +typename DGtal::FrontierEvolver2::Point +DGtal::FrontierEvolver2 +::getOuterPoint(const Surfel& s) const +{ + return myKSpace.sCoords( myKSpace.sIndirectIncident( s, *myKSpace.sOrthDirs( s ) ) ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Implementation of inline functions // + +template +inline +std::ostream& +DGtal::operator<< ( std::ostream & out, + const FrontierEvolver2 & object ) +{ + object.selfDisplay( out ); + return out; +} + +// // +/////////////////////////////////////////////////////////////////////////////// + + diff --git a/deformations/FrontierEvolverHelpers.h b/deformations/FrontierEvolverHelpers.h new file mode 100644 index 0000000..e32ca47 --- /dev/null +++ b/deformations/FrontierEvolverHelpers.h @@ -0,0 +1,120 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file FrontierEvolverHelpers.h + * + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * @date 2012/04/19 + * + * This file is part of the DGtal library. + */ + +#if defined(FrontierEvolverHelpers_RECURSES) +#error Recursive header files inclusion detected in FrontierEvolverHelpers.h +#else // defined(FrontierEvolverHelpers_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define FrontierEvolverHelpers_RECURSES + +#if !defined FrontierEvolverHelpers_h +/** Prevents repeated inclusion of headers. */ +#define FrontierEvolverHelpers_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include "DGtal/base/Common.h" +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + + //------------------------------------------------------------------------------ + template +struct SetFromImageDomainValueTraits + { + public: + typedef DigitalSetBySTLSet Set; + public: + public: + static Set get(I& aImage) + { + return Set(aImage.domain()); + } + }; + //Partial specialization + template +struct SetFromImageDomainValueTraits< + ImageContainerBySTLMap, + D, V > + { + public: + typedef DigitalSetFromMap > Set; + public: + static Set get(ImageContainerBySTLMap& aImage) + { + return Set(aImage); + } + }; + //------------------------------------------------------------------------------ + template +struct SetFromImageSelector + { + public: + BOOST_CONCEPT_ASSERT(( CImage )); + typedef typename I::Domain Domain; + typedef typename I::Value Value; + + typedef typename SetFromImageDomainValueTraits::Set Set; + + public: + static Set get(I& i) + { + return SetFromImageDomainValueTraits::get(i); + } + }; + + //------------------------------------------------------------------------------ + namespace details + { + class CompareSecondElement { + public: + template + bool operator()(const T& a, const T& b) + { + return ( a.second < b.second ); + } + }; + + } + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +//#include "FrontierEvolverHelpers.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined FrontierEvolverHelpers_h + +#undef FrontierEvolverHelpers_RECURSES +#endif // else defined(FrontierEvolverHelpers_RECURSES) diff --git a/deformations/PartitionEvolver.h b/deformations/PartitionEvolver.h index b8a8235..e40a59c 100644 --- a/deformations/PartitionEvolver.h +++ b/deformations/PartitionEvolver.h @@ -61,7 +61,7 @@ namespace DGtal template - class FrontierEvolver; + class FrontierEvolver2; ///////////////////////////////////////////////////////////////////////////// // template class PartitionEvolver @@ -134,7 +134,7 @@ namespace DGtal typedef TTopoPredicate TopoPredicate; /// Frontier evolver - typedef FrontierEvolver Evolver; + typedef FrontierEvolver2 Evolver; typedef CountedPtr EvolverPtr; @@ -296,6 +296,7 @@ namespace DGtal /////////////////////////////////////////////////////////////////////////////// // Includes inline functions. #include "FrontierEvolver.h" +#include "FrontierEvolver2.h" #include "PartitionEvolver.ih" // // From e0cfa5220434d2dd4e495dca2a8afbf601d98021 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 19 Apr 2012 20:14:28 +0200 Subject: [PATCH 061/108] still pb that comes from the way that FMMPointFunctor deals with values of different signs --- deformations/FrontierEvolver2.ih | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index ec6d041..95cc771 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -262,6 +262,12 @@ DGtal::FrontierEvolver2 > LabelPredicate; + // typedef CascadingPointPredicate< typename Domain::Predicate, + // LabelPredicate > PointPredicate4FMM; + // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + // PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); + // typedef FMM FMM; typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); typedef FMM FMM; From 98f3e572c6269b879c30d838b1d2cd5162bf7161 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 20 Apr 2012 12:00:01 +0200 Subject: [PATCH 062/108] little bug correction in CascadingPredicates --- deformations/PointPredicates.h | 1 + 1 file changed, 1 insertion(+) diff --git a/deformations/PointPredicates.h b/deformations/PointPredicates.h index 0d1af43..0210425 100644 --- a/deformations/PointPredicates.h +++ b/deformations/PointPredicates.h @@ -150,6 +150,7 @@ ::operator()( const Point & p ) const { if ( myPred1->operator()( p ) ) return myPred2->operator()( p ); + else return false; } From 24d75f689a8481eb3e87f2352698394a5570f8ef Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 20 Apr 2012 12:16:47 +0200 Subject: [PATCH 063/108] cleaning FMM in initNarrowBand in FrontierEvolver2 --- deformations/FrontierEvolver2.ih | 58 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index 95cc771..e37daba 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -320,49 +320,49 @@ DGtal::FrontierEvolver2-0.0001)) - || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ) ) - { - trace.info() << p << " in " << myLImage(p) << " at " << d << std::endl; - } - #endif - - ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) - || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) - || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); - *res++ = p; - } - } + fmm.compute(); + + // Point p = Point::diagonal(0); //last point + // Distance d = 0; //its distance + // //first pass + // { + // double threshold = 2.0; // distance threshold + // while ( (fmm.computeOneStep( p, d )) + // && (std::abs(d) < threshold) ) + // { + // ASSERT( myDImage(p) == d ); + // #ifdef WITHINFO + // if (! ( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) + // || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) + // || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ) ) + // { + // trace.info() << p << " in " << myLImage(p) << " at " << d << std::endl; + // } + // #endif + + // ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) + // || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) + // || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); + // *res++ = p; + // } + // } #ifdef WITHINFO trace.info() << fmm << std::endl; #endif + std::copy( myPointSet.begin(), myPointSet.end(), res ); } From 6b384fda3551f3f91f73ff3bd2e7661a91735cf5 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Fri, 20 Apr 2012 18:07:35 +0200 Subject: [PATCH 064/108] try with FMM within the two adjacent regions --- deformations/FrontierEvolver2.ih | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index e37daba..6def2b3 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -262,14 +262,14 @@ DGtal::FrontierEvolver2 > LabelPredicate; - // typedef CascadingPointPredicate< typename Domain::Predicate, - // LabelPredicate > PointPredicate4FMM; - // LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); - // PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); - // typedef FMM FMM; - typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); - typedef FMM FMM; + typedef TwoLabelsPredicate > LabelPredicate; + typedef CascadingPointPredicate< typename Domain::Predicate, + LabelPredicate > PointPredicate4FMM; + LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); + typedef FMM FMM; + // typename Domain::Predicate pointPredicate = myDImage.domain().predicate(); + // typedef FMM FMM; /// initialization of the band from the /// points adjacent to the digital frontier @@ -292,19 +292,20 @@ DGtal::FrontierEvolver2 0) din = -0.5; + ASSERT( din <= 0 ); + std::pair rin + = adjacentPoints.insert( PointDistance( in, din ) ); + Point out( getOuterPoint( *it ) ); ASSERT( myLImage(out) == myOuterLabel ); Distance dout = myDImage( out ); + //arbitrary correction + if (dout <= 0) dout = 0.5; ASSERT( dout > 0 ); - - std::pair rin - = adjacentPoints.insert( PointDistance( in, din ) ); - std::pair rout = adjacentPoints.insert( PointDistance( out, dout ) ); } From 9afaaef5f27c25bcc1387b95934ade8f9fbb7b5c Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 23 Apr 2012 15:33:11 +0200 Subject: [PATCH 065/108] new procedure for tracking the starting surfel in the digital frontier --- deformations/FrontierEvolver2.h | 21 ++++++- deformations/FrontierEvolver2.ih | 104 +++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 27 deletions(-) diff --git a/deformations/FrontierEvolver2.h b/deformations/FrontierEvolver2.h index a80f47c..284fa82 100644 --- a/deformations/FrontierEvolver2.h +++ b/deformations/FrontierEvolver2.h @@ -411,9 +411,28 @@ namespace DGtal /** * Update the starting surfel @a mySurfel * of the digital frontier from point @a p + * before the flip. The frontier is tracked + * until a surfel that is not adjacent to @a p + * is found. + * * @param p any (digital) point + * @return 'true' if a new surfel has been found + * 'false' otherwise */ - void updateFrontier ( const Point& p ); + bool updateFrontierBefore ( const Point& p ); + + /** + * Update the starting surfel @a mySurfel + * of the digital frontier from point @a p + * after the flip. Among the surfels adjacent + * to @a p one surfel is chosen. + * + * @param p any (digital) point + * @return 'true' if a new surfel has been found + * 'false' otherwise + */ + bool updateFrontierAfter ( const Point& p ); + /** * Get inner point. diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index 6def2b3..66395f6 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -243,8 +243,8 @@ DGtal::FrontierEvolver2 0) - updateFrontier( lastP ); + // if (nbFlips > 0) + // updateFrontier( lastP ); return aT; } @@ -262,7 +262,7 @@ DGtal::FrontierEvolver2 > LabelPredicate; + typedef TwoLabelsPredicate > LabelPredicate; typedef CascadingPointPredicate< typename Domain::Predicate, LabelPredicate > PointPredicate4FMM; LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); @@ -323,6 +323,10 @@ DGtal::FrontierEvolver2(std::cerr, ", ") ); +} #endif @@ -407,17 +411,22 @@ DGtal::FrontierEvolver2 speedFunctor( tmpDImage, tmpSet, speedImage ); - typedef FMM FMM; + typedef TwoLabelsPredicate > LabelPredicate; + typedef CascadingPointPredicate< typename Domain::Predicate, + LabelPredicate > PointPredicate4FMM; + LabelPredicate predOnLabels( myLImage, myInnerLabel, myOuterLabel ); + PointPredicate4FMM pointPredicate( myLImage.domain().predicate(), predOnLabels ); + typedef FMM FMM; FMM::initFromBelsRange( myKSpace, myFrontier->begin(), myFrontier->end(), myDImage, tmpDImage, tmpSet ); - const double maxWidth = 2.0; - FMM fmm( tmpDImage, tmpSet, myDImage.domain().predicate() ); + //TODO point predicate must be derived from the narrow band + FMM fmm( tmpDImage, tmpSet, pointPredicate, + myDImage.domain().size(), 3.0 ); Point lastPt = Point::diagonal(0); //last point double lastDist = 0.0; //its distance - while ( (fmm.computeOneStep( lastPt, lastDist )) - && (std::abs( lastDist ) < 2.0) ) + while ( fmm.computeOneStep( lastPt, lastDist ) ) { //new speed value speedImage.setValue( lastPt, speedFunctor( lastPt ) ); } @@ -478,12 +487,19 @@ DGtal::FrontierEvolver2 inline -void +bool DGtal::FrontierEvolver2 -::updateFrontier(const Point& p) +::updateFrontierAfter(const Point& p) { + /// spel creation typename KSpace::SCell spel; const Label pLabel = myLImage(p); if ( pLabel == myInnerLabel ) - { - ASSERT( (myDImage(p) <= 0) ); spel = myKSpace.sSpel( p, KSpace::POS ); - } - else if ( pLabel == myOuterLabel ) - { - ASSERT( (myDImage(p) > 0) ); - spel = myKSpace.sSpel( p, KSpace::NEG ); - } else - ASSERT( false && "impossible label in updateFrontier method" ); + spel = myKSpace.sSpel( p, KSpace::NEG ); /// for each direction Surfel newSurfel; @@ -549,9 +558,52 @@ DGtal::FrontierEvolver2setSurfel( newSurfel ); + return true; + } + else + return false; +} - this->setSurfel( newSurfel ); +template +inline +bool +DGtal::FrontierEvolver2 +::updateFrontierBefore(const Point& p) +{ + + const Surfel s = mySurfel; + if ( (getInnerPoint(s) == p)||(getOuterPoint(s) == p) ) + { /// if s is adjacent to p + + #ifdef WITHINFO + trace.info() << "updating frontier..." << std::endl; + #endif + /// tracking until a new surfel is found + bool flag = true; + for ( SurfelIterator it = myFrontier->begin(), + itEnd = myFrontier->end(); + ( (it != itEnd)&&(flag) ); ++it ) + { + SCell newS = *it; + if ( (getInnerPoint(newS) != p) && (getOuterPoint(newS) != p) ) + {/// if newS is not adjacent to aPoint + + /// update + this->setSurfel( newS ); + flag = false; + #ifdef WITHINFO + trace.info() << s << " moved to " << newS << std::endl; + #endif + } + } + return ( flag == false ); + } + else + return true; } @@ -598,9 +650,9 @@ DGtal::FrontierEvolver2 0)&&(myLImage( p ) == myOuterLabel) ) - || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); + // ASSERT( ( (newDist <= 0)&&(myLImage( p ) == myInnerLabel) ) + // || ( (newDist > 0)&&(myLImage( p ) == myOuterLabel) ) + // || ( (myLImage( p ) != myInnerLabel)&&(myLImage( p ) != myOuterLabel) ) ); // set value From e9c947a810077610eb32e8d4de0e7f8d45df199f Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Mon, 23 Apr 2012 17:25:19 +0200 Subject: [PATCH 066/108] adding file for the generation of simple test partitions --- deformations/CMakeLists.txt | 4 ++ deformations/generate3d.cpp | 133 ++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 deformations/generate3d.cpp diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 9cf37f8..342ba27 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -32,6 +32,10 @@ LINK_DIRECTORIES(/usr/lib/) ADD_EXECUTABLE(3dVolViewer 3dVolViewer) TARGET_LINK_LIBRARIES(3dVolViewer ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) +ADD_EXECUTABLE(generate3d generate3d) +TARGET_LINK_LIBRARIES(generate3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) + + ADD_EXECUTABLE(testLocalDeformation3d testLocalDeformation3d) TARGET_LINK_LIBRARIES(testLocalDeformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) diff --git a/deformations/generate3d.cpp b/deformations/generate3d.cpp new file mode 100644 index 0000000..8b857ce --- /dev/null +++ b/deformations/generate3d.cpp @@ -0,0 +1,133 @@ +#include +#include + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +///////////////////// +#include +#include + +using namespace Z3i; + + +/////////////////////////// useful functions +#include "deformationFunctions.h" +#include "deformationDisplay3d.h" +#include "DGtal/io/readers/VolReader.h" + +/////////////////////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + DGtal::trace.info() << "Generating 3d partitions using DGtal "; + DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; + + + + // parse command line ---------------------------------------------- + po::options_description general_opt("Allowed options are"); + general_opt.add_options() + ("help,h", "display this message") + ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) + ("shape,s", po::value()->default_value("ball"), + "Generated shape: either (default) or <2balls> " ) + ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ); + + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help")||argc<=1) + { + trace.info()<< "Generating 3d partitions" << std::endl + << "Basic usage: "< -s " + << std::endl + << general_opt << "\n"; + return 0; + } + + //Parse options + //domain size + int dsize; + if (!(vm.count("domainSize"))) trace.info() << "Domain size default value: 32" << std::endl; + dsize = vm["domainSize"].as(); + + //files + std::string outputFiles; + if (!(vm.count("outputFiles"))) + trace.info() << "output files begin with : interface" << std::endl; + outputFiles = vm["outputFiles"].as(); + + //image and implicit function + typedef ImageContainerBySTLVector LabelImage; + Point p = Point::diagonal(0); + Point q = Point::diagonal(dsize); + Domain d = Domain(p,q); + LabelImage labelImage( Domain(p,q) ); + + DGtal::trace.beginBlock("image reading..."); + if (vm.count("shape")) + { + if ( (vm["shape"].as()) == "ball" ) + { + Point c = Point::diagonal(dsize/2); + double r = (((double)dsize*3.0/5.0)/2.0); + Domain::ConstIterator cIt = d.begin(); + Domain::ConstIterator cItEnd = d.end(); + for ( ; cIt != cItEnd; ++cIt) + { //for each domain point + double dist = (*cIt-c).norm(Point::L_2) - r; + LabelImage::Value v = ( dist <= 0 )?255:0; + labelImage.setValue(*cIt, v); + } + + } + + if ( (vm["shape"].as()) == "2balls" ) + { + Point c1 = Point::diagonal(dsize/3 + 1); + Point c2 = Point::diagonal(dsize/3*2 - 1); + double r = (dsize/3); + Domain::ConstIterator cIt = d.begin(); + Domain::ConstIterator cItEnd = d.end(); + for ( ; cIt != cItEnd; ++cIt) + { //for each domain point + double dist1 = (*cIt-c1).norm(Point::L_2) - r; + double dist2 = (*cIt-c2).norm(Point::L_2) - r; + LabelImage::Value v = ( dist1 <= 0 )?255:0; + if (dist2 <= 0) v = 127; + labelImage.setValue(*cIt, v); + } + } + +/* if ( (vm["shape"].as()) == "pyramid" ) + { + Point c = Point::diagonal(dsize/2); + initWithBallPredicate( labelImage, c, (dsize*3/5)/2 ); + inv( labelImage ); + } +*/ + + } + else + trace.info() << "shape not known, use option -h" << std::endl; + + trace.info() << "starting interface initialized with a " + << (vm["shape"].as()) << std::endl; + DGtal::trace.endBlock(); + + //write into a vol file + std::stringstream s; + s << outputFiles << ".vol"; + typedef GradientColorMap ColorMap; + VolWriter::exportVol( s.str(), labelImage, 0, 255 ); + + return 1; +} + From cf56fa25bf4d66e7a039a5495a94eb616404bc5d Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 24 Apr 2012 11:25:13 +0200 Subject: [PATCH 067/108] bug fix on updateFrontier (set surfel outside of the loop) --- deformations/FrontierEvolver2.h | 7 ++- deformations/FrontierEvolver2.ih | 83 +++++++++++++------------------- deformations/PartitionEvolver.ih | 31 +----------- 3 files changed, 39 insertions(+), 82 deletions(-) diff --git a/deformations/FrontierEvolver2.h b/deformations/FrontierEvolver2.h index 284fa82..3ca1673 100644 --- a/deformations/FrontierEvolver2.h +++ b/deformations/FrontierEvolver2.h @@ -407,6 +407,7 @@ namespace DGtal TInputIterator2 aDistanceSpeedIt, const TSet& aSet, const double& t ); + public: /** * Update the starting surfel @a mySurfel @@ -419,7 +420,9 @@ namespace DGtal * @return 'true' if a new surfel has been found * 'false' otherwise */ - bool updateFrontierBefore ( const Point& p ); + bool updateFrontier ( const Point& p ); + + private: /** * Update the starting surfel @a mySurfel @@ -431,7 +434,7 @@ namespace DGtal * @return 'true' if a new surfel has been found * 'false' otherwise */ - bool updateFrontierAfter ( const Point& p ); + bool retrieveFrontier ( const Point& p ); /** diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index 66395f6..b6787c4 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -197,11 +197,13 @@ DGtal::FrontierEvolver2= candidates.size() ); #ifdef WITHINFO trace.info() << candidates.size() << " candidates " << std::endl; #endif - if (candidates.begin() != candidates.end()) + if ( (narrowBand.size() != 0)&&(candidates.size() != 0) ) { //if there are candidates /// ordering of the points according @@ -242,10 +244,6 @@ DGtal::FrontierEvolver2 0) - // updateFrontier( lastP ); - return aT; } else @@ -329,7 +327,7 @@ DGtal::FrontierEvolver2-0.0001)) - // || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ) ) - // { - // trace.info() << p << " in " << myLImage(p) << " at " << d << std::endl; - // } - // #endif - - // ASSERT( ((myLImage(p) == myInnerLabel)&&(d<0.0001)) - // || ((myLImage(p) == myOuterLabel)&&(d>-0.0001)) - // || ( (myLImage(p) != myInnerLabel)&&(myLImage(p) != myOuterLabel) ) ); - // *res++ = p; - // } - // } #ifdef WITHINFO trace.info() << fmm << std::endl; #endif - + std::copy( myPointSet.begin(), myPointSet.end(), res ); } @@ -487,16 +461,16 @@ DGtal::FrontierEvolver2 -::updateFrontierAfter(const Point& p) +::retrieveFrontier(const Point& p) { +#ifdef WITHINFO + trace.info() << "updating frontier..." << std::endl; +#endif + /// spel creation typename KSpace::SCell spel; const Label pLabel = myLImage(p); @@ -572,7 +550,7 @@ template -::updateFrontierBefore(const Point& p) +::updateFrontier(const Point& p) { const Surfel s = mySurfel; @@ -583,24 +561,29 @@ DGtal::FrontierEvolver2begin(), - itEnd = myFrontier->end(); - ( (it != itEnd)&&(flag) ); ++it ) + bool flag = true; + SurfelIterator it = myFrontier->begin(); + SurfelIterator itEnd = myFrontier->end(); + SCell newS; + while ( (it != itEnd)&&(flag) ) { - SCell newS = *it; + newS = *it; if ( (getInnerPoint(newS) != p) && (getOuterPoint(newS) != p) ) - {/// if newS is not adjacent to aPoint - - /// update - this->setSurfel( newS ); + {/// if newS is not adjacent to aPoint flag = false; - #ifdef WITHINFO - trace.info() << s << " moved to " << newS << std::endl; - #endif } + ++it; } - return ( flag == false ); + if (!flag) + { + setSurfel( newS ); + #ifdef WITHINFO + trace.info() << s << " moved to " << newS << std::endl; + #endif + return true; + } + else + return false; } else return true; diff --git a/deformations/PartitionEvolver.ih b/deformations/PartitionEvolver.ih index 26c5f7b..a092112 100644 --- a/deformations/PartitionEvolver.ih +++ b/deformations/PartitionEvolver.ih @@ -148,42 +148,13 @@ void DGtal::PartitionEvolver ::checkFrontiers(const Evolver* aPtrToCaller, const Point& aPoint) { - trace.info() << " checking frontiers... " << std::endl; - for (typename std::vector::const_iterator it = myEvolvers.begin(), itEnd = myEvolvers.end(); it != itEnd; ++it) { /// for each frontier (except aPtrToCaller) if ( it->get() != aPtrToCaller ) { - SCell s = (*it)->surfel(); - - SCellToIncidentPoints func( myKSpace ); - typename SCellToIncidentPoints::Output points = func( s ); - - if ( (points.first == aPoint)||(points.second == aPoint) ) - { /// if s is adjacent to aPoint - - /// tracking until a new surfel is found - bool flag = true; - typedef typename Evolver::SurfelIterator SurfelIterator; - for ( SurfelIterator sit = (*it)->begin(), - sitEnd = (*it)->end(); - ( (sit != sitEnd)&&(flag) ); ++sit ) - { - SCell newS = *sit; - typename SCellToIncidentPoints::Output newPoints = func( newS ); - if ( (newPoints.first != aPoint) && (newPoints.second != aPoint) ) - {/// if newS is not adjacent to aPoint - - /// update - (*it)->setSurfel( newS ); - flag = false; - trace.info() << s << " moved to " << newS << std::endl; - } - } - ASSERT( flag == false ); - } + (*it)->updateFrontier( aPoint ); } } } From 60d9379c49b6f30112466957816079f8b5c396da Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 24 Apr 2012 17:55:26 +0200 Subject: [PATCH 068/108] displaying 3d partitions --- deformations/deformation3d.cpp | 22 +++---- deformations/deformationDisplay3d.h | 89 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index e141a24..4e7fe1c 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -58,8 +58,8 @@ int main(int argc, char** argv) ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) - ("outputFormat,f", po::value()->default_value("png"), - "Output files format: either (3d to 2d, default) or (3d)" ) + ("outputFormat,f", po::value()->default_value("vol"), + "Output files format: either (3d to 2d) or (3d, default)" ) ("withVisu", "Enables interactive 3d visualization after evolution" ); @@ -151,12 +151,6 @@ int main(int argc, char** argv) //domain Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); - //display - std::stringstream ss; - ss << outputFiles << "0001"; - writeImage( *labelImage, ss.str(), format ); - - //algo std::string algo; if (!(vm.count("algo"))) trace.info() << "default algorithm: levelSet" << std::endl; @@ -199,7 +193,7 @@ int main(int argc, char** argv) //display std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + s << outputFiles << setfill('0') << std::setw(4) << (i/step); writeImage( implicitFunction, s.str(), format ); } @@ -258,7 +252,7 @@ int main(int argc, char** argv) //display std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + s << outputFiles << setfill('0') << std::setw(4) << (i/step); writeImage( implicitFunction, s.str(), format, 0.5 ); } @@ -308,8 +302,10 @@ int main(int argc, char** argv) { //display std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - writeImage( *labelImage, s.str(), format ); + s << outputFiles << setfill('0') << std::setw(4) << (i/step) + << ".vol"; + typedef GradientColorMap ColorMap; + VolWriter::exportVol( s.str(), *labelImage, 0, 255 ); } sumt += tstep; DGtal::trace.info() << "Time spent: " << sumt << std::endl; @@ -318,7 +314,7 @@ int main(int argc, char** argv) DGtal::trace.endBlock(); //interactive display after the evolution - if (vm.count("withVisu")) displayImage( argc, argv, *labelImage ); + if (vm.count("withVisu")) displayPartition( argc, argv, *labelImage ); } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 8790f38..486da4f 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -267,3 +267,92 @@ bool displayImage2(int argc, char** argv, const TLabelImage limg, #endif } +template< typename TImage > +bool displayPartition(int argc, char** argv, const TImage& img) +{ + + typedef typename TImage::Value Label; + + //KhalimskySpace + Domain d = img.domain(); + Point aLowerBound = d.lowerBound(); + Point aUpperBound = d.upperBound(); + KSpace aKSpace; + aKSpace.init(aLowerBound, aUpperBound, true); + + //container + std::set aSet; + + //mark bels + for (DGtal::Dimension k = 0; k < KSpace::dimension; ++k ) + { + Cell dir_low_uid = aKSpace.uSpel( aLowerBound ); + Cell dir_up_uid = aKSpace.uGetDecr( aKSpace.uSpel( aUpperBound ), k); + Cell p = dir_low_uid; + do + { + Label here = img( aKSpace.uCoords(p) ); + Label next = img( aKSpace.uCoords(aKSpace.uGetIncr( p, k )) ); + if ( here != next ) + { // add new bel to the set. + aSet.insert( aKSpace.uIncident( p, k, true )); + } + } + while ( aKSpace.uNext( p, dir_low_uid, dir_up_uid ) ); + } + + #ifdef WITH_VISU3D_QGLVIEWER + QApplication application(argc,argv); + Viewer3D viewer; + viewer.show(); + + GradientColorMap colorMap( 0, 510 ); + colorMap.addColor(Color::Blue); + colorMap.addColor(Color::Yellow); + colorMap.addColor(Color::Red); + colorMap.addColor(Color::Green); + + /// retrieve frontiers + unsigned int counter = 0; + while(!aSet.empty()){ + + SCell sbel = aKSpace.signs( *(aSet.begin()), true ); + //incident points + SCellToIncidentPoints func( aKSpace ); + typename SCellToIncidentPoints::Output points = func( sbel ); + Label iLabel( img( points.first ) ); + Label oLabel( img( points.second ) ); + + /// frontier from sbel + typedef FrontierPredicate SurfelPredicate; + /// !!!!!! be careful oLabel and iLabel are swaped because func is wrong + SurfelPredicate surfelPred( aKSpace, img, oLabel, iLabel ); + typedef LightExplicitDigitalSurface Frontier; + Frontier frontier( aKSpace, + surfelPred, + SurfelAdjacency( true ), + sbel ); + + // tracking (and removing bels belonging to this frontier) + // and display + counter++; + typedef typename Frontier::SurfelConstIterator SurfelIterator; + for ( SurfelIterator it = frontier.begin(), + itEnd = frontier.end(); + it != itEnd; ++it ) + { + viewer << DGtal::CustomColors3D( colorMap( iLabel+oLabel ), + colorMap( iLabel+oLabel ) ); + viewer << *it; + aSet.erase( aKSpace.unsigns( *it ) ); + } + + } + + viewer << Viewer3D::updateDisplay; + + return application.exec(); +#else + return false; +#endif +} From e45f3b866f5aab15f3002bb7a1b44823d365efdb Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Tue, 24 Apr 2012 20:41:44 +0200 Subject: [PATCH 069/108] QGL snapshot --- deformations/deformationDisplay3d.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 486da4f..f30f313 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -349,7 +349,9 @@ bool displayPartition(int argc, char** argv, const TImage& img) } + viewer.setSnapshotFormat("PNG"); viewer << Viewer3D::updateDisplay; + viewer.saveSnapshot(true, true); return application.exec(); #else From e1926afecd1cf2671efcf12bb666e0f79c4123fa Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 25 Apr 2012 08:48:53 +0200 Subject: [PATCH 070/108] try: 3d to 2d with QGL Viewer + cleaning display functions --- deformations/deformation3d.cpp | 23 ++- deformations/deformationDisplay3d.h | 297 ++++++++++++++-------------- deformations/deformationFunctions.h | 32 ++- 3 files changed, 191 insertions(+), 161 deletions(-) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 4e7fe1c..28f2694 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -59,7 +59,7 @@ int main(int argc, char** argv) ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) ("outputFormat,f", po::value()->default_value("vol"), - "Output files format: either (3d to 2d) or (3d, default)" ) + "Output files format: either (3d to 2d with QGLViewer), (3d to 2d with Cairo) or (3d, default)" ) ("withVisu", "Enables interactive 3d visualization after evolution" ); @@ -193,8 +193,9 @@ int main(int argc, char** argv) //display std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step); - writeImage( implicitFunction, s.str(), format ); + s << outputFiles << setfill('0') << std::setw(4) << (i/step); + updateLabelImage( *labelImage, implicitFunction ); + writePartition( *labelImage, s.str(), format ); } sumt += tstep; @@ -204,7 +205,9 @@ int main(int argc, char** argv) DGtal::trace.endBlock(); //interactive display after the evolution - if (vm.count("withVisu")) displayImage2( argc, argv, implicitFunction, implicitFunction, a, b ); + updateLabelImage( *labelImage, implicitFunction, 0 ); + if (vm.count("withVisu")) + displayImageWithInfo( argc, argv, *labelImage, implicitFunction, a, b ); } else if (algo.compare("phaseField")==0) { @@ -253,7 +256,8 @@ int main(int argc, char** argv) //display std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/step); - writeImage( implicitFunction, s.str(), format, 0.5 ); + updateLabelImage( *labelImage, implicitFunction, 0.5 ); + writePartition( *labelImage, s.str(), format ); } sumt += tstep; @@ -263,7 +267,8 @@ int main(int argc, char** argv) DGtal::trace.endBlock(); //interactive display after the evolution - if (vm.count("withVisu")) displayImage( argc, argv, implicitFunction, 0.5 ); + updateLabelImage( *labelImage, implicitFunction, 0.5 ); + if (vm.count("withVisu")) displayPartition( argc, argv, *labelImage ); } else if (algo.compare("localLevelSet")==0) { @@ -302,10 +307,8 @@ int main(int argc, char** argv) { //display std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step) - << ".vol"; - typedef GradientColorMap ColorMap; - VolWriter::exportVol( s.str(), *labelImage, 0, 255 ); + s << outputFiles << setfill('0') << std::setw(4) << (i/step); + writePartition( *labelImage, s.str(), format ); } sumt += tstep; DGtal::trace.info() << "Time spent: " << sumt << std::endl; diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index f30f313..31480dd 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -10,23 +10,116 @@ #include "DGtal/io/colormaps/GradientColorMap.h" #include "DGtal/io/writers/VolWriter.h" +#include "LocalMCM.h" + +#include "DGtal/topology/KhalimskySpaceND.h" +#include "DGtal/topology/helpers/Surfaces.h" +#include "DGtal/base/BasicFunctors.h" +#include "DGtal/kernel/BasicPointPredicates.h" + +// interactive +#include +#include "DGtal/io/viewers/Viewer3D.h" +#include "DGtal/io/CDrawableWithDisplay3D.h" +#include "DGtal/io/DrawWithDisplay3DModifier.h" + + +template< typename TViewer, typename TImage > +bool displayPartition(TViewer& viewer, const TImage& img) +{ + typedef typename TImage::Value Label; + + //KhalimskySpace + Domain d = img.domain(); + Point aLowerBound = d.lowerBound(); + Point aUpperBound = d.upperBound(); + KSpace aKSpace; + aKSpace.init(aLowerBound, aUpperBound, true); + + //container + std::set aSet; + + //mark bels + for (DGtal::Dimension k = 0; k < KSpace::dimension; ++k ) + { + Cell dir_low_uid = aKSpace.uSpel( aLowerBound ); + Cell dir_up_uid = aKSpace.uGetDecr( aKSpace.uSpel( aUpperBound ), k); + Cell p = dir_low_uid; + do + { + Label here = img( aKSpace.uCoords(p) ); + Label next = img( aKSpace.uCoords(aKSpace.uGetIncr( p, k )) ); + if ( here != next ) + { // add new bel to the set. + aSet.insert( aKSpace.uIncident( p, k, true )); + } + } + while ( aKSpace.uNext( p, dir_low_uid, dir_up_uid ) ); + } + + GradientColorMap colorMap( 0, 510 ); + colorMap.addColor(Color::Blue); + colorMap.addColor(Color::Yellow); + colorMap.addColor(Color::Red); + colorMap.addColor(Color::Green); + + /// retrieve frontiers + unsigned int counter = 0; + while(!aSet.empty()){ + + SCell sbel = aKSpace.signs( *(aSet.begin()), true ); + //incident points + SCellToIncidentPoints func( aKSpace ); + typename SCellToIncidentPoints::Output points = func( sbel ); + Label iLabel( img( points.first ) ); + Label oLabel( img( points.second ) ); + + /// frontier from sbel + typedef FrontierPredicate SurfelPredicate; + /// !!!!!! be careful oLabel and iLabel are swaped because func is wrong + SurfelPredicate surfelPred( aKSpace, img, oLabel, iLabel ); + typedef LightExplicitDigitalSurface Frontier; + Frontier frontier( aKSpace, + surfelPred, + SurfelAdjacency( true ), + sbel ); + + // tracking (and removing bels belonging to this frontier) + // and display + counter++; + typedef typename Frontier::SurfelConstIterator SurfelIterator; + for ( SurfelIterator it = frontier.begin(), + itEnd = frontier.end(); + it != itEnd; ++it ) + { + viewer << DGtal::CustomColors3D( colorMap( iLabel+oLabel ), + colorMap( iLabel+oLabel ) ); + viewer << *it; + aSet.erase( aKSpace.unsigns( *it ) ); + } + } + trace.info() << counter << " frontier(s) displayed" << std::endl; + +} + template< typename TImage > -bool writeImage(const TImage& img, string filename, string format, const double& threshold = 0) +bool writePartition(const TImage& img, string filename, string format) { - if (format.compare("png")==0) + if (format.compare("pngc")==0) { #ifdef WITH_CAIRO Board3DTo2D viewer; - Domain d = img.domain(); - Domain::ConstIterator cIt = d.begin(); - Domain::ConstIterator cItEnd = d.end(); - for ( ; cIt != cItEnd; ++cIt) - { - if (img(*cIt) <= threshold) - viewer << *cIt; - } + displayPartition( viewer, img ); + // Domain d = img.domain(); + // Domain::ConstIterator cIt = d.begin(); + // Domain::ConstIterator cItEnd = d.end(); + // for ( ; cIt != cItEnd; ++cIt) + // { + // if (img(*cIt) <= threshold) + // viewer << *cIt; + // } //reading camera configuration for the 3d to 2d projection std::ifstream file(".camera", ios::in); @@ -102,27 +195,29 @@ bool writeImage(const TImage& img, string filename, string format, const double& return false; #endif - } else if (format.compare("vol")==0) - { + } else if (format.compare("png")==0) + { + trace.emphase() << "snapshot with QGLViewer" << std::endl; + + //QApplication application(1,"appli"); + Viewer3D viewer; + viewer.show(); + + displayPartition(viewer, img); + + viewer.setSnapshotFormat("PNG"); + viewer << Viewer3D::updateDisplay; + viewer.saveSnapshot(true, true); - //create a label image from the implicit function - typedef ImageContainerBySTLVector LabelImage; - LabelImage labelImage( img.domain() ); - Domain d(labelImage.domain()); - Domain::ConstIterator cIt = d.begin(); - Domain::ConstIterator cItEnd = d.end(); - for ( ; cIt != cItEnd; ++cIt) - { - if (img(*cIt) <= threshold) - labelImage.setValue(*cIt,255); - else - labelImage.setValue(*cIt,0); } + else if (format.compare("vol")==0) + { + //write it into a vol file std::stringstream s; s << filename << ".vol"; - typedef GradientColorMap ColorMap; - VolWriter::exportVol( s.str(), labelImage, 0, 255 ); + typedef GradientColorMap ColorMap; + VolWriter::exportVol( s.str(), img, 0, 255 ); return true; @@ -131,61 +226,47 @@ bool writeImage(const TImage& img, string filename, string format, const double& } -// interactive -#include -#include "DGtal/io/viewers/Viewer3D.h" -#include "DGtal/io/CDrawableWithDisplay3D.h" -#include "DGtal/images/imagesSetsUtils/SimpleThresholdForegroundPredicate.h" +// template< typename TImage > +// bool displayImage(int argc, char** argv, const TImage& img, const double& threshold = 0) +// { -#include "DGtal/topology/KhalimskySpaceND.h" -#include "DGtal/topology/helpers/Surfaces.h" +// //KhalimskySpace +// Domain d = img.domain(); +// KSpace K; +// K.init(d.lowerBound(), d.upperBound(), true); +// //adjacency +// SurfelAdjacency<3> SAdj( true ); +// std::vector > vectConnectedSCell; +// //predicate +// typedef SimpleThresholdForegroundPredicate PointPredicate; +// PointPredicate predicate(img,threshold); +// //tracking +// Surfaces::extractAllConnectedSCell(vectConnectedSCell,K, SAdj, predicate, true); -template< typename TImage > -bool displayImage(int argc, char** argv, const TImage& img, const double& threshold = 0) -{ - - //KhalimskySpace - Domain d = img.domain(); - KSpace K; - K.init(d.lowerBound(), d.upperBound(), true); - //adjacency - SurfelAdjacency<3> SAdj( true ); - std::vector > vectConnectedSCell; - //predicate - typedef SimpleThresholdForegroundPredicate PointPredicate; - PointPredicate predicate(img,threshold); - //tracking - Surfaces::extractAllConnectedSCell(vectConnectedSCell,K, SAdj, predicate, true); - - #ifdef WITH_VISU3D_QGLVIEWER - QApplication application(argc,argv); - Viewer3D viewer; - viewer.show(); +// #ifdef WITH_VISU3D_QGLVIEWER +// QApplication application(argc,argv); +// Viewer3D viewer; +// viewer.show(); - for(unsigned int i=0; i< vectConnectedSCell.size();i++){ - for(unsigned int j=0; j< vectConnectedSCell.at(i).size();j++){ - viewer << vectConnectedSCell.at(i).at(j); - } - } +// for(unsigned int i=0; i< vectConnectedSCell.size();i++){ +// for(unsigned int j=0; j< vectConnectedSCell.at(i).size();j++){ +// viewer << vectConnectedSCell.at(i).at(j); +// } +// } - viewer << Viewer3D::updateDisplay; - - return application.exec(); -#else - return false; -#endif -} +// viewer << Viewer3D::updateDisplay; +// return application.exec(); +// #else +// return false; +// #endif +// } -#include "LocalMCM.h" -#include "DGtal/base/BasicFunctors.h" -#include "DGtal/kernel/BasicPointPredicates.h" -#include "DGtal/io/DrawWithDisplay3DModifier.h" template< typename TLabelImage, typename TDistanceImage, typename TExternImage > -bool displayImage2(int argc, char** argv, const TLabelImage limg, +bool displayImageWithInfo(int argc, char** argv, const TLabelImage& limg, TDistanceImage& img, const TExternImage& ext1, const TExternImage& ext2, const short int& threshold = 0) @@ -267,87 +348,17 @@ bool displayImage2(int argc, char** argv, const TLabelImage limg, #endif } + template< typename TImage > bool displayPartition(int argc, char** argv, const TImage& img) { - typedef typename TImage::Value Label; - - //KhalimskySpace - Domain d = img.domain(); - Point aLowerBound = d.lowerBound(); - Point aUpperBound = d.upperBound(); - KSpace aKSpace; - aKSpace.init(aLowerBound, aUpperBound, true); - - //container - std::set aSet; - - //mark bels - for (DGtal::Dimension k = 0; k < KSpace::dimension; ++k ) - { - Cell dir_low_uid = aKSpace.uSpel( aLowerBound ); - Cell dir_up_uid = aKSpace.uGetDecr( aKSpace.uSpel( aUpperBound ), k); - Cell p = dir_low_uid; - do - { - Label here = img( aKSpace.uCoords(p) ); - Label next = img( aKSpace.uCoords(aKSpace.uGetIncr( p, k )) ); - if ( here != next ) - { // add new bel to the set. - aSet.insert( aKSpace.uIncident( p, k, true )); - } - } - while ( aKSpace.uNext( p, dir_low_uid, dir_up_uid ) ); - } - #ifdef WITH_VISU3D_QGLVIEWER QApplication application(argc,argv); Viewer3D viewer; viewer.show(); - GradientColorMap colorMap( 0, 510 ); - colorMap.addColor(Color::Blue); - colorMap.addColor(Color::Yellow); - colorMap.addColor(Color::Red); - colorMap.addColor(Color::Green); - - /// retrieve frontiers - unsigned int counter = 0; - while(!aSet.empty()){ - - SCell sbel = aKSpace.signs( *(aSet.begin()), true ); - //incident points - SCellToIncidentPoints func( aKSpace ); - typename SCellToIncidentPoints::Output points = func( sbel ); - Label iLabel( img( points.first ) ); - Label oLabel( img( points.second ) ); - - /// frontier from sbel - typedef FrontierPredicate SurfelPredicate; - /// !!!!!! be careful oLabel and iLabel are swaped because func is wrong - SurfelPredicate surfelPred( aKSpace, img, oLabel, iLabel ); - typedef LightExplicitDigitalSurface Frontier; - Frontier frontier( aKSpace, - surfelPred, - SurfelAdjacency( true ), - sbel ); - - // tracking (and removing bels belonging to this frontier) - // and display - counter++; - typedef typename Frontier::SurfelConstIterator SurfelIterator; - for ( SurfelIterator it = frontier.begin(), - itEnd = frontier.end(); - it != itEnd; ++it ) - { - viewer << DGtal::CustomColors3D( colorMap( iLabel+oLabel ), - colorMap( iLabel+oLabel ) ); - viewer << *it; - aSet.erase( aKSpace.unsigns( *it ) ); - } - - } + displayPartition(viewer, img); viewer.setSnapshotFormat("PNG"); viewer << Viewer3D::updateDisplay; diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index b9cd5b6..7e95588 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -23,20 +23,36 @@ int getSize(TImage& img, const double& threshold = 0) return c; } +template< typename TLabelImage, typename TDistanceImage > +void updateLabelImage(TLabelImage& limg, const TDistanceImage& dimg, const double& threshold = 0) +{ + + typename TLabelImage::Domain d = limg.domain(); + typename TLabelImage::Domain::ConstIterator cIt = d.begin(); + typename TLabelImage::Domain::ConstIterator cItEnd = d.end(); + for ( ; cIt != cItEnd; ++cIt) + { //for each domain point + if (dimg(*cIt) <= threshold) + limg.setValue(*cIt, 255); + else + limg.setValue(*cIt, 0); + } + +} + template< typename TImage > void inv(TImage& img, const double& threshold = 0) { - typename TImage::OutputIterator res = img.outputIterator(); - typename TImage::ConstRange r = img.range(); - typename TImage::ConstRange::ConstIterator cIt = r.begin(); - typename TImage::ConstRange::ConstIterator cItEnd = r.end(); + typename TImage::Domain d = img.domain(); + typename TImage::Domain::ConstIterator cIt = d.begin(); + typename TImage::Domain::ConstIterator cItEnd = d.end(); for ( ; cIt != cItEnd; ++cIt) - { //for each - if (*cIt <= threshold) - *res++ = 1; + { //for each domain point + if (img(*cIt) <= threshold) + img.setValue( *cIt, 1 ); else - *res++ = 0; + img.setValue( *cIt, 0 ); } } From f222fce62867ca7e20ab069617c49687b6420161 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 25 Apr 2012 12:15:33 +0200 Subject: [PATCH 071/108] snapshot with QGL viewer ok --- deformations/deformation3d.cpp | 4 ++-- deformations/deformationDisplay3d.h | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 28f2694..db52794 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -107,9 +107,9 @@ int main(int argc, char** argv) if (!(vm.count("outputFormat"))) trace.info() << "output files format is png (3d to 2d) " << std::endl; format = vm["outputFormat"].as(); - if ((format != "png")&&(format != "vol")) + if ((format != "png")&&(format != "vol")&&(format != "pngc")) { - trace.info() << "format is expected to be either png or vol " << std::endl; + trace.info() << "format is expected to be either , or " << std::endl; return 0; } diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 31480dd..e18bd7c 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -199,16 +199,41 @@ bool writePartition(const TImage& img, string filename, string format) { trace.emphase() << "snapshot with QGLViewer" << std::endl; - //QApplication application(1,"appli"); + int argc = 1; + string sargv1 = "QGLViewer"; + char* argv1 = const_cast( sargv1.c_str() ); + char* argv[1]; + argv[0] = argv1; + QApplication application(argc,argv); Viewer3D viewer; viewer.show(); displayPartition(viewer, img); + //viewer.setStateFileName(".qglviewer.xml"); + if (!viewer.restoreStateFromFile()) + { + string s = viewer.stateFileName().toStdString(); + trace.emphase() << " file " << s + << " not found " + << std::endl; + } + + viewer.setSnapshotFileName(filename.c_str()); viewer.setSnapshotFormat("PNG"); viewer << Viewer3D::updateDisplay; viewer.saveSnapshot(true, true); + //renommage du fichier + string oldf = viewer.stateFileName().toStdString(); + std::stringstream news; + news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)+1) << ".xml"; + string newf = news.str(); + rename (oldf.c_str(), newf.c_str()); + + //viewer.saveStateToFile(); + + application.exit(); } else if (format.compare("vol")==0) { From 8f66eef3f4316b2fc1031b6a7ea07fba953611ff Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 25 Apr 2012 16:52:11 +0200 Subject: [PATCH 072/108] adding an orientation to move the camera in QGL snapshots --- deformations/deformation3d.cpp | 3 ++ deformations/deformationDisplay3d.h | 43 +++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index db52794..a968963 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -151,6 +151,9 @@ int main(int argc, char** argv) //domain Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); + if (vm["outputFormat"].as() == "png") //visu for choosing camera position + displayPartition( argc, argv, *labelImage ); + //algo std::string algo; if (!(vm.count("algo"))) trace.info() << "default algorithm: levelSet" << std::endl; diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index e18bd7c..5037f9d 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -208,9 +208,20 @@ bool writePartition(const TImage& img, string filename, string format) Viewer3D viewer; viewer.show(); + //display displayPartition(viewer, img); - //viewer.setStateFileName(".qglviewer.xml"); + if (QGLViewer::QGLViewerIndex(&viewer) > 0) + {//rename state file + string oldf = ".qglviewer.xml"; + std::stringstream news; + news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)) << ".xml"; + string newf = news.str(); + if (!rename (oldf.c_str(), newf.c_str())) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } + if (!viewer.restoreStateFromFile()) { string s = viewer.stateFileName().toStdString(); @@ -219,20 +230,41 @@ bool writePartition(const TImage& img, string filename, string format) << std::endl; } + const int max = 20; + viewer.camera()->setOrientation((QGLViewer::QGLViewerIndex(&viewer)/max)*2.0*M_PI, 0.0); + viewer.showEntireScene(); //fit camera to scene + viewer.setSnapshotFileName(filename.c_str()); viewer.setSnapshotFormat("PNG"); + viewer << Viewer3D::updateDisplay; viewer.saveSnapshot(true, true); - //renommage du fichier + {//rename snapshot + std::stringstream olds; + olds << viewer.snapshotFileName().toStdString() + << "-" << setfill('0') << std::setw(4) + << (viewer.snapshotCounter()-1) << ".png"; + string oldf = olds.str(); + std::stringstream news; + news << filename << ".png"; + string newf = news.str(); + if (!rename (oldf.c_str(), newf.c_str())) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } + + {//rename state file string oldf = viewer.stateFileName().toStdString(); std::stringstream news; news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)+1) << ".xml"; string newf = news.str(); - rename (oldf.c_str(), newf.c_str()); + if (!rename (oldf.c_str(), newf.c_str())) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } - //viewer.saveStateToFile(); - + viewer.setStateFileName(QString::null); application.exit(); } else if (format.compare("vol")==0) @@ -387,7 +419,6 @@ bool displayPartition(int argc, char** argv, const TImage& img) viewer.setSnapshotFormat("PNG"); viewer << Viewer3D::updateDisplay; - viewer.saveSnapshot(true, true); return application.exec(); #else From c99da24e9115986f1ea11ef9704e3bf8fe72fb24 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Wed, 25 Apr 2012 17:12:38 +0200 Subject: [PATCH 073/108] adding an orientation to move the camera in QGL snapshots (correction) --- deformations/deformationDisplay3d.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 5037f9d..0fc5290 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -230,7 +230,7 @@ bool writePartition(const TImage& img, string filename, string format) << std::endl; } - const int max = 20; + const double max = 20; viewer.camera()->setOrientation((QGLViewer::QGLViewerIndex(&viewer)/max)*2.0*M_PI, 0.0); viewer.showEntireScene(); //fit camera to scene From 9286d2a539d901f5e0dfc87d8e89f091c214f9c5 Mon Sep 17 00:00:00 2001 From: Tristan Roussillon Date: Thu, 26 Apr 2012 13:51:53 +0200 Subject: [PATCH 074/108] improvement of the QGLviewer snapshot mechanism --- deformations/3dVolProjector.cpp | 203 ++++++++++++++++++++++++++ deformations/CMakeLists.txt | 3 + deformations/FrontierEvolver.ih | 2 - deformations/FrontierEvolver2.ih | 2 - deformations/FrontierEvolverHelpers.h | 3 + deformations/deformationDisplay3d.h | 20 +-- deformations/images/partition32.vol | Bin 0 -> 36030 bytes 7 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 deformations/3dVolProjector.cpp create mode 100644 deformations/images/partition32.vol diff --git a/deformations/3dVolProjector.cpp b/deformations/3dVolProjector.cpp new file mode 100644 index 0000000..8ee4d83 --- /dev/null +++ b/deformations/3dVolProjector.cpp @@ -0,0 +1,203 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ +/** + * @file visuDistanceTransform.cpp + * @ingroup Examples + * @author Bertrand Kerautret (\c kerautre@loria.fr ) + * LORIA (CNRS, UMR 7503), University of Nancy, France + * + * @date 2011/01/04 + * + * An example file named qglViewer. + * + * This file is part of the DGtal library. + */ + +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include "DGtal/base/Common.h" +#include "DGtal/io/readers/VolReader.h" +#include "DGtal/io/viewers/Viewer3D.h" +#include "DGtal/io/DrawWithDisplay3DModifier.h" + + +using namespace std; +using namespace DGtal; +using namespace Z3i; + +#include "deformationDisplay3d.h" + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +int displayOneFile(int argc, char** argv, + const string& inputFilename, + const string& outputBasename, + const int& offset = 0, const double& step = 0) +{ + //image reading + typedef ImageSelector::Type Image; + Image image = VolReader::importVol( inputFilename ); + + QApplication application(argc,argv); + Viewer3D viewer; + viewer.show(); + + //display + displayPartition(viewer, image); + + viewer << Viewer3D::updateDisplay; + + if (!viewer.restoreStateFromFile()) + { + string s = viewer.stateFileName().toStdString(); + trace.emphase() << " file " << s + << " not found " + << std::endl; + } + viewer.updateGL(); + + if (offset != 0) + { + viewer.camera()->setOrientation( -(offset*step), 0.0); + viewer.showEntireScene(); + } + + viewer.setSnapshotFileName(outputBasename.c_str()); + viewer.setSnapshotFormat("PNG"); + viewer.saveSnapshot(true, true); + + {//rename snapshot + std::stringstream olds; + olds << viewer.snapshotFileName().toStdString() + << "-" << setfill('0') << std::setw(4) + << (viewer.snapshotCounter()-1) << ".png"; + string oldf = olds.str(); + std::stringstream news; + news << outputBasename << ".png"; + string newf = news.str(); + if (rename (oldf.c_str(), newf.c_str()) == -1) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } + + {//rename state file + string oldf = viewer.stateFileName().toStdString(); + std::stringstream news; + news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)+1) << ".xml"; + string newf = news.str(); + if (rename (oldf.c_str(), newf.c_str()) == -1) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } + + application.exit(); + + return 0; +} + +int main( int argc, char** argv ) +{ + // parse command line ---------------------------------------------- + po::options_description general_opt("Allowed options are: "); + general_opt.add_options() + ("help,h", "display this message") + ("output-file,o", po::value()->default_value("interface"), "output file(s) basename" ) + ("input-file,i", po::value(), "volume file" ) + ("start,s", po::value()->default_value(1), "starting number (for option -mi)" ) + ("end,e", po::value()->default_value(2), "ending number, not included (for option -mi)" ) + ("angle-step,a", po::value()->default_value(360), "angle step as a fraction of 2PI (for option -mi)" ) + ("multi-input,mi", po::value(), "volume files basename " ) ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help")||argc<=1) + { + std::cout << "Usage: " << argv[0] << " [input-file]\n" + << "Display volume file as a set of digital frontiers" + << general_opt << "\n"; + return 0; + } + + //files + if (!(vm.count("output-file"))) + trace.info() << "output file begin with : interface" << std::endl; + string outputBasename = vm["output-file"].as(); + + + if(vm.count("input-file")) + { + if (vm.count("multi-input")) + { + trace.error() << " Cannot use both input options in the same time " + << endl; + return 1; + } + string inputFilename = vm["input-file"].as(); + displayOneFile(argc, argv, inputFilename,outputBasename); + } + else + { + if (vm.count("multi-input")) + { + string inputBasename = vm["multi-input"].as(); + + int start = vm["start"].as(); + int end = vm["end"].as(); + for (int i = start; i != end; ++i) + { + std::stringstream si; + si << inputBasename << setfill('0') << std::setw(4) + << i << ".vol"; + trace.info() << si.str() << std::endl; + std::stringstream so; + so << outputBasename << setfill('0') << std::setw(4) + << i; + + double angleStep = ( (2.0*M_PI)/((double)vm["angle-step"].as()) ); + displayOneFile(argc, argv, si.str(), so.str(), i, angleStep); + + } + + {//rename state file + std::stringstream olds; + olds << ".qglviewer" << (end-start) << ".xml"; + string oldf = olds.str(); + string newf = ".qglviewer.xml"; + if (rename (oldf.c_str(), newf.c_str()) == -1) + trace.info() << "renaming " << oldf << " into " + << newf << " failed " << std::endl; + } + + } + else + { + trace.error() << " No file name defined" << endl; + return 1; + } + } + + + return 0; +} diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 1a4d39a..ff4830c 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -32,6 +32,9 @@ LINK_DIRECTORIES(/usr/lib/) ADD_EXECUTABLE(3dVolViewer 3dVolViewer) TARGET_LINK_LIBRARIES(3dVolViewer ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) +ADD_EXECUTABLE(3dVolProjector 3dVolProjector) +TARGET_LINK_LIBRARIES(3dVolProjector ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) + #ADD_EXECUTABLE(testLocalDeformation3d testLocalDeformation3d) #TARGET_LINK_LIBRARIES(testLocalDeformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) diff --git a/deformations/FrontierEvolver.ih b/deformations/FrontierEvolver.ih index 6b5660d..7cbe2c1 100644 --- a/deformations/FrontierEvolver.ih +++ b/deformations/FrontierEvolver.ih @@ -27,8 +27,6 @@ */ -#define WITHINFO - ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/FrontierEvolver2.ih b/deformations/FrontierEvolver2.ih index b6787c4..1f29120 100644 --- a/deformations/FrontierEvolver2.ih +++ b/deformations/FrontierEvolver2.ih @@ -27,8 +27,6 @@ */ -#define WITHINFO - ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/FrontierEvolverHelpers.h b/deformations/FrontierEvolverHelpers.h index e32ca47..1a0de47 100644 --- a/deformations/FrontierEvolverHelpers.h +++ b/deformations/FrontierEvolverHelpers.h @@ -41,6 +41,9 @@ #include "DGtal/base/Common.h" ////////////////////////////////////////////////////////////////////////////// + +//#define WITHINFO + namespace DGtal { diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 0fc5290..6735528 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -16,6 +16,12 @@ #include "DGtal/topology/helpers/Surfaces.h" #include "DGtal/base/BasicFunctors.h" #include "DGtal/kernel/BasicPointPredicates.h" +// frontier +#include "DGtal/topology/SurfelAdjacency.h" +#include "DGtal/topology/helpers/FrontierPredicate.h" +#include "DGtal/topology/LightExplicitDigitalSurface.h" + + // interactive #include @@ -210,6 +216,7 @@ bool writePartition(const TImage& img, string filename, string format) //display displayPartition(viewer, img); + viewer << Viewer3D::updateDisplay; if (QGLViewer::QGLViewerIndex(&viewer) > 0) {//rename state file @@ -217,7 +224,7 @@ bool writePartition(const TImage& img, string filename, string format) std::stringstream news; news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)) << ".xml"; string newf = news.str(); - if (!rename (oldf.c_str(), newf.c_str())) + if (rename (oldf.c_str(), newf.c_str()) == -1) trace.info() << "renaming " << oldf << " into " << newf << " failed " << std::endl; } @@ -229,15 +236,10 @@ bool writePartition(const TImage& img, string filename, string format) << " not found " << std::endl; } - - const double max = 20; - viewer.camera()->setOrientation((QGLViewer::QGLViewerIndex(&viewer)/max)*2.0*M_PI, 0.0); - viewer.showEntireScene(); //fit camera to scene + viewer.updateGL(); viewer.setSnapshotFileName(filename.c_str()); viewer.setSnapshotFormat("PNG"); - - viewer << Viewer3D::updateDisplay; viewer.saveSnapshot(true, true); {//rename snapshot @@ -249,7 +251,7 @@ bool writePartition(const TImage& img, string filename, string format) std::stringstream news; news << filename << ".png"; string newf = news.str(); - if (!rename (oldf.c_str(), newf.c_str())) + if (rename (oldf.c_str(), newf.c_str()) == -1) trace.info() << "renaming " << oldf << " into " << newf << " failed " << std::endl; } @@ -259,7 +261,7 @@ bool writePartition(const TImage& img, string filename, string format) std::stringstream news; news << ".qglviewer" << (QGLViewer::QGLViewerIndex(&viewer)+1) << ".xml"; string newf = news.str(); - if (!rename (oldf.c_str(), newf.c_str())) + if (rename (oldf.c_str(), newf.c_str()) == -1) trace.info() << "renaming " << oldf << " into " << newf << " failed " << std::endl; } diff --git a/deformations/images/partition32.vol b/deformations/images/partition32.vol new file mode 100644 index 0000000000000000000000000000000000000000..e5d3a17f6261ad10ba8a7f0470718a5af534a8ae GIT binary patch literal 36030 zcmeI0!EPos5QKBiQ{)AL*v&0Bgg9_US^>9}h(x5-1}z*Amppo~XFPUQciEj}NZ8Ep zJ@9+FzNxl*y3NAR*B4h;=f5of{B`-~hr7RTK3)EF`_Ikw#k=$GKK=3g$II{UKHYt} zzWDZh6@U2r+wI5C`T57se_ht6cki#xKiquz^Y$)j@6W$EKbwDM1!e_i1!e`_QUxB~ z(q`vgX9Z>jY6Tu1hSQtm{HNk>vFd%G=zWX*z*)417&yy_JKGG*3LL!xJhybH|i(>$M zJ@`|a`$GY25q&MGr(h{(PoD9Ut3c|A!I|s$b(pGmTtJru>4Gr2Cw2qQz~}CfjXr_RiM+a+Zmzfwh;Y-F1vo!yTRsm z<-94~PtA6N2DcIpE$DlL0X}1jyM0qUtpNAy8-k;XymJe_?=5 zInuF98X&k9%Tqf37)VqIG(u!pL&c-3XW@RRPH|j;+EpE_>SksN4su?4lL#=nvv9g4 zzD6LmEmwj!DY_Z~IXEG(4Q>L#fHqP+B7k(VC|L%;N{oQDG(>Q<9tpJjgSXhsAV&-G zsvsQXr-X1|K4Aq)S78X(wdw5O76^1nkS++Ldm;jyZY^E_xHmT?rw~1ffb41jK*!E) zLC1B~v8KJdu=pE|t#h9dm2!^eYk2B|*9(BEab0;%Pu>Dmn`|K+gfv z0MM~(DnL3A8(?%#M1a$+#RyRU`H^`zYC?t%8GQx7=fFM6O<2HMINcmX=tM|81xq!0 z@+rji)v%qs^#1l}f49*{zgAkFLDxhCkghDA1gOsq1~40Vno599bGHGcBT)dOdm;jy zZY_pD{u@RB)QLb2Yw;?;HkNG@yalld3s?)M8xNrqA@vk2TkOd*zWlXzRE9DeJ!G4$ z^sA8w09{)|0O++LX)6t=I?m<#KMpela$bT-v4{YpI}4{HA$E{?*u`79ABM-w=LrE% zU>TOR@o>7e@Br;Y$thN|bo3d1Oa(euLwU6fSJ$ZM`gTZfRlP?LKm)})fE$1}vl-NG z$O}SNf^;Sp!01GTKt884Ad6SIAH)`T6K!T1O0{|oz~|sCz+`W`w1Bm6y73Tt3T^J( zE`}Y7hMkYksX&^Y(QC`_jgSZ^`a}0~7oh59X38xFa$fS5vqc0L-CDGEY#=9T@wz%m zz*maPke+IR)`in!fIR&BOQdG$=req*3Y70H50&n)+752C*Ec|y1nGh>x+fyQ>DJ;H z0Dg$|MD~lhb6UV!IGw(>En}e}i+Fzt6{IK6_^~PweD0`WK$k5?x*&}1i3o7IwKxV~ zr{A8^41Yef>r+z+ryCEU6Cw2!ENOc3j32E6s@K{XYuB|9t*S0MHiMu`f^FQY+e~aO(Q=AoeqZLS#G1_@JI1y0vewO_}Jl)YIQw0(- vs>9S~1!e`l+6v6s{c1nW+}NzZtiY_mtiY_mtiY_mtiY_mtiY_mfhzDX0m4yl literal 0 HcmV?d00001 From 00be2ed915445979f44b428111e4e061b63b342e Mon Sep 17 00:00:00 2001 From: troussil Date: Thu, 12 Jul 2012 08:40:26 +0200 Subject: [PATCH 075/108] small changes --- deformations/ExplicitReactionEvolver.h | 2 +- deformations/FFT.h | 1 + deformations/WeickertKuhneEvolver.ih | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deformations/ExplicitReactionEvolver.h b/deformations/ExplicitReactionEvolver.h index 1542b08..ad5a291 100644 --- a/deformations/ExplicitReactionEvolver.h +++ b/deformations/ExplicitReactionEvolver.h @@ -45,7 +45,7 @@ #include "DGtal/base/Common.h" #include "DGtal/images/CImage.h" -#include "DGtal/images/DifferentialOperators.h" +#include "DifferentialOperators.h" ////////////////////////////////////////////////////////////////////////////// diff --git a/deformations/FFT.h b/deformations/FFT.h index c31794a..6fc781a 100644 --- a/deformations/FFT.h +++ b/deformations/FFT.h @@ -6,6 +6,7 @@ #include #include +#include namespace DGtal{ diff --git a/deformations/WeickertKuhneEvolver.ih b/deformations/WeickertKuhneEvolver.ih index 2281132..f54fc62 100644 --- a/deformations/WeickertKuhneEvolver.ih +++ b/deformations/WeickertKuhneEvolver.ih @@ -30,7 +30,7 @@ ////////////////////////////////////////////////////////////////////////////// #include -#include "DGtal/images/DifferentialOperators.h" +#include "DifferentialOperators.h" ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// From 88cff8e92e281b9347d2fafba63ce568701238a5 Mon Sep 17 00:00:00 2001 From: troussil Date: Thu, 12 Jul 2012 12:03:38 +0200 Subject: [PATCH 076/108] adding multi phase field --- deformations/MultiPhaseField.h | 231 +++++++++++++++++++++++++++++ deformations/MultiPhaseField.ih | 250 ++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 deformations/MultiPhaseField.h create mode 100644 deformations/MultiPhaseField.ih diff --git a/deformations/MultiPhaseField.h b/deformations/MultiPhaseField.h new file mode 100644 index 0000000..11d7b15 --- /dev/null +++ b/deformations/MultiPhaseField.h @@ -0,0 +1,231 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +#pragma once + +/** + * @file MultiPhaseField.h + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2012/07/12 + * + * Header file for module MultiPhaseField.cpp + * + * This file is part of the DGtal library. + */ + +#if defined(MultiPhaseField_RECURSES) +#error Recursive header files inclusion detected in MultiPhaseField.h +#else // defined(MultiPhaseField_RECURSES) +/** Prevents recursive inclusion of headers. */ +#define MultiPhaseField_RECURSES + +#if !defined MultiPhaseField_h +/** Prevents repeated inclusion of headers. */ +#define MultiPhaseField_h + +////////////////////////////////////////////////////////////////////////////// +// Inclusions +#include + +#include "DGtal/base/Common.h" +#include "DGtal/images/CImage.h" + +#include "DGtal/base/CowPtr.h" +#include "DGtal/base/CountedPtr.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace DGtal +{ + + + ///////////////////////////////////////////////////////////////////////////// + // template class MultiPhaseField + /** + * Description of template class 'MultiPhaseField'

+ * \brief Aim: This class is a way of deforming an image of labels. + * Each region (ie. set of points having a same label) is viewed as + * the set of points having a value greater than 0.5 for a given phase field. + * Each region is evolved through its phase field. + * + * @tparam TLabelImage a model of CImage (storing labels) + * @tparam TFieldImage a model of CImage (storing phase field values) + * @tparam TEvolver a model of phase field evolver + */ + template + class MultiPhaseField + { + + // ----------------------- Types check ----------------------- + + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_STATIC_ASSERT + (( ConceptUtils::SameType< typename TLabelImage::Point, + typename TFieldImage::Point>::value )); + + + // ----------------------- Types ------------------------------ + public: + + /// Image of labels + typedef TLabelImage LabelImage; + typedef typename LabelImage::Value Label; + typedef typename LabelImage::Domain Domain; + typedef typename Domain::Point Point; + + /// Images of phase field values + typedef TFieldImage FieldImage; + typedef CowPtr FieldImagePtr; + + + /// Phase field evolver + typedef TEvolver Evolver; + + // ------------------------- Protected Datas ------------------------------ + protected: + // ------------------------- Private Datas -------------------------------- + private: + + + // ------------------------- References -------------------------------- + /** + * Reference on the image of labels + */ + LabelImage& myLabelImage; + /** + * Constant reference on the evolver + */ + const Evolver& myEvolver; + + + // ------------------------- Data -------------------------------- + /** + * List of smart owning pointers on phase fields + */ + std::vector myFields; + /** + * List of labels + */ + std::vector

+ * \brief Aim: Computes the forward difference at a point. + * + * + * @tparam TFonctor model of CPointFunctor + * @tparam TPointPredicate model of CPointPredicate + * @tparam TOutputValue type of returned value (default TFunctor::Value) + */ + template + class ForwardDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + ForwardDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~ForwardDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class BackwardDifference + /** + * Description of template class 'BackwardDifference'

+ * \brief Aim: Computes the backward difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class BackwardDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + BackwardDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~BackwardDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class CentralDifference + /** + * Description of template class 'CentralDifference'

+ * \brief Aim: Computes the backward difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class CentralDifference + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + CentralDifference( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~CentralDifference() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + + ///////////////////////////////////////////////////////////////////////////// + // template class Difference2 + /** + * Description of template class 'Difference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class Difference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Difference2( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Difference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward difference. + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class NormalizedDifference2 + /** + * Description of template class 'NormalizedDifference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class NormalizedDifference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + NormalizedDifference2( Image& aStartingImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~NormalizedDifference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward difference + * normalized by the inverse of the gradient modulus + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return first derivative along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myU; + + /** + * Grid step + */ + OutputValue myH; + + // ------------------------- Internals -------------------------------- + private: + + /** + * Return the harmonic average of the inverse of @a aV1 and @a aV2 + * + * @param aV1 a first value + * @param aV2 a second value + * @return the average + */ + double average ( const Value& aV1, const Value& aN2 ) const; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class WeightedDifference2 + /** + * Description of template class 'WeightedDifference2'

+ * \brief Aim: Computes the second difference at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TImage type of image + * @tparam TOutputValue type of returned value (default TImage::Value) + */ + template + class WeightedDifference2 + { + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef TOutputValue OutputValue; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + // ----------------------- Standard services ------------------------------ + public: + + + /** + * Constructor. + * + * @param aImage any image + * @param aWImage any image of weights + * @param aGridStep any length (=1 by default) + */ + WeightedDifference2( Image& aImage, Image& aWImage, const OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~WeightedDifference2() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Second forward/backward differences on @a aImage + * weighted by @a aWImage and normalized + * by the inverse of the gradient modulus + * + * @param aPoint the point where the derivative is computed + * @param aDim the axis along which the derivative is computed + * @return second derivative of @a aImage along axis @a aDim at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Dimension& aDim ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Reference on an image + */ + Image& myImage; + /** + * Reference on the weights image + */ + Image& myWImage; + + /** + * Grid step + */ + OutputValue myH; + + // ------------------------- Internals -------------------------------- + private: + + /** + * Return the harmonic average of @a aV1 and @a aV2, + * @a aV1 and @a aV2 being normalized by @a aN1 and @a aN2. + * + * @param aV1 a first value + * @param aN1 any value dividing @a aV1 + * @param aV2 a second value + * @param aN2 any value dividing @a aV2 + * @return the normalized harmonic average of @a aV1 and @a aV2 + */ + double average ( const Value& aV1, const double& aN1, + const Value& aV2, const double& aN2 ) const; + + }; + + /////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // template class Gradient + /** + * Description of template class 'Gradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class Gradient + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TDifference FiniteDifference; + typedef typename FiniteDifference::Dimension Dimension; + static const typename FiniteDifference::Dimension dimension = FiniteDifference::dimension; + typedef typename FiniteDifference::Image Image; + typedef typename FiniteDifference::Point Point; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aD a finite difference operator + */ + Gradient( const FiniteDifference& aD): myD(aD) {} + + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Gradient( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Gradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Finite difference + */ + FiniteDifference myD; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class UpwindGradient + /** + * Description of template class 'UpwindGradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class UpwindGradient + { + + + // ----------------------- Types ------------------------------ + public: + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + UpwindGradient( Image& aStartingImage, + const TOutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~UpwindGradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @param aVector displacement vector of the interface + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, const Vector& aVector ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Forward difference + */ + ForwardDifference myF; + /** + * Backward difference + */ + BackwardDifference myB; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class GodunovGradient + /** + * Description of template class 'GodunovGradient'

+ * \brief Aim: Computes the gradient at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class GodunovGradient + { + + + // ----------------------- Types ------------------------------ + public: + + BOOST_CONCEPT_ASSERT(( CConstImage )); + + // ----------------------- Types ------------------------------ + public: + + typedef TImage Image; + typedef typename Image::Value Value; + + typedef typename Image::Point Point; + typedef typename Image::Vector Vector; + typedef typename Image::Domain Domain; + + typedef typename Image::Dimension Dimension; + static const typename Image::Dimension dimension = Image::dimension; + + typedef DGtal::PointVector OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aStartingImage any image + * @param isPositive flag equal to 'true' if the + * interface moves in the direction of the normal + * and 'false' if it moves in the opposite direction + * (='true' by default) + * @param aGridStep any length (=1 by default) + */ + GodunovGradient( Image& aStartingImage, bool isPositive = true, + const TOutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~GodunovGradient() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + /** + * Gradient + * + * @param aPoint the point where the gradient is computed + * @param isPositive flag equal to 'true' if the + * interface moves in the direction of the normal + * and 'false' if it moves in the opposite direction + * (='true' by default) + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint, bool isPositive ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Forward difference + */ + ForwardDifference myF; + /** + * Backward difference + */ + BackwardDifference myB; + /** + * Flag + */ + bool myIsPositive; + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class Divergence + /** + * Description of template class 'Divergence'

+ * \brief Aim: Computes the divergence at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TDifference type of directionnal differential operator + */ + template + class Divergence + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TDifference FiniteDifference; + typedef typename FiniteDifference::Dimension Dimension; + static const typename FiniteDifference::Dimension dimension = FiniteDifference::dimension; + typedef typename FiniteDifference::Image Image; + typedef typename FiniteDifference::Point Point; + typedef typename FiniteDifference::OutputValue OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aD a finite difference operator + */ + Divergence( const FiniteDifference& aD ): myD(aD) {} + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + Divergence( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep = 1); + + /** + * Destructor. Does nothing. + */ + ~Divergence() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Divergence + * + * @param aPoint the point where the divergence is computed + * @return gradient of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Finite difference + */ + FiniteDifference myD; + + }; + + ///////////////////////////////////////////////////////////////////////////// + // template class GradientModulus + /** + * Description of template class 'GradientModulus'

+ * \brief Aim: Computes the gradient modulus at a point + * of an image. + * + * @code + * @endcode + * + * @tparam TGradient type of gradient + */ + template + class GradientModulus + { + + + // ----------------------- Types ------------------------------ + public: + + typedef TGradient Gradient; + typedef typename Gradient::Dimension Dimension; + static const typename Gradient::Dimension dimension = Gradient::dimension; + typedef typename Gradient::Point Point; + + typedef double OutputValue; + + // ----------------------- Standard services ------------------------------ + public: + + /** + * Constructor. + * + * @param aG any gradient operator + */ + GradientModulus( const Gradient& aG) : myG(aG) {} + + /** + * Constructor. + * + * @param aStartingImage any image of signed values + * @param aGridStep any length (=1 by default) + */ + GradientModulus( typename Gradient::Image& aStartingImage, + const typename Gradient::OutputValue::Component& aGridStep = 1); + + + /** + * Destructor. Does nothing. + */ + ~GradientModulus() {} + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const {return true;} + + /** + * Gradient modulus + * + * @param aPoint the point where the gradient modulus is computed + * @return gradient modulus of @a myU at @ aPoint + */ + OutputValue operator() ( const Point& aPoint ) const; + + // ------------------------- Private Datas -------------------------------- + private: + + /** + * Gradient + */ + Gradient myG; + + }; + + + /////////////////////////////////////////////////////////////////// + + + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "DifferentialOperators.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined DifferentialOperators_h + +#undef DifferentialOperators_RECURSES +#endif // else defined(DifferentialOperators_RECURSES) diff --git a/deformations/DifferentialOperators.ih b/deformations/DifferentialOperators.ih new file mode 100644 index 0000000..8165f86 --- /dev/null +++ b/deformations/DifferentialOperators.ih @@ -0,0 +1,459 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file DifferentialOperators.ih + * @author Tristan Roussillon (\c tristan.roussillon@liris.cnrs.fr ) + * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS, France + * + * @date 2011/12/19 + * + * @brief Implementation of inline methods defined in DifferentialOperators.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// --------------------One-dimensional differential operators ----------------- + +template +inline +DGtal::ForwardDifference +::ForwardDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::ForwardDifference::OutputValue +DGtal::ForwardDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Point next = aPoint; + next[aDim] += 1; + if ( myU.domain().isInside(next) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else + { + Point prev = aPoint; + prev[aDim] -= 1; + if ( myU.domain().isInside(prev) ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + ASSERT( false && "too small image" ) ; + } +} + +template +inline +DGtal::BackwardDifference +::BackwardDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::BackwardDifference::OutputValue +DGtal::BackwardDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Point prev = aPoint; + prev[aDim] -= 1; + + if ( myU.domain().isInside(prev) ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + { + Point next = aPoint; + next[aDim] += 1; + if ( myU.domain().isInside(next) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else + ASSERT( false && "too small image" ) ; + } +} + +template +inline +DGtal::CentralDifference +::CentralDifference( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::CentralDifference::OutputValue +DGtal::CentralDifference:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next[aDim] += 1; + bool nextInside = d.isInside(next); + Point prev = aPoint; + prev[aDim] -= 1; + bool prevInside = d.isInside(prev); + + if (nextInside && prevInside ) + return ( (myU(next) - myU(prev)) / (2*myH) ); + else if ( nextInside && (!prevInside) ) + return ( (myU(next) - myU(aPoint)) / myH ); + else if ( (!nextInside) && prevInside ) + return ( (myU(aPoint) - myU(prev)) / myH ); + else + ASSERT( false && "too small image" ) ; +} + +template +inline +DGtal::Difference2 +::Difference2( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::Difference2::OutputValue +DGtal::Difference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next[aDim] += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous[aDim] -= 1; + bool previousInside = d.isInside(previous); + + if (nextInside && previousInside ) + return ( (myU(next) - 2*myU(aPoint) + myU(previous) ) / (myH*myH) ); + else + return 0; +} + +template +inline +DGtal::NormalizedDifference2 +::NormalizedDifference2( Image& aStartingImage, const OutputValue& aGridStep ) + : myU( aStartingImage ), myH( aGridStep ) +{ +} + +template +inline +typename DGtal::NormalizedDifference2::OutputValue +DGtal::NormalizedDifference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myU.domain(); + Point next = aPoint; + next[aDim] += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous[aDim] -= 1; + bool previousInside = d.isInside(previous); + + typedef Gradient > Gradient; + GradientModulus m( myU ); + double mod = m(aPoint); + + if (nextInside && previousInside ) + { + double nMod = m(next); + double pMod = m(previous); + return ( ( average(nMod,mod)*(myU(next) - myU(aPoint)) ) + - ( average(mod,pMod)*(myU(aPoint) - myU(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!nextInside) && previousInside ) + { + double pMod = m(previous); + return ( ( ( 1 - average(pMod,mod) ) + *(myU(aPoint) - myU(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!previousInside) && nextInside ) + { + double nMod = m(next); + return ( ( ( average(nMod,mod) - 1 ) + *(myU(next) - myU(aPoint)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else + ASSERT( false && "too small image" ) ; +} + +template +inline +double +DGtal::NormalizedDifference2:: +average( const Value& aV1, const Value& aV2 ) const +{ + double som = NumberTraits::castToDouble(aV1 + aV2); + if (som == 0) return 0; + else return 2/som; +} + +template +inline +DGtal::WeightedDifference2 +::WeightedDifference2( Image& aImage, Image& aWImage, const OutputValue& aGridStep ) + : myImage( aImage ), myWImage( aWImage), myH( aGridStep ) +{ + ASSERT(aWImage.domain().lowerBound() == aImage.domain().lowerBound()); + ASSERT(aWImage.domain().upperBound() == aImage.domain().upperBound()); +} + +template +inline +typename DGtal::WeightedDifference2::OutputValue +DGtal::WeightedDifference2:: +operator() (const Point& aPoint, const Dimension& aDim) const +{ + ASSERT( (aDim >= 0) && (aDim < dimension) ); + + Domain d = myImage.domain(); + Point next = aPoint; + next[aDim] += 1; + bool nextInside = d.isInside(next); + Point previous = aPoint; + previous[aDim] -= 1; + bool previousInside = d.isInside(previous); + + typedef Gradient > Gradient; + GradientModulus m( myImage ); + double mod = m(aPoint); + + if (nextInside && previousInside ) + { + double nMod = m(next); + double pMod = m(previous); + return ( ( average(myWImage(next),nMod,myWImage(aPoint),mod) + *(myImage(next) - myImage(aPoint)) ) + - ( average(myWImage(aPoint),mod,myWImage(previous),pMod) + *(myImage(aPoint) - myImage(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!nextInside) && previousInside ) + { + double pMod = m(previous); + return ( ( ( myWImage(aPoint) + - average(myWImage(previous),pMod,myWImage(aPoint),mod) ) + *(myImage(aPoint) - myImage(previous)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else if ( (!previousInside) && nextInside ) + { + double nMod = m(next); + return ( ( ( average(myWImage(next),nMod,myWImage(aPoint),mod) + - myWImage(aPoint) ) + *(myImage(next) - myImage(aPoint)) ) + / NumberTraits::castToDouble(myH*myH) ); + } + else + ASSERT( false && "too small image" ) ; + +} + +template +inline +double +DGtal::WeightedDifference2:: +average( const Value& aV1, const double& aN1, + const Value& aV2, const double& aN2 ) const +{ + ASSERT(aV1 != 0); + ASSERT(aV2 != 0); + double q1 = aN1 / NumberTraits::castToDouble(aV1); + double q2 = aN2 / NumberTraits::castToDouble(aV2); + double sum = q1 + q2; + if (sum == 0) return 0; + else return 2/sum; +} + +/////////////////////////////////////////////////////////////////////////////// +// -------------------- Gradient operators ----------------- + + +template +inline +DGtal::Gradient +::Gradient( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep ) + : myD( FiniteDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::Gradient::OutputValue +DGtal::Gradient:: +operator() (const Point& aPoint) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + g[k] = myD(aPoint,k); + } + return g; +} + + +template +inline +DGtal::UpwindGradient +::UpwindGradient( Image& aStartingImage, const TOutputValue& aGridStep ) + : myF( ForwardDifference( aStartingImage, aGridStep ) ), + myB( BackwardDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::UpwindGradient::OutputValue +DGtal::UpwindGradient:: + operator() (const Point& aPoint, const Vector& aVector) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + if (aVector[k] > 0) + g[k] = myB(aPoint,k); + else if (aVector[k] < 0) + g[k] = myF(aPoint,k); + else //== 0 + g[k] = 0; + } + return g; +} + +template +inline +DGtal::GodunovGradient +::GodunovGradient( Image& aStartingImage, bool isPositive, const TOutputValue& aGridStep ) + : myF( ForwardDifference( aStartingImage, aGridStep ) ), + myB( BackwardDifference( aStartingImage, aGridStep ) ), + myIsPositive( isPositive ) +{ +} + +template +inline +typename DGtal::GodunovGradient::OutputValue +DGtal::GodunovGradient:: + operator() (const Point& aPoint) const +{ + return operator() (aPoint,myIsPositive); +} + +template +inline +typename DGtal::GodunovGradient::OutputValue +DGtal::GodunovGradient:: +operator() (const Point& aPoint, bool isPositive) const +{ + OutputValue g; + for (Dimension k = 0; k < dimension; ++k ) + { + if (isPositive) + { + typename OutputValue::Coordinate a = myB(aPoint,k); + if (a < 0) a = 0; + typename OutputValue::Coordinate b = myF(aPoint,k); + if (b > 0) b = 0; + g[k] = std::sqrt( std::max(a*a,b*b) ); + } + else + { + typename OutputValue::Coordinate a = myB(aPoint,k); + if (a > 0) a = 0; + typename OutputValue::Coordinate b = myF(aPoint,k); + if (b < 0) b = 0; + g[k] = std::sqrt( std::max(a*a,b*b) ); + } + } + return g; +} + + +template +inline +DGtal::GradientModulus +::GradientModulus( typename Gradient::Image& aStartingImage, + const typename Gradient::OutputValue::Component& aGridStep ) + : myG( Gradient( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::GradientModulus::OutputValue +DGtal::GradientModulus:: +operator() (const Point& aPoint) const +{ + typename Gradient::OutputValue g = myG( aPoint ); + return g.norm( Gradient::OutputValue::L_2 ); +} + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Divergence Operator ------------------------------ + + +template +inline +DGtal::Divergence +::Divergence( typename FiniteDifference::Image& aStartingImage, + const typename FiniteDifference::OutputValue& aGridStep ) + : myD( FiniteDifference( aStartingImage, aGridStep ) ) +{ +} + +template +inline +typename DGtal::Divergence::OutputValue +DGtal::Divergence:: +operator() (const Point& aPoint) const +{ + OutputValue sum = 0; + for (Dimension k = 0; k < dimension; ++k ) + { + sum += myD(aPoint,k); + } + return sum; +} diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 1dbffa7..40e7da0 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -82,25 +82,6 @@ void initWithFlower(TImage& img, const typename TImage::Point& c, double r, doub #include "DGtal/geometry/volumes/distance/DistanceTransformation.h" -#include - -template< typename TValue > -TValue aFunction(const TValue& v) -{ - if (v == 0) return 1; - else return 0; -} - -struct Predicate -{ - template< typename TValue > - bool operator()(const TValue& v) - { - if (v == 0) return true; - else return false; - } -}; - template< typename TImage > void initWithDT(const TImage& inputImage, ImageContainerBySTLVector& outputImage) { @@ -134,7 +115,8 @@ void initWithDT(const TImage& inputImage, ImageContainerBySTLVector::OutputIterator out; + typename ImageContainerBySTLVector::Range::Iterator + out = outputImage.range().begin(); for ( typename DT::ConstRange::ConstIterator it = dt.constRange().begin(), itend = dt.constRange().end(); it != itend; ++it) @@ -146,6 +128,7 @@ void initWithDT(const TImage& inputImage, ImageContainerBySTLVector DT; - // DT dt; - // typename DT::OutputImage dtImage = dt.compute ( inputImage ); - - // //inv - // TImage rInputImage(d); - // std::transform(inputImage.begin(), inputImage.end(), - // rInputImage.begin(), aFunction ); - // typename DT::OutputImage rDtImage = dt.compute ( rInputImage ); - - // //deduce the signed distance function - // typename TImage::Domain::ConstIterator cIt = d.begin(); - // typename TImage::Domain::ConstIterator cItEnd = d.end(); - // for ( ; cIt != cItEnd; ++cIt) - // { //for each domain point - - // typedef typename TImage::Point Point; - // Point p( *cIt ); //point p - - // double dist = 0; //signed distance - // if ( dtImage( p ) == 0 ) - // { - // if ( rDtImage( p ) == 0 ) - // { - // std::cerr << "Error init with DT" << std::endl; - // } - // else - // { - // dist = std::sqrt( (double) rDtImage( p ) ) - 0.5; - // } - // } - // else - // { - // dist = - ( std::sqrt( (double) dtImage( p ) ) - 0.5 ); - // } - - // outputImage.setValue(p, (double) dist); - // } } class Profile { From 7f545c77aae2c0cdaa8fa7c0d2dbdd663bf30b56 Mon Sep 17 00:00:00 2001 From: troussil Date: Fri, 19 Apr 2013 16:43:48 +0200 Subject: [PATCH 081/108] evolution with respect to DGtal: vol writer --- deformations/deformation3d.cpp | 1 + deformations/deformationDisplay3d.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 3450760..07eed29 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -13,6 +13,7 @@ namespace po = boost::program_options; #include #include "DGtal/io/readers/VolReader.h" +using namespace DGtal; using namespace Z3i; //evolvers diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index 4f7233e..a6e76b2 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -11,7 +11,7 @@ #include "DGtal/io/writers/VolWriter.h" template< typename TImage > -bool writeImage(const TImage& img, string filename, string format, const double& threshold = 0) +bool writeImage(const TImage& img, std::string filename, std::string format, const double& threshold = 0) { if (format.compare("png")==0) @@ -121,8 +121,8 @@ bool writeImage(const TImage& img, string filename, string format, const double& //write it into a vol file std::stringstream s; s << filename << ".vol"; - typedef GradientColorMap ColorMap; - VolWriter::exportVol( s.str(), labelImage, 0, 255 ); + typedef CastFunctor Fonctor; + VolWriter::exportVol( s.str(), labelImage, Fonctor() ); return true; From 68751446ebcaa3e708af795354e6c904d09eb458 Mon Sep 17 00:00:00 2001 From: troussil Date: Fri, 19 Apr 2013 16:54:38 +0200 Subject: [PATCH 082/108] evolution with respect to DGtal: missing namespaces added --- deformations/imageBlurring.cpp | 8 +++++++- deformations/testDisk.cpp | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/deformations/imageBlurring.cpp b/deformations/imageBlurring.cpp index a5ab975..bcce270 100644 --- a/deformations/imageBlurring.cpp +++ b/deformations/imageBlurring.cpp @@ -1,4 +1,8 @@ ///////////////////// +#include +#include +#include + #include #include @@ -10,13 +14,15 @@ namespace po = boost::program_options; ///////////////////// +using namespace std; +using namespace DGtal; +using namespace Z2i; #include "DGtal/io/readers/PNMReader.h" #include "DGtal/io/Color.h" #include "DGtal/io/colormaps/GradientColorMap.h" #include "DGtal/io/writers/PNMWriter.h" -using namespace Z2i; #include "ExactDiffusionEvolver.h" #include "WeickertKuhneEvolver.h" diff --git a/deformations/testDisk.cpp b/deformations/testDisk.cpp index f3e74cf..57948be 100644 --- a/deformations/testDisk.cpp +++ b/deformations/testDisk.cpp @@ -13,6 +13,7 @@ namespace po = boost::program_options; #include #include "DGtal/io/readers/PNMReader.h" +using namespace DGtal; using namespace Z2i; //evolvers From f81238a7258939df8de28bc4068cf9412ce65ab5 Mon Sep 17 00:00:00 2001 From: troussil Date: Wed, 25 Jun 2014 08:56:05 +0200 Subject: [PATCH 083/108] update from DGtal + row-major order for fftw --- deformations/CMakeLists.txt | 13 +++++-------- deformations/FFT.ih | 10 +++++----- deformations/IFFT.ih | 5 +++-- deformations/deformation2d.cpp | 17 +++++++++++++++-- deformations/deformation3d.cpp | 1 + deformations/deformationDisplay3d.h | 14 +++++++------- deformations/testDisk.cpp | 2 +- 7 files changed, 37 insertions(+), 25 deletions(-) diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 8c9fd0b..c3e45a0 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -13,7 +13,7 @@ LINK_DIRECTORIES(${DGTAL_LIBRARY_DIRS}) #Inclusion de Boost include(FindBoost) find_package(Boost 1.36.0 REQUIRED program_options) -message(STATUS "Found Boost: ${Boost_LIBRARIES} ") +message(STATUS "Found Boost: ${Boost_LIBRARIES} in ${Boost_LIBRARY_DIRS} and ${Boost_INCLUDE_DIRS} ") link_directories(${Boost_LIBRARY_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) @@ -22,17 +22,14 @@ INCLUDE_DIRECTORIES(/usr/include/) LINK_DIRECTORIES(/usr/lib/) ########################################## -ADD_EXECUTABLE(3dVolViewer 3dVolViewer) -TARGET_LINK_LIBRARIES(3dVolViewer ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) - ADD_EXECUTABLE(testDisk testDisk) -TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) +TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) ADD_EXECUTABLE(deformation2d deformation2d) -TARGET_LINK_LIBRARIES(deformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) +TARGET_LINK_LIBRARIES(deformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) ADD_EXECUTABLE(deformation3d deformation3d) -TARGET_LINK_LIBRARIES(deformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) +TARGET_LINK_LIBRARIES(deformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) ADD_EXECUTABLE(imageBlurring imageBlurring) -TARGET_LINK_LIBRARIES(imageBlurring ${DGTAL_LIBRARIES} fftw3) +TARGET_LINK_LIBRARIES(imageBlurring ${DGTAL_LIBRARIES} fftw3 boost_program_options) diff --git a/deformations/FFT.ih b/deformations/FFT.ih index ba6449d..582072c 100644 --- a/deformations/FFT.ih +++ b/deformations/FFT.ih @@ -29,22 +29,21 @@ DGtal::FFT::compute(ComplexImage& anImage) //image size Vector v = myImage.extent(); - int t[dimension]; + int t[dimension]; int n = 1; - for (unsigned int i= 0; i < dimension; ++i) - { + for (int i = dimension - 1; i >= 0; --i) + { //row-major order t[i] = v[i]; n *= t[i]; } -//using fftw library + //using fftw library //input and output arrays fftw_complex* spatial_repr; fftw_complex* frequency_repr; spatial_repr=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*n); frequency_repr=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*n); - //fill the arrays Domain d = myImage.domain(); typename Domain::ConstIterator it = d.begin(); typename Domain::ConstIterator itEnd = d.end(); @@ -52,6 +51,7 @@ DGtal::FFT::compute(ComplexImage& anImage) { spatial_repr[i][0] = (double) myImage(*it); spatial_repr[i][1] = 0.0; + std::cerr << *it << myImage(*it) << std::endl; } //plan diff --git a/deformations/IFFT.ih b/deformations/IFFT.ih index 04c4b4a..581f231 100644 --- a/deformations/IFFT.ih +++ b/deformations/IFFT.ih @@ -33,8 +33,8 @@ DGtal::IFFT::compute(TOutputImage& anImage) Vector v = myImage.extent(); int t[dimension]; int n = 1; - for (unsigned int i= 0; i < dimension; ++i) - { + for (int i = dimension - 1; i >= 0; --i) + { //row-major order t[i] = v[i]; n *= t[i]; } @@ -53,6 +53,7 @@ DGtal::IFFT::compute(TOutputImage& anImage) for(unsigned int i=0; it != itEnd; ++it, ++i) { Value c = myImage(*it); + std::cerr << *it << c << std::endl; frequency_repr[i][0] = real(c); //real part frequency_repr[i][1] = imag(c); //imaginary part } diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index f84ab70..445e016 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -1,5 +1,6 @@ #include #include +#include ///////////////////// #include @@ -15,6 +16,7 @@ namespace po = boost::program_options; using namespace DGtal; using namespace Z2i; +using namespace std; //evolvers //level set @@ -115,7 +117,7 @@ int main(int argc, char** argv) //image and implicit function Point p(0,0); - Point q(dsize,dsize); + Point q(dsize+5,dsize); //ATTENTION Point c(dsize/2,dsize/2); ImageContainerBySTLVector implicitFunction( Domain(p,q) ); //initWithBall( implicitFunction, c, (dsize*3/5)/2 ); @@ -228,11 +230,22 @@ int main(int argc, char** argv) s0 << "iteration # " << i; DGtal::trace.beginBlock( s0.str() ); - e.update( implicitFunction, (tstep*step) ); + // cout << "avant" << endl; + // std::copy( implicitFunction.constRange().begin(), + // implicitFunction.constRange().end(), + // ostream_iterator(std::cout, " ") ); + e.update( implicitFunction, (tstep*step) ); + // cout << "apres" << endl; + // std::copy( implicitFunction.constRange().begin(), + // implicitFunction.constRange().end(), + // ostream_iterator(std::cout, " ") ); std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; drawContour(implicitFunction, s.str(), format, 0.5); + std::stringstream s2; + s2 << outputFiles << "-function" << setfill('0') << std::setw(4) << (i/step)+1; + drawFunction(implicitFunction, s2.str()); DGtal::trace.endBlock(); diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 07eed29..71e07a0 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -15,6 +15,7 @@ namespace po = boost::program_options; using namespace DGtal; using namespace Z3i; +using namespace std; //evolvers //level set diff --git a/deformations/deformationDisplay3d.h b/deformations/deformationDisplay3d.h index a6e76b2..da347fd 100644 --- a/deformations/deformationDisplay3d.h +++ b/deformations/deformationDisplay3d.h @@ -17,7 +17,7 @@ bool writeImage(const TImage& img, std::string filename, std::string format, con if (format.compare("png")==0) { #ifdef WITH_CAIRO - Board3DTo2D viewer; + Board3DTo2D<> viewer; Domain d = img.domain(); Domain::ConstIterator cIt = d.begin(); @@ -86,16 +86,16 @@ bool writeImage(const TImage& img, std::string filename, std::string format, con //default config typename TImage::Vector v = img.extent(); - viewer << CameraPosition(v.at(0)/2, v.at(1)/2, 2*v.at(2)) + viewer << CameraPosition(v[0]/2, v[1]/2, 2*v[2]) << CameraDirection(0, 0, -1) << CameraUpVector(0, 1, 0) - << CameraZNearFar(v.at(2)/2, 3*v.at(2)); + << CameraZNearFar(v[2]/2, 3*v[2]); } - int size = img.extent().at(0); + int size = img.extent()[0]; std::stringstream s; s << filename << ".png"; - viewer.saveCairo(s.str().c_str(),Board3DTo2D::CairoPNG,3*size/2,3*size/2 ); + viewer.saveCairo(s.str().c_str(),Board3DTo2D<>::CairoPNG,3*size/2,3*size/2 ); return true; #else trace.emphase() << "Failed to use Cairo 3d to 2d (not installed)" << std::endl; @@ -160,7 +160,7 @@ bool displayImage(int argc, char** argv, const TImage& img, const double& thresh #ifdef WITH_VISU3D_QGLVIEWER QApplication application(argc,argv); - Viewer3D viewer; + Viewer3D<> viewer; viewer.show(); for(unsigned int i=0; i< vectConnectedSCell.size();i++){ @@ -169,7 +169,7 @@ bool displayImage(int argc, char** argv, const TImage& img, const double& thresh } } - viewer << Viewer3D::updateDisplay; + viewer << Viewer3D<>::updateDisplay; return application.exec(); #else diff --git a/deformations/testDisk.cpp b/deformations/testDisk.cpp index 57948be..ab9df16 100644 --- a/deformations/testDisk.cpp +++ b/deformations/testDisk.cpp @@ -15,7 +15,7 @@ namespace po = boost::program_options; using namespace DGtal; using namespace Z2i; - +using namespace std; //evolvers //level set #include "WeickertKuhneEvolver.h" From 60168425aaef7b4537cbfe4915a3286ab3ea598f Mon Sep 17 00:00:00 2001 From: troussil Date: Wed, 2 Jul 2014 14:45:45 +0200 Subject: [PATCH 084/108] bug fixin diffusion by FFT for non-rectangular images --- deformations/FFT.ih | 7 +- deformations/IFFT.ih | 7 +- deformations/deformation2d.cpp | 35 +- deformations/images/square.pgm | 4100 -------------------------------- 4 files changed, 19 insertions(+), 4130 deletions(-) delete mode 100644 deformations/images/square.pgm diff --git a/deformations/FFT.ih b/deformations/FFT.ih index 582072c..f16aad2 100644 --- a/deformations/FFT.ih +++ b/deformations/FFT.ih @@ -31,10 +31,10 @@ DGtal::FFT::compute(ComplexImage& anImage) Vector v = myImage.extent(); int t[dimension]; int n = 1; - for (int i = dimension - 1; i >= 0; --i) + for (int i = 0; i < dimension; ++i) { //row-major order - t[i] = v[i]; - n *= t[i]; + t[dimension-1-i] = v[i]; + n *= v[i]; } //using fftw library @@ -51,7 +51,6 @@ DGtal::FFT::compute(ComplexImage& anImage) { spatial_repr[i][0] = (double) myImage(*it); spatial_repr[i][1] = 0.0; - std::cerr << *it << myImage(*it) << std::endl; } //plan diff --git a/deformations/IFFT.ih b/deformations/IFFT.ih index 581f231..353fe34 100644 --- a/deformations/IFFT.ih +++ b/deformations/IFFT.ih @@ -33,10 +33,10 @@ DGtal::IFFT::compute(TOutputImage& anImage) Vector v = myImage.extent(); int t[dimension]; int n = 1; - for (int i = dimension - 1; i >= 0; --i) + for (int i = 0; i < dimension; ++i) { //row-major order - t[i] = v[i]; - n *= t[i]; + t[dimension-1-i] = v[i]; + n *= v[i]; } //using fftw library @@ -53,7 +53,6 @@ DGtal::IFFT::compute(TOutputImage& anImage) for(unsigned int i=0; it != itEnd; ++it, ++i) { Value c = myImage(*it); - std::cerr << *it << c << std::endl; frequency_repr[i][0] = real(c); //real part frequency_repr[i][1] = imag(c); //imaginary part } diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index 445e016..29eeb30 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -117,7 +117,7 @@ int main(int argc, char** argv) //image and implicit function Point p(0,0); - Point q(dsize+5,dsize); //ATTENTION + Point q(dsize,dsize); Point c(dsize/2,dsize/2); ImageContainerBySTLVector implicitFunction( Domain(p,q) ); //initWithBall( implicitFunction, c, (dsize*3/5)/2 ); @@ -155,11 +155,11 @@ int main(int argc, char** argv) drawContour(implicitFunction, ss.str(), format); //data functions - ImageContainerBySTLVector a( Domain(p,q) ); + ImageContainerBySTLVector a( implicitFunction.domain() ); std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( Domain(p,q) ); + ImageContainerBySTLVector b( implicitFunction.domain() ); std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( Domain(p,q) ); + ImageContainerBySTLVector g( implicitFunction.domain() ); std::fill(g.begin(),g.end(), 1.0 ); //evolution @@ -223,35 +223,26 @@ int main(int argc, char** argv) Reaction reaction( epsilon, a, k, flagWithCstVol ); LieSplittingEvolver e(diffusion, reaction); - for (unsigned int i = step; i <= max; i += step) + for (unsigned int i = 1; i <= max; ++i) { std::stringstream s0; s0 << "iteration # " << i; DGtal::trace.beginBlock( s0.str() ); - // cout << "avant" << endl; - // std::copy( implicitFunction.constRange().begin(), - // implicitFunction.constRange().end(), - // ostream_iterator(std::cout, " ") ); - e.update( implicitFunction, (tstep*step) ); - // cout << "apres" << endl; - // std::copy( implicitFunction.constRange().begin(), - // implicitFunction.constRange().end(), - // ostream_iterator(std::cout, " ") ); - - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format, 0.5); - std::stringstream s2; - s2 << outputFiles << "-function" << setfill('0') << std::setw(4) << (i/step)+1; - drawFunction(implicitFunction, s2.str()); + e.update( implicitFunction, tstep); + + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format, 0.5); + } DGtal::trace.endBlock(); //area trace.info() << "# area: " << setSize( implicitFunction, 0.5 ) << std::endl; - } } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; diff --git a/deformations/images/square.pgm b/deformations/images/square.pgm deleted file mode 100644 index c9700d5..0000000 --- a/deformations/images/square.pgm +++ /dev/null @@ -1,4100 +0,0 @@ -P2 -# CREATOR: GIMP PNM Filter Version 1.1 -64 64 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -255 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 From 8e39d10b77d51f8ccbb6b2b2d4ed046c54952f17 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Fri, 9 Jan 2015 12:47:29 +0100 Subject: [PATCH 085/108] evolutions with respect to DGtal --- deformations/.gitignore | 2 ++ deformations/3dVolProjector.cpp | 4 +-- deformations/3dVolViewer.cpp | 4 +-- deformations/CMakeLists.txt | 12 +++++--- deformations/DifferentialOperators.h | 16 +++++----- deformations/DifferentialOperators.ih | 33 +++++++++++++------- deformations/ExactDiffusionEvolver.h | 2 +- deformations/ExactReactionEvolver.h | 2 +- deformations/ExplicitReactionEvolver.h | 2 +- deformations/FFT.h | 2 +- deformations/FMM.h | 8 ++--- deformations/FMM.ih | 12 +++++--- deformations/FMMPointFunctors.h | 22 ++++++------- deformations/FrontierEvolver.h | 10 +++--- deformations/FrontierEvolver2.h | 10 +++--- deformations/FrontierEvolverHelpers.h | 2 +- deformations/GrayscaleMapCast.h | 22 +++++++++++++ deformations/IFFT.h | 2 +- deformations/LieSplittingEvolver.h | 4 +-- deformations/LocalBalloonForce.h | 4 +-- deformations/LocalMCM.h | 4 +-- deformations/MultiPhaseField.h | 4 +-- deformations/MultiPhaseField.ih | 28 ++++++++++++----- deformations/PartitionEvolver.h | 6 ++-- deformations/PointPredicates.h | 1 + deformations/SimplePointHelper.h | 3 +- deformations/SimplePointHelper.ih | 2 +- deformations/SimplePointHelperDetails.ih | 26 ++++++++-------- deformations/WeickertKuhneEvolver.h | 2 +- deformations/deformation2d.cpp | 4 +-- deformations/deformationDisplay2d.h | 15 ++++----- deformations/deformationDisplay3d.h | 33 +++++++++++++------- deformations/deformationFunctions.h | 2 ++ deformations/generate3d.cpp | 39 ++++++++++++------------ deformations/imageBlurring.cpp | 12 ++++---- deformations/testDisk.cpp | 2 +- deformations/testLocalDeformation2d.cpp | 4 +-- 37 files changed, 217 insertions(+), 145 deletions(-) create mode 100644 deformations/.gitignore create mode 100644 deformations/GrayscaleMapCast.h diff --git a/deformations/.gitignore b/deformations/.gitignore new file mode 100644 index 0000000..4e002af --- /dev/null +++ b/deformations/.gitignore @@ -0,0 +1,2 @@ +build*/ +**/*.swp diff --git a/deformations/3dVolProjector.cpp b/deformations/3dVolProjector.cpp index 621d402..77070a3 100644 --- a/deformations/3dVolProjector.cpp +++ b/deformations/3dVolProjector.cpp @@ -61,7 +61,7 @@ int displayOneFile(int argc, char** argv, Image image = VolReader::importVol( inputFilename ); QApplication application(argc,argv); - Viewer3D viewer; + Viewer3D<> viewer; viewer.show(); //display @@ -84,7 +84,7 @@ int displayOneFile(int argc, char** argv, } - viewer << Viewer3D::updateDisplay; + viewer << Viewer3D<>::updateDisplay; if (!viewer.restoreStateFromFile()) { diff --git a/deformations/3dVolViewer.cpp b/deformations/3dVolViewer.cpp index 54a00d7..c37f0e5 100644 --- a/deformations/3dVolViewer.cpp +++ b/deformations/3dVolViewer.cpp @@ -84,7 +84,7 @@ int main( int argc, char** argv ) unsigned char transp = vm["transparency"].as(); QApplication application(argc,argv); - Viewer3D viewer; + Viewer3D<> viewer; viewer.setWindowTitle("simple Volume Viewer"); viewer.show(); @@ -109,6 +109,6 @@ int main( int argc, char** argv ) viewer << *it; } } - viewer << Viewer3D::updateDisplay; + viewer << Viewer3D<>::updateDisplay; return application.exec(); } diff --git a/deformations/CMakeLists.txt b/deformations/CMakeLists.txt index 437d449..c83e505 100644 --- a/deformations/CMakeLists.txt +++ b/deformations/CMakeLists.txt @@ -19,6 +19,9 @@ link_directories(${Boost_LIBRARY_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) +# Workaround for strange bug while trying to include boost_program_options +SET(BOOST_LIBRARIES ${BOOST_LIBRARIES} boost_program_options) + #fftw INCLUDE_DIRECTORIES(/usr/include/) LINK_DIRECTORIES(/usr/lib/) @@ -40,13 +43,14 @@ TARGET_LINK_LIBRARIES(generate3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) #TARGET_LINK_LIBRARIES(testLocalDeformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES}) ADD_EXECUTABLE(testDisk testDisk) -TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) +TARGET_LINK_LIBRARIES(testDisk ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) ADD_EXECUTABLE(deformation2d deformation2d) -TARGET_LINK_LIBRARIES(deformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) +TARGET_LINK_LIBRARIES(deformation2d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) ADD_EXECUTABLE(deformation3d deformation3d) -TARGET_LINK_LIBRARIES(deformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3 boost_program_options) +TARGET_LINK_LIBRARIES(deformation3d ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) ADD_EXECUTABLE(imageBlurring imageBlurring) -TARGET_LINK_LIBRARIES(imageBlurring ${DGTAL_LIBRARIES} fftw3 boost_program_options) +TARGET_LINK_LIBRARIES(imageBlurring ${DGTAL_LIBRARIES} ${BOOST_LIBRARIES} fftw3) + diff --git a/deformations/DifferentialOperators.h b/deformations/DifferentialOperators.h index 4804f64..77d3bfa 100644 --- a/deformations/DifferentialOperators.h +++ b/deformations/DifferentialOperators.h @@ -64,7 +64,7 @@ namespace DGtal class ForwardDifference { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -144,7 +144,7 @@ namespace DGtal class BackwardDifference { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -224,7 +224,7 @@ namespace DGtal class CentralDifference { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -305,7 +305,7 @@ namespace DGtal class Difference2 { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -385,7 +385,7 @@ namespace DGtal class NormalizedDifference2 { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -478,7 +478,7 @@ namespace DGtal class WeightedDifference2 { - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -663,7 +663,7 @@ namespace DGtal // ----------------------- Types ------------------------------ public: - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: @@ -746,7 +746,7 @@ namespace DGtal // ----------------------- Types ------------------------------ public: - BOOST_CONCEPT_ASSERT(( CConstImage )); + BOOST_CONCEPT_ASSERT(( concepts::CConstImage )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/DifferentialOperators.ih b/deformations/DifferentialOperators.ih index 8165f86..a8132b5 100644 --- a/deformations/DifferentialOperators.ih +++ b/deformations/DifferentialOperators.ih @@ -29,6 +29,7 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -62,10 +63,12 @@ operator() (const Point& aPoint, const Dimension& aDim) const { Point prev = aPoint; prev[aDim] -= 1; - if ( myU.domain().isInside(prev) ) - return ( (myU(aPoint) - myU(prev)) / myH ); - else - ASSERT( false && "too small image" ) ; + if ( myU.domain().isInside(prev) ) { + return ( (myU(aPoint) - myU(prev)) / myH ); + } else { + ASSERT( false && "too small image" ) ; + throw std::domain_error("too small image"); + } } } @@ -94,10 +97,12 @@ operator() (const Point& aPoint, const Dimension& aDim) const { Point next = aPoint; next[aDim] += 1; - if ( myU.domain().isInside(next) ) - return ( (myU(next) - myU(aPoint)) / myH ); - else - ASSERT( false && "too small image" ) ; + if ( myU.domain().isInside(next) ) { + return ( (myU(next) - myU(aPoint)) / myH ); + } else { + ASSERT( false && "too small image" ) ; + throw std::domain_error("too small image"); + } } } @@ -131,8 +136,10 @@ operator() (const Point& aPoint, const Dimension& aDim) const return ( (myU(next) - myU(aPoint)) / myH ); else if ( (!nextInside) && prevInside ) return ( (myU(aPoint) - myU(prev)) / myH ); - else + else { ASSERT( false && "too small image" ) ; + throw std::domain_error("too small image"); + } } template @@ -215,8 +222,10 @@ operator() (const Point& aPoint, const Dimension& aDim) const *(myU(next) - myU(aPoint)) ) / NumberTraits::castToDouble(myH*myH) ); } - else + else { ASSERT( false && "too small image" ) ; + throw std::domain_error("too small image"); + } } template @@ -286,8 +295,10 @@ operator() (const Point& aPoint, const Dimension& aDim) const *(myImage(next) - myImage(aPoint)) ) / NumberTraits::castToDouble(myH*myH) ); } - else + else { ASSERT( false && "too small image" ) ; + throw std::domain_error("too small image"); + } } diff --git a/deformations/ExactDiffusionEvolver.h b/deformations/ExactDiffusionEvolver.h index 804afa4..72f5cad 100644 --- a/deformations/ExactDiffusionEvolver.h +++ b/deformations/ExactDiffusionEvolver.h @@ -70,7 +70,7 @@ namespace DGtal { //ASSERT - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/ExactReactionEvolver.h b/deformations/ExactReactionEvolver.h index b3ac392..306c05e 100644 --- a/deformations/ExactReactionEvolver.h +++ b/deformations/ExactReactionEvolver.h @@ -65,7 +65,7 @@ namespace DGtal { //ASSERT - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/ExplicitReactionEvolver.h b/deformations/ExplicitReactionEvolver.h index ad5a291..7521261 100644 --- a/deformations/ExplicitReactionEvolver.h +++ b/deformations/ExplicitReactionEvolver.h @@ -68,7 +68,7 @@ namespace DGtal { //ASSERT - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/FFT.h b/deformations/FFT.h index 6fc781a..9e547bf 100644 --- a/deformations/FFT.h +++ b/deformations/FFT.h @@ -21,7 +21,7 @@ namespace DGtal{ { //ASSERT - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/FMM.h b/deformations/FMM.h index 5c201ba..0c92582 100644 --- a/deformations/FMM.h +++ b/deformations/FMM.h @@ -136,10 +136,10 @@ namespace DGtal //concept assert - BOOST_CONCEPT_ASSERT(( CImage )); - BOOST_CONCEPT_ASSERT(( CDigitalSet )); - BOOST_CONCEPT_ASSERT(( CPointPredicate )); - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CPointPredicate )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); typedef TImage Image; typedef TSet AcceptedPointSet; diff --git a/deformations/FMM.ih b/deformations/FMM.ih index ad47272..d69f16c 100644 --- a/deformations/FMM.ih +++ b/deformations/FMM.ih @@ -36,6 +36,8 @@ #include "DGtal/topology/SCellsFunctors.h" +using namespace DGtal::functors; + /////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION of inline methods. /////////////////////////////////////////////////////////////////////////////// @@ -458,12 +460,12 @@ DGtal::FMM::update(const Point& aP Point neighbor = aPoint; for (Dimension k = 0; k < dimension; ++k) { - typename Point::Coordinate c = neighbor.at(k); - neighbor.at(k) = (c+1); + typename Point::Coordinate c = neighbor[k]; + neighbor[k] = (c+1); addNewCandidate(neighbor); - neighbor.at(k) = (c-1); + neighbor[k] = (c-1); addNewCandidate(neighbor); - neighbor.at(k) = c; + neighbor[k] = c; } } @@ -504,4 +506,4 @@ DGtal::operator<< ( std::ostream & out, // // /////////////////////////////////////////////////////////////////////////////// - +/* vim: set ts=2 sw=2 : */ diff --git a/deformations/FMMPointFunctors.h b/deformations/FMMPointFunctors.h index 2029052..cbcc0d4 100644 --- a/deformations/FMMPointFunctors.h +++ b/deformations/FMMPointFunctors.h @@ -112,13 +112,13 @@ namespace DGtal /// image - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef TImage Image; typedef typename Image::Point Point; typedef typename Image::Value Value; /// set - BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); typedef TSet Set; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); @@ -241,13 +241,13 @@ namespace DGtal /// image - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef TImage Image; typedef typename Image::Point Point; typedef typename Image::Value Value; /// set - BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); typedef TSet Set; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); @@ -369,13 +369,13 @@ namespace DGtal /// image - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef TImage Image; typedef typename Image::Point Point; typedef typename Image::Value Value; /// set - BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); typedef TSet Set; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); @@ -484,13 +484,13 @@ namespace DGtal /// image - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef TImage Image; typedef typename Image::Point Point; typedef typename Image::Value Value; /// set - BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); typedef TSet Set; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); @@ -716,17 +716,17 @@ namespace DGtal /// image - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef TDistanceImage DistanceImage; typedef typename DistanceImage::Point Point; typedef typename DistanceImage::Value DistanceValue; - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); typedef TSpeedFunctor SpeedFunctor; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename SpeedFunctor::Point >::value )); typedef typename SpeedFunctor::Value Value; /// set - BOOST_CONCEPT_ASSERT(( CDigitalSet )); + BOOST_CONCEPT_ASSERT(( concepts::CDigitalSet )); typedef TSet Set; BOOST_STATIC_ASSERT(( boost::is_same< Point, typename TSet::Point >::value )); diff --git a/deformations/FrontierEvolver.h b/deformations/FrontierEvolver.h index fd238ed..30eb6c7 100644 --- a/deformations/FrontierEvolver.h +++ b/deformations/FrontierEvolver.h @@ -48,7 +48,7 @@ #include "DGtal/kernel/CPointPredicate.h" //predicates -#include "DGtal/base/BasicBoolFunctions.h" +#include "DGtal/base/BasicBoolFunctors.h" #include "DGtal/kernel/BasicPointPredicates.h" #include "PointPredicates.h" @@ -108,8 +108,8 @@ namespace DGtal { - BOOST_CONCEPT_ASSERT(( CImage )); - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TLabelImage::Point>::value )); @@ -117,12 +117,12 @@ namespace DGtal (( ConceptUtils::SameType< typename TKSpace::Point, typename TDistanceImage::Point>::value )); - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TFunctor::Point>::value )); - // BOOST_CONCEPT_ASSERT(( CPointPredicate )); + // BOOST_CONCEPT_ASSERT(( concepts::CPointPredicate )); // BOOST_STATIC_ASSERT // (( ConceptUtils::SameType< typename TKSpace::Point, // typename TTopoPredicate::Point>::value )); diff --git a/deformations/FrontierEvolver2.h b/deformations/FrontierEvolver2.h index 3ca1673..45e3285 100644 --- a/deformations/FrontierEvolver2.h +++ b/deformations/FrontierEvolver2.h @@ -48,7 +48,7 @@ #include "DGtal/kernel/CPointPredicate.h" //predicates -#include "DGtal/base/BasicBoolFunctions.h" +#include "DGtal/base/BasicBoolFunctors.h" #include "DGtal/kernel/BasicPointPredicates.h" #include "PointPredicates.h" @@ -112,8 +112,8 @@ namespace DGtal { - BOOST_CONCEPT_ASSERT(( CImage )); - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TLabelImage::Point>::value )); @@ -121,12 +121,12 @@ namespace DGtal (( ConceptUtils::SameType< typename TKSpace::Point, typename TDistanceImage::Point>::value )); - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TFunctor::Point>::value )); - // BOOST_CONCEPT_ASSERT(( CPointPredicate )); + // BOOST_CONCEPT_ASSERT(( concepts::CPointPredicate )); // BOOST_STATIC_ASSERT // (( ConceptUtils::SameType< typename TKSpace::Point, // typename TTopoPredicate::Point>::value )); diff --git a/deformations/FrontierEvolverHelpers.h b/deformations/FrontierEvolverHelpers.h index 1a0de47..e0a6d22 100644 --- a/deformations/FrontierEvolverHelpers.h +++ b/deformations/FrontierEvolverHelpers.h @@ -80,7 +80,7 @@ struct SetFromImageDomainValueTraits< struct SetFromImageSelector { public: - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); typedef typename I::Domain Domain; typedef typename I::Value Value; diff --git a/deformations/GrayscaleMapCast.h b/deformations/GrayscaleMapCast.h new file mode 100644 index 0000000..ba3a375 --- /dev/null +++ b/deformations/GrayscaleMapCast.h @@ -0,0 +1,22 @@ +#ifndef DIGITALSNOW_DEFORMATIONS_GRAYSCALEMAPCAST_HPP +#define DIGITALSNOW_DEFORMATIONS_GRAYSCALEMAPCAST_HPP + +// Grayscale map returning value casted to specified type +template +class GrayscaleMapCast +{ +public: + GrayscaleMapCast() : m_min(0), m_max(255) {} + GrayscaleMapCast(T min_value, T max_value) : m_min(min_value), m_max(max_value) {} + + inline + unsigned char operator() (T value) const + { + return static_cast( (255*(value - m_min)) / (m_max - m_min) ); + } + +private: + T m_min, m_max; +}; + +#endif // DIGITALSNOW_DEFORMATIONS_GRAYSCALEMAPCAST_HPP diff --git a/deformations/IFFT.h b/deformations/IFFT.h index e1960f4..da3b308 100644 --- a/deformations/IFFT.h +++ b/deformations/IFFT.h @@ -20,7 +20,7 @@ namespace DGtal{ { //ASSERT - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT((boost::is_same< typename TImage::Value, std::complex >::value)); diff --git a/deformations/LieSplittingEvolver.h b/deformations/LieSplittingEvolver.h index de0135f..5cd40da 100644 --- a/deformations/LieSplittingEvolver.h +++ b/deformations/LieSplittingEvolver.h @@ -71,8 +71,8 @@ namespace DGtal //concepts to write //ASSERT - //BOOST_CONCEPT_ASSERT(( CImplicitEvolver )); - //BOOST_CONCEPT_ASSERT(( CImplicitEvolver )); + //BOOST_CONCEPT_ASSERT(( concepts::CImplicitEvolver )); + //BOOST_CONCEPT_ASSERT(( concepts::CImplicitEvolver )); // ----------------------- Types ------------------------------ public: diff --git a/deformations/LocalBalloonForce.h b/deformations/LocalBalloonForce.h index 623dae3..77e8354 100644 --- a/deformations/LocalBalloonForce.h +++ b/deformations/LocalBalloonForce.h @@ -67,8 +67,8 @@ namespace DGtal typedef TFunction PointFunctor; typedef TExternField ExternField; - BOOST_CONCEPT_ASSERT(( CPointFunctor )); - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename PointFunctor::Point, typename ExternField::Point>::value )); diff --git a/deformations/LocalMCM.h b/deformations/LocalMCM.h index c3b94a4..d68d77c 100644 --- a/deformations/LocalMCM.h +++ b/deformations/LocalMCM.h @@ -69,8 +69,8 @@ namespace DGtal typedef TFunction PointFunctor; typedef TExternField ExternField; - BOOST_CONCEPT_ASSERT(( CPointFunctor )); - BOOST_CONCEPT_ASSERT(( CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); + BOOST_CONCEPT_ASSERT(( concepts::CPointFunctor )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename PointFunctor::Point, typename ExternField::Point>::value )); diff --git a/deformations/MultiPhaseField.h b/deformations/MultiPhaseField.h index 21d369a..cd77994 100644 --- a/deformations/MultiPhaseField.h +++ b/deformations/MultiPhaseField.h @@ -79,8 +79,8 @@ namespace DGtal // ----------------------- Types check ----------------------- - BOOST_CONCEPT_ASSERT(( CImage )); - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TLabelImage::Point, typename TFieldImage::Point>::value )); diff --git a/deformations/MultiPhaseField.ih b/deformations/MultiPhaseField.ih index 7b86b20..d1ae827 100644 --- a/deformations/MultiPhaseField.ih +++ b/deformations/MultiPhaseField.ih @@ -26,7 +26,7 @@ * This file is part of the DGtal library. */ - +#include ////////////////////////////////////////////////////////////////////////////// @@ -206,12 +206,24 @@ DGtal::MultiPhaseField copy2.setValue( *cIt, 1 ); } - //DT computation - typedef DistanceTransformation DT; - DT dt; - typename DT::OutputImage dtImage = dt.compute ( copy1 ); - typename DT::OutputImage rDtImage = dt.compute ( copy2 ); - + // Distance transformation + // Old code was: + // typedef DistanceTransformation DT; + // DT dt; + // typename DT::OutputImage dtImage = dt.compute ( copy1 ); + // typename DT::OutputImage rDtImage = dt.compute ( copy2 ); + // + // I suppose that 2 means L2Metric (with the correct Z#i-namespace in scope), + // and that 0 value is used as threshold for the predicate. + typedef typename DGtal::functors::SimpleThresholdForegroundPredicate PointPredicate; + typedef typename DGtal::DistanceTransformation DT; + + PointPredicate copy1Predicate( copy1, 0 ); + PointPredicate copy2Predicate( copy2, 0 ); + + DT dtImage( copy1.domain(), copy1Predicate, l2Metric ); + DT rDtImage( copy2.domain(), copy2Predicate, l2Metric ); + //deduce the signed distance function for (cIt = cItBegin; cIt != cItEnd; ++cIt) { //for each domain point @@ -252,4 +264,6 @@ DGtal::operator<< ( std::ostream & out, // // /////////////////////////////////////////////////////////////////////////////// +/* vim: set tabstop=2 shiftwidth=2 : */ + diff --git a/deformations/PartitionEvolver.h b/deformations/PartitionEvolver.h index e40a59c..53b1abf 100644 --- a/deformations/PartitionEvolver.h +++ b/deformations/PartitionEvolver.h @@ -85,8 +85,8 @@ namespace DGtal { - BOOST_CONCEPT_ASSERT(( CImage )); - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TLabelImage::Point>::value )); @@ -94,7 +94,7 @@ namespace DGtal (( ConceptUtils::SameType< typename TKSpace::Point, typename TDistanceImage::Point>::value )); - BOOST_CONCEPT_ASSERT(( CImage )); + BOOST_CONCEPT_ASSERT(( concepts::CImage )); BOOST_STATIC_ASSERT (( ConceptUtils::SameType< typename TKSpace::Point, typename TExternImage::Point>::value )); diff --git a/deformations/PointPredicates.h b/deformations/PointPredicates.h index 0210425..fc220e4 100644 --- a/deformations/PointPredicates.h +++ b/deformations/PointPredicates.h @@ -133,6 +133,7 @@ ::operator=( const CascadingPointPredicate& other ) myPred1 = other.myPred1; myPred2 = other.myPred2; } + return *this; } //------------------------------------------------------------------------------ template diff --git a/deformations/SimplePointHelper.h b/deformations/SimplePointHelper.h index ea2a5b9..3a42f05 100644 --- a/deformations/SimplePointHelper.h +++ b/deformations/SimplePointHelper.h @@ -119,6 +119,7 @@ namespace DGtal typedef TImage LabelsImage; typedef typename TImage::Value Label; + // Why is this concept not in DGtal::concepts namespace ? BOOST_CONCEPT_ASSERT ((CLabel

+ * @brief Aim: + * + * @see http://www.vtk.org/VTK/img/file-formats.pdf + */ + template + class VTKWriter; + + template + class VTKWriter< HyperRectDomain > + { + // ----------------------- Standard services ------------------------------ + public: + + typedef HyperRectDomain Domain; + + /** + * Constructor + * + * @param filename name of the file ... + * @param domain domain of the datas to be exported. + */ + VTKWriter(std::string const& filename, Domain domain); + + /** + * Destructor + */ + ~VTKWriter(); + + /** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ + bool isValid() const; + + /** + * Write the VTK header. + * + * It is automatically done at the first data export + * @return a reference to the writer instance + */ + VTKWriter & init() throw(DGtal::IOException); + + + /** + * Set the name of the next field + * + * @param fieldname the name of the next field. + * @return a reference to the writer instance. + */ + VTKWriter & operator<< ( std::string const& fieldname ); + VTKWriter & operator<< ( const char* fieldname ); + + /** + * Write a field + * + * @tparam TImage type of the image. + * @param field the image. + * @return a reference to the writer instance. + * + * @todo enable only if TImage is a model a concepts::CImage !! + */ + template + VTKWriter & operator<< ( TImage const& field ) throw(DGtal::IOException); + + /** + * Write a field, given his name and optionally specifying export type + * @tparam TImage type of the image. + * @tparam T type of values. + * @return a reference to the write instance. + */ + template < + typename TImage, + typename T = typename TImage::Value + > + VTKWriter & write( std::string const& fieldname, TImage const& field ) throw(DGtal::IOException); + + + /** + * Close the file + */ + void close(); + + // ------------------------- Protected Datas ------------------------------ + protected: + // ------------------------- Private Datas -------------------------------- + private: + Domain m_domain; + std::string m_fieldname; + std::ofstream m_fstream; + bool m_header; + + // ------------------------- Hidden services ------------------------------ + protected: + + /** + * Constructor. + * Forbidden by default (protected to avoid g++ warnings). + */ + VTKWriter(); + + private: + + /** + * Copy constructor. + * @param other the object to clone. + * Forbidden by default. + */ + VTKWriter ( const VTKWriter & other ); + + /** + * Assignment. + * @param other the object to copy. + * @return a reference on 'this'. + * Forbidden by default. + */ + VTKWriter & operator= ( const VTKWriter & other ); + + // ------------------------- Internals ------------------------------------ + private: + + }; // end of class VTKWriter + +} // namespace DGtal + + +/////////////////////////////////////////////////////////////////////////////// +// Includes inline functions. +#include "VTKWriter.ih" + +// // +/////////////////////////////////////////////////////////////////////////////// + +#endif // !defined VTKWriter_h + +#undef VTKWriter_RECURSES +#endif // else defined(VTKWriter_RECURSES) + +/* GNU coding style */ +/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ + diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih new file mode 100644 index 0000000..b083bf6 --- /dev/null +++ b/deformations/VTKWriter.ih @@ -0,0 +1,263 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file VTKWriter.ih + * @author Roland Denis (\c roland.denis@univ-savoie.fr ) + * LAboratory of MAthematics - LAMA (CNRS, UMR 5127), University of Savoie, France + * + * @date 2015/01/22 + * + * Implementation of inline methods defined in VTKWriter.h + * + * This file is part of the DGtal library. + */ + + +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// -------------------------- Some Tools -------------------------- + + +//! Type info for VTK (name and dimension) +template +struct VTKType; + +template <> +struct VTKType +{ + static inline + std::string name() + { + return "double"; + } + + static inline constexpr + size_t dim() + { + return 1; + } + + template + static inline + std::string format(TValue const& value) + { + std::stringstream ss; + ss.imbue(std::locale()); + ss << static_cast(value); + return ss.str(); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION of inline methods. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// ----------------------- Standard services ------------------------------ + +/** + * Constructor. + */ +template +inline +DGtal::VTKWriter< HyperRectDomain >:: +VTKWriter( std::string const& filename, HyperRectDomain domain ) + : m_domain(domain), m_fieldname(""), + m_fstream( filename+".vtk", std::ofstream::out ), m_header(false) +{} + +/** + * Destructor. + */ +template +inline +DGtal::VTKWriter< HyperRectDomain >:: +~VTKWriter() +{ + close(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Interface - public : + +/** + * Checks the validity/consistency of the object. + * @return 'true' if the object is valid, 'false' otherwise. + */ +template +inline +bool +DGtal::VTKWriter< HyperRectDomain >:: +isValid() const +{ + return m_fstream.good(); +} + +/** + * Write the VTK header + */ +template +DGtal::VTKWriter< HyperRectDomain > & +DGtal::VTKWriter< HyperRectDomain >:: +init() + throw(DGtal::IOException) +{ + if ( !m_header ) + { + const typename Domain::Vector dimensions = + m_domain.upperBound() - m_domain.lowerBound() + Domain::Point::diagonal(1); + + try + { + m_fstream << "# vtk DataFile Version 2.0\n"; + m_fstream << "Exported with DGtal\n"; + m_fstream << "ASCII\n"; + m_fstream << "DATASET STRUCTURED_POINTS\n"; + m_fstream << "DIMENSIONS " + << ( (Domain::dimension >= 1) ? dimensions(0) : 1 ) << " " + << ( (Domain::dimension >= 2) ? dimensions(1) : 1 ) << " " + << ( (Domain::dimension >= 3) ? dimensions(2) : 1 ) + << "\n"; + m_fstream << "ORIGIN 0 0 0\n"; + m_fstream << "SPACING 1 1 1\n"; + m_fstream << "POINT_DATA " << m_domain.size() << "\n"; + } + catch( ... ) + { + throw DGtal::IOException(); + } + + m_header = true; + } + + return *this; +} + +/** + * Set the name of the next field + */ +template +inline +DGtal::VTKWriter< HyperRectDomain > & +DGtal::VTKWriter< HyperRectDomain >:: +operator<< ( std::string const& fieldname ) +{ + m_fieldname = fieldname; + return *this; +} + +template +inline +DGtal::VTKWriter< HyperRectDomain > & +DGtal::VTKWriter< HyperRectDomain >:: +operator<< ( const char* fieldname ) +{ + m_fieldname = fieldname; + return *this; +} + +/** + * Write a field + */ +template +template +DGtal::VTKWriter< HyperRectDomain > & +DGtal::VTKWriter< HyperRectDomain >:: +operator<< ( TImage const& field ) + throw(DGtal::IOException) +{ + return write( m_fieldname, field ); +} + +/** + * Write a field, given his name + */ +template +template < + typename TImage, + typename T +> +DGtal::VTKWriter< HyperRectDomain > & +DGtal::VTKWriter< HyperRectDomain >:: +write ( std::string const& fieldname, TImage const& field ) + throw(DGtal::IOException) +{ + BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage) ); + + // Write header is not already done + init(); + + // Dimension permutation + const std::vector dim = { 0, 1, 2}; + + try + { + // Field header + m_fstream << "SCALARS " << fieldname << " " << VTKType::name() << " " << VTKType::dim() << "\n"; + m_fstream << "LOOKUP_TABLE default\n"; + + // Export + //for ( auto it = m_domain.range(dim).begin(); it != m_domain.range(dim).end(); ++it ) + for ( auto const& pt : m_domain.subRange(dim) ) + { + m_fstream << VTKType::format(field(pt)) << "\n"; + } + + m_fstream << "\n"; + } + catch( ... ) + { + throw DGtal::IOException(); + } + + return *this; +} + +/* + * Close the file + */ +template +void +DGtal::VTKWriter< HyperRectDomain >:: +close() +{ + m_fstream.close(); +} + + +// // +/////////////////////////////////////////////////////////////////////////////// + +/* GNU coding style */ +/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ + diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 1a32802..65aed25 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -38,6 +38,7 @@ using namespace std; #include "deformationFunctions.h" #include "deformationDisplay3d.h" #include "DGtal/io/readers/VolReader.h" +#include "VTKWriter.h" // Qt #include @@ -278,6 +279,8 @@ int main(int argc, char** argv) s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); updateLabelImage( *labelImage, implicitFunction, 0.5 ); writePartition( *labelImage, s.str(), outputFormat ); + //VTKWriter vtk(s.str(), implicitFunction.domain()); + //vtk << "phi" << implicitFunction; } sumt += tstep; From 89e6f172b960517f56af3bd2e5bc17f7390aa802 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Fri, 23 Jan 2015 14:48:29 +0100 Subject: [PATCH 100/108] VTKWrite: concept based overloading for operator<< --- deformations/VTKWriter.h | 6 +++++- deformations/VTKWriter.ih | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/deformations/VTKWriter.h b/deformations/VTKWriter.h index 01092ec..36f3690 100644 --- a/deformations/VTKWriter.h +++ b/deformations/VTKWriter.h @@ -42,6 +42,8 @@ #include #include +#include + #include #include ////////////////////////////////////////////////////////////////////////////// @@ -115,7 +117,9 @@ namespace DGtal * @todo enable only if TImage is a model a concepts::CImage !! */ template - VTKWriter & operator<< ( TImage const& field ) throw(DGtal::IOException); + BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), + ( VTKWriter > & )) + operator<< ( TImage const& field ) throw(DGtal::IOException); /** * Write a field, given his name and optionally specifying export type diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index b083bf6..1576a90 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -191,7 +191,8 @@ operator<< ( const char* fieldname ) */ template template -DGtal::VTKWriter< HyperRectDomain > & +BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), +( DGtal::VTKWriter< HyperRectDomain > & )) DGtal::VTKWriter< HyperRectDomain >:: operator<< ( TImage const& field ) throw(DGtal::IOException) @@ -214,7 +215,7 @@ write ( std::string const& fieldname, TImage const& field ) { BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage) ); - // Write header is not already done + // Write header if not already done init(); // Dimension permutation @@ -227,7 +228,6 @@ write ( std::string const& fieldname, TImage const& field ) m_fstream << "LOOKUP_TABLE default\n"; // Export - //for ( auto it = m_domain.range(dim).begin(); it != m_domain.range(dim).end(); ++it ) for ( auto const& pt : m_domain.subRange(dim) ) { m_fstream << VTKType::format(field(pt)) << "\n"; From b476ee58d097faf6b153f29d1807192c3abd348d Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Fri, 23 Jan 2015 15:01:14 +0100 Subject: [PATCH 101/108] Adding .ih syntax highlighting in GitHub --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5cc6475 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.ih linguist-language=C++ From 1d0446295af0db62c31350c483cb1a34115678d5 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Fri, 23 Jan 2015 19:06:41 +0100 Subject: [PATCH 102/108] Adding support for binary VTK legacy format It is now the default format, as the write speed is faster. VTK files seems to be in Little Endian by default. TODO: support for VTK XML format (so the endianness can be specified). --- deformations/VTKWriter.h | 53 +++++++++--- deformations/VTKWriter.ih | 169 +++++++++++++++++++++++++++++--------- 2 files changed, 171 insertions(+), 51 deletions(-) diff --git a/deformations/VTKWriter.h b/deformations/VTKWriter.h index 36f3690..b49bfd6 100644 --- a/deformations/VTKWriter.h +++ b/deformations/VTKWriter.h @@ -54,16 +54,21 @@ namespace DGtal ///////////////////////////////////////////////////////////////////////////// // template class VTKWriter /** - * Description of template class 'VTKWriter'

- * @brief Aim: + * VTK writer for DGtal Images + * + * @tparam TDomain Type of the domain used for export + * @tparam Binary 'true' for BINARY format, 'false' for ASCII format * * @see http://www.vtk.org/VTK/img/file-formats.pdf */ - template + template < + typename TDomain, + bool Binary = true + > class VTKWriter; - template - class VTKWriter< HyperRectDomain > + template + class VTKWriter< HyperRectDomain, Binary > { // ----------------------- Standard services ------------------------------ public: @@ -95,7 +100,7 @@ namespace DGtal * It is automatically done at the first data export * @return a reference to the writer instance */ - VTKWriter & init() throw(DGtal::IOException); + VTKWriter & init(); /** @@ -104,8 +109,8 @@ namespace DGtal * @param fieldname the name of the next field. * @return a reference to the writer instance. */ - VTKWriter & operator<< ( std::string const& fieldname ); - VTKWriter & operator<< ( const char* fieldname ); + VTKWriter & operator<< ( std::string const& fieldname ); + VTKWriter & operator<< ( const char* fieldname ); /** * Write a field @@ -118,11 +123,16 @@ namespace DGtal */ template BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), - ( VTKWriter > & )) - operator<< ( TImage const& field ) throw(DGtal::IOException); + ( VTKWriter,Binary> & )) + operator<< ( TImage const& field ); /** - * Write a field, given his name and optionally specifying export type + * Write a field, given his name and optionally specifying export type. + * + * By specifying T template, it is possible to cast values to a specified + * type before export. For example, it can export double values as float, + * to save disk space. + * * @tparam TImage type of the image. * @tparam T type of values. * @return a reference to the write instance. @@ -131,7 +141,7 @@ namespace DGtal typename TImage, typename T = typename TImage::Value > - VTKWriter & write( std::string const& fieldname, TImage const& field ) throw(DGtal::IOException); + VTKWriter & write( std::string const& fieldname, TImage const& field ); /** @@ -177,6 +187,25 @@ namespace DGtal // ------------------------- Internals ------------------------------------ private: + /** + * Internal data stream + */ + struct DataStream + { + DataStream( std::ofstream & fstream ); + + std::string data_format(); + + template + DataStream& operator<< (TValue const& value); + + void separator(); + + std::ofstream & m_fstream; + }; + + DataStream m_dataStream; + }; // end of class VTKWriter } // namespace DGtal diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index 1576a90..998d98c 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -46,6 +46,8 @@ ////////////////////////////////////////////////////////////////////////////// // -------------------------- Some Tools -------------------------- +// Local namespace +namespace { //! Type info for VTK (name and dimension) template @@ -55,28 +57,81 @@ template <> struct VTKType { static inline - std::string name() + std::string name() { return "double"; } + + static inline constexpr + size_t dim() { return 1; } + + template < typename TStream, typename TValue > + static inline + void write( TStream & stream, TValue const& value ) { - return "double"; + stream << static_cast(value); } +}; + +template <> +struct VTKType +{ + static inline + std::string name() { return "float"; } static inline constexpr - size_t dim() + size_t dim() { return 1; } + + template < typename TStream, typename TValue > + static inline + void write( TStream & stream, TValue const& value ) { - return 1; + stream << static_cast(value); } +}; - template +//! VTK Stream writer +template +struct VTKDataWriter; + +//! VTK Stream writer for ASCII format +template <> +struct VTKDataWriter +{ static inline - std::string format(TValue const& value) + std::string separator() { return "\n"; } + + template < typename TStream, typename TValue > + static inline + void write( TStream & stream, TValue const& value ) { - std::stringstream ss; - ss.imbue(std::locale()); - ss << static_cast(value); - return ss.str(); + stream << value << " "; } + + static inline + std::string data_format() { return "ASCII"; } }; +//! VTK Stream writer for BINARY format +template <> +struct VTKDataWriter +{ + static inline + std::string separator() { return ""; } + + template < typename TStream, typename TValue > + static inline + void write( TStream & stream, TValue const& value ) + { + //stream.write( reinterpret_cast(&value), sizeof value ); + // *@#! endianness + const char* raw = reinterpret_cast(&value); + for (size_t i = sizeof(TValue); i > 0; --i) + stream.put(raw[i-1]); + } + + static inline + std::string data_format() { return "BINARY"; } +}; + +} // namespace /////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION of inline methods. @@ -88,20 +143,22 @@ struct VTKType /** * Constructor. */ -template +template inline -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary >:: VTKWriter( std::string const& filename, HyperRectDomain domain ) : m_domain(domain), m_fieldname(""), - m_fstream( filename+".vtk", std::ofstream::out ), m_header(false) + m_fstream( filename+".vtk", std::ofstream::out | std::ofstream::binary ), + m_header(false), + m_dataStream(m_fstream) {} /** * Destructor. */ -template +template inline -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary >:: ~VTKWriter() { close(); @@ -114,10 +171,10 @@ DGtal::VTKWriter< HyperRectDomain >:: * Checks the validity/consistency of the object. * @return 'true' if the object is valid, 'false' otherwise. */ -template +template inline bool -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary >:: isValid() const { return m_fstream.good(); @@ -126,11 +183,10 @@ isValid() const /** * Write the VTK header */ -template -DGtal::VTKWriter< HyperRectDomain > & -DGtal::VTKWriter< HyperRectDomain >:: +template +DGtal::VTKWriter< HyperRectDomain, Binary > & +DGtal::VTKWriter< HyperRectDomain, Binary >:: init() - throw(DGtal::IOException) { if ( !m_header ) { @@ -141,7 +197,7 @@ init() { m_fstream << "# vtk DataFile Version 2.0\n"; m_fstream << "Exported with DGtal\n"; - m_fstream << "ASCII\n"; + m_fstream << m_dataStream.data_format() << "\n"; m_fstream << "DATASET STRUCTURED_POINTS\n"; m_fstream << "DIMENSIONS " << ( (Domain::dimension >= 1) ? dimensions(0) : 1 ) << " " @@ -166,20 +222,20 @@ init() /** * Set the name of the next field */ -template +template inline -DGtal::VTKWriter< HyperRectDomain > & -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary > & +DGtal::VTKWriter< HyperRectDomain, Binary >:: operator<< ( std::string const& fieldname ) { m_fieldname = fieldname; return *this; } -template +template inline -DGtal::VTKWriter< HyperRectDomain > & -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary > & +DGtal::VTKWriter< HyperRectDomain, Binary >:: operator<< ( const char* fieldname ) { m_fieldname = fieldname; @@ -189,13 +245,12 @@ operator<< ( const char* fieldname ) /** * Write a field */ -template +template template BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), -( DGtal::VTKWriter< HyperRectDomain > & )) -DGtal::VTKWriter< HyperRectDomain >:: +( DGtal::VTKWriter< HyperRectDomain, Binary > & )) +DGtal::VTKWriter< HyperRectDomain, Binary >:: operator<< ( TImage const& field ) - throw(DGtal::IOException) { return write( m_fieldname, field ); } @@ -203,15 +258,14 @@ operator<< ( TImage const& field ) /** * Write a field, given his name */ -template +template template < typename TImage, typename T > -DGtal::VTKWriter< HyperRectDomain > & -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary > & +DGtal::VTKWriter< HyperRectDomain, Binary >:: write ( std::string const& fieldname, TImage const& field ) - throw(DGtal::IOException) { BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage) ); @@ -230,7 +284,8 @@ write ( std::string const& fieldname, TImage const& field ) // Export for ( auto const& pt : m_domain.subRange(dim) ) { - m_fstream << VTKType::format(field(pt)) << "\n"; + VTKType::write( m_dataStream, field(pt) ); + m_dataStream.separator(); } m_fstream << "\n"; @@ -246,14 +301,50 @@ write ( std::string const& fieldname, TImage const& field ) /* * Close the file */ -template +template void -DGtal::VTKWriter< HyperRectDomain >:: +DGtal::VTKWriter< HyperRectDomain, Binary >:: close() { m_fstream.close(); } +/** + * Internale data stream + */ +template +DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +DataStream( std::ofstream & fstream ) + : m_fstream(fstream) +{ + m_fstream.imbue(std::locale()); // Dot separator for decimal numbers +} + +template +template +typename DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream & +DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +operator<< ( TValue const& value ) +{ + VTKDataWriter::write( m_fstream, value ); + return *this; +} + +template +std::string +DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +data_format() +{ + return VTKDataWriter::data_format(); +} + +template +void +DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +separator() +{ + m_fstream << VTKDataWriter::separator(); +} // // /////////////////////////////////////////////////////////////////////////////// From b97b053ded2afb317f7c42311a9b4d4cbf612f72 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Tue, 27 Jan 2015 11:42:37 +0100 Subject: [PATCH 103/108] Adding VTK export for multi phase-field. The current workaround was to add a phase-accessor to the MultiPhaseField evolver. The export in deformation3d.cpp need to cleaned. --- deformations/MultiPhaseField.h | 14 ++++++++++- deformations/MultiPhaseField.ih | 24 ++++++++++++++++++ deformations/deformation3d.cpp | 38 ++++++++++++++++++++++++++--- deformations/deformationFunctions.h | 3 ++- 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/deformations/MultiPhaseField.h b/deformations/MultiPhaseField.h index cd77994..c2d51f2 100644 --- a/deformations/MultiPhaseField.h +++ b/deformations/MultiPhaseField.h @@ -41,6 +41,7 @@ ////////////////////////////////////////////////////////////////////////////// // Inclusions #include +#include #include "DGtal/base/Common.h" #include "DGtal/images/CImage.h" @@ -176,8 +177,15 @@ namespace DGtal */ void selfDisplay ( std::ostream & out ) const; + /** + * Return the number of phases. + */ + size_t getNumPhase() const; - + /** + * Return one of the phase fields + */ + FieldImage const& getPhase( size_t i ) const; // ------------------------- Hidden services ------------------------------ protected: @@ -242,3 +250,7 @@ namespace DGtal #undef MultiPhaseField_RECURSES #endif // else defined(MultiPhaseField_RECURSES) + +/* GNU coding style */ +/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ + diff --git a/deformations/MultiPhaseField.ih b/deformations/MultiPhaseField.ih index 54e012c..61d4777 100644 --- a/deformations/MultiPhaseField.ih +++ b/deformations/MultiPhaseField.ih @@ -270,6 +270,30 @@ DGtal::MultiPhaseField } +/** + * Return the number of phases + */ +template +inline +size_t +DGtal::MultiPhaseField +::getNumPhase() const +{ + return myFields.size(); +} + +/** + * Return one of the phase fields + */ +template +inline +typename DGtal::MultiPhaseField::FieldImage const& +DGtal::MultiPhaseField +::getPhase( size_t i ) const +{ + return *(myFields[i]); +} + /////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions // diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 65aed25..2783950 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -250,7 +250,7 @@ int main(int argc, char** argv) ImageContainerBySTLVector > Reaction; ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); - std::fill(a.begin(), a.end(), 1.0 ); + std::fill(a.begin(), a.end(), 0.0 ); Reaction reaction( epsilon, a, balloon, flagWithCstVol ); // Lie splitting @@ -263,6 +263,13 @@ int main(int argc, char** argv) s << outputFiles << setfill('0') << std::setw(4) << 0; writePartition( *labelImage, s.str(), outputFormat ); + // VTK export + { + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; + } + + // Time integration double sumt = 0; for (unsigned int i = 1; i <= max_step; ++i) @@ -278,9 +285,12 @@ int main(int argc, char** argv) std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); updateLabelImage( *labelImage, implicitFunction, 0.5 ); + writePartition( *labelImage, s.str(), outputFormat ); - //VTKWriter vtk(s.str(), implicitFunction.domain()); - //vtk << "phi" << implicitFunction; + + // VTK export + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; } sumt += tstep; @@ -330,7 +340,7 @@ int main(int argc, char** argv) ImageContainerBySTLVector > Reaction; ImageContainerBySTLVector a( d ); - std::fill(a.begin(), a.end(), 1.0 ); + std::fill(a.begin(), a.end(), 0.0 ); Reaction reaction( epsilon, a, balloon, flagWithCstVol ); // Lie splitting @@ -345,6 +355,16 @@ int main(int argc, char** argv) std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << 0; writePartition( *labelImage, s.str(), outputFormat ); + // VTK export + { + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } + } // Time integration double sumt = 0; @@ -360,7 +380,17 @@ int main(int argc, char** argv) { std::stringstream s; s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + writePartition( *labelImage, s.str(), outputFormat ); + + // VTK export + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } } diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 2f01da0..07f8d83 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -287,7 +287,8 @@ class Profile { Profile (const double& anEpsilon) : myEpsilon( anEpsilon ) {} double operator()( const double& v ) { - return 0.5 - 0.5*std::tanh(-v/(2*myEpsilon)); + //return 0.5 - 0.5*std::tanh(-v/(2*myEpsilon)); + return 0.5 - 0.5*std::tanh(-v/myEpsilon); } }; From faddb12b0f258acf1f7229d19b3eef2276e33dd4 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Tue, 27 Jan 2015 17:10:18 +0100 Subject: [PATCH 104/108] Merging 2D & 3D code. The dimension is fixed by a preprocessor macro. The two versions are very similar and differs mainly for the IO part. The VTKWriter works the same, regardless of the dimension. --- deformations/VTKWriter.ih | 14 +- deformations/deformation2d.cpp | 396 +----------------- deformations/deformation2d.old.cpp | 394 ++++++++++++++++++ deformations/deformation3d.cpp | 490 +--------------------- deformations/deformation3d.old.cpp | 489 ++++++++++++++++++++++ deformations/deformationFunctions.h | 15 + deformations/deformationNd.cpp | 609 ++++++++++++++++++++++++++++ 7 files changed, 1519 insertions(+), 888 deletions(-) create mode 100644 deformations/deformation2d.old.cpp create mode 100644 deformations/deformation3d.old.cpp create mode 100644 deformations/deformationNd.cpp diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index 998d98c..00f613a 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -273,9 +273,11 @@ write ( std::string const& fieldname, TImage const& field ) init(); // Dimension permutation - const std::vector dim = { 0, 1, 2}; + std::vector dim; + for (size_t i = 0; i < Domain::dimension; ++i) + dim.push_back(i); - try + //try { // Field header m_fstream << "SCALARS " << fieldname << " " << VTKType::name() << " " << VTKType::dim() << "\n"; @@ -290,10 +292,10 @@ write ( std::string const& fieldname, TImage const& field ) m_fstream << "\n"; } - catch( ... ) - { - throw DGtal::IOException(); - } + //catch( ... ) + // { + // throw DGtal::IOException(); + // } return *this; } diff --git a/deformations/deformation2d.cpp b/deformations/deformation2d.cpp index dc12388..93e6159 100644 --- a/deformations/deformation2d.cpp +++ b/deformations/deformation2d.cpp @@ -1,394 +1,2 @@ -#include -#include -#include - -///////////////////// -#include -#include -#include - -namespace po = boost::program_options; - -///////////////////// -#include -#include -#include "DGtal/io/readers/PGMReader.h" - -using namespace DGtal; -using namespace Z2i; -using namespace std; - -//evolvers -//level set -#include "WeickertKuhneEvolver.h" - -//phase field -#include "ExactDiffusionEvolver.h" -#include "ExplicitReactionEvolver.h" -#include "ExactReactionEvolver.h" -#include "LieSplittingEvolver.h" -#include "MultiPhaseField.h" - -//local level set -#include "BinaryPredicates.h" -#include "SimplePointHelper.h" -#include "PartitionEvolver.h" - - - -/////////////////////////// useful functions -#include "deformationFunctions.h" -#include "deformationDisplay2d.h" - - -/////////////////////////////////////////////////////////////////// -int main(int argc, char** argv) -{ - - DGtal::trace.info() << "2d interface evolution using DGtal "; - DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; - - // parse command line ---------------------------------------------- - po::options_description general_opt("Allowed options are"); - general_opt.add_options() - ("help,h", "display this message") - ("inputImage,i", po::value(), "Binary image to initialize the starting interface (.pgm)" ) - ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) - ("shape,s", po::value()->default_value("ball"), - "Generated shape: either (default) or " ) - ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) - ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) - ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) - ("algo,a", po::value()->default_value("levelSet"), - "can be: \n \n or \n or \n or " ) - ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) - ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) - ("withCstVol", "with volume conservation (only for phase fields)" ) - ("withFunction", po::value(), "Output pgm file basename, where the starting implicit function is stored" ) - ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) - ("outputFormat,f", po::value()->default_value("raster"), - "Output files format: either (image, default) or (domain representation)" ); - - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, general_opt), vm); - po::notify(vm); - if(vm.count("help")||argc<=1) - { - trace.info()<< "Evolution of a 2d interface" << std::endl - << "Basic usage: "< -n " << std::endl - << general_opt << "\n"; - return 0; - } - - //Parse options - //domain size - int dsize; - if (!(vm.count("domainSize"))) trace.info() << "Domain size default value: 64" << std::endl; - dsize = vm["domainSize"].as(); - - //time step - double tstep; - if (!(vm.count("timeStep"))) trace.info() << "time step default value: 1.0" << std::endl; - tstep = vm["timeStep"].as(); - - //iterations - int step; - if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; - step = vm["displayStep"].as(); - int max; - if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; - max = vm["stepsNumber"].as(); - - //files - std::string outputFiles; - if (!(vm.count("outputFiles"))) - trace.info() << "output files beginning with : interface" << std::endl; - outputFiles = vm["outputFiles"].as(); - - //files format - std::string format; - if (!(vm.count("outputFormat"))) - trace.info() << "output files format is 'vector' " << std::endl; - format = vm["outputFormat"].as(); - if ((format != "vector")&&(format != "raster")) - { - trace.info() << "format is expected to be either vector, or raster " << std::endl; - return 0; - } - - //image and implicit function - typedef ImageContainerBySTLVector LabelImage; - LabelImage* labelImage = NULL; - - if (vm.count("inputImage")) - { - string imageFileName = vm["inputImage"].as(); - trace.emphase() << imageFileName <::importPGM( imageFileName ); - labelImage = new LabelImage( tmp ); - DGtal::trace.endBlock(); - - std::stringstream ss; - ss << outputFiles << "0000"; - drawContours(*labelImage, ss.str(), format); - - } - else - { - DGtal::trace.beginBlock("image reading..."); - Point p(0,0); - Point q(dsize,dsize); - Point c(dsize/2,dsize/2); - labelImage = new LabelImage( Domain(p,q) ); - if (vm.count("shape")) - { - if ( (vm["shape"].as()) == "flower" ) - initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - } - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - trace.info() << "starting interface initialized with a " - << (vm["shape"].as()) << std::endl; - DGtal::trace.endBlock(); - } - - //domain - Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); - - - //algo - std::string algo; - if (!(vm.count("algo"))) trace.info() << "default algorithm: levelSet" << std::endl; - algo = vm["algo"].as(); - - if (algo.compare("levelSet")==0) - { - - //balloon force - double k; - if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; - k = vm["balloonForce"].as(); - - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - if (vm.count("withFunction")) - drawFunction( implicitFunction, vm["withFunction"].as() ); - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format); - - //data functions - ImageContainerBySTLVector a( implicitFunction.domain() ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( implicitFunction.domain() ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( implicitFunction.domain() ); - std::fill(g.begin(),g.end(), 1.0 ); - - //evolution - WeickertKuhneEvolver > e(a,b,g,k,1); - - DGtal::trace.beginBlock( "Deformation (Weickert level set method)" ); - - for (unsigned int i = 1; i <= max; ++i) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( implicitFunction, tstep); - - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format); - } - - //area - trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; - } - - DGtal::trace.endBlock(); - - } else if (algo.compare("phaseField")==0) - { - - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } - - bool flagWithCstVol = false; - if (vm.count("withCstVol")) - flagWithCstVol = true; - - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - //computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - - if (vm.count("withFunction")) - drawFunction( implicitFunction, vm["withFunction"].as() ); - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format, 0.5); - - - - typedef ExactDiffusionEvolver > Diffusion; - typedef ExactReactionEvolver > Reaction; - Diffusion diffusion; - Reaction reaction( epsilon ); - // typedef ExplicitReactionEvolver, - // ImageContainerBySTLVector > Reaction; - // ImageContainerBySTLVector a( implicitFunction.domain() ); - // std::fill(a.begin(),a.end(), 1 ); - // Diffusion diffusion; - // Reaction reaction( epsilon, a, k, flagWithCstVol ); - LieSplittingEvolver e(diffusion, reaction); - - DGtal::trace.beginBlock( "Deformation (phase field)" ); - - for (unsigned int i = 1; i <= max; ++i) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( implicitFunction, tstep); - - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format, 0.5); - } - - //area - trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; - - } - - DGtal::trace.endBlock(); - } else if (algo.compare("localLevelSet")==0) - { - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContours(*labelImage, ss.str(), format); - - //space - KSpace ks; - ks.init( d.lowerBound(), d.upperBound(), true ); - - //distance image... - typedef ImageContainerBySTLVector DistanceImage; - //and extern data... - DistanceImage g( d ); - std::fill(g.begin(), g.end(), 1.0); - - // topological predicate - // typedef TrueBinaryPredicate TopologicalPredicate; - // TopologicalPredicate topologicalPredicate; - typedef SimplePointHelper TopologicalPredicate; - TopologicalPredicate topologicalPredicate(*labelImage); - - //frontier evolver - DGtal::trace.beginBlock( "Partition construction" ); - PartitionEvolver - e(ks, *labelImage, g, topologicalPredicate); - - DGtal::trace.info() << e << std::endl; - DGtal::trace.endBlock(); - - DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); - - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - //update - e.update(tstep); - - if ((i%step)==0) - { - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContours(*labelImage, s.str(), format); - } - sumt += tstep; - } - - DGtal::trace.endBlock(); - - } else if (algo.compare("multiPhaseField")==0) - { - - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContours(*labelImage, ss.str(), format); - - typedef ImageContainerBySTLVector FieldImage; - typedef ExactDiffusionEvolver Diffusion; - typedef ExactReactionEvolver Reaction; - Diffusion diffusion; - Reaction reaction( epsilon ); - LieSplittingEvolver phaseField(diffusion, reaction); - MultiPhaseField > e(*labelImage, phaseField); - - DGtal::trace.beginBlock( "Deformation (multi phase field)" ); - - for (unsigned int i = step; i <= max; i += step) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( tstep ); - - if ((i%step)==0) - { - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContours(*labelImage, s.str(), format); - } - - } - - DGtal::trace.endBlock(); - } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; - - - DGtal::trace.info() << "end" << std::endl; - - //free - delete( labelImage ); - - return 1; -} - +#define DIMENSION 2 +#include "deformationNd.cpp" diff --git a/deformations/deformation2d.old.cpp b/deformations/deformation2d.old.cpp new file mode 100644 index 0000000..dc12388 --- /dev/null +++ b/deformations/deformation2d.old.cpp @@ -0,0 +1,394 @@ +#include +#include +#include + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +///////////////////// +#include +#include +#include "DGtal/io/readers/PGMReader.h" + +using namespace DGtal; +using namespace Z2i; +using namespace std; + +//evolvers +//level set +#include "WeickertKuhneEvolver.h" + +//phase field +#include "ExactDiffusionEvolver.h" +#include "ExplicitReactionEvolver.h" +#include "ExactReactionEvolver.h" +#include "LieSplittingEvolver.h" +#include "MultiPhaseField.h" + +//local level set +#include "BinaryPredicates.h" +#include "SimplePointHelper.h" +#include "PartitionEvolver.h" + + + +/////////////////////////// useful functions +#include "deformationFunctions.h" +#include "deformationDisplay2d.h" + + +/////////////////////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + DGtal::trace.info() << "2d interface evolution using DGtal "; + DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; + + // parse command line ---------------------------------------------- + po::options_description general_opt("Allowed options are"); + general_opt.add_options() + ("help,h", "display this message") + ("inputImage,i", po::value(), "Binary image to initialize the starting interface (.pgm)" ) + ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) + ("shape,s", po::value()->default_value("ball"), + "Generated shape: either (default) or " ) + ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) + ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) + ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) + ("algo,a", po::value()->default_value("levelSet"), + "can be: \n \n or \n or \n or " ) + ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) + ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) + ("withCstVol", "with volume conservation (only for phase fields)" ) + ("withFunction", po::value(), "Output pgm file basename, where the starting implicit function is stored" ) + ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) + ("outputFormat,f", po::value()->default_value("raster"), + "Output files format: either (image, default) or (domain representation)" ); + + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help")||argc<=1) + { + trace.info()<< "Evolution of a 2d interface" << std::endl + << "Basic usage: "< -n " << std::endl + << general_opt << "\n"; + return 0; + } + + //Parse options + //domain size + int dsize; + if (!(vm.count("domainSize"))) trace.info() << "Domain size default value: 64" << std::endl; + dsize = vm["domainSize"].as(); + + //time step + double tstep; + if (!(vm.count("timeStep"))) trace.info() << "time step default value: 1.0" << std::endl; + tstep = vm["timeStep"].as(); + + //iterations + int step; + if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; + step = vm["displayStep"].as(); + int max; + if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; + max = vm["stepsNumber"].as(); + + //files + std::string outputFiles; + if (!(vm.count("outputFiles"))) + trace.info() << "output files beginning with : interface" << std::endl; + outputFiles = vm["outputFiles"].as(); + + //files format + std::string format; + if (!(vm.count("outputFormat"))) + trace.info() << "output files format is 'vector' " << std::endl; + format = vm["outputFormat"].as(); + if ((format != "vector")&&(format != "raster")) + { + trace.info() << "format is expected to be either vector, or raster " << std::endl; + return 0; + } + + //image and implicit function + typedef ImageContainerBySTLVector LabelImage; + LabelImage* labelImage = NULL; + + if (vm.count("inputImage")) + { + string imageFileName = vm["inputImage"].as(); + trace.emphase() << imageFileName <::importPGM( imageFileName ); + labelImage = new LabelImage( tmp ); + DGtal::trace.endBlock(); + + std::stringstream ss; + ss << outputFiles << "0000"; + drawContours(*labelImage, ss.str(), format); + + } + else + { + DGtal::trace.beginBlock("image reading..."); + Point p(0,0); + Point q(dsize,dsize); + Point c(dsize/2,dsize/2); + labelImage = new LabelImage( Domain(p,q) ); + if (vm.count("shape")) + { + if ( (vm["shape"].as()) == "flower" ) + initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + } + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + trace.info() << "starting interface initialized with a " + << (vm["shape"].as()) << std::endl; + DGtal::trace.endBlock(); + } + + //domain + Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); + + + //algo + std::string algo; + if (!(vm.count("algo"))) trace.info() << "default algorithm: levelSet" << std::endl; + algo = vm["algo"].as(); + + if (algo.compare("levelSet")==0) + { + + //balloon force + double k; + if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; + k = vm["balloonForce"].as(); + + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + + if (vm.count("withFunction")) + drawFunction( implicitFunction, vm["withFunction"].as() ); + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(implicitFunction, ss.str(), format); + + //data functions + ImageContainerBySTLVector a( implicitFunction.domain() ); + std::fill(a.begin(),a.end(), 1.0 ); + ImageContainerBySTLVector b( implicitFunction.domain() ); + std::fill(b.begin(),b.end(), 1.0 ); + ImageContainerBySTLVector g( implicitFunction.domain() ); + std::fill(g.begin(),g.end(), 1.0 ); + + //evolution + WeickertKuhneEvolver > e(a,b,g,k,1); + + DGtal::trace.beginBlock( "Deformation (Weickert level set method)" ); + + for (unsigned int i = 1; i <= max; ++i) + { + + DGtal::trace.info() << "iteration # " << i << std::endl; + + e.update( implicitFunction, tstep); + + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format); + } + + //area + trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; + } + + DGtal::trace.endBlock(); + + } else if (algo.compare("phaseField")==0) + { + + double epsilon = 3.0; + if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; + epsilon = vm["epsilon"].as(); + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 0; + } + + bool flagWithCstVol = false; + if (vm.count("withCstVol")) + flagWithCstVol = true; + + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + + //computing the profile from the signed distance + Profile p(epsilon); + std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); + + if (vm.count("withFunction")) + drawFunction( implicitFunction, vm["withFunction"].as() ); + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(implicitFunction, ss.str(), format, 0.5); + + + + typedef ExactDiffusionEvolver > Diffusion; + typedef ExactReactionEvolver > Reaction; + Diffusion diffusion; + Reaction reaction( epsilon ); + // typedef ExplicitReactionEvolver, + // ImageContainerBySTLVector > Reaction; + // ImageContainerBySTLVector a( implicitFunction.domain() ); + // std::fill(a.begin(),a.end(), 1 ); + // Diffusion diffusion; + // Reaction reaction( epsilon, a, k, flagWithCstVol ); + LieSplittingEvolver e(diffusion, reaction); + + DGtal::trace.beginBlock( "Deformation (phase field)" ); + + for (unsigned int i = 1; i <= max; ++i) + { + + DGtal::trace.info() << "iteration # " << i << std::endl; + + e.update( implicitFunction, tstep); + + if ((i%step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContour(implicitFunction, s.str(), format, 0.5); + } + + //area + trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; + + } + + DGtal::trace.endBlock(); + } else if (algo.compare("localLevelSet")==0) + { + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContours(*labelImage, ss.str(), format); + + //space + KSpace ks; + ks.init( d.lowerBound(), d.upperBound(), true ); + + //distance image... + typedef ImageContainerBySTLVector DistanceImage; + //and extern data... + DistanceImage g( d ); + std::fill(g.begin(), g.end(), 1.0); + + // topological predicate + // typedef TrueBinaryPredicate TopologicalPredicate; + // TopologicalPredicate topologicalPredicate; + typedef SimplePointHelper TopologicalPredicate; + TopologicalPredicate topologicalPredicate(*labelImage); + + //frontier evolver + DGtal::trace.beginBlock( "Partition construction" ); + PartitionEvolver + e(ks, *labelImage, g, topologicalPredicate); + + DGtal::trace.info() << e << std::endl; + DGtal::trace.endBlock(); + + DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); + + double sumt = 0; + for (unsigned int i = 1; i <= max; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + //update + e.update(tstep); + + if ((i%step)==0) + { + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContours(*labelImage, s.str(), format); + } + sumt += tstep; + } + + DGtal::trace.endBlock(); + + } else if (algo.compare("multiPhaseField")==0) + { + + double epsilon = 3.0; + if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; + epsilon = vm["epsilon"].as(); + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 0; + } + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContours(*labelImage, ss.str(), format); + + typedef ImageContainerBySTLVector FieldImage; + typedef ExactDiffusionEvolver Diffusion; + typedef ExactReactionEvolver Reaction; + Diffusion diffusion; + Reaction reaction( epsilon ); + LieSplittingEvolver phaseField(diffusion, reaction); + MultiPhaseField > e(*labelImage, phaseField); + + DGtal::trace.beginBlock( "Deformation (multi phase field)" ); + + for (unsigned int i = step; i <= max; i += step) + { + + DGtal::trace.info() << "iteration # " << i << std::endl; + + e.update( tstep ); + + if ((i%step)==0) + { + //display + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; + drawContours(*labelImage, s.str(), format); + } + + } + + DGtal::trace.endBlock(); + } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + + + DGtal::trace.info() << "end" << std::endl; + + //free + delete( labelImage ); + + return 1; +} + diff --git a/deformations/deformation3d.cpp b/deformations/deformation3d.cpp index 2783950..c6cb8a6 100644 --- a/deformations/deformation3d.cpp +++ b/deformations/deformation3d.cpp @@ -1,489 +1,3 @@ -#include -#include -#include -#include -#include - -///////////////////// -#include -#include -#include - -namespace po = boost::program_options; - -///////////////////// -#include -#include - -using namespace DGtal; -using namespace Z3i; -using namespace std; - -//evolvers -//level set -#include "WeickertKuhneEvolver.h" - -//phase field -#include "ExactDiffusionEvolver.h" -#include "ExactReactionEvolver.h" -#include "ExplicitReactionEvolver.h" -#include "LieSplittingEvolver.h" -#include "MultiPhaseField.h" - -//local level set -#include "SimplePointHelper.h" -#include "PartitionEvolver.h" - -/////////////////////////// useful functions -#include "deformationFunctions.h" -#include "deformationDisplay3d.h" -#include "DGtal/io/readers/VolReader.h" -#include "VTKWriter.h" - -// Qt -#include - -/////////////////////////////////////////////////////////////////// -int main(int argc, char** argv) -{ - - DGtal::trace.info() << "3d interface evolution using DGtal "; - DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; - - // QApplication initialization with command-line parameters - QApplication application(argc, argv); - - // Default options - size_t dsize = 64; // Domain size - double tstep = 0.25; // Time step - size_t disp_step = 1; // Display step - size_t max_step = 1; // Maximum number of steps - string shape = "ball"; // Generated shape - string algo = "levelSet"; // Algorithm used for evolution - double balloon = 0.; // Balloon Force - double epsilon = 3.; // Interface width - - string outputFiles = "interface"; // Output files basename - string outputFormat = "vol"; // Output files format - bool flagWithCstVol = false; // Volume Conservation - bool flagWithVisu = false; // Interactive 3d visualization after evolution - - // Parse command line ---------------------------------------------- - po::options_description general_opt("Allowed options are"); - general_opt.add_options() - ("help,h", "display this message") - ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) - ("domainSize,d", po::value(&dsize)->default_value(dsize), "Domain size (if default starting interface)" ) - ("shape,s", po::value(&shape)->default_value(shape), - "Generated shape: either or " ) - ("timeStep,t", po::value(&tstep)->default_value(tstep), "Time step for the evolution" ) - ("displayStep", po::value(&disp_step)->default_value(disp_step), "Number of time steps between 2 drawings" ) - ("stepsNumber,n", po::value(&max_step)->default_value(max_step), "Maximal number of steps" ) - ("algo,a", po::value(&algo)->default_value(algo), - "can be: \n \n or \n or \n or " ) - ("balloonForce,k", po::value(&balloon)->default_value(balloon), "Balloon force" ) - ("epsilon,e", po::value(&epsilon)->default_value(epsilon), "Interface width (only for phase fields)" ) - ("withCstVol", po::bool_switch(&flagWithCstVol), "with volume conservation (only for phase fields)" ) - ("outputFiles,o", po::value(&outputFiles)->default_value(outputFiles), "Output files basename" ) - ("outputFormat,f", po::value(&outputFormat)->default_value(outputFormat), - "Output files format: either (3d to 2d with QGLViewer), (3d to 2d with Cairo) or (3d)" ) - ("withVisu", po::bool_switch(&flagWithVisu), "Enables interactive 3d visualization after evolution" ); - - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, general_opt), vm); - po::notify(vm); - if(vm.count("help") || argc<=1) - { - trace.info()<< "Evolution of a 3d interface" << std::endl - << "Basic usage: "< -n --withVisu" - << std::endl - << general_opt << "\n"; - return 1; - } - - // Options validity - // Files format - if ( (outputFormat != "png") && (outputFormat != "vol") && (outputFormat != "pngc") ) - { - trace.info() << "format is expected to be either , or " << std::endl; - return 1; - } - - // Generated shape - if ( vm.count("inputImage") == 0 && shape != "ball" && shape != "flower" ) - { - trace.info() << "if no input file is specified, shape is expected to be either or " << std::endl; - return 1; - } - - // Evolution algorithm - if ( algo != "levelSet" && algo != "phaseField" && algo != "multiPhaseField" && algo != "localLevelSet" ) - { - trace.info() << "algo is expected to be either , , or " << std::endl; - return 1; - } - - - // Image and implicit function - typedef ImageContainerBySTLVector LabelImage; - LabelImage* labelImage = NULL; - - if (vm.count("inputImage")) - { - string imageFileName = vm["inputImage"].as(); - trace.emphase() << imageFileName <::importVol( imageFileName ); - labelImage = new LabelImage( tmp ); - DGtal::trace.endBlock(); - } - else - { - DGtal::trace.beginBlock("image reading..."); - Point p(0, 0, 0); - Point q(dsize, dsize, dsize); - Point c(dsize/2, dsize/2, dsize/2); - labelImage = new LabelImage( Domain(p,q) ); - - if ( (vm["shape"].as()) == "flower" ) - initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - - trace.info() << "starting interface initialized with a " << shape << std::endl; - - DGtal::trace.endBlock(); - } - - // Domain - Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); - - // Pre-visualization for choosing camera position - if (outputFormat == "png") - displayPartition( *labelImage ); - - // Algorithm dispatch - if ( algo == "levelSet" ) - { - - // Distance function - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - // Data functions - ImageContainerBySTLVector a( d ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( d ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( d ); - std::fill(g.begin(),g.end(), 1.0 ); - - // Interface evolver - WeickertKuhneEvolver > e(a, b, g, balloon, 1); - - DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(implicitFunction,tstep); - - // Display - if ((i % disp_step) == 0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - updateLabelImage( *labelImage, implicitFunction ); - writePartition( *labelImage, s.str(), outputFormat ); - } - - sumt += tstep; - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - updateLabelImage( *labelImage, implicitFunction, 0 ); - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayImageWithInfo( *labelImage, implicitFunction, a, b ); - - } - else if ( algo == "phaseField" ) - { - // Option's validity - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 1; - } - - // Distance function - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - // Computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - - // Diffusion evolver - typedef ExactDiffusionEvolver > Diffusion; - Diffusion diffusion; - - // Exact reaction evolver (no possible volume conservation) - /* - typedef ExactReactionEvolver > Reaction; - Reaction reaction( epsilon ); - */ - - // Explicit reaction evolver (with possible volume conservation) - typedef ExplicitReactionEvolver< - ImageContainerBySTLVector, - ImageContainerBySTLVector - > Reaction; - ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); - std::fill(a.begin(), a.end(), 0.0 ); - Reaction reaction( epsilon, a, balloon, flagWithCstVol ); - - // Lie splitting - LieSplittingEvolver e(diffusion, reaction); - - DGtal::trace.beginBlock( "Deformation (phase field)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - { - VTKWriter vtk(s.str(), implicitFunction.domain()); - vtk << "phi" << implicitFunction; - } - - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(implicitFunction, tstep); - - // Display - if ((i % disp_step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - updateLabelImage( *labelImage, implicitFunction, 0.5 ); - - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - VTKWriter vtk(s.str(), implicitFunction.domain()); - vtk << "phi" << implicitFunction; - } - - sumt += tstep; - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; - - const double vol_test = std::accumulate( implicitFunction.begin(), implicitFunction.end(), 0.); - DGtal::trace.info() << "Real volume: " << vol_test << std::endl; - - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - // Post-processing - updateLabelImage( *labelImage, implicitFunction, 0.5 ); - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayPartition( *labelImage ); - - } - else if ( algo == "multiPhaseField" ) - { - // Options's validity - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 1; - } - - // Field image - typedef ImageContainerBySTLVector FieldImage; - - // Diffusion evolver - typedef ExactDiffusionEvolver< FieldImage > Diffusion; - Diffusion diffusion; - - // Exact Reaction Evolver (no possible volume conservation) - /* - typedef ExactReactionEvolver < FieldImage > Reaction; - Reaction reaction( epsilon ); - */ - - // Explicit Reaction Evolver (with possible volume conservation) - typedef ExplicitReactionEvolver< - ImageContainerBySTLVector, - ImageContainerBySTLVector - > Reaction; - ImageContainerBySTLVector a( d ); - std::fill(a.begin(), a.end(), 0.0 ); - Reaction reaction( epsilon, a, balloon, flagWithCstVol ); - - // Lie splitting - LieSplittingEvolver< Diffusion, Reaction > phaseEvolver(diffusion, reaction); - - // Multi phase-field - MultiPhaseField< LabelImage, FieldImage, LieSplittingEvolver > evolver(*labelImage, phaseEvolver); - - DGtal::trace.beginBlock( "Deformation (multi phase field)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - // VTK export - { - VTKWriter vtk(s.str(), labelImage->domain()); - for (size_t j = 0; j < evolver.getNumPhase(); ++j) - { - stringstream s_phase; - s_phase << "phi" << setfill('0') << std::setw(2) << j; - vtk << s_phase.str() << evolver.getPhase(j); - } - } - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - evolver.update( tstep ); - - // Display - if ( (i % disp_step) == 0 ) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - VTKWriter vtk(s.str(), labelImage->domain()); - for (size_t j = 0; j < evolver.getNumPhase(); ++j) - { - stringstream s_phase; - s_phase << "phi" << setfill('0') << std::setw(2) << j; - vtk << s_phase.str() << evolver.getPhase(j); - } - - } - - sumt += tstep; - - // Volume of each phase - typedef std::map Histo; - Histo histo; - calcHistogram( *labelImage, histo ); - DGtal::trace.info() << "Volume: "; - for ( Histo::const_iterator it = histo.begin(); it != histo.end(); ++it ) - DGtal::trace.info() << "V(" << it->first << ") = " << it->second; - DGtal::trace.info() << std::endl; - - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayPartition( *labelImage ); - - } - else if ( algo == "localLevelSet" ) - { - // Space - KSpace ks; - ks.init( d.lowerBound(), d.upperBound(), true ); - - // Distance image... - typedef ImageContainerBySTLVector DistanceImage; - // ... and extern data. - DistanceImage g( d ); - std::fill(g.begin(), g.end(), 1.0); - - // Topological predicate - typedef SimplePointHelper TopologicalPredicate; - TopologicalPredicate topologicalPredicate(*labelImage); - - // Frontier evolver - PartitionEvolver - e(ks, *labelImage, g, topologicalPredicate); - - DGtal::trace.info() << e << std::endl; - - DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(tstep); - - // Display - if ((i % disp_step) == 0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - writePartition( *labelImage, s.str(), outputFormat ); - } - - sumt += tstep; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) displayPartition( *labelImage ); - - } - else - { - trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; - return 1; - } - - // Free - delete( labelImage ); - - return 0; -} - -/* GNU coding style */ -/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ +#define DIMENSION 3 +#include "deformationNd.cpp" diff --git a/deformations/deformation3d.old.cpp b/deformations/deformation3d.old.cpp new file mode 100644 index 0000000..2783950 --- /dev/null +++ b/deformations/deformation3d.old.cpp @@ -0,0 +1,489 @@ +#include +#include +#include +#include +#include + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +///////////////////// +#include +#include + +using namespace DGtal; +using namespace Z3i; +using namespace std; + +//evolvers +//level set +#include "WeickertKuhneEvolver.h" + +//phase field +#include "ExactDiffusionEvolver.h" +#include "ExactReactionEvolver.h" +#include "ExplicitReactionEvolver.h" +#include "LieSplittingEvolver.h" +#include "MultiPhaseField.h" + +//local level set +#include "SimplePointHelper.h" +#include "PartitionEvolver.h" + +/////////////////////////// useful functions +#include "deformationFunctions.h" +#include "deformationDisplay3d.h" +#include "DGtal/io/readers/VolReader.h" +#include "VTKWriter.h" + +// Qt +#include + +/////////////////////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + DGtal::trace.info() << "3d interface evolution using DGtal "; + DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; + + // QApplication initialization with command-line parameters + QApplication application(argc, argv); + + // Default options + size_t dsize = 64; // Domain size + double tstep = 0.25; // Time step + size_t disp_step = 1; // Display step + size_t max_step = 1; // Maximum number of steps + string shape = "ball"; // Generated shape + string algo = "levelSet"; // Algorithm used for evolution + double balloon = 0.; // Balloon Force + double epsilon = 3.; // Interface width + + string outputFiles = "interface"; // Output files basename + string outputFormat = "vol"; // Output files format + bool flagWithCstVol = false; // Volume Conservation + bool flagWithVisu = false; // Interactive 3d visualization after evolution + + // Parse command line ---------------------------------------------- + po::options_description general_opt("Allowed options are"); + general_opt.add_options() + ("help,h", "display this message") + ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) + ("domainSize,d", po::value(&dsize)->default_value(dsize), "Domain size (if default starting interface)" ) + ("shape,s", po::value(&shape)->default_value(shape), + "Generated shape: either or " ) + ("timeStep,t", po::value(&tstep)->default_value(tstep), "Time step for the evolution" ) + ("displayStep", po::value(&disp_step)->default_value(disp_step), "Number of time steps between 2 drawings" ) + ("stepsNumber,n", po::value(&max_step)->default_value(max_step), "Maximal number of steps" ) + ("algo,a", po::value(&algo)->default_value(algo), + "can be: \n \n or \n or \n or " ) + ("balloonForce,k", po::value(&balloon)->default_value(balloon), "Balloon force" ) + ("epsilon,e", po::value(&epsilon)->default_value(epsilon), "Interface width (only for phase fields)" ) + ("withCstVol", po::bool_switch(&flagWithCstVol), "with volume conservation (only for phase fields)" ) + ("outputFiles,o", po::value(&outputFiles)->default_value(outputFiles), "Output files basename" ) + ("outputFormat,f", po::value(&outputFormat)->default_value(outputFormat), + "Output files format: either (3d to 2d with QGLViewer), (3d to 2d with Cairo) or (3d)" ) + ("withVisu", po::bool_switch(&flagWithVisu), "Enables interactive 3d visualization after evolution" ); + + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help") || argc<=1) + { + trace.info()<< "Evolution of a 3d interface" << std::endl + << "Basic usage: "< -n --withVisu" + << std::endl + << general_opt << "\n"; + return 1; + } + + // Options validity + // Files format + if ( (outputFormat != "png") && (outputFormat != "vol") && (outputFormat != "pngc") ) + { + trace.info() << "format is expected to be either , or " << std::endl; + return 1; + } + + // Generated shape + if ( vm.count("inputImage") == 0 && shape != "ball" && shape != "flower" ) + { + trace.info() << "if no input file is specified, shape is expected to be either or " << std::endl; + return 1; + } + + // Evolution algorithm + if ( algo != "levelSet" && algo != "phaseField" && algo != "multiPhaseField" && algo != "localLevelSet" ) + { + trace.info() << "algo is expected to be either , , or " << std::endl; + return 1; + } + + + // Image and implicit function + typedef ImageContainerBySTLVector LabelImage; + LabelImage* labelImage = NULL; + + if (vm.count("inputImage")) + { + string imageFileName = vm["inputImage"].as(); + trace.emphase() << imageFileName <::importVol( imageFileName ); + labelImage = new LabelImage( tmp ); + DGtal::trace.endBlock(); + } + else + { + DGtal::trace.beginBlock("image reading..."); + Point p(0, 0, 0); + Point q(dsize, dsize, dsize); + Point c(dsize/2, dsize/2, dsize/2); + labelImage = new LabelImage( Domain(p,q) ); + + if ( (vm["shape"].as()) == "flower" ) + initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + + trace.info() << "starting interface initialized with a " << shape << std::endl; + + DGtal::trace.endBlock(); + } + + // Domain + Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); + + // Pre-visualization for choosing camera position + if (outputFormat == "png") + displayPartition( *labelImage ); + + // Algorithm dispatch + if ( algo == "levelSet" ) + { + + // Distance function + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + + // Data functions + ImageContainerBySTLVector a( d ); + std::fill(a.begin(),a.end(), 1.0 ); + ImageContainerBySTLVector b( d ); + std::fill(b.begin(),b.end(), 1.0 ); + ImageContainerBySTLVector g( d ); + std::fill(g.begin(),g.end(), 1.0 ); + + // Interface evolver + WeickertKuhneEvolver > e(a, b, g, balloon, 1); + + DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(implicitFunction,tstep); + + // Display + if ((i % disp_step) == 0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + updateLabelImage( *labelImage, implicitFunction ); + writePartition( *labelImage, s.str(), outputFormat ); + } + + sumt += tstep; + DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + updateLabelImage( *labelImage, implicitFunction, 0 ); + DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; + DGtal::trace.endBlock(); + + // Interactive display after the evolution + if ( flagWithVisu ) + displayImageWithInfo( *labelImage, implicitFunction, a, b ); + + } + else if ( algo == "phaseField" ) + { + // Option's validity + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 1; + } + + // Distance function + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + + // Computing the profile from the signed distance + Profile p(epsilon); + std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); + + // Diffusion evolver + typedef ExactDiffusionEvolver > Diffusion; + Diffusion diffusion; + + // Exact reaction evolver (no possible volume conservation) + /* + typedef ExactReactionEvolver > Reaction; + Reaction reaction( epsilon ); + */ + + // Explicit reaction evolver (with possible volume conservation) + typedef ExplicitReactionEvolver< + ImageContainerBySTLVector, + ImageContainerBySTLVector + > Reaction; + ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); + std::fill(a.begin(), a.end(), 0.0 ); + Reaction reaction( epsilon, a, balloon, flagWithCstVol ); + + // Lie splitting + LieSplittingEvolver e(diffusion, reaction); + + DGtal::trace.beginBlock( "Deformation (phase field)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; + writePartition( *labelImage, s.str(), outputFormat ); + + // VTK export + { + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; + } + + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(implicitFunction, tstep); + + // Display + if ((i % disp_step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + updateLabelImage( *labelImage, implicitFunction, 0.5 ); + + writePartition( *labelImage, s.str(), outputFormat ); + + // VTK export + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; + } + + sumt += tstep; + DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; + + const double vol_test = std::accumulate( implicitFunction.begin(), implicitFunction.end(), 0.); + DGtal::trace.info() << "Real volume: " << vol_test << std::endl; + + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + // Post-processing + updateLabelImage( *labelImage, implicitFunction, 0.5 ); + DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; + DGtal::trace.endBlock(); + + // Interactive display after the evolution + if ( flagWithVisu ) + displayPartition( *labelImage ); + + } + else if ( algo == "multiPhaseField" ) + { + // Options's validity + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 1; + } + + // Field image + typedef ImageContainerBySTLVector FieldImage; + + // Diffusion evolver + typedef ExactDiffusionEvolver< FieldImage > Diffusion; + Diffusion diffusion; + + // Exact Reaction Evolver (no possible volume conservation) + /* + typedef ExactReactionEvolver < FieldImage > Reaction; + Reaction reaction( epsilon ); + */ + + // Explicit Reaction Evolver (with possible volume conservation) + typedef ExplicitReactionEvolver< + ImageContainerBySTLVector, + ImageContainerBySTLVector + > Reaction; + ImageContainerBySTLVector a( d ); + std::fill(a.begin(), a.end(), 0.0 ); + Reaction reaction( epsilon, a, balloon, flagWithCstVol ); + + // Lie splitting + LieSplittingEvolver< Diffusion, Reaction > phaseEvolver(diffusion, reaction); + + // Multi phase-field + MultiPhaseField< LabelImage, FieldImage, LieSplittingEvolver > evolver(*labelImage, phaseEvolver); + + DGtal::trace.beginBlock( "Deformation (multi phase field)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; + writePartition( *labelImage, s.str(), outputFormat ); + // VTK export + { + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } + } + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + evolver.update( tstep ); + + // Display + if ( (i % disp_step) == 0 ) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + + writePartition( *labelImage, s.str(), outputFormat ); + + // VTK export + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } + + } + + sumt += tstep; + + // Volume of each phase + typedef std::map Histo; + Histo histo; + calcHistogram( *labelImage, histo ); + DGtal::trace.info() << "Volume: "; + for ( Histo::const_iterator it = histo.begin(); it != histo.end(); ++it ) + DGtal::trace.info() << "V(" << it->first << ") = " << it->second; + DGtal::trace.info() << std::endl; + + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + DGtal::trace.endBlock(); + + // Interactive display after the evolution + if ( flagWithVisu ) + displayPartition( *labelImage ); + + } + else if ( algo == "localLevelSet" ) + { + // Space + KSpace ks; + ks.init( d.lowerBound(), d.upperBound(), true ); + + // Distance image... + typedef ImageContainerBySTLVector DistanceImage; + // ... and extern data. + DistanceImage g( d ); + std::fill(g.begin(), g.end(), 1.0); + + // Topological predicate + typedef SimplePointHelper TopologicalPredicate; + TopologicalPredicate topologicalPredicate(*labelImage); + + // Frontier evolver + PartitionEvolver + e(ks, *labelImage, g, topologicalPredicate); + + DGtal::trace.info() << e << std::endl; + + DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; + writePartition( *labelImage, s.str(), outputFormat ); + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(tstep); + + // Display + if ((i % disp_step) == 0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + writePartition( *labelImage, s.str(), outputFormat ); + } + + sumt += tstep; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + DGtal::trace.endBlock(); + + // Interactive display after the evolution + if ( flagWithVisu ) displayPartition( *labelImage ); + + } + else + { + trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + return 1; + } + + // Free + delete( labelImage ); + + return 0; +} + +/* GNU coding style */ +/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ + diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 07f8d83..135e812 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -8,6 +8,7 @@ /** Prevents repeated inclusion of headers. */ #define deformationFunctions_h +#include // Algorithms //images #include @@ -67,6 +68,20 @@ void calcHistogram( TImage const& img, TMap & map ) } } +/** Calculate area/volume of a phase from his implicit function + * + * It simply integrates the function over the full domain. + * + * @tparam T type of the result. + * @tparam TField type of the implicit function (must be iterable). + * @param field the implicit function. + */ +template < typename T, typename TField > +inline +T getVolume( TField const& field ) +{ + return std::accumulate( std::begin(field), std::end(field), T(0) ); +} template< typename TLabelImage, typename TDistanceImage > diff --git a/deformations/deformationNd.cpp b/deformations/deformationNd.cpp new file mode 100644 index 0000000..92df1f4 --- /dev/null +++ b/deformations/deformationNd.cpp @@ -0,0 +1,609 @@ +#include +#include +#include +#include +#include + +///////////////////// +#include +#include +#include + +namespace po = boost::program_options; + +///////////////////// +#include +#include + +// Dimension (default 3) +#ifndef DIMENSION + #define DIMENSION 3 +#endif +// See: http://stackoverflow.com/questions/1489932/c-preprocessor-and-token-concatenation +#define PASTER(dim) Z ## dim ## i +#define EVALUATOR(dim) PASTER(dim) +#define ZNI EVALUATOR( DIMENSION ) + +using namespace DGtal; +using namespace ZNI; +using namespace std; + +// Evolvers +// Level-Set +#include "WeickertKuhneEvolver.h" + +// Phase-Field +#include "ExactDiffusionEvolver.h" +#include "ExactReactionEvolver.h" +#include "ExplicitReactionEvolver.h" +#include "LieSplittingEvolver.h" +#include "MultiPhaseField.h" + +// Local Level-Set +#include "SimplePointHelper.h" +#include "PartitionEvolver.h" + +// Useful functions +#include "deformationFunctions.h" + +// IO functions +#include "VTKWriter.h" +#if DIMENSION == 2 + #include "deformationDisplay2d.h" + #include "DGtal/io/readers/PGMReader.h" +#elif DIMENSION == 3 + #include "deformationDisplay3d.h" + #include "DGtal/io/readers/VolReader.h" + #include // Qt +#endif + +// Dimension as a variable +namespace +{ + static const + unsigned int dimension = DIMENSION ; +} + +/////////////////////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + DGtal::trace.info() << dimension << "d interface evolution using DGtal "; + DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; + +#if DIMENSION == 3 + // QApplication initialization with command-line parameters + QApplication application(argc, argv); +#endif + + // Default options + size_t dsize = 64; // Domain size + double tstep = 0.25; // Time step + size_t disp_step = 1; // Display step + size_t max_step = 1; // Maximum number of steps + string shape = "ball"; // Generated shape + string algo = "levelSet"; // Algorithm used for evolution + double balloon = 0.; // Balloon Force + double epsilon = 3.; // Interface width + bool flagWithCstVol = false; // Volume Conservation + + string outputFiles = "interface"; // Output files basename + +#if DIMENSION == 2 + string outputFormat = "raster"; // Output files format +#elif DIMENSION == 3 + string outputFormat = "vol"; // Output files format + bool flagWithVisu = false; // Interactive 3d visualization after evolution +#endif + + // Command-line options description + po::options_description general_opt("Allowed options are"); + general_opt.add_options() + ("help,h", "display this message") + ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) + ("domainSize,d", po::value(&dsize)->default_value(dsize), "Domain size (if default starting interface)" ) + ("shape,s", po::value(&shape)->default_value(shape), + "Generated shape: either or " ) + ("timeStep,t", po::value(&tstep)->default_value(tstep), "Time step for the evolution" ) + ("displayStep", po::value(&disp_step)->default_value(disp_step), "Number of time steps between 2 drawings" ) + ("stepsNumber,n", po::value(&max_step)->default_value(max_step), "Maximal number of steps" ) + ("algo,a", po::value(&algo)->default_value(algo), + "can be: \n \n or \n or \n or " ) + ("balloonForce,k", po::value(&balloon)->default_value(balloon), "Balloon force" ) + ("epsilon,e", po::value(&epsilon)->default_value(epsilon), "Interface width (only for phase fields)" ) + ("withCstVol", po::bool_switch(&flagWithCstVol), "with volume conservation (only for phase fields)" ) + ("outputFiles,o", po::value(&outputFiles)->default_value(outputFiles), "Output files basename" ) +#if DIMENSION == 2 + ("outputFormat,f", po::value(&outputFormat)->default_value(outputFormat), + "Output files format: either (image, default) or (domain representation)" ); +#elif DIMENSION == 3 + ("outputFormat,f", po::value(&outputFormat)->default_value(outputFormat), + "Output files format: either (3d to 2d with QGLViewer), (3d to 2d with Cairo) or (3d)" ) + ("withVisu", po::bool_switch(&flagWithVisu), "Enables interactive 3d visualization after evolution" ); +#endif + + // Command-line parsing + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, general_opt), vm); + po::notify(vm); + if(vm.count("help") || argc<=1) + { + trace.info()<< "Evolution of a " << dimension << "d interface" << std::endl + << "Basic usage: "< -n " + << std::endl + << general_opt << "\n"; + return 1; + } + + // Options validity + // Files format +#if DIMENSION == 2 + if ( (outputFormat != "vector") && (outputFormat != "raster") ) + { + trace.info() << "format is expected to be either or " << std::endl; + return 1; + } +#elif DIMENSION == 3 + if ( (outputFormat != "png") && (outputFormat != "vol") && (outputFormat != "pngc") ) + { + trace.info() << "format is expected to be either , or " << std::endl; + return 1; + } +#endif + + // Generated shape + if ( vm.count("inputImage") == 0 && shape != "ball" && shape != "flower" ) + { + trace.info() << "if no input file is specified, shape is expected to be either or " << std::endl; + return 1; + } + + // Evolution algorithm + if ( algo != "levelSet" && algo != "phaseField" && algo != "multiPhaseField" && algo != "localLevelSet" ) + { + trace.info() << "algo is expected to be either , , or " << std::endl; + return 1; + } + + + // Image and implicit function + typedef ImageContainerBySTLVector LabelImage; + LabelImage* labelImage = NULL; + + if (vm.count("inputImage")) + { + string imageFileName = vm["inputImage"].as(); + trace.emphase() << imageFileName <::importPGM( imageFileName ); +#elif DIMENSION == 3 + LabelImage tmp = VolReader::importVol( imageFileName ); +#endif + + labelImage = new LabelImage( tmp ); + DGtal::trace.endBlock(); + } + else + { + DGtal::trace.beginBlock("image reading..."); + Point p = Point::diagonal(0); + Point q = Point::diagonal(dsize); + Point c = Point::diagonal(dsize/2); + labelImage = new LabelImage( Domain(p,q) ); + + if ( (vm["shape"].as()) == "flower" ) + initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); + else + initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); + + trace.info() << "starting interface initialized with a " << shape << std::endl; + + DGtal::trace.endBlock(); + } + + // Domain + Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); + +#if DIMENSION == 3 + // Pre-visualization for choosing camera position + if (outputFormat == "png") + displayPartition( *labelImage ); +#endif + + // Algorithm dispatch + if ( algo == "levelSet" ) + { + + // Distance function + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + +#if DIMENSION == 2 + if (vm.count("withFunction")) + drawFunction( implicitFunction, vm["withFunction"].as() ); + + std::stringstream ss; + ss << outputFiles << "0001"; + drawContour(implicitFunction, ss.str(), outputFormat); +#endif + + // Data functions + ImageContainerBySTLVector a( d ); + std::fill(a.begin(),a.end(), 1.0 ); + ImageContainerBySTLVector b( d ); + std::fill(b.begin(),b.end(), 1.0 ); + ImageContainerBySTLVector g( d ); + std::fill(g.begin(),g.end(), 1.0 ); + + // Interface evolver + WeickertKuhneEvolver > e(a, b, g, balloon, 1); + + DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(implicitFunction, tstep); + + // Display + if ((i % disp_step) == 0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); +#if DIMENSION == 2 + drawContour(implicitFunction, s.str(), outputFormat); +#elif DIMENSION == 3 + updateLabelImage( *labelImage, implicitFunction ); + writePartition( *labelImage, s.str(), outputFormat ); +#endif + } + + sumt += tstep; + + // DGtal::trace.info() << "Area: " << getSize( implicitFunction ) << std::endl; + //DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; + + DGtal::trace.info() + << ( dimension == 2 ? "Area: " : "Volume: " ) + << getVolume( implicitFunction ) + << std::endl; + + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + //updateLabelImage( *labelImage, implicitFunction, 0 ); + //DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; + DGtal::trace.endBlock(); + +#if DIMENSION == 3 + // Interactive display after the evolution + if ( flagWithVisu ) + displayImageWithInfo( *labelImage, implicitFunction, a, b ); +#endif + + } + else if ( algo == "phaseField" ) + { + // Option's validity + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 1; + } + + // Distance function + ImageContainerBySTLVector implicitFunction( d ); + initWithDT( *labelImage, implicitFunction ); + + // Computing the profile from the signed distance + Profile p(epsilon); + std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); + +#if DIMENSION == 2 + if (vm.count("withFunction")) + drawFunction( implicitFunction, vm["withFunction"].as() ); +#endif + + // Diffusion evolver + typedef ExactDiffusionEvolver > Diffusion; + Diffusion diffusion; + + // Exact reaction evolver (no possible volume conservation) + /* + typedef ExactReactionEvolver > Reaction; + Reaction reaction( epsilon ); + */ + + // Explicit reaction evolver (with possible volume conservation) + typedef ExplicitReactionEvolver< + ImageContainerBySTLVector, + ImageContainerBySTLVector + > Reaction; + ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); + std::fill(a.begin(), a.end(), 0.0 ); + Reaction reaction( epsilon, a, balloon, flagWithCstVol ); + + // Lie splitting + LieSplittingEvolver e(diffusion, reaction); + + DGtal::trace.beginBlock( "Deformation (phase field)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; +#if DIMENSION == 2 + drawContour(implicitFunction, s.str(), outputFormat, 0.5); +#elif DIMENSION == 3 + writePartition( *labelImage, s.str(), outputFormat ); +#endif + + // VTK export + { + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; + } + + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(implicitFunction, tstep); + + // Display + if ((i % disp_step)==0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); + +#if DIMENSION == 2 + drawContour(implicitFunction, s.str(), outputFormat, 0.5); +#elif DIMENSION == 3 + updateLabelImage( *labelImage, implicitFunction, 0.5 ); + writePartition( *labelImage, s.str(), outputFormat ); +#endif + + // VTK export + VTKWriter vtk(s.str(), implicitFunction.domain()); + vtk << "phi" << implicitFunction; + } + + sumt += tstep; + + DGtal::trace.info() + << (dimension==2 ? "Area: " : "Volume: " ) + << getVolume( implicitFunction ) + << std::endl; + + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + // Post-processing + // updateLabelImage( *labelImage, implicitFunction, 0.5 ); + // DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; + + DGtal::trace.endBlock(); + +#if DIMENSION == 3 + // Interactive display after the evolution + if ( flagWithVisu ) + displayPartition( *labelImage ); +#endif + + } + else if ( algo == "multiPhaseField" ) + { + // Options's validity + if (epsilon <= 0) + { + trace.error() << "epsilon should be greater than 0" << std::endl; + return 1; + } + + // Field image + typedef ImageContainerBySTLVector FieldImage; + + // Diffusion evolver + typedef ExactDiffusionEvolver< FieldImage > Diffusion; + Diffusion diffusion; + + // Exact Reaction Evolver (no possible volume conservation) + /* + typedef ExactReactionEvolver < FieldImage > Reaction; + Reaction reaction( epsilon ); + */ + + // Explicit Reaction Evolver (with possible volume conservation) + typedef ExplicitReactionEvolver< + ImageContainerBySTLVector, + ImageContainerBySTLVector + > Reaction; + ImageContainerBySTLVector a( d ); + std::fill(a.begin(), a.end(), 0.0 ); + Reaction reaction( epsilon, a, balloon, flagWithCstVol ); + + // Lie splitting + LieSplittingEvolver< Diffusion, Reaction > phaseEvolver(diffusion, reaction); + + // Multi phase-field + MultiPhaseField< LabelImage, FieldImage, LieSplittingEvolver > evolver(*labelImage, phaseEvolver); + + DGtal::trace.beginBlock( "Deformation (multi phase field)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; +#if DIMENSION == 2 + drawContours( *labelImage, s.str(), outputFormat ); +#elif DIMENSION == 3 + writePartition( *labelImage, s.str(), outputFormat ); +#endif + + // VTK export + { + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } + } + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + evolver.update( tstep ); + + // Display + if ( (i % disp_step) == 0 ) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); +#if DIMENSION == 2 + drawContours( *labelImage, s.str(), outputFormat ); +#elif DIMENSION == 3 + writePartition( *labelImage, s.str(), outputFormat ); +#endif + + // VTK export + VTKWriter vtk(s.str(), labelImage->domain()); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + stringstream s_phase; + s_phase << "phi" << setfill('0') << std::setw(2) << j; + vtk << s_phase.str() << evolver.getPhase(j); + } + + } + + sumt += tstep; + + // Volume of each phase + /* + typedef std::map Histo; + Histo histo; + calcHistogram( *labelImage, histo ); + DGtal::trace.info() << "Volume: "; + for ( Histo::const_iterator it = histo.begin(); it != histo.end(); ++it ) + DGtal::trace.info() << "V(" << it->first << ") = " << it->second; + DGtal::trace.info() << std::endl; + */ + + // Volume of each phase + DGtal::trace.info() << ( dimension == 2 ? "Area: " : "Volume: " ); + for (size_t j = 0; j < evolver.getNumPhase(); ++j) + { + DGtal::trace.info() << "V(" << j << ") = " << getVolume(evolver.getPhase(j)); + } + DGtal::trace.info() << std::endl; + + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + DGtal::trace.endBlock(); + +#if DIMENSION == 3 + // Interactive display after the evolution + if ( flagWithVisu ) + displayPartition( *labelImage ); +#endif + + } + else if ( algo == "localLevelSet" ) + { + // Space + KSpace ks; + ks.init( d.lowerBound(), d.upperBound(), true ); + + // Distance image... + typedef ImageContainerBySTLVector DistanceImage; + // ... and extern data. + DistanceImage g( d ); + std::fill(g.begin(), g.end(), 1.0); + + // Topological predicate + typedef SimplePointHelper TopologicalPredicate; + TopologicalPredicate topologicalPredicate(*labelImage); + + // Frontier evolver + DGtal::trace.beginBlock("Partition construction"); + PartitionEvolver + e(ks, *labelImage, g, topologicalPredicate); + + DGtal::trace.info() << e << std::endl; + DGtal::trace.endBlock(); + + DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); + + // Initial state export + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << 0; +#if DIMENSION == 2 + drawContours( *labelImage, s.str(), outputFormat ); +#elif DIMENSION == 3 + writePartition( *labelImage, s.str(), outputFormat ); +#endif + + // Time integration + double sumt = 0; + for (unsigned int i = 1; i <= max_step; ++i) + { + DGtal::trace.info() << "iteration # " << i << std::endl; + + // Update + e.update(tstep); + + // Display + if ((i % disp_step) == 0) + { + std::stringstream s; + s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); +#if DIMENSION == 2 + drawContours( *labelImage, s.str(), outputFormat ); +#elif DIMENSION == 3 + writePartition( *labelImage, s.str(), outputFormat ); +#endif + } + + sumt += tstep; + DGtal::trace.info() << "Time spent: " << sumt << std::endl; + } + + DGtal::trace.endBlock(); + +#if DIMENSION == 3 + // Interactive display after the evolution + if ( flagWithVisu ) displayPartition( *labelImage ); +#endif + + } + else + { + trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; + return 1; + } + + // Free + delete( labelImage ); + + return 0; +} + +/* GNU coding style */ +/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ + From 82509043057e242107887dd49848e74eee1d2eb9 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Tue, 27 Jan 2015 17:32:36 +0100 Subject: [PATCH 105/108] Reverting a debug comment. --- deformations/VTKWriter.ih | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index 00f613a..3e64d6c 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -277,7 +277,7 @@ write ( std::string const& fieldname, TImage const& field ) for (size_t i = 0; i < Domain::dimension; ++i) dim.push_back(i); - //try + try { // Field header m_fstream << "SCALARS " << fieldname << " " << VTKType::name() << " " << VTKType::dim() << "\n"; @@ -292,10 +292,10 @@ write ( std::string const& fieldname, TImage const& field ) m_fstream << "\n"; } - //catch( ... ) - // { - // throw DGtal::IOException(); - // } + catch( ... ) + { + throw DGtal::IOException(); + } return *this; } From 93b94dc4292851fbfba5448d5ae64a3e724f00e3 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Wed, 28 Jan 2015 14:44:00 +0100 Subject: [PATCH 106/108] Cleaning old file. Roll-backs the profile. --- deformations/deformation2d.old.cpp | 394 ---------------------- deformations/deformation3d.old.cpp | 489 ---------------------------- deformations/deformationFunctions.h | 3 +- 3 files changed, 1 insertion(+), 885 deletions(-) delete mode 100644 deformations/deformation2d.old.cpp delete mode 100644 deformations/deformation3d.old.cpp diff --git a/deformations/deformation2d.old.cpp b/deformations/deformation2d.old.cpp deleted file mode 100644 index dc12388..0000000 --- a/deformations/deformation2d.old.cpp +++ /dev/null @@ -1,394 +0,0 @@ -#include -#include -#include - -///////////////////// -#include -#include -#include - -namespace po = boost::program_options; - -///////////////////// -#include -#include -#include "DGtal/io/readers/PGMReader.h" - -using namespace DGtal; -using namespace Z2i; -using namespace std; - -//evolvers -//level set -#include "WeickertKuhneEvolver.h" - -//phase field -#include "ExactDiffusionEvolver.h" -#include "ExplicitReactionEvolver.h" -#include "ExactReactionEvolver.h" -#include "LieSplittingEvolver.h" -#include "MultiPhaseField.h" - -//local level set -#include "BinaryPredicates.h" -#include "SimplePointHelper.h" -#include "PartitionEvolver.h" - - - -/////////////////////////// useful functions -#include "deformationFunctions.h" -#include "deformationDisplay2d.h" - - -/////////////////////////////////////////////////////////////////// -int main(int argc, char** argv) -{ - - DGtal::trace.info() << "2d interface evolution using DGtal "; - DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; - - // parse command line ---------------------------------------------- - po::options_description general_opt("Allowed options are"); - general_opt.add_options() - ("help,h", "display this message") - ("inputImage,i", po::value(), "Binary image to initialize the starting interface (.pgm)" ) - ("domainSize,d", po::value()->default_value(64), "Domain size (if default starting interface)" ) - ("shape,s", po::value()->default_value("ball"), - "Generated shape: either (default) or " ) - ("timeStep,t", po::value()->default_value(0.25), "Time step for the evolution" ) - ("displayStep", po::value()->default_value(1), "Number of time steps between 2 drawings" ) - ("stepsNumber,n", po::value()->default_value(1), "Maximal number of steps" ) - ("algo,a", po::value()->default_value("levelSet"), - "can be: \n \n or \n or \n or " ) - ("balloonForce,k", po::value()->default_value(0.0), "Balloon force" ) - ("epsilon,e", po::value()->default_value(3.0), "Interface width (only for phase fields)" ) - ("withCstVol", "with volume conservation (only for phase fields)" ) - ("withFunction", po::value(), "Output pgm file basename, where the starting implicit function is stored" ) - ("outputFiles,o", po::value()->default_value("interface"), "Output files basename" ) - ("outputFormat,f", po::value()->default_value("raster"), - "Output files format: either (image, default) or (domain representation)" ); - - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, general_opt), vm); - po::notify(vm); - if(vm.count("help")||argc<=1) - { - trace.info()<< "Evolution of a 2d interface" << std::endl - << "Basic usage: "< -n " << std::endl - << general_opt << "\n"; - return 0; - } - - //Parse options - //domain size - int dsize; - if (!(vm.count("domainSize"))) trace.info() << "Domain size default value: 64" << std::endl; - dsize = vm["domainSize"].as(); - - //time step - double tstep; - if (!(vm.count("timeStep"))) trace.info() << "time step default value: 1.0" << std::endl; - tstep = vm["timeStep"].as(); - - //iterations - int step; - if (!(vm.count("displayStep"))) trace.info() << "number of steps between two drawings: 1 by default" << std::endl; - step = vm["displayStep"].as(); - int max; - if (!(vm.count("stepsNumber"))) trace.info() << "maximal number of steps: 1 by default" << std::endl; - max = vm["stepsNumber"].as(); - - //files - std::string outputFiles; - if (!(vm.count("outputFiles"))) - trace.info() << "output files beginning with : interface" << std::endl; - outputFiles = vm["outputFiles"].as(); - - //files format - std::string format; - if (!(vm.count("outputFormat"))) - trace.info() << "output files format is 'vector' " << std::endl; - format = vm["outputFormat"].as(); - if ((format != "vector")&&(format != "raster")) - { - trace.info() << "format is expected to be either vector, or raster " << std::endl; - return 0; - } - - //image and implicit function - typedef ImageContainerBySTLVector LabelImage; - LabelImage* labelImage = NULL; - - if (vm.count("inputImage")) - { - string imageFileName = vm["inputImage"].as(); - trace.emphase() << imageFileName <::importPGM( imageFileName ); - labelImage = new LabelImage( tmp ); - DGtal::trace.endBlock(); - - std::stringstream ss; - ss << outputFiles << "0000"; - drawContours(*labelImage, ss.str(), format); - - } - else - { - DGtal::trace.beginBlock("image reading..."); - Point p(0,0); - Point q(dsize,dsize); - Point c(dsize/2,dsize/2); - labelImage = new LabelImage( Domain(p,q) ); - if (vm.count("shape")) - { - if ( (vm["shape"].as()) == "flower" ) - initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - } - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - trace.info() << "starting interface initialized with a " - << (vm["shape"].as()) << std::endl; - DGtal::trace.endBlock(); - } - - //domain - Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); - - - //algo - std::string algo; - if (!(vm.count("algo"))) trace.info() << "default algorithm: levelSet" << std::endl; - algo = vm["algo"].as(); - - if (algo.compare("levelSet")==0) - { - - //balloon force - double k; - if (!(vm.count("balloonForce"))) trace.info() << "balloon force default value: 0" << std::endl; - k = vm["balloonForce"].as(); - - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - if (vm.count("withFunction")) - drawFunction( implicitFunction, vm["withFunction"].as() ); - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format); - - //data functions - ImageContainerBySTLVector a( implicitFunction.domain() ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( implicitFunction.domain() ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( implicitFunction.domain() ); - std::fill(g.begin(),g.end(), 1.0 ); - - //evolution - WeickertKuhneEvolver > e(a,b,g,k,1); - - DGtal::trace.beginBlock( "Deformation (Weickert level set method)" ); - - for (unsigned int i = 1; i <= max; ++i) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( implicitFunction, tstep); - - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format); - } - - //area - trace.info() << "# area: " << getSize( implicitFunction ) << std::endl; - } - - DGtal::trace.endBlock(); - - } else if (algo.compare("phaseField")==0) - { - - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } - - bool flagWithCstVol = false; - if (vm.count("withCstVol")) - flagWithCstVol = true; - - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - //computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - - if (vm.count("withFunction")) - drawFunction( implicitFunction, vm["withFunction"].as() ); - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContour(implicitFunction, ss.str(), format, 0.5); - - - - typedef ExactDiffusionEvolver > Diffusion; - typedef ExactReactionEvolver > Reaction; - Diffusion diffusion; - Reaction reaction( epsilon ); - // typedef ExplicitReactionEvolver, - // ImageContainerBySTLVector > Reaction; - // ImageContainerBySTLVector a( implicitFunction.domain() ); - // std::fill(a.begin(),a.end(), 1 ); - // Diffusion diffusion; - // Reaction reaction( epsilon, a, k, flagWithCstVol ); - LieSplittingEvolver e(diffusion, reaction); - - DGtal::trace.beginBlock( "Deformation (phase field)" ); - - for (unsigned int i = 1; i <= max; ++i) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( implicitFunction, tstep); - - if ((i%step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContour(implicitFunction, s.str(), format, 0.5); - } - - //area - trace.info() << "# area: " << getSize( implicitFunction, 0.5 ) << std::endl; - - } - - DGtal::trace.endBlock(); - } else if (algo.compare("localLevelSet")==0) - { - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContours(*labelImage, ss.str(), format); - - //space - KSpace ks; - ks.init( d.lowerBound(), d.upperBound(), true ); - - //distance image... - typedef ImageContainerBySTLVector DistanceImage; - //and extern data... - DistanceImage g( d ); - std::fill(g.begin(), g.end(), 1.0); - - // topological predicate - // typedef TrueBinaryPredicate TopologicalPredicate; - // TopologicalPredicate topologicalPredicate; - typedef SimplePointHelper TopologicalPredicate; - TopologicalPredicate topologicalPredicate(*labelImage); - - //frontier evolver - DGtal::trace.beginBlock( "Partition construction" ); - PartitionEvolver - e(ks, *labelImage, g, topologicalPredicate); - - DGtal::trace.info() << e << std::endl; - DGtal::trace.endBlock(); - - DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); - - double sumt = 0; - for (unsigned int i = 1; i <= max; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - //update - e.update(tstep); - - if ((i%step)==0) - { - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContours(*labelImage, s.str(), format); - } - sumt += tstep; - } - - DGtal::trace.endBlock(); - - } else if (algo.compare("multiPhaseField")==0) - { - - double epsilon = 3.0; - if (!(vm.count("epsilon"))) trace.info() << "epsilon default value: 3.0" << std::endl; - epsilon = vm["epsilon"].as(); - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 0; - } - - std::stringstream ss; - ss << outputFiles << "0001"; - drawContours(*labelImage, ss.str(), format); - - typedef ImageContainerBySTLVector FieldImage; - typedef ExactDiffusionEvolver Diffusion; - typedef ExactReactionEvolver Reaction; - Diffusion diffusion; - Reaction reaction( epsilon ); - LieSplittingEvolver phaseField(diffusion, reaction); - MultiPhaseField > e(*labelImage, phaseField); - - DGtal::trace.beginBlock( "Deformation (multi phase field)" ); - - for (unsigned int i = step; i <= max; i += step) - { - - DGtal::trace.info() << "iteration # " << i << std::endl; - - e.update( tstep ); - - if ((i%step)==0) - { - //display - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/step)+1; - drawContours(*labelImage, s.str(), format); - } - - } - - DGtal::trace.endBlock(); - } else trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; - - - DGtal::trace.info() << "end" << std::endl; - - //free - delete( labelImage ); - - return 1; -} - diff --git a/deformations/deformation3d.old.cpp b/deformations/deformation3d.old.cpp deleted file mode 100644 index 2783950..0000000 --- a/deformations/deformation3d.old.cpp +++ /dev/null @@ -1,489 +0,0 @@ -#include -#include -#include -#include -#include - -///////////////////// -#include -#include -#include - -namespace po = boost::program_options; - -///////////////////// -#include -#include - -using namespace DGtal; -using namespace Z3i; -using namespace std; - -//evolvers -//level set -#include "WeickertKuhneEvolver.h" - -//phase field -#include "ExactDiffusionEvolver.h" -#include "ExactReactionEvolver.h" -#include "ExplicitReactionEvolver.h" -#include "LieSplittingEvolver.h" -#include "MultiPhaseField.h" - -//local level set -#include "SimplePointHelper.h" -#include "PartitionEvolver.h" - -/////////////////////////// useful functions -#include "deformationFunctions.h" -#include "deformationDisplay3d.h" -#include "DGtal/io/readers/VolReader.h" -#include "VTKWriter.h" - -// Qt -#include - -/////////////////////////////////////////////////////////////////// -int main(int argc, char** argv) -{ - - DGtal::trace.info() << "3d interface evolution using DGtal "; - DGtal::trace.emphase() << "(version "<< DGTAL_VERSION << ")"<< std::endl; - - // QApplication initialization with command-line parameters - QApplication application(argc, argv); - - // Default options - size_t dsize = 64; // Domain size - double tstep = 0.25; // Time step - size_t disp_step = 1; // Display step - size_t max_step = 1; // Maximum number of steps - string shape = "ball"; // Generated shape - string algo = "levelSet"; // Algorithm used for evolution - double balloon = 0.; // Balloon Force - double epsilon = 3.; // Interface width - - string outputFiles = "interface"; // Output files basename - string outputFormat = "vol"; // Output files format - bool flagWithCstVol = false; // Volume Conservation - bool flagWithVisu = false; // Interactive 3d visualization after evolution - - // Parse command line ---------------------------------------------- - po::options_description general_opt("Allowed options are"); - general_opt.add_options() - ("help,h", "display this message") - ("inputImage,i", po::value(), "Binary image to initialize the starting interface (vol format)" ) - ("domainSize,d", po::value(&dsize)->default_value(dsize), "Domain size (if default starting interface)" ) - ("shape,s", po::value(&shape)->default_value(shape), - "Generated shape: either or " ) - ("timeStep,t", po::value(&tstep)->default_value(tstep), "Time step for the evolution" ) - ("displayStep", po::value(&disp_step)->default_value(disp_step), "Number of time steps between 2 drawings" ) - ("stepsNumber,n", po::value(&max_step)->default_value(max_step), "Maximal number of steps" ) - ("algo,a", po::value(&algo)->default_value(algo), - "can be: \n \n or \n or \n or " ) - ("balloonForce,k", po::value(&balloon)->default_value(balloon), "Balloon force" ) - ("epsilon,e", po::value(&epsilon)->default_value(epsilon), "Interface width (only for phase fields)" ) - ("withCstVol", po::bool_switch(&flagWithCstVol), "with volume conservation (only for phase fields)" ) - ("outputFiles,o", po::value(&outputFiles)->default_value(outputFiles), "Output files basename" ) - ("outputFormat,f", po::value(&outputFormat)->default_value(outputFormat), - "Output files format: either (3d to 2d with QGLViewer), (3d to 2d with Cairo) or (3d)" ) - ("withVisu", po::bool_switch(&flagWithVisu), "Enables interactive 3d visualization after evolution" ); - - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, general_opt), vm); - po::notify(vm); - if(vm.count("help") || argc<=1) - { - trace.info()<< "Evolution of a 3d interface" << std::endl - << "Basic usage: "< -n --withVisu" - << std::endl - << general_opt << "\n"; - return 1; - } - - // Options validity - // Files format - if ( (outputFormat != "png") && (outputFormat != "vol") && (outputFormat != "pngc") ) - { - trace.info() << "format is expected to be either , or " << std::endl; - return 1; - } - - // Generated shape - if ( vm.count("inputImage") == 0 && shape != "ball" && shape != "flower" ) - { - trace.info() << "if no input file is specified, shape is expected to be either or " << std::endl; - return 1; - } - - // Evolution algorithm - if ( algo != "levelSet" && algo != "phaseField" && algo != "multiPhaseField" && algo != "localLevelSet" ) - { - trace.info() << "algo is expected to be either , , or " << std::endl; - return 1; - } - - - // Image and implicit function - typedef ImageContainerBySTLVector LabelImage; - LabelImage* labelImage = NULL; - - if (vm.count("inputImage")) - { - string imageFileName = vm["inputImage"].as(); - trace.emphase() << imageFileName <::importVol( imageFileName ); - labelImage = new LabelImage( tmp ); - DGtal::trace.endBlock(); - } - else - { - DGtal::trace.beginBlock("image reading..."); - Point p(0, 0, 0); - Point q(dsize, dsize, dsize); - Point c(dsize/2, dsize/2, dsize/2); - labelImage = new LabelImage( Domain(p,q) ); - - if ( (vm["shape"].as()) == "flower" ) - initWithFlowerPredicate( *labelImage, c, (dsize*3/5)/2, (dsize*1/5)/2, 5 ); - else - initWithBallPredicate( *labelImage, c, (dsize*3/5)/2 ); - - trace.info() << "starting interface initialized with a " << shape << std::endl; - - DGtal::trace.endBlock(); - } - - // Domain - Domain d = Domain( labelImage->domain().lowerBound(), labelImage->domain().upperBound() ); - - // Pre-visualization for choosing camera position - if (outputFormat == "png") - displayPartition( *labelImage ); - - // Algorithm dispatch - if ( algo == "levelSet" ) - { - - // Distance function - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - // Data functions - ImageContainerBySTLVector a( d ); - std::fill(a.begin(),a.end(), 1.0 ); - ImageContainerBySTLVector b( d ); - std::fill(b.begin(),b.end(), 1.0 ); - ImageContainerBySTLVector g( d ); - std::fill(g.begin(),g.end(), 1.0 ); - - // Interface evolver - WeickertKuhneEvolver > e(a, b, g, balloon, 1); - - DGtal::trace.beginBlock( "Deformation (Weickert's level set method)" ); - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(implicitFunction,tstep); - - // Display - if ((i % disp_step) == 0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - updateLabelImage( *labelImage, implicitFunction ); - writePartition( *labelImage, s.str(), outputFormat ); - } - - sumt += tstep; - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - updateLabelImage( *labelImage, implicitFunction, 0 ); - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0) << std::endl; - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayImageWithInfo( *labelImage, implicitFunction, a, b ); - - } - else if ( algo == "phaseField" ) - { - // Option's validity - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 1; - } - - // Distance function - ImageContainerBySTLVector implicitFunction( d ); - initWithDT( *labelImage, implicitFunction ); - - // Computing the profile from the signed distance - Profile p(epsilon); - std::transform(implicitFunction.begin(), implicitFunction.end(), implicitFunction.begin(), p); - - // Diffusion evolver - typedef ExactDiffusionEvolver > Diffusion; - Diffusion diffusion; - - // Exact reaction evolver (no possible volume conservation) - /* - typedef ExactReactionEvolver > Reaction; - Reaction reaction( epsilon ); - */ - - // Explicit reaction evolver (with possible volume conservation) - typedef ExplicitReactionEvolver< - ImageContainerBySTLVector, - ImageContainerBySTLVector - > Reaction; - ImageContainerBySTLVector a( Domain( implicitFunction.domain() ) ); - std::fill(a.begin(), a.end(), 0.0 ); - Reaction reaction( epsilon, a, balloon, flagWithCstVol ); - - // Lie splitting - LieSplittingEvolver e(diffusion, reaction); - - DGtal::trace.beginBlock( "Deformation (phase field)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - { - VTKWriter vtk(s.str(), implicitFunction.domain()); - vtk << "phi" << implicitFunction; - } - - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(implicitFunction, tstep); - - // Display - if ((i % disp_step)==0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - updateLabelImage( *labelImage, implicitFunction, 0.5 ); - - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - VTKWriter vtk(s.str(), implicitFunction.domain()); - vtk << "phi" << implicitFunction; - } - - sumt += tstep; - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; - - const double vol_test = std::accumulate( implicitFunction.begin(), implicitFunction.end(), 0.); - DGtal::trace.info() << "Real volume: " << vol_test << std::endl; - - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - // Post-processing - updateLabelImage( *labelImage, implicitFunction, 0.5 ); - DGtal::trace.info() << "Volume: " << getSize(*labelImage, 0.5) << std::endl; - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayPartition( *labelImage ); - - } - else if ( algo == "multiPhaseField" ) - { - // Options's validity - if (epsilon <= 0) - { - trace.error() << "epsilon should be greater than 0" << std::endl; - return 1; - } - - // Field image - typedef ImageContainerBySTLVector FieldImage; - - // Diffusion evolver - typedef ExactDiffusionEvolver< FieldImage > Diffusion; - Diffusion diffusion; - - // Exact Reaction Evolver (no possible volume conservation) - /* - typedef ExactReactionEvolver < FieldImage > Reaction; - Reaction reaction( epsilon ); - */ - - // Explicit Reaction Evolver (with possible volume conservation) - typedef ExplicitReactionEvolver< - ImageContainerBySTLVector, - ImageContainerBySTLVector - > Reaction; - ImageContainerBySTLVector a( d ); - std::fill(a.begin(), a.end(), 0.0 ); - Reaction reaction( epsilon, a, balloon, flagWithCstVol ); - - // Lie splitting - LieSplittingEvolver< Diffusion, Reaction > phaseEvolver(diffusion, reaction); - - // Multi phase-field - MultiPhaseField< LabelImage, FieldImage, LieSplittingEvolver > evolver(*labelImage, phaseEvolver); - - DGtal::trace.beginBlock( "Deformation (multi phase field)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - // VTK export - { - VTKWriter vtk(s.str(), labelImage->domain()); - for (size_t j = 0; j < evolver.getNumPhase(); ++j) - { - stringstream s_phase; - s_phase << "phi" << setfill('0') << std::setw(2) << j; - vtk << s_phase.str() << evolver.getPhase(j); - } - } - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - evolver.update( tstep ); - - // Display - if ( (i % disp_step) == 0 ) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - - writePartition( *labelImage, s.str(), outputFormat ); - - // VTK export - VTKWriter vtk(s.str(), labelImage->domain()); - for (size_t j = 0; j < evolver.getNumPhase(); ++j) - { - stringstream s_phase; - s_phase << "phi" << setfill('0') << std::setw(2) << j; - vtk << s_phase.str() << evolver.getPhase(j); - } - - } - - sumt += tstep; - - // Volume of each phase - typedef std::map Histo; - Histo histo; - calcHistogram( *labelImage, histo ); - DGtal::trace.info() << "Volume: "; - for ( Histo::const_iterator it = histo.begin(); it != histo.end(); ++it ) - DGtal::trace.info() << "V(" << it->first << ") = " << it->second; - DGtal::trace.info() << std::endl; - - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) - displayPartition( *labelImage ); - - } - else if ( algo == "localLevelSet" ) - { - // Space - KSpace ks; - ks.init( d.lowerBound(), d.upperBound(), true ); - - // Distance image... - typedef ImageContainerBySTLVector DistanceImage; - // ... and extern data. - DistanceImage g( d ); - std::fill(g.begin(), g.end(), 1.0); - - // Topological predicate - typedef SimplePointHelper TopologicalPredicate; - TopologicalPredicate topologicalPredicate(*labelImage); - - // Frontier evolver - PartitionEvolver - e(ks, *labelImage, g, topologicalPredicate); - - DGtal::trace.info() << e << std::endl; - - DGtal::trace.beginBlock( "Deformation (narrow band with topological control)" ); - - // Initial state export - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << 0; - writePartition( *labelImage, s.str(), outputFormat ); - - // Time integration - double sumt = 0; - for (unsigned int i = 1; i <= max_step; ++i) - { - DGtal::trace.info() << "iteration # " << i << std::endl; - - // Update - e.update(tstep); - - // Display - if ((i % disp_step) == 0) - { - std::stringstream s; - s << outputFiles << setfill('0') << std::setw(4) << (i/disp_step); - writePartition( *labelImage, s.str(), outputFormat ); - } - - sumt += tstep; - DGtal::trace.info() << "Time spent: " << sumt << std::endl; - } - - DGtal::trace.endBlock(); - - // Interactive display after the evolution - if ( flagWithVisu ) displayPartition( *labelImage ); - - } - else - { - trace.error() << "unknown algo. Try option -h to see the available algorithms " << std::endl; - return 1; - } - - // Free - delete( labelImage ); - - return 0; -} - -/* GNU coding style */ -/* vim: set ts=2 sw=2 expandtab cindent cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 : */ - diff --git a/deformations/deformationFunctions.h b/deformations/deformationFunctions.h index 135e812..21dcff6 100644 --- a/deformations/deformationFunctions.h +++ b/deformations/deformationFunctions.h @@ -302,8 +302,7 @@ class Profile { Profile (const double& anEpsilon) : myEpsilon( anEpsilon ) {} double operator()( const double& v ) { - //return 0.5 - 0.5*std::tanh(-v/(2*myEpsilon)); - return 0.5 - 0.5*std::tanh(-v/myEpsilon); + return 0.5 - 0.5*std::tanh(-v/(2*myEpsilon)); } }; From 41277eb15c5a02019d3e8827692bf81f56ed64b7 Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Wed, 8 Apr 2015 12:13:54 +0200 Subject: [PATCH 107/108] Relaxing images concept checking for VTK export. CConstImage instead of CImage. --- deformations/VTKWriter.h | 3 ++- deformations/VTKWriter.ih | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/deformations/VTKWriter.h b/deformations/VTKWriter.h index b49bfd6..9b64759 100644 --- a/deformations/VTKWriter.h +++ b/deformations/VTKWriter.h @@ -46,6 +46,7 @@ #include #include +#include ////////////////////////////////////////////////////////////////////////////// namespace DGtal @@ -122,7 +123,7 @@ namespace DGtal * @todo enable only if TImage is a model a concepts::CImage !! */ template - BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), + BOOST_CONCEPT_REQUIRES( (( concepts::CConstImage )), ( VTKWriter,Binary> & )) operator<< ( TImage const& field ); diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index 3e64d6c..6e6562c 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -247,7 +247,7 @@ operator<< ( const char* fieldname ) */ template template -BOOST_CONCEPT_REQUIRES( (( concepts::CImage )), +BOOST_CONCEPT_REQUIRES( (( concepts::CConstImage )), ( DGtal::VTKWriter< HyperRectDomain, Binary > & )) DGtal::VTKWriter< HyperRectDomain, Binary >:: operator<< ( TImage const& field ) @@ -267,7 +267,7 @@ DGtal::VTKWriter< HyperRectDomain, Binary > & DGtal::VTKWriter< HyperRectDomain, Binary >:: write ( std::string const& fieldname, TImage const& field ) { - BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage) ); + BOOST_CONCEPT_ASSERT( (DGtal::concepts::CConstImage) ); // Write header if not already done init(); From a021455893d8269e0b1f1ff8c59181add645a3cf Mon Sep 17 00:00:00 2001 From: Roland Denis Date: Wed, 8 Apr 2015 17:25:39 +0200 Subject: [PATCH 108/108] Fixing lack of DGtal:: before HyperRectDomain ... ... by brute force : namespace DGtal {}. --- deformations/VTKWriter.ih | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/deformations/VTKWriter.ih b/deformations/VTKWriter.ih index 6e6562c..d44c9bf 100644 --- a/deformations/VTKWriter.ih +++ b/deformations/VTKWriter.ih @@ -39,7 +39,7 @@ #include #include -#include +#include ////////////////////////////////////////////////////////////////////////////// @@ -137,6 +137,9 @@ struct VTKDataWriter // IMPLEMENTATION of inline methods. /////////////////////////////////////////////////////////////////////////////// +namespace DGtal +{ + /////////////////////////////////////////////////////////////////////////////// // ----------------------- Standard services ------------------------------ @@ -145,7 +148,7 @@ struct VTKDataWriter */ template inline -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary >:: VTKWriter( std::string const& filename, HyperRectDomain domain ) : m_domain(domain), m_fieldname(""), m_fstream( filename+".vtk", std::ofstream::out | std::ofstream::binary ), @@ -158,7 +161,7 @@ VTKWriter( std::string const& filename, HyperRectDomain domain ) */ template inline -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary >:: ~VTKWriter() { close(); @@ -174,7 +177,7 @@ DGtal::VTKWriter< HyperRectDomain, Binary >:: template inline bool -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary >:: isValid() const { return m_fstream.good(); @@ -184,8 +187,8 @@ isValid() const * Write the VTK header */ template -DGtal::VTKWriter< HyperRectDomain, Binary > & -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary > & +VTKWriter< HyperRectDomain, Binary >:: init() { if ( !m_header ) @@ -210,7 +213,7 @@ init() } catch( ... ) { - throw DGtal::IOException(); + throw IOException(); } m_header = true; @@ -224,8 +227,8 @@ init() */ template inline -DGtal::VTKWriter< HyperRectDomain, Binary > & -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary > & +VTKWriter< HyperRectDomain, Binary >:: operator<< ( std::string const& fieldname ) { m_fieldname = fieldname; @@ -234,8 +237,8 @@ operator<< ( std::string const& fieldname ) template inline -DGtal::VTKWriter< HyperRectDomain, Binary > & -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary > & +VTKWriter< HyperRectDomain, Binary >:: operator<< ( const char* fieldname ) { m_fieldname = fieldname; @@ -248,8 +251,8 @@ operator<< ( const char* fieldname ) template template BOOST_CONCEPT_REQUIRES( (( concepts::CConstImage )), -( DGtal::VTKWriter< HyperRectDomain, Binary > & )) -DGtal::VTKWriter< HyperRectDomain, Binary >:: +( VTKWriter< HyperRectDomain, Binary > & )) +VTKWriter< HyperRectDomain, Binary >:: operator<< ( TImage const& field ) { return write( m_fieldname, field ); @@ -263,11 +266,11 @@ template < typename TImage, typename T > -DGtal::VTKWriter< HyperRectDomain, Binary > & -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary > & +VTKWriter< HyperRectDomain, Binary >:: write ( std::string const& fieldname, TImage const& field ) { - BOOST_CONCEPT_ASSERT( (DGtal::concepts::CConstImage) ); + BOOST_CONCEPT_ASSERT( (concepts::CConstImage) ); // Write header if not already done init(); @@ -294,7 +297,7 @@ write ( std::string const& fieldname, TImage const& field ) } catch( ... ) { - throw DGtal::IOException(); + throw IOException(); } return *this; @@ -305,7 +308,7 @@ write ( std::string const& fieldname, TImage const& field ) */ template void -DGtal::VTKWriter< HyperRectDomain, Binary >:: +VTKWriter< HyperRectDomain, Binary >:: close() { m_fstream.close(); @@ -315,7 +318,7 @@ close() * Internale data stream */ template -DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +VTKWriter< HyperRectDomain, Binary >::DataStream:: DataStream( std::ofstream & fstream ) : m_fstream(fstream) { @@ -324,8 +327,8 @@ DataStream( std::ofstream & fstream ) template template -typename DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream & -DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +typename VTKWriter< HyperRectDomain, Binary >::DataStream & +VTKWriter< HyperRectDomain, Binary >::DataStream:: operator<< ( TValue const& value ) { VTKDataWriter::write( m_fstream, value ); @@ -334,7 +337,7 @@ operator<< ( TValue const& value ) template std::string -DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +VTKWriter< HyperRectDomain, Binary >::DataStream:: data_format() { return VTKDataWriter::data_format(); @@ -342,12 +345,14 @@ data_format() template void -DGtal::VTKWriter< HyperRectDomain, Binary >::DataStream:: +VTKWriter< HyperRectDomain, Binary >::DataStream:: separator() { m_fstream << VTKDataWriter::separator(); } +} // namespace DGtal + // // ///////////////////////////////////////////////////////////////////////////////