<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "meshobjectreader.h"

// appleseed.renderer headers.
#include "renderer/modeling/object/meshobject.h"
#include "renderer/modeling/object/triangle.h"

// appleseed.foundation headers.
#include "foundation/core/exceptions/exception.h"
#include "foundation/core/exceptions/exceptionioerror.h"
#include "foundation/math/triangulator.h"
#include "foundation/mesh/imeshbuilder.h"
#include "foundation/mesh/imeshfilereader.h"
#include "foundation/mesh/objmeshfilereader.h"
#include "foundation/utility/foreach.h"
#include "foundation/utility/memory.h"
#include "foundation/utility/stopwatch.h"
#include "foundation/utility/string.h"

// Standard headers.
#include <vector>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// MeshObjectArray class implementation.
//

DEFINE_ARRAY(MeshObjectArray);

//
// MeshObjectReader class implementation.
//

namespace
{
//
// Disable erroneous Visual Studio warning C4267:
//
//   conversion from 'size_t' to 'foundation::uint32', possible loss of data
//
// for this piece of code. This is a workaround for a bug in Visual Studio:
//
//   https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=253172
//

#pragma warning (push)
#pragma warning (disable : 4267)

    //
    // Mesh object builder.
    //

    class MeshObjectBuilder
      : public IMeshBuilder
    {
      public:
        typedef vector<MeshObject*> MeshObjectVector;

        MeshObjectBuilder(
            const ParamArray&   params,
            const string&       base_object_name)
          : m_params(params)
          , m_base_object_name(base_object_name)
          , m_untitled_mesh_counter(0)
        {
        }

        const MeshObjectVector& get_objects() const
        {
            return m_objects;
        }

        virtual void begin_mesh(const string& name)
        {
            string object_name;
            if (name.empty())
            {
                // Anonymous meshes are assigned increasing numbers, starting at 0.
                object_name = m_base_object_name + "." +
                    to_string<size_t>(m_untitled_mesh_counter++);
            }
            else
            {
                // Generate the object name from the base name and the mesh name.
                object_name = m_base_object_name + "." + name;
            }

            // Create an empty mesh object.
            m_objects.push_back(
                MeshObjectFactory::create(object_name.c_str(), m_params).release());

            m_face_count = 0;
            m_triangulation_errors = 0;
        }

        virtual void end_mesh()
        {
            // Print the number of faces that could not be triangulated (if any).
            if (m_triangulation_errors > 0)
            {
                RENDERER_LOG_WARNING(
                    "%s polygonal %s (out of %s) could not be triangulated",
                    pretty_int(m_triangulation_errors).c_str(),
                    plural(m_triangulation_errors, "face").c_str(),
                    pretty_int(m_face_count).c_str());
            }

            // Print the number of vertices and triangles in the mesh.
            const size_t vertex_count = m_objects.back()->get_vertex_count();
            const size_t triangle_count = m_objects.back()->get_triangle_count();
            RENDERER_LOG_INFO(
                "loaded mesh object \"%s\" (%s %s, %s %s)",
                m_objects.back()->get_name(),
                pretty_int(vertex_count).c_str(),
                plural(vertex_count, "vertex", "vertices").c_str(),
                pretty_int(triangle_count).c_str(),
                plural(triangle_count, "triangle").c_str());
        }

        virtual size_t push_vertex(const Vector3d& v)
        {
            return m_objects.back()->push_vertex(GVector3(v));
        }

        virtual size_t push_vertex_normal(const Vector3d& v)
        {
            return m_objects.back()->push_vertex_normal(GVector3(v));
        }

        virtual size_t push_tex_coords(const Vector2d& v)
        {
            return m_objects.back()->push_tex_coords(GVector2(v));
        }

        virtual void begin_face(const size_t vertex_count)
        {
            assert(vertex_count >= 3);

            clear_keep_memory(m_face_vertices);
            clear_keep_memory(m_face_normals);
            clear_keep_memory(m_face_tex_coords);

            ++m_face_count;

            m_vertex_count = vertex_count;
            m_face_material = Triangle::None;
        }

        virtual void end_face()
        {
            assert(m_face_vertices.size() == m_vertex_count);
            assert(m_face_normals.size() == 0 || m_face_normals.size() == m_vertex_count);
            assert(m_face_tex_coords.size() == 0 || m_face_tex_coords.size() == m_vertex_count);

            if (m_vertex_count > 3)
            {
                // Create the polygon to triangulate.
                clear_keep_memory(m_polygon);
                for (size_t i = 0; i < m_face_vertices.size(); ++i)
                {
                    m_polygon.push_back(
                        Vector3d(m_objects.back()->get_vertex(m_face_vertices[i])));
                }

                // Triangulate the polygonal face.
                clear_keep_memory(m_triangles);
                if (!m_triangulator.triangulate(m_polygon, m_triangles))
                {
                    // Skip problematic polygonal faces.
                    ++m_triangulation_errors;
                    return;
                }

                // Insert all triangles of the triangulation into the mesh.
                for (size_t i = 0; i < m_triangles.size(); i += 3)
                {
                    insert_triangle(
                        m_triangles[i + 0],
                        m_triangles[i + 1],
                        m_triangles[i + 2]);
                }
            }
            else
            {
                // The face is already a triangle, no triangulation is necessary.
                insert_triangle(0, 1, 2);
            }
        }

        virtual void set_face_vertices(const size_t vertices[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_vertices.push_back(static_cast<uint32>(vertices[i]));
        }

        virtual void set_face_vertex_normals(const size_t vertex_normals[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_normals.push_back(static_cast<uint32>(vertex_normals[i]));
        }

        virtual void set_face_vertex_tex_coords(const size_t tex_coords[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_tex_coords.push_back(static_cast<uint32>(tex_coords[i]));
        }

        virtual void set_face_material(const size_t material)
        {
            m_face_material = static_cast<uint32>(material);
        }

      private:
        ParamArray              m_params;
        const string            m_base_object_name;
        size_t                  m_untitled_mesh_counter;
        MeshObjectVector        m_objects;

        size_t                  m_vertex_count;
        vector<uint32>          m_face_vertices;
        vector<uint32>          m_face_normals;
        vector<uint32>          m_face_tex_coords;
        uint32                  m_face_material;

        Triangulator<double>    m_triangulator;
        vector<Vector3d>        m_polygon;
        vector<size_t>          m_triangles;

        size_t                  m_face_count;
        size_t                  m_triangulation_errors;

        void insert_triangle(
            const size_t        v0_index,
            const size_t        v1_index,
            const size_t        v2_index)
        {
            Triangle triangle;

            // Set triangle vertices.
            triangle.m_v0 = m_face_vertices[v0_index];
            triangle.m_v1 = m_face_vertices[v1_index];
            triangle.m_v2 = m_face_vertices[v2_index];

            // Set triangle vertex normals.
            if (m_face_normals.size() == m_vertex_count)
            {
                triangle.m_n0 = m_face_normals[v0_index];
                triangle.m_n1 = m_face_normals[v1_index];
                triangle.m_n2 = m_face_normals[v2_index];
            }
            else
            {
                // Fetch the triangle vertices.
                const Vector3d v0 = Vector3d(m_objects.back()->get_vertex(triangle.m_v0));
                const Vector3d v1 = Vector3d(m_objects.back()->get_vertex(triangle.m_v1));
                const Vector3d v2 = Vector3d(m_objects.back()->get_vertex(triangle.m_v2));

                // Compute the geometric normal to the triangle.
                const Vector3d geometric_normal = normalize(cross(v1 - v0, v2 - v0));

                // Insert the geometric normal into the mesh.
                const size_t geometric_normal_index =
                    m_objects.back()->push_vertex_normal(GVector3(geometric_normal));

                // Assign the geometric normal to all vertices of the triangle.
                triangle.m_n0 = geometric_normal_index;
                triangle.m_n1 = geometric_normal_index;
                triangle.m_n2 = geometric_normal_index;
            }

            // Set triangle vertex texture coordinates (if any).
            if (m_face_tex_coords.size() == m_vertex_count)
            {
                triangle.m_a0 = m_face_tex_coords[v0_index];
                triangle.m_a1 = m_face_tex_coords[v1_index];
                triangle.m_a2 = m_face_tex_coords[v2_index];
            }
            else
            {
                triangle.m_a0 = Triangle::None;
                triangle.m_a1 = Triangle::None;
                triangle.m_a2 = Triangle::None;
            }

            // Set triangle material.
//          triangle.m_pa = m_face_material;
            triangle.m_pa = 0;

            // Insert the triangle into the mesh.
            m_objects.back()->push_triangle(triangle);
        }
    };

#pragma warning (pop)
}

MeshObjectArray MeshObjectReader::read(
    const char*         filename,
    const char*         base_object_name,
    const ParamArray&   params)
{
    assert(filename);
    assert(base_object_name);

    OBJMeshFileReader reader;
    MeshObjectBuilder builder(params, base_object_name);

    Stopwatch<DefaultWallclockTimer> stopwatch;
    stopwatch.start();

    try
    {
        reader.read(filename, builder);
    }
    catch (const OBJMeshFileReader::ExceptionInvalidFaceDef& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: invalid face definition on line " FMT_SIZE_T,
            filename,
            e.m_line);
        return MeshObjectArray();
    }
    catch (const OBJMeshFileReader::ExceptionParseError& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: parse error on line " FMT_SIZE_T,
            filename,
            e.m_line);
        return MeshObjectArray();
    }
    catch (const ExceptionIOError&)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: i/o error",
            filename);
        return MeshObjectArray();
    }
    catch (const Exception& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: %s",
            filename,
            e.what());
        return MeshObjectArray();
    }

    stopwatch.measure();

    MeshObjectArray objects;
    for (const_each<vector<MeshObject*> > i = builder.get_objects(); i; ++i)
        objects.push_back(*i);

    // Print the number of loaded objects.
    RENDERER_LOG_INFO(
        "loaded mesh file %s (%s %s) in %s",
        filename,
        pretty_int(objects.size()).c_str(),
        plural(objects.size(), "object").c_str(),
        pretty_time(stopwatch.get_seconds()).c_str());

    return objects;
}

}   // namespace renderer
<commit_msg>removed obsolete #pragma directives, cleaned up and simplified code.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "meshobjectreader.h"

// appleseed.renderer headers.
#include "renderer/modeling/object/meshobject.h"
#include "renderer/modeling/object/triangle.h"

// appleseed.foundation headers.
#include "foundation/core/exceptions/exception.h"
#include "foundation/core/exceptions/exceptionioerror.h"
#include "foundation/math/triangulator.h"
#include "foundation/mesh/imeshbuilder.h"
#include "foundation/mesh/imeshfilereader.h"
#include "foundation/mesh/objmeshfilereader.h"
#include "foundation/utility/foreach.h"
#include "foundation/utility/memory.h"
#include "foundation/utility/stopwatch.h"
#include "foundation/utility/string.h"

// Standard headers.
#include <vector>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// MeshObjectArray class implementation.
//

DEFINE_ARRAY(MeshObjectArray);

//
// MeshObjectReader class implementation.
//

namespace
{
    class MeshObjectBuilder
      : public IMeshBuilder
    {
      public:
        typedef vector<MeshObject*> MeshObjectVector;

        MeshObjectBuilder(
            const ParamArray&   params,
            const string&       base_object_name)
          : m_params(params)
          , m_base_object_name(base_object_name)
          , m_untitled_mesh_counter(0)
          , m_vertex_count(0)
          , m_face_material(0)
          , m_face_count(0)
          , m_triangulation_error_count(0)
        {
        }

        const MeshObjectVector& get_objects() const
        {
            return m_objects;
        }

        virtual void begin_mesh(const string& name)
        {
            // If the mesh has no name, assign it a number (starting with 0).
            const string mesh_name = name.empty() ? to_string(m_untitled_mesh_counter++) : name;

            // Construct the final object name from the base object name and the mesh name.
            const string object_name = m_base_object_name + "." + mesh_name;

            // Create an empty mesh object.
            m_objects.push_back(
                MeshObjectFactory::create(object_name.c_str(), m_params).release());

            m_face_count = 0;
            m_triangulation_error_count = 0;
        }

        virtual void end_mesh()
        {
            // Print the number of faces that could not be triangulated (if any).
            if (m_triangulation_error_count > 0)
            {
                RENDERER_LOG_WARNING(
                    "%s polygonal %s (out of %s) could not be triangulated",
                    pretty_int(m_triangulation_error_count).c_str(),
                    plural(m_triangulation_error_count, "face").c_str(),
                    pretty_int(m_face_count).c_str());
            }

            // Print the number of vertices and triangles in the mesh.
            const size_t vertex_count = m_objects.back()->get_vertex_count();
            const size_t triangle_count = m_objects.back()->get_triangle_count();
            RENDERER_LOG_INFO(
                "loaded mesh object \"%s\" (%s %s, %s %s)",
                m_objects.back()->get_name(),
                pretty_int(vertex_count).c_str(),
                plural(vertex_count, "vertex", "vertices").c_str(),
                pretty_int(triangle_count).c_str(),
                plural(triangle_count, "triangle").c_str());
        }

        virtual size_t push_vertex(const Vector3d& v)
        {
            return m_objects.back()->push_vertex(GVector3(v));
        }

        virtual size_t push_vertex_normal(const Vector3d& v)
        {
            return m_objects.back()->push_vertex_normal(GVector3(v));
        }

        virtual size_t push_tex_coords(const Vector2d& v)
        {
            return m_objects.back()->push_tex_coords(GVector2(v));
        }

        virtual void begin_face(const size_t vertex_count)
        {
            assert(vertex_count >= 3);

            clear_keep_memory(m_face_vertices);
            clear_keep_memory(m_face_normals);
            clear_keep_memory(m_face_tex_coords);

            ++m_face_count;

            m_vertex_count = vertex_count;
            m_face_material = Triangle::None;
        }

        virtual void end_face()
        {
            assert(m_face_vertices.size() == m_vertex_count);
            assert(m_face_normals.size() == 0 || m_face_normals.size() == m_vertex_count);
            assert(m_face_tex_coords.size() == 0 || m_face_tex_coords.size() == m_vertex_count);

            if (m_vertex_count > 3)
            {
                // Create the polygon to triangulate.
                clear_keep_memory(m_polygon);
                for (size_t i = 0; i < m_vertex_count; ++i)
                {
                    m_polygon.push_back(
                        Vector3d(m_objects.back()->get_vertex(m_face_vertices[i])));
                }

                // Triangulate the polygonal face.
                clear_keep_memory(m_triangles);
                if (!m_triangulator.triangulate(m_polygon, m_triangles))
                {
                    // Skip problematic polygonal faces.
                    ++m_triangulation_error_count;
                    return;
                }

                // Insert all triangles of the triangulation into the mesh.
                const size_t m_triangle_count = m_triangles.size();
                for (size_t i = 0; i < m_triangle_count; i += 3)
                {
                    insert_triangle(
                        m_triangles[i + 0],
                        m_triangles[i + 1],
                        m_triangles[i + 2]);
                }
            }
            else
            {
                // The face is already a triangle, no triangulation is necessary.
                insert_triangle(0, 1, 2);
            }
        }

        virtual void set_face_vertices(const size_t vertices[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_vertices.push_back(static_cast<uint32>(vertices[i]));
        }

        virtual void set_face_vertex_normals(const size_t vertex_normals[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_normals.push_back(static_cast<uint32>(vertex_normals[i]));
        }

        virtual void set_face_vertex_tex_coords(const size_t tex_coords[])
        {
            for (size_t i = 0; i < m_vertex_count; ++i)
                m_face_tex_coords.push_back(static_cast<uint32>(tex_coords[i]));
        }

        virtual void set_face_material(const size_t material)
        {
            m_face_material = static_cast<uint32>(material);
        }

      private:
        ParamArray              m_params;
        const string            m_base_object_name;
        size_t                  m_untitled_mesh_counter;
        MeshObjectVector        m_objects;

        size_t                  m_vertex_count;
        vector<uint32>          m_face_vertices;
        vector<uint32>          m_face_normals;
        vector<uint32>          m_face_tex_coords;
        uint32                  m_face_material;

        Triangulator<double>    m_triangulator;
        vector<Vector3d>        m_polygon;
        vector<size_t>          m_triangles;

        size_t                  m_face_count;
        size_t                  m_triangulation_error_count;

        void insert_triangle(
            const size_t        v0_index,
            const size_t        v1_index,
            const size_t        v2_index)
        {
            Triangle triangle;

            // Set triangle vertices.
            triangle.m_v0 = m_face_vertices[v0_index];
            triangle.m_v1 = m_face_vertices[v1_index];
            triangle.m_v2 = m_face_vertices[v2_index];

            // Set triangle vertex normals.
            if (m_face_normals.size() == m_vertex_count)
            {
                triangle.m_n0 = m_face_normals[v0_index];
                triangle.m_n1 = m_face_normals[v1_index];
                triangle.m_n2 = m_face_normals[v2_index];
            }
            else
            {
                // Fetch the triangle vertices.
                const Vector3d v0 = Vector3d(m_objects.back()->get_vertex(triangle.m_v0));
                const Vector3d v1 = Vector3d(m_objects.back()->get_vertex(triangle.m_v1));
                const Vector3d v2 = Vector3d(m_objects.back()->get_vertex(triangle.m_v2));

                // Compute the geometric normal to the triangle.
                const Vector3d geometric_normal = normalize(cross(v1 - v0, v2 - v0));

                // Insert the geometric normal into the mesh.
                const size_t geometric_normal_index =
                    m_objects.back()->push_vertex_normal(GVector3(geometric_normal));

                // Assign the geometric normal to all vertices of the triangle.
                triangle.m_n0 = geometric_normal_index;
                triangle.m_n1 = geometric_normal_index;
                triangle.m_n2 = geometric_normal_index;
            }

            // Set triangle vertex texture coordinates (if any).
            if (m_face_tex_coords.size() == m_vertex_count)
            {
                triangle.m_a0 = m_face_tex_coords[v0_index];
                triangle.m_a1 = m_face_tex_coords[v1_index];
                triangle.m_a2 = m_face_tex_coords[v2_index];
            }
            else
            {
                triangle.m_a0 = Triangle::None;
                triangle.m_a1 = Triangle::None;
                triangle.m_a2 = Triangle::None;
            }

            // Set triangle material.
//          triangle.m_pa = m_face_material;
            triangle.m_pa = 0;

            // Insert the triangle into the mesh.
            m_objects.back()->push_triangle(triangle);
        }
    };
}

MeshObjectArray MeshObjectReader::read(
    const char*         filename,
    const char*         base_object_name,
    const ParamArray&   params)
{
    assert(filename);
    assert(base_object_name);

    OBJMeshFileReader reader;
    MeshObjectBuilder builder(params, base_object_name);

    Stopwatch<DefaultWallclockTimer> stopwatch;
    stopwatch.start();

    try
    {
        reader.read(filename, builder);
    }
    catch (const OBJMeshFileReader::ExceptionInvalidFaceDef& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: invalid face definition on line " FMT_SIZE_T,
            filename,
            e.m_line);
        return MeshObjectArray();
    }
    catch (const OBJMeshFileReader::ExceptionParseError& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: parse error on line " FMT_SIZE_T,
            filename,
            e.m_line);
        return MeshObjectArray();
    }
    catch (const ExceptionIOError&)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: i/o error",
            filename);
        return MeshObjectArray();
    }
    catch (const Exception& e)
    {
        RENDERER_LOG_ERROR(
            "failed to load mesh file %s: %s",
            filename,
            e.what());
        return MeshObjectArray();
    }

    stopwatch.measure();

    MeshObjectArray objects;
    for (const_each<vector<MeshObject*> > i = builder.get_objects(); i; ++i)
        objects.push_back(*i);

    // Print the number of loaded objects.
    RENDERER_LOG_INFO(
        "loaded mesh file %s (%s %s) in %s",
        filename,
        pretty_int(objects.size()).c_str(),
        plural(objects.size(), "object").c_str(),
        pretty_time(stopwatch.get_seconds()).c_str());

    return objects;
}

}   // namespace renderer
<|endoftext|>


<commit_before>/*
 * PrimeSieve.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
 */

#include "PrimeSieve.h"
#include "defs.h"
#include "ParallelPrimeSieve.h"
#include "pmath.h"
#include "PreSieve.h"
#include "PrimeNumberFinder.h"
#include "PrimeNumberGenerator.h"

#include <stdexcept>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>

PrimeSieve::PrimeSieve() :
  startNumber_(0), stopNumber_(0), flags_(COUNT_PRIMES) {
  parent_ = this;
  this->setSieveSize(defs::PRIMESIEVE_SIEVESIZE);
  this->setPreSieveLimit(defs::PRIMESIEVE_PRESIEVE_LIMIT);
  this->reset();
}

/**
 * ParallelPrimeSieve uses multiple PrimeSieve objects and threads to
 * sieve primes in parallel.
 * @see ParallelPrimeSieve::sieve()
 */
PrimeSieve::PrimeSieve(uint64_t startNumber, uint64_t stopNumber,
    ParallelPrimeSieve* parent) :
  sieveSize_(parent->sieveSize_),
    flags_(parent->flags_),
    preSieveLimit_(parent->preSieveLimit_),
    callback_(parent->callback_),
    callbackOOP_(parent->callbackOOP_),
    cbObj_(parent->cbObj_),
    parent_(parent) {
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  this->reset();
}

uint64_t PrimeSieve::getStartNumber() const {
  return startNumber_;
}

uint64_t PrimeSieve::getStopNumber() const {
  return stopNumber_;
}

/**
 * Get the sieve size in Kilobytes.
 */
uint32_t PrimeSieve::getSieveSize() const {
  return sieveSize_;
}

uint32_t PrimeSieve::getPreSieveLimit() const {
  return preSieveLimit_;
}

/**
 * Get the current set public flags.
 */
uint32_t PrimeSieve::getFlags() const {
  // clear out private flags
  return flags_ & ((1u << 20) - 1);
}

/**
 * Get the count of prime numbers within the interval
 * [startNumber, stopNumber].
 */
uint64_t PrimeSieve::getPrimeCount(uint64_t startNumber, uint64_t stopNumber) {
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  this->setFlags(COUNT_PRIMES);
  this->sieve();
  return this->getPrimeCount();
}

/**
 * Get the count of prime numbers after sieve().
 */
uint64_t PrimeSieve::getPrimeCount() const {
  return counts_[0];
}

/**
 * Get the count of twin primes after sieve().
 */
uint64_t PrimeSieve::getTwinCount() const {
  return counts_[1];
}

/**
 * Get the count of prime triplets after sieve().
 */
uint64_t PrimeSieve::getTripletCount() const {
  return counts_[2];
}

/**
 * Get the count of prime quadruplets after sieve().
 */
uint64_t PrimeSieve::getQuadrupletCount() const {
  return counts_[3];
}

/**
 * Get the count of prime quintuplets after sieve().
 */
uint64_t PrimeSieve::getQuintupletCount() const {
  return counts_[4];
}

/**
 * Get the count of prime sextuplets after sieve().
 */
uint64_t PrimeSieve::getSextupletCount() const {
  return counts_[5];
}

/**
 * Get the count of prime septuplets after sieve().
 */
uint64_t PrimeSieve::getSeptupletCount() const {
  return counts_[6];
}

/**
 * Get the count of prime numbers or prime k-tuplets after sieve().
 * @param type = 0 : Count of prime numbers,
 *        type = 1 : Count of twin primes,
 *        type = 2 : Count of prime triplets,
 *        type = 3 : Count of prime quadruplets,
 *        type = 4 : Count of prime quintuplets,
 *        type = 5 : Count of prime sextuplets,
 *        type = 6 : Count of prime septuplets.
 */
uint64_t PrimeSieve::getCounts(uint32_t type) const {
  if (type >= COUNTS_SIZE)
    throw std::out_of_range("getCounts(uint32_t) type out of range");
  return counts_[type];
}

/**
 * Get the time elapsed in seconds of sieve().
 */
double PrimeSieve::getTimeElapsed() const {
  return timeElapsed_;
}

/**
 * Set a start number for sieving.
 * @pre startNumber < (2^64-1) - (2^32-1) * 10
 */
void PrimeSieve::setStartNumber(uint64_t startNumber) {
  // EratMedium and EratBig stopNumber limit
  if (startNumber >= UINT64_MAX - UINT32_MAX * UINT64_C(10))
    throw std::invalid_argument("START must be < (2^64-1) - (2^32-1) * 10");
  startNumber_ = startNumber;
}

/**
 * Set a stop number for sieving.
 * @pre stopNumber < (2^64-1) - (2^32-1) * 10
 */
void PrimeSieve::setStopNumber(uint64_t stopNumber) {
  // EratMedium and EratBig stopNumber limit
  if (stopNumber >= UINT64_MAX - UINT32_MAX * UINT64_C(10))
    throw std::invalid_argument("STOP must be < (2^64-1) - (2^32-1) * 10");
  stopNumber_ = stopNumber;
}

/**
 * Set the size of the sieve of Eratosthenes array (in KiloBytes).
 * Default sieveSize = 64 KB.
 * The best performance is achieved with a sieve size that matches
 * the CPU's L1 cache size (usually 32 or 64 KB) when sieving < 10^14
 * and a sieve size of the CPU's L2 cache size (e.g. 512 KB) above.
 *
 * @pre    sieveSize >= 1 && <= 8192 KiloBytes.
 * @remark sieveSize is rounded up to the next highest power of 2
 */
void PrimeSieve::setSieveSize(uint32_t sieveSize) {
  // SieveOfEratosthenes needs sieveSize >= 1 KB
  // EratSmall, EratMedium and EratBig need sieveSize <= 8192
  if (sieveSize < 1 || sieveSize > 8192)
    throw std::invalid_argument("sieve size must be >= 1 && <= 8192 KiloBytes");
  // EratBig needs a power of 2 sieveSize
  sieveSize_ = nextHighestPowerOf2(sieveSize);
}

/**
 * Multiples of small primes <= preSieveLimit are pre-sieved to speed
 * up the sieve of Eratosthenes.
 * @pre preSieveLimit >= 11 && preSieveLimit <= 23
 */
void PrimeSieve::setPreSieveLimit(uint32_t preSieveLimit) {
  if (preSieveLimit < 11 || preSieveLimit > 23)
    throw std::invalid_argument("pre-sieve limit must be >= 11 && <= 23");
  preSieveLimit_ = preSieveLimit;
}

/**
 * Settings for sieve().
 * @see   ../docs/USAGE_EXAMPLES
 * @param flags
 *   PrimeSieve::COUNT_PRIMES      OR (bitwise '|')
 *   PrimeSieve::COUNT_TWINS       OR
 *   PrimeSieve::COUNT_TRIPLETS    OR
 *   PrimeSieve::COUNT_QUADRUPLETS OR
 *   PrimeSieve::COUNT_QUINTUPLETS OR
 *   PrimeSieve::COUNT_SEXTUPLETS  OR
 *   PrimeSieve::COUNT_SEPTUPLETS  OR
 *   PrimeSieve::PRINT_PRIMES      OR
 *   PrimeSieve::PRINT_TWINS       OR
 *   PrimeSieve::PRINT_TRIPLETS    OR
 *   PrimeSieve::PRINT_QUADRUPLETS OR
 *   PrimeSieve::PRINT_QUINTUPLETS OR
 *   PrimeSieve::PRINT_SEXTUPLETS  OR
 *   PrimeSieve::PRINT_SEPTUPLETS  OR
 *   PrimeSieve::PRINT_STATUS.
 */
void PrimeSieve::setFlags(uint32_t flags) {
  if (flags >= (1u << 20))
    throw std::invalid_argument("invalid flags");
  flags_ = flags;
}

/**
 * Generate the prime numbers within the interval
 * [startNumber, stopNumber] and call a callback function for each
 * prime.
 */
void PrimeSieve::generatePrimes(uint64_t startNumber, uint64_t stopNumber,
    void (*callback)(uint64_t)) {
  if (callback == NULL)
    throw std::invalid_argument("callback must not be NULL");
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  flags_ = CALLBACK_PRIMES;
  callback_ = callback;
  this->sieve();
}

/**
 * Generate the prime numbers within the interval
 * [startNumber, stopNumber] and call an OOP callback function for
 * each prime.
 */
void PrimeSieve::generatePrimes(uint64_t startNumber, uint64_t stopNumber,
    void (*callback)(uint64_t, void*), void* cbObj) {
  if (callback == NULL)
    throw std::invalid_argument("callback must not be NULL");
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  flags_ = CALLBACK_PRIMES_OOP;
  callbackOOP_ = callback;
  cbObj_ = cbObj;
  this->sieve();
}

void PrimeSieve::reset() {
  segments_ = 0;
  for (uint32_t i = 0; i < COUNTS_SIZE; i++)
    counts_[i] = 0;
  status_ = -1.0;
  timeElapsed_ = 0.0;
  parent_->doStatus(0);
}

/**
 * Calculate the current status in percent of sieve().
 */
void PrimeSieve::doStatus(uint32_t segment) {
  segments_ += segment;
  int old = static_cast<int> (status_);
  status_ = std::min<double>(100.0, (static_cast<double> (segments_) /
      (1 + stopNumber_ - startNumber_)) * 100.0);
  if (flags_ & PRINT_STATUS) {
    int status = static_cast<int> (status_);
    if (status > old)
      std::cout << '\r' << status << '%' << std::flush;
  }
}

void PrimeSieve::doSmallPrime(uint32_t low, uint32_t high, uint32_t type,
    const std::string& prime) {
  if (startNumber_ <= low && stopNumber_ >= high) {
    if (flags_ & (COUNT_PRIMES << type))
      counts_[type]++;
    if (flags_ & (PRINT_PRIMES << type))
      std::cout << prime << std::endl;
    else if (type == 0 && (flags_ & CALLBACK_PRIMES))
      this->callback_(prime[0]-'0');
    else if (type == 0 && (flags_ & CALLBACK_PRIMES_OOP))
      this->callbackOOP_(prime[0]-'0', cbObj_);
  }
}

/**
 * Sieve the prime numbers and/or prime k-tuplets within the interval
 * [startNumber_, stopNumber_].
 */
void PrimeSieve::sieve() {
  clock_t t1 = std::clock();
  this->reset();
  if (stopNumber_ < startNumber_)
    throw std::invalid_argument("STOP must be >= START");

  // small primes have to be examined manually
  if (startNumber_ <= 5) {
    this->doSmallPrime(2,  2, 0, "2");
    this->doSmallPrime(3,  3, 0, "3");
    this->doSmallPrime(5,  5, 0, "5");
    this->doSmallPrime(3,  5, 1, "(3, 5)");
    this->doSmallPrime(5,  7, 1, "(5, 7)");
    this->doSmallPrime(5, 11, 2, "(5, 7, 11)");
    this->doSmallPrime(5, 13, 3, "(5, 7, 11, 13)");
    this->doSmallPrime(5, 17, 4, "(5, 7, 11, 13, 17)");
  }

  if (stopNumber_ >= 7) {
    // used to sieve the primes and prime k-tuplets within the
    // interval [startNumber_, stopNumber_]
    PrimeNumberFinder finder(this);

    if (isqrt(stopNumber_) > finder.getPreSieveLimit()) {
      /// used to generate the primes up to stopNumber_^0.5 needed for
      /// sieving by finder
      /// @see PrimeNumberGenerator::generate(const uint8_t*, uint32_t)
      PrimeNumberGenerator generator(finder);

      // the following sieve of Eratosthenes implementation generates
      // the primes up to stopNumber_^0.25 needed for sieving by the
      // faster PrimeNumberGenerator
      uint32_t N = isqrt(generator.getStopNumber());
      std::vector<uint8_t> isPrime((N+8)/8, 0xAA);
      for (uint32_t i = 3; i*i <= N; i += 2) {
        if (isPrime[i>>3] & (1<<(i&7)))
          for (uint32_t j = i*i; j <= N; j += i*2)
            isPrime[j>>3] &= ~(1<<(j&7));
      }
      for (uint32_t i = generator.getPreSieveLimit() + 1; i <= N; i++) {
        if (isPrime[i>>3] & (1<<(i&7)))
          generator.sieve(i);
      }
      generator.finish();
    }
    finder.finish();
  }
  // set status_ to 100.0 percent
  parent_->doStatus(10);
  timeElapsed_ = static_cast<double> (std::clock() - t1) / CLOCKS_PER_SEC;
}
<commit_msg>improved code readability<commit_after>/*
 * PrimeSieve.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
 */

#include "PrimeSieve.h"
#include "defs.h"
#include "ParallelPrimeSieve.h"
#include "pmath.h"
#include "PreSieve.h"
#include "PrimeNumberFinder.h"
#include "PrimeNumberGenerator.h"

#include <stdexcept>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>

PrimeSieve::PrimeSieve() :
  startNumber_(0), stopNumber_(0), flags_(COUNT_PRIMES) {
  parent_ = this;
  this->setSieveSize(defs::PRIMESIEVE_SIEVESIZE);
  this->setPreSieveLimit(defs::PRIMESIEVE_PRESIEVE_LIMIT);
  this->reset();
}

/**
 * ParallelPrimeSieve uses multiple PrimeSieve objects and threads to
 * sieve primes in parallel.
 * @see ParallelPrimeSieve::sieve()
 */
PrimeSieve::PrimeSieve(uint64_t startNumber, uint64_t stopNumber,
    ParallelPrimeSieve* parent) :
  sieveSize_(parent->sieveSize_),
    flags_(parent->flags_),
    preSieveLimit_(parent->preSieveLimit_),
    callback_(parent->callback_),
    callbackOOP_(parent->callbackOOP_),
    cbObj_(parent->cbObj_),
    parent_(parent) {
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  this->reset();
}

uint64_t PrimeSieve::getStartNumber() const {
  return startNumber_;
}

uint64_t PrimeSieve::getStopNumber() const {
  return stopNumber_;
}

/**
 * Get the sieve size in Kilobytes.
 */
uint32_t PrimeSieve::getSieveSize() const {
  return sieveSize_;
}

uint32_t PrimeSieve::getPreSieveLimit() const {
  return preSieveLimit_;
}

/**
 * Get the current set public flags.
 */
uint32_t PrimeSieve::getFlags() const {
  // clear out private flags
  return flags_ & ((1u << 20) - 1);
}

/**
 * Get the count of prime numbers within the interval
 * [startNumber, stopNumber].
 */
uint64_t PrimeSieve::getPrimeCount(uint64_t startNumber, uint64_t stopNumber) {
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  this->setFlags(COUNT_PRIMES);
  this->sieve();
  return this->getPrimeCount();
}

/**
 * Get the count of prime numbers after sieve().
 */
uint64_t PrimeSieve::getPrimeCount() const {
  return counts_[0];
}

/**
 * Get the count of twin primes after sieve().
 */
uint64_t PrimeSieve::getTwinCount() const {
  return counts_[1];
}

/**
 * Get the count of prime triplets after sieve().
 */
uint64_t PrimeSieve::getTripletCount() const {
  return counts_[2];
}

/**
 * Get the count of prime quadruplets after sieve().
 */
uint64_t PrimeSieve::getQuadrupletCount() const {
  return counts_[3];
}

/**
 * Get the count of prime quintuplets after sieve().
 */
uint64_t PrimeSieve::getQuintupletCount() const {
  return counts_[4];
}

/**
 * Get the count of prime sextuplets after sieve().
 */
uint64_t PrimeSieve::getSextupletCount() const {
  return counts_[5];
}

/**
 * Get the count of prime septuplets after sieve().
 */
uint64_t PrimeSieve::getSeptupletCount() const {
  return counts_[6];
}

/**
 * Get the count of prime numbers or prime k-tuplets after sieve().
 * @param type = 0 : Count of prime numbers,
 *        type = 1 : Count of twin primes,
 *        type = 2 : Count of prime triplets,
 *        type = 3 : Count of prime quadruplets,
 *        type = 4 : Count of prime quintuplets,
 *        type = 5 : Count of prime sextuplets,
 *        type = 6 : Count of prime septuplets.
 */
uint64_t PrimeSieve::getCounts(uint32_t type) const {
  if (type >= COUNTS_SIZE)
    throw std::out_of_range("getCounts(uint32_t) type out of range");
  return counts_[type];
}

/**
 * Get the time elapsed in seconds of sieve().
 */
double PrimeSieve::getTimeElapsed() const {
  return timeElapsed_;
}

/**
 * Set a start number for sieving.
 * @pre startNumber < (2^64-1) - (2^32-1) * 10
 */
void PrimeSieve::setStartNumber(uint64_t startNumber) {
  // EratMedium and EratBig stopNumber limit
  if (startNumber >= UINT64_MAX - UINT32_MAX * UINT64_C(10))
    throw std::invalid_argument("START must be < (2^64-1) - (2^32-1) * 10");
  startNumber_ = startNumber;
}

/**
 * Set a stop number for sieving.
 * @pre stopNumber < (2^64-1) - (2^32-1) * 10
 */
void PrimeSieve::setStopNumber(uint64_t stopNumber) {
  // EratMedium and EratBig stopNumber limit
  if (stopNumber >= UINT64_MAX - UINT32_MAX * UINT64_C(10))
    throw std::invalid_argument("STOP must be < (2^64-1) - (2^32-1) * 10");
  stopNumber_ = stopNumber;
}

/**
 * Set the size of the sieve of Eratosthenes array (in KiloBytes).
 * Default sieveSize = 64 KB.
 * The best performance is achieved with a sieve size that matches
 * the CPU's L1 cache size (usually 32 or 64 KB) when sieving < 10^14
 * and a sieve size of the CPU's L2 cache size (e.g. 512 KB) above.
 *
 * @pre    sieveSize >= 1 && <= 8192 KiloBytes.
 * @remark sieveSize is rounded up to the next highest power of 2
 */
void PrimeSieve::setSieveSize(uint32_t sieveSize) {
  // SieveOfEratosthenes needs sieveSize >= 1 KB
  // EratSmall, EratMedium and EratBig need sieveSize <= 8192
  if (sieveSize < 1 || sieveSize > 8192)
    throw std::invalid_argument("sieve size must be >= 1 && <= 8192 KiloBytes");
  // EratBig needs a power of 2 sieveSize
  sieveSize_ = nextHighestPowerOf2(sieveSize);
}

/**
 * Multiples of small primes <= preSieveLimit are pre-sieved to speed
 * up the sieve of Eratosthenes.
 * @pre preSieveLimit >= 11 && preSieveLimit <= 23
 */
void PrimeSieve::setPreSieveLimit(uint32_t preSieveLimit) {
  if (preSieveLimit < 11 || preSieveLimit > 23)
    throw std::invalid_argument("pre-sieve limit must be >= 11 && <= 23");
  preSieveLimit_ = preSieveLimit;
}

/**
 * Settings for sieve().
 * @see   ../docs/USAGE_EXAMPLES
 * @param flags
 *   PrimeSieve::COUNT_PRIMES      OR (bitwise '|')
 *   PrimeSieve::COUNT_TWINS       OR
 *   PrimeSieve::COUNT_TRIPLETS    OR
 *   PrimeSieve::COUNT_QUADRUPLETS OR
 *   PrimeSieve::COUNT_QUINTUPLETS OR
 *   PrimeSieve::COUNT_SEXTUPLETS  OR
 *   PrimeSieve::COUNT_SEPTUPLETS  OR
 *   PrimeSieve::PRINT_PRIMES      OR
 *   PrimeSieve::PRINT_TWINS       OR
 *   PrimeSieve::PRINT_TRIPLETS    OR
 *   PrimeSieve::PRINT_QUADRUPLETS OR
 *   PrimeSieve::PRINT_QUINTUPLETS OR
 *   PrimeSieve::PRINT_SEXTUPLETS  OR
 *   PrimeSieve::PRINT_SEPTUPLETS  OR
 *   PrimeSieve::PRINT_STATUS.
 */
void PrimeSieve::setFlags(uint32_t flags) {
  if (flags >= (1u << 20))
    throw std::invalid_argument("invalid flags");
  flags_ = flags;
}

/**
 * Generate the prime numbers within the interval
 * [startNumber, stopNumber] and call a callback function for each
 * prime.
 */
void PrimeSieve::generatePrimes(uint64_t startNumber, uint64_t stopNumber,
    void (*callback)(uint64_t)) {
  if (callback == NULL)
    throw std::invalid_argument("callback must not be NULL");
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  flags_ = CALLBACK_PRIMES;
  callback_ = callback;
  this->sieve();
}

/**
 * Generate the prime numbers within the interval
 * [startNumber, stopNumber] and call an OOP callback function for
 * each prime.
 */
void PrimeSieve::generatePrimes(uint64_t startNumber, uint64_t stopNumber,
    void (*callback)(uint64_t, void*), void* cbObj) {
  if (callback == NULL)
    throw std::invalid_argument("callback must not be NULL");
  this->setStartNumber(startNumber);
  this->setStopNumber(stopNumber);
  flags_ = CALLBACK_PRIMES_OOP;
  callbackOOP_ = callback;
  cbObj_ = cbObj;
  this->sieve();
}

void PrimeSieve::reset() {
  segments_ = 0;
  for (uint32_t i = 0; i < COUNTS_SIZE; i++)
    counts_[i] = 0;
  status_ = -1.0;
  timeElapsed_ = 0.0;
  parent_->doStatus(0);
}

/**
 * Calculate the current status in percent of sieve().
 */
void PrimeSieve::doStatus(uint32_t segment) {
  segments_ += segment;
  int old = static_cast<int> (status_);
  status_ = std::min<double>(100.0, (static_cast<double> (segments_) /
      (1 + stopNumber_ - startNumber_)) * 100.0);
  if (flags_ & PRINT_STATUS) {
    int status = static_cast<int> (status_);
    if (status > old)
      std::cout << '\r' << status << '%' << std::flush;
  }
}

void PrimeSieve::doSmallPrime(uint32_t low, uint32_t high, uint32_t type,
    const std::string& prime) {
  if (startNumber_ <= low && stopNumber_ >= high) {
    if (flags_ & (COUNT_PRIMES << type))
      counts_[type]++;
    if (flags_ & (PRINT_PRIMES << type))
      std::cout << prime << std::endl;
    else if (type == 0 && (flags_ & CALLBACK_PRIMES))
      this->callback_(prime[0]-'0');
    else if (type == 0 && (flags_ & CALLBACK_PRIMES_OOP))
      this->callbackOOP_(prime[0]-'0', cbObj_);
  }
}

/**
 * Sieve the prime numbers and/or prime k-tuplets within the interval
 * [startNumber_, stopNumber_].
 */
void PrimeSieve::sieve() {
  clock_t t1 = std::clock();
  this->reset();
  if (stopNumber_ < startNumber_)
    throw std::invalid_argument("STOP must be >= START");

  // small primes have to be examined manually
  if (startNumber_ <= 5) {
    this->doSmallPrime(2,  2, 0, "2");
    this->doSmallPrime(3,  3, 0, "3");
    this->doSmallPrime(5,  5, 0, "5");
    this->doSmallPrime(3,  5, 1, "(3, 5)");
    this->doSmallPrime(5,  7, 1, "(5, 7)");
    this->doSmallPrime(5, 11, 2, "(5, 7, 11)");
    this->doSmallPrime(5, 13, 3, "(5, 7, 11, 13)");
    this->doSmallPrime(5, 17, 4, "(5, 7, 11, 13, 17)");
  }

  if (stopNumber_ >= 7) {
    // used to sieve the primes and prime k-tuplets within the
    // interval [startNumber_, stopNumber_]
    PrimeNumberFinder finder(this);

    if (isqrt(stopNumber_) > finder.getPreSieveLimit()) {
      /// used to generate the primes up to stopNumber_^0.5 needed for
      /// sieving by finder
      /// @see PrimeNumberGenerator::generate(const uint8_t*, uint32_t)
      PrimeNumberGenerator generator(finder);

      // the following sieve of Eratosthenes implementation generates
      // the primes up to stopNumber_^0.25 needed for sieving by the
      // faster PrimeNumberGenerator
      uint32_t N = isqrt(generator.getStopNumber());
      std::vector<uint8_t> isPrime(N/8+1, 0xAA);
      for (uint32_t i = 3; i*i <= N; i += 2) {
        if (isPrime[i>>3] & (1<<(i&7)))
          for (uint32_t j = i*i; j <= N; j += i*2)
            isPrime[j>>3] &= ~(1<<(j&7));
      }
      for (uint32_t i = generator.getPreSieveLimit() + 1; i <= N; i++) {
        if (isPrime[i>>3] & (1<<(i&7)))
          generator.sieve(i);
      }
      generator.finish();
    }
    finder.finish();
  }
  // set status_ to 100.0 percent
  parent_->doStatus(10);
  timeElapsed_ = static_cast<double> (std::clock() - t1) / CLOCKS_PER_SEC;
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    TiffVolumeConverter.h
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include "TiffVolumeConverter.h"
#include "../3rdParty/boost/cstdint.hpp"
#include "../3rdParty/tiff/tiffio.h"
#include "../StdTuvokDefines.h"
#include "../Controller/MasterController.h"
#include "../Basics/SysTools.h"

#ifdef __GNUC__
# define _malloc __attribute__((malloc))
#else
# define _malloc /* nothing */
#endif

static void tv_dimensions(TIFF *, size_t dims[3]);
_malloc static BYTE* tv_read_slice(TIFF *, AbstrDebugOut &);
#if 0
// currently disabled -- mistakenly thought I was reading 4-component data for
// a while.  left in because we'll probably want to be able to convert
// 4-component data to 1-component data at some point.
_malloc static UINT32* tv_vector_to_scalar_magnitude(UINT32 *, size_t, size_t);
#endif

TiffVolumeConverter::TiffVolumeConverter()
{
  m_vConverterDesc = "TIFF Volume (Image stack)";
  m_vSupportedExt.push_back("OME.TIF");
  m_vSupportedExt.push_back("OME.TIFF");
  m_vSupportedExt.push_back("TIF");
  m_vSupportedExt.push_back("TIFF");
}

// converts a TiffVolume to a `raw' file.  We'll read through the TIFF
// slice-by-slice, copying each slice to the raw file.
bool
TiffVolumeConverter::ConvertToRAW(const std::string& strSourceFilename,
                                  const std::string& strTempDir,
                                  MasterController* pMasterController,
                                  bool, UINT64& iHeaderSkip,
                                  UINT64& iComponentSize,
                                  UINT64& iComponentCount,
                                  bool& bConvertEndianess, bool& bSigned,
                                  bool& bIsFloat, UINTVECTOR3& vVolumeSize,
                                  FLOATVECTOR3& vVolumeAspect,
                                  std::string& strTitle,
                                  std::string& strSource,
                                  UVFTables::ElementSemanticTable& eType,
                                  std::string& strIntermediateFile,
                                  bool& bDeleteIntermediateFile)
{
  AbstrDebugOut& dbg = *(pMasterController->DebugOut());
  dbg.Message(_func_, "Attempting to convert TiffVolume: %s",
              strSourceFilename.c_str());

  TIFF *tif = TIFFOpen(strSourceFilename.c_str(), "r");
  if(tif == NULL) {
    dbg.Error(_func_, "Could not open %s", strSourceFilename.c_str());
    return false;
  }

  // Get the dimensions of the volume.
  {
    size_t dims[3];
    tv_dimensions(tif, dims);
    vVolumeSize[0] = dims[0];
    vVolumeSize[1] = dims[1];
    vVolumeSize[2] = dims[2];
    dbg.Message(_func_, "TiffVolume dimensions: %zux%zux%zu",
                dims[0], dims[1], dims[2]);
    if(dims[2] <= 1) {
      dbg.Error(_func_, "TIFF is not a volume; use "
                        "`Load Dataset from Directory' instead!");
      TIFFClose(tif);
      return false;
    }
  }
  iHeaderSkip = 0;

  // read the number of bits per component from the tiff tag.
  {
    boost::uint16_t bits_per_sample;
    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
    iComponentSize = bits_per_sample;
    dbg.Message(_func_, "%ld bits per component.", iComponentSize);
  }
  // likewise for the number of components / pixel.
  {
    boost::uint16_t components;
    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &components);
    iComponentCount = components;
    dbg.Message(_func_, "%ld component%s.", iComponentCount,
                (components == 1) ? "" : "s");
  }
  // IIRC libtiff handles all the endian issues for us.
  bConvertEndianess = false;

  // This group might be bugs; not quite sure where to read these from.  In any
  // case, we don't have any data which does not have these properties.
  bSigned = false;
  bIsFloat = false;
  vVolumeAspect[0] = 1;
  vVolumeAspect[1] = 1;
  vVolumeAspect[2] = 1;

  strTitle = "TIFF Volume";
  // @todo FIXME: this assignment to be the same in every reader, should be
  // moved to the caller or parent:
  strSource = SysTools::GetFilename(strSourceFilename);
  eType = UVFTables::ES_UNDEFINED;

  // Create an intermediate file to hold the data.
  strIntermediateFile = strTempDir +
                        SysTools::GetFilename(strSourceFilename) + ".binary";
  LargeRAWFile binary(strIntermediateFile);
  binary.Create(iComponentSize/8 * iComponentCount * vVolumeSize.volume());
  if(!binary.IsOpen()) {
    dbg.Error(_func_, "Could not create binary file %s",
              strIntermediateFile.c_str());
    TIFFClose(tif);
    return false;
  }
  bDeleteIntermediateFile = true;
  // Populate the intermediate file.  We'll do this slice-by-slice, which isn't
  // kosher for Tuvok semantics -- a slice could technically be larger than
  // INCORESIZE.  But it won't be.
  do {
    BYTE* slice = tv_read_slice(tif, dbg);
    if(slice) {
      // assuming 8-bit monochrome data here, which might not always be valid.
      binary.WriteRAW(static_cast<unsigned char*>(slice),
                      vVolumeSize[0]*vVolumeSize[1]*sizeof(BYTE));
      _TIFFfree(slice);
    } else {
      binary.Close();
      binary.Delete();
      TIFFClose(tif);
      return false;
    }
  } while(TIFFReadDirectory(tif));
  binary.Close();

  TIFFClose(tif);
  return true;
}

// unimplemented!
bool
TiffVolumeConverter::ConvertToNative(const std::string&,
                                     const std::string&,
                                     UINT64, UINT64,
                                     UINT64, bool,
                                     bool,
                                     UINTVECTOR3,
                                     FLOATVECTOR3,
                                     MasterController*,
                                     bool)
{
  return false;
}

// Reads the dimensions of the TIFF volume.  X and Y come from the dimensions
// of the first image in the stack: we assume that this stays constant
// throughout the volume.  Z comes from the number of images in the stack.
static void
tv_dimensions(TIFF *tif, size_t dims[3])
{
  UINT32 x,y;
  size_t z=0;

  TIFFSetDirectory(tif, 0);
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x);
  // tiff calls the height "length" for some reason.
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y);
  do {
    ++z;
  } while(TIFFReadDirectory(tif));
  TIFFSetDirectory(tif, 0);

  dims[0] = x;
  dims[1] = y;
  dims[2] = z;
}

_malloc static BYTE*
tv_read_slice(TIFF *tif, AbstrDebugOut& dbg)
{
  BYTE *slice;
  UINT32 width;
  UINT32 height;
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);

  dbg.Message(_func_, "Reading %ux%u TIFF slice.", width, height);
  slice = static_cast<BYTE*>(_TIFFmalloc((width*height) * sizeof(BYTE)));
  if(slice == NULL) {
    dbg.Error(_func_, "TIFFmalloc failed.");
    return NULL;
  }
  const tstrip_t n_strips = TIFFNumberOfStrips(tif);
  {
    BYTE *data = slice;
    tdata_t buf = static_cast<tdata_t>(_TIFFmalloc(TIFFStripSize(tif)));
    for(tstrip_t s=0; s < n_strips; ++s) {
      /// @todo FIXME: don't assume the strip is raw; could be encoded.
      /// There's a `compression scheme' tag which probably details this.
      tsize_t n_bytes = TIFFReadRawStrip(tif, s, buf,
                                         static_cast<tsize_t>(-1));
      memcpy(data, buf, n_bytes);
      data += TIFFStripSize(tif);
    }
    _TIFFfree(buf);
  }

  return slice;
}

#if 0
// Converts an RGBA vector `field' to a scalar field of the "vector"'s
// magnitude.  Ignores the alpha component.
_malloc static UINT32*
tv_vector_to_scalar_magnitude(UINT32 *field, size_t w, size_t h)
{
  UINT32* ret = new UINT32[w*h];
  for(size_t i=0; i < w*h; ++i) {
    unsigned char r = field[i] & 0xFF000000;
    unsigned char g = field[i] & 0x00FF0000;
    unsigned char b = field[i] & 0x0000FF00;
    ret[i] = (static_cast<UINT32>(r) +
              static_cast<UINT32>(g) +
              static_cast<UINT32>(b)) / 3;
  }
  return ret;
}
#endif
<commit_msg>Fix comments in the TiffVolume reader.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    TiffVolumeConverter.h
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include "TiffVolumeConverter.h"
#include "../3rdParty/boost/cstdint.hpp"
#include "../3rdParty/tiff/tiffio.h"
#include "../StdTuvokDefines.h"
#include "../Controller/MasterController.h"
#include "../Basics/SysTools.h"

#ifdef __GNUC__
# define _malloc __attribute__((malloc))
#else
# define _malloc /* nothing */
#endif

static void tv_dimensions(TIFF *, size_t dims[3]);
_malloc static BYTE* tv_read_slice(TIFF *, AbstrDebugOut &);
#if 0
// currently disabled -- mistakenly thought I was reading 4-component data for
// a while.  left in because we'll probably want to be able to convert
// 4-component data to 1-component data at some point.
_malloc static UINT32* tv_vector_to_scalar_magnitude(UINT32 *, size_t, size_t);
#endif

TiffVolumeConverter::TiffVolumeConverter()
{
  m_vConverterDesc = "TIFF Volume (Image stack)";
  m_vSupportedExt.push_back("OME.TIF");
  m_vSupportedExt.push_back("OME.TIFF");
  m_vSupportedExt.push_back("TIF");
  m_vSupportedExt.push_back("TIFF");
}

// converts a TiffVolume to a `raw' file.  We'll read through the TIFF
// slice-by-slice, copying each slice to the raw file.
bool
TiffVolumeConverter::ConvertToRAW(const std::string& strSourceFilename,
                                  const std::string& strTempDir,
                                  MasterController* pMasterController,
                                  bool, UINT64& iHeaderSkip,
                                  UINT64& iComponentSize,
                                  UINT64& iComponentCount,
                                  bool& bConvertEndianess, bool& bSigned,
                                  bool& bIsFloat, UINTVECTOR3& vVolumeSize,
                                  FLOATVECTOR3& vVolumeAspect,
                                  std::string& strTitle,
                                  std::string& strSource,
                                  UVFTables::ElementSemanticTable& eType,
                                  std::string& strIntermediateFile,
                                  bool& bDeleteIntermediateFile)
{
  AbstrDebugOut& dbg = *(pMasterController->DebugOut());
  dbg.Message(_func_, "Attempting to convert TiffVolume: %s",
              strSourceFilename.c_str());

  TIFF *tif = TIFFOpen(strSourceFilename.c_str(), "r");
  if(tif == NULL) {
    dbg.Error(_func_, "Could not open %s", strSourceFilename.c_str());
    return false;
  }

  // Get the dimensions of the volume.
  {
    size_t dims[3];
    tv_dimensions(tif, dims);
    vVolumeSize[0] = dims[0];
    vVolumeSize[1] = dims[1];
    vVolumeSize[2] = dims[2];
    dbg.Message(_func_, "TiffVolume dimensions: %zux%zux%zu",
                dims[0], dims[1], dims[2]);
    if(dims[2] <= 1) {
      dbg.Error(_func_, "TIFF is not a volume; use "
                        "`Load Dataset from Directory' instead!");
      TIFFClose(tif);
      return false;
    }
  }
  iHeaderSkip = 0;

  // read the number of bits per component from the tiff tag.
  {
    boost::uint16_t bits_per_sample;
    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
    iComponentSize = bits_per_sample;
    dbg.Message(_func_, "%ld bits per component.", iComponentSize);
  }
  // likewise for the number of components / pixel.
  {
    boost::uint16_t components;
    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &components);
    iComponentCount = components;
    dbg.Message(_func_, "%ld component%s.", iComponentCount,
                (components == 1) ? "" : "s");
  }
  // IIRC libtiff handles all the endian issues for us.
  bConvertEndianess = false;

  // One might consider setting the values below explicitly as bugs, but we're
  // not quite sure where to read these from.  In any case, we don't have any
  // data for which these settings are invalid.
  bSigned = false;
  bIsFloat = false;
  vVolumeAspect[0] = 1;
  vVolumeAspect[1] = 1;
  vVolumeAspect[2] = 1;

  strTitle = "TIFF Volume";
  // @todo FIXME: this assignment appears to be the same in every reader,
  // should be moved to the caller or parent:
  strSource = SysTools::GetFilename(strSourceFilename);
  eType = UVFTables::ES_UNDEFINED;

  // Create an intermediate file to hold the data.
  strIntermediateFile = strTempDir +
                        SysTools::GetFilename(strSourceFilename) + ".binary";
  LargeRAWFile binary(strIntermediateFile);
  binary.Create(iComponentSize/8 * iComponentCount * vVolumeSize.volume());
  if(!binary.IsOpen()) {
    dbg.Error(_func_, "Could not create binary file %s",
              strIntermediateFile.c_str());
    TIFFClose(tif);
    return false;
  }
  bDeleteIntermediateFile = true;
  // Populate the intermediate file.  We'll do this slice-by-slice, which isn't
  // exactly kosher in Tuvok -- a slice could technically be larger than
  // INCORESIZE.  But it won't be.
  do {
    BYTE* slice = tv_read_slice(tif, dbg);
    if(slice) {
      // assuming 8-bit monochrome data here, which might not always be valid.
      binary.WriteRAW(static_cast<unsigned char*>(slice),
                      vVolumeSize[0]*vVolumeSize[1]*sizeof(BYTE));
      _TIFFfree(slice);
    } else {
      binary.Close();
      binary.Delete();
      TIFFClose(tif);
      return false;
    }
  } while(TIFFReadDirectory(tif));
  binary.Close();

  TIFFClose(tif);
  return true;
}

// unimplemented!
bool
TiffVolumeConverter::ConvertToNative(const std::string&,
                                     const std::string&,
                                     UINT64, UINT64,
                                     UINT64, bool,
                                     bool,
                                     UINTVECTOR3,
                                     FLOATVECTOR3,
                                     MasterController*,
                                     bool)
{
  return false;
}

// Reads the dimensions of the TIFF volume.  X and Y come from the dimensions
// of the first image in the stack: we assume that this stays constant
// throughout the volume.  Z comes from the number of images in the stack.
static void
tv_dimensions(TIFF *tif, size_t dims[3])
{
  UINT32 x,y;
  size_t z=0;

  TIFFSetDirectory(tif, 0);
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x);
  // tiff calls the height "length" for some reason.
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y);
  do {
    ++z;
  } while(TIFFReadDirectory(tif));
  TIFFSetDirectory(tif, 0);

  dims[0] = x;
  dims[1] = y;
  dims[2] = z;
}

_malloc static BYTE*
tv_read_slice(TIFF *tif, AbstrDebugOut& dbg)
{
  BYTE *slice;
  UINT32 width;
  UINT32 height;
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);

  dbg.Message(_func_, "Reading %ux%u TIFF slice.", width, height);
  slice = static_cast<BYTE*>(_TIFFmalloc((width*height) * sizeof(BYTE)));
  if(slice == NULL) {
    dbg.Error(_func_, "TIFFmalloc failed.");
    return NULL;
  }
  const tstrip_t n_strips = TIFFNumberOfStrips(tif);
  {
    BYTE *data = slice;
    tdata_t buf = static_cast<tdata_t>(_TIFFmalloc(TIFFStripSize(tif)));
    for(tstrip_t s=0; s < n_strips; ++s) {
      /// @todo FIXME: don't assume the strip is raw; could be encoded.
      /// There's a `compression scheme' tag which probably details this.
      tsize_t n_bytes = TIFFReadRawStrip(tif, s, buf,
                                         static_cast<tsize_t>(-1));
      memcpy(data, buf, n_bytes);
      data += TIFFStripSize(tif);
    }
    _TIFFfree(buf);
  }

  return slice;
}

#if 0
// Converts an RGBA vector `field' to a scalar field of the "vector"'s
// magnitude.  Ignores the alpha component.
_malloc static UINT32*
tv_vector_to_scalar_magnitude(UINT32 *field, size_t w, size_t h)
{
  UINT32* ret = new UINT32[w*h];
  for(size_t i=0; i < w*h; ++i) {
    unsigned char r = field[i] & 0xFF000000;
    unsigned char g = field[i] & 0x00FF0000;
    unsigned char b = field[i] & 0x0000FF00;
    ret[i] = (static_cast<UINT32>(r) +
              static_cast<UINT32>(g) +
              static_cast<UINT32>(b)) / 3;
  }
  return ret;
}
#endif
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageExport.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to David G. Gobbi who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include <ctype.h>
#include <string.h>
#include "vtkImageExport.h"
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageExport* vtkImageExport::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageExport");
  if(ret)
    {
    return (vtkImageExport*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageExport;
}

//----------------------------------------------------------------------------
vtkImageExport::vtkImageExport()
{
  this->ImageLowerLeft = 1;
  this->ExportVoidPointer = 0;
  this->DataDimensions[0] = this->DataDimensions[1] =
    this->DataDimensions[2] = 0;
  this->LastPipelineMTime = 0;
}

//----------------------------------------------------------------------------
vtkImageExport::~vtkImageExport()
{
}

//----------------------------------------------------------------------------
void vtkImageExport::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkProcessObject::PrintSelf(os,indent);

  os << indent << "ImageLowerLeft: "
     << (this->ImageLowerLeft ? "On\n" : "Off\n");
}

//----------------------------------------------------------------------------
void vtkImageExport::SetInput(vtkImageData *input)
{
  this->vtkProcessObject::SetNthInput(0, input);
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageExport::GetInput()
{
  if (this->NumberOfInputs < 1)
    {
    return NULL;
    }

  return (vtkImageData *)(this->Inputs[0]);
}

//----------------------------------------------------------------------------
int vtkImageExport::GetDataMemorySize()
{
  vtkImageData *input = this->GetInput();
  if (input == NULL)
    {
    return 0;
    }

  input->UpdateInformation();
  int *extent = input->GetWholeExtent();
  int size = input->GetScalarSize();
  size *= input->GetNumberOfScalarComponents();
  size *= (extent[1] - extent[0] + 1);
  size *= (extent[3] - extent[2] + 1);
  size *= (extent[5] - extent[4] + 1);

  return size;
}

//----------------------------------------------------------------------------
void vtkImageExport::GetDataDimensions(int *dims)
{
  vtkImageData *input = this->GetInput();
  if (input == NULL)
    {
    dims[0] = dims[1] = dims[2] = 0;
    return;
    }

  input->UpdateInformation();
  int *extent = input->GetWholeExtent();
  dims[0] = extent[1]-extent[0]+1;
  dims[1] = extent[3]-extent[2]+1;
  dims[2] = extent[5]-extent[4]+1;
}

//----------------------------------------------------------------------------
void vtkImageExport::SetExportVoidPointer(void *ptr)
{
  if (this->ExportVoidPointer == ptr)
    {
    return;
    }
  this->ExportVoidPointer = ptr;
  this->Modified();
}

//----------------------------------------------------------------------------
// Exports all the data from the input.
void vtkImageExport::Export(void *output)
{
  if (this->ImageLowerLeft)
    {
    memcpy(output,this->GetPointerToData(),this->GetDataMemorySize());
    }
  else
    { // flip the image when it is output
    void *ptr = this->GetPointerToData();
    int *extent = this->GetInput()->GetWholeExtent();
    int xsize = extent[1]-extent[0]+1;
    int ysize = extent[3]-extent[2]+1;
    int zsize = extent[5]-extent[4]+1;
    int csize = this->GetInput()->GetScalarSize()* \
                this->GetInput()->GetNumberOfScalarComponents();

    for (int i = 0; i < zsize; i++)
      {
      ptr = (void *)(((char *)ptr) + ysize*xsize*csize);
      for (int j = 0; j < ysize; j++)
        {
        ptr = (void *)(((char *)ptr) - xsize*csize);
        memcpy(output, ptr, xsize*csize);
        output = (void *)(((char *)output) + xsize*csize);
        }
      ptr = (void *)(((char *)ptr) + ysize*xsize*csize);
      }
    }
}

//----------------------------------------------------------------------------
// Provides a valid pointer to the data (only valid until the next
// update, though)

void *vtkImageExport::GetPointerToData()
{
  // Error checking
  if ( this->GetInput() == NULL )
    {
    vtkErrorMacro(<<"Export: Please specify an input!");
    return 0;
    }

  vtkImageData *input = this->GetInput();
  input->UpdateInformation();
  input->SetUpdateExtent(input->GetWholeExtent());
  input->ReleaseDataFlagOff();

  input->Update();
  this->UpdateProgress(0.0);
  this->UpdateProgress(1.0);

  return input->GetScalarPointer();
}

//----------------------------------------------------------------------------
void* vtkImageExport::GetCallbackUserData()
{
  return this;
}

vtkImageExport::UpdateInformationCallbackType
vtkImageExport::GetUpdateInformationCallback() const
{
  return &vtkImageExport::UpdateInformationCallbackFunction;
}

vtkImageExport::PipelineModifiedCallbackType
vtkImageExport::GetPipelineModifiedCallback() const
{
  return &vtkImageExport::PipelineModifiedCallbackFunction;
}

vtkImageExport::WholeExtentCallbackType
vtkImageExport::GetWholeExtentCallback() const
{
  return &vtkImageExport::WholeExtentCallbackFunction;
}

vtkImageExport::SpacingCallbackType
vtkImageExport::GetSpacingCallback() const
{
  return &vtkImageExport::SpacingCallbackFunction;
}

vtkImageExport::OriginCallbackType
vtkImageExport::GetOriginCallback() const
{
  return &vtkImageExport::OriginCallbackFunction;
}

vtkImageExport::ScalarTypeCallbackType
vtkImageExport::GetScalarTypeCallback() const
{
  return &vtkImageExport::ScalarTypeCallbackFunction;
}

vtkImageExport::NumberOfComponentsCallbackType
vtkImageExport::GetNumberOfComponentsCallback() const
{
  return &vtkImageExport::NumberOfComponentsCallbackFunction;
}

vtkImageExport::PropagateUpdateExtentCallbackType
vtkImageExport::GetPropagateUpdateExtentCallback() const
{
  return &vtkImageExport::PropagateUpdateExtentCallbackFunction;
}

vtkImageExport::UpdateDataCallbackType
vtkImageExport::GetUpdateDataCallback() const
{
  return &vtkImageExport::UpdateDataCallbackFunction;
}

vtkImageExport::DataExtentCallbackType
vtkImageExport::GetDataExtentCallback() const
{
  return &vtkImageExport::DataExtentCallbackFunction;
}

vtkImageExport::BufferPointerCallbackType
vtkImageExport::GetBufferPointerCallback() const
{
  return &vtkImageExport::BufferPointerCallbackFunction;
}

//----------------------------------------------------------------------------
void vtkImageExport::UpdateInformationCallbackFunction(void* userData)
{
  static_cast<vtkImageExport*>(userData)->
    UpdateInformationCallback();
}

int vtkImageExport::PipelineModifiedCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    PipelineModifiedCallback();
}

int* vtkImageExport::WholeExtentCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    WholeExtentCallback();
}

float* vtkImageExport::SpacingCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    SpacingCallback();
}

float* vtkImageExport::OriginCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    OriginCallback();
}

const char* vtkImageExport::ScalarTypeCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    ScalarTypeCallback();
}

int vtkImageExport::NumberOfComponentsCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    NumberOfComponentsCallback();
}

void vtkImageExport::PropagateUpdateExtentCallbackFunction(void* userData,
                                                               int* extent)
{
  static_cast<vtkImageExport*>(userData)->
    PropagateUpdateExtentCallback(extent);
}

void vtkImageExport::UpdateDataCallbackFunction(void* userData)
{
  static_cast<vtkImageExport*>(userData)->
    UpdateDataCallback();
}

int* vtkImageExport::DataExtentCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    DataExtentCallback();
}

void* vtkImageExport::BufferPointerCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    BufferPointerCallback();
}

//----------------------------------------------------------------------------
void vtkImageExport::UpdateInformationCallback()
{
  this->GetInput()->UpdateInformation();
}

int vtkImageExport::PipelineModifiedCallback()
{
  unsigned long mtime = this->GetInput()->GetPipelineMTime();
  if(mtime > this->LastPipelineMTime)
    {
    this->LastPipelineMTime = mtime;
    return 1;
    }
  return 0;
}

int* vtkImageExport::WholeExtentCallback()
{
  return this->GetInput()->GetWholeExtent();
}

float* vtkImageExport::SpacingCallback()
{
  return this->GetInput()->GetSpacing();
}

float* vtkImageExport::OriginCallback()
{
  return this->GetInput()->GetOrigin();
}

const char* vtkImageExport::ScalarTypeCallback()
{
  switch (this->GetInput()->GetScalarType())
    {
    case VTK_DOUBLE:
      { return "double"; } break;
    case VTK_FLOAT:
      { return "float"; } break;
    case VTK_LONG:
      { return "long"; } break;
    case VTK_UNSIGNED_LONG:
      { return "unsigned long"; } break;
    case VTK_INT:
      { return "int"; } break;
    case VTK_UNSIGNED_INT:
      { return "unsigned int"; } break;
    case VTK_SHORT:
      { return "short"; } break;
    case VTK_UNSIGNED_SHORT:
      { return "unsigned short"; } break;
    case VTK_CHAR:
      { return "char"; } break;
    case VTK_UNSIGNED_CHAR:
      { return "unsigned char"; } break;
    default:
      { return "<unsupported>"; } break;
    }
}

int vtkImageExport::NumberOfComponentsCallback()
{
  return this->GetInput()->GetNumberOfScalarComponents();
}

void vtkImageExport::PropagateUpdateExtentCallback(int* extent)
{
  this->GetInput()->SetUpdateExtent(extent);
}

void vtkImageExport::UpdateDataCallback()
{
  this->GetInput()->Update();
}

int* vtkImageExport::DataExtentCallback()
{
  return this->GetInput()->GetExtent();
}

void* vtkImageExport::BufferPointerCallback()
{
  return this->GetInput()->GetScalarPointer();
}
<commit_msg>ERR: unreachable statements caused warnings.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageExport.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to David G. Gobbi who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include <ctype.h>
#include <string.h>
#include "vtkImageExport.h"
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageExport* vtkImageExport::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageExport");
  if(ret)
    {
    return (vtkImageExport*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageExport;
}

//----------------------------------------------------------------------------
vtkImageExport::vtkImageExport()
{
  this->ImageLowerLeft = 1;
  this->ExportVoidPointer = 0;
  this->DataDimensions[0] = this->DataDimensions[1] =
    this->DataDimensions[2] = 0;
  this->LastPipelineMTime = 0;
}

//----------------------------------------------------------------------------
vtkImageExport::~vtkImageExport()
{
}

//----------------------------------------------------------------------------
void vtkImageExport::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkProcessObject::PrintSelf(os,indent);

  os << indent << "ImageLowerLeft: "
     << (this->ImageLowerLeft ? "On\n" : "Off\n");
}

//----------------------------------------------------------------------------
void vtkImageExport::SetInput(vtkImageData *input)
{
  this->vtkProcessObject::SetNthInput(0, input);
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageExport::GetInput()
{
  if (this->NumberOfInputs < 1)
    {
    return NULL;
    }

  return (vtkImageData *)(this->Inputs[0]);
}

//----------------------------------------------------------------------------
int vtkImageExport::GetDataMemorySize()
{
  vtkImageData *input = this->GetInput();
  if (input == NULL)
    {
    return 0;
    }

  input->UpdateInformation();
  int *extent = input->GetWholeExtent();
  int size = input->GetScalarSize();
  size *= input->GetNumberOfScalarComponents();
  size *= (extent[1] - extent[0] + 1);
  size *= (extent[3] - extent[2] + 1);
  size *= (extent[5] - extent[4] + 1);

  return size;
}

//----------------------------------------------------------------------------
void vtkImageExport::GetDataDimensions(int *dims)
{
  vtkImageData *input = this->GetInput();
  if (input == NULL)
    {
    dims[0] = dims[1] = dims[2] = 0;
    return;
    }

  input->UpdateInformation();
  int *extent = input->GetWholeExtent();
  dims[0] = extent[1]-extent[0]+1;
  dims[1] = extent[3]-extent[2]+1;
  dims[2] = extent[5]-extent[4]+1;
}

//----------------------------------------------------------------------------
void vtkImageExport::SetExportVoidPointer(void *ptr)
{
  if (this->ExportVoidPointer == ptr)
    {
    return;
    }
  this->ExportVoidPointer = ptr;
  this->Modified();
}

//----------------------------------------------------------------------------
// Exports all the data from the input.
void vtkImageExport::Export(void *output)
{
  if (this->ImageLowerLeft)
    {
    memcpy(output,this->GetPointerToData(),this->GetDataMemorySize());
    }
  else
    { // flip the image when it is output
    void *ptr = this->GetPointerToData();
    int *extent = this->GetInput()->GetWholeExtent();
    int xsize = extent[1]-extent[0]+1;
    int ysize = extent[3]-extent[2]+1;
    int zsize = extent[5]-extent[4]+1;
    int csize = this->GetInput()->GetScalarSize()* \
                this->GetInput()->GetNumberOfScalarComponents();

    for (int i = 0; i < zsize; i++)
      {
      ptr = (void *)(((char *)ptr) + ysize*xsize*csize);
      for (int j = 0; j < ysize; j++)
        {
        ptr = (void *)(((char *)ptr) - xsize*csize);
        memcpy(output, ptr, xsize*csize);
        output = (void *)(((char *)output) + xsize*csize);
        }
      ptr = (void *)(((char *)ptr) + ysize*xsize*csize);
      }
    }
}

//----------------------------------------------------------------------------
// Provides a valid pointer to the data (only valid until the next
// update, though)

void *vtkImageExport::GetPointerToData()
{
  // Error checking
  if ( this->GetInput() == NULL )
    {
    vtkErrorMacro(<<"Export: Please specify an input!");
    return 0;
    }

  vtkImageData *input = this->GetInput();
  input->UpdateInformation();
  input->SetUpdateExtent(input->GetWholeExtent());
  input->ReleaseDataFlagOff();

  input->Update();
  this->UpdateProgress(0.0);
  this->UpdateProgress(1.0);

  return input->GetScalarPointer();
}

//----------------------------------------------------------------------------
void* vtkImageExport::GetCallbackUserData()
{
  return this;
}

vtkImageExport::UpdateInformationCallbackType
vtkImageExport::GetUpdateInformationCallback() const
{
  return &vtkImageExport::UpdateInformationCallbackFunction;
}

vtkImageExport::PipelineModifiedCallbackType
vtkImageExport::GetPipelineModifiedCallback() const
{
  return &vtkImageExport::PipelineModifiedCallbackFunction;
}

vtkImageExport::WholeExtentCallbackType
vtkImageExport::GetWholeExtentCallback() const
{
  return &vtkImageExport::WholeExtentCallbackFunction;
}

vtkImageExport::SpacingCallbackType
vtkImageExport::GetSpacingCallback() const
{
  return &vtkImageExport::SpacingCallbackFunction;
}

vtkImageExport::OriginCallbackType
vtkImageExport::GetOriginCallback() const
{
  return &vtkImageExport::OriginCallbackFunction;
}

vtkImageExport::ScalarTypeCallbackType
vtkImageExport::GetScalarTypeCallback() const
{
  return &vtkImageExport::ScalarTypeCallbackFunction;
}

vtkImageExport::NumberOfComponentsCallbackType
vtkImageExport::GetNumberOfComponentsCallback() const
{
  return &vtkImageExport::NumberOfComponentsCallbackFunction;
}

vtkImageExport::PropagateUpdateExtentCallbackType
vtkImageExport::GetPropagateUpdateExtentCallback() const
{
  return &vtkImageExport::PropagateUpdateExtentCallbackFunction;
}

vtkImageExport::UpdateDataCallbackType
vtkImageExport::GetUpdateDataCallback() const
{
  return &vtkImageExport::UpdateDataCallbackFunction;
}

vtkImageExport::DataExtentCallbackType
vtkImageExport::GetDataExtentCallback() const
{
  return &vtkImageExport::DataExtentCallbackFunction;
}

vtkImageExport::BufferPointerCallbackType
vtkImageExport::GetBufferPointerCallback() const
{
  return &vtkImageExport::BufferPointerCallbackFunction;
}

//----------------------------------------------------------------------------
void vtkImageExport::UpdateInformationCallbackFunction(void* userData)
{
  static_cast<vtkImageExport*>(userData)->
    UpdateInformationCallback();
}

int vtkImageExport::PipelineModifiedCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    PipelineModifiedCallback();
}

int* vtkImageExport::WholeExtentCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    WholeExtentCallback();
}

float* vtkImageExport::SpacingCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    SpacingCallback();
}

float* vtkImageExport::OriginCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    OriginCallback();
}

const char* vtkImageExport::ScalarTypeCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    ScalarTypeCallback();
}

int vtkImageExport::NumberOfComponentsCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    NumberOfComponentsCallback();
}

void vtkImageExport::PropagateUpdateExtentCallbackFunction(void* userData,
                                                               int* extent)
{
  static_cast<vtkImageExport*>(userData)->
    PropagateUpdateExtentCallback(extent);
}

void vtkImageExport::UpdateDataCallbackFunction(void* userData)
{
  static_cast<vtkImageExport*>(userData)->
    UpdateDataCallback();
}

int* vtkImageExport::DataExtentCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    DataExtentCallback();
}

void* vtkImageExport::BufferPointerCallbackFunction(void* userData)
{
  return static_cast<vtkImageExport*>(userData)->
    BufferPointerCallback();
}

//----------------------------------------------------------------------------
void vtkImageExport::UpdateInformationCallback()
{
  this->GetInput()->UpdateInformation();
}

int vtkImageExport::PipelineModifiedCallback()
{
  unsigned long mtime = this->GetInput()->GetPipelineMTime();
  if(mtime > this->LastPipelineMTime)
    {
    this->LastPipelineMTime = mtime;
    return 1;
    }
  return 0;
}

int* vtkImageExport::WholeExtentCallback()
{
  return this->GetInput()->GetWholeExtent();
}

float* vtkImageExport::SpacingCallback()
{
  return this->GetInput()->GetSpacing();
}

float* vtkImageExport::OriginCallback()
{
  return this->GetInput()->GetOrigin();
}

const char* vtkImageExport::ScalarTypeCallback()
{
  switch (this->GetInput()->GetScalarType())
    {
    case VTK_DOUBLE:
      { return "double"; }
    case VTK_FLOAT:
      { return "float"; }
    case VTK_LONG:
      { return "long"; }
    case VTK_UNSIGNED_LONG:
      { return "unsigned long"; }
    case VTK_INT:
      { return "int"; }
    case VTK_UNSIGNED_INT:
      { return "unsigned int"; }
    case VTK_SHORT:
      { return "short"; }
    case VTK_UNSIGNED_SHORT:
      { return "unsigned short"; }
    case VTK_CHAR:
      { return "char"; }
    case VTK_UNSIGNED_CHAR:
      { return "unsigned char"; }
    default:
      { return "<unsupported>"; }
    }
}

int vtkImageExport::NumberOfComponentsCallback()
{
  return this->GetInput()->GetNumberOfScalarComponents();
}

void vtkImageExport::PropagateUpdateExtentCallback(int* extent)
{
  this->GetInput()->SetUpdateExtent(extent);
}

void vtkImageExport::UpdateDataCallback()
{
  this->GetInput()->Update();
}

int* vtkImageExport::DataExtentCallback()
{
  return this->GetInput()->GetExtent();
}

void* vtkImageExport::BufferPointerCallback()
{
  return this->GetInput()->GetScalarPointer();
}
<|endoftext|>