<commit_before>#ifndef __MAPNIK_VECTOR_TILE_UTIL_H__
#define __MAPNIK_VECTOR_TILE_UTIL_H__

#include "clipper.hpp"
#include "vector_tile.pb.h"
#include <mapnik/vertex.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry.hpp>
#include <stdexcept>
#include <string>

namespace mapnik { namespace vector {

    bool is_solid_clipper(mapnik::vector::tile const& tile, std::string & key)
    {
        ClipperLib::Clipper clipper;

        for (int i = 0; i < tile.layers_size(); i++)
        {
            mapnik::vector::tile_layer const& layer = tile.layers(i);
            unsigned extent = layer.extent();
            unsigned side = extent - 1;
            double extent_area = side * side;

            ClipperLib::Polygon clip_box;
            clip_box.push_back(ClipperLib::IntPoint(0, 0));
            clip_box.push_back(ClipperLib::IntPoint(side, 0));
            clip_box.push_back(ClipperLib::IntPoint(side, side));
            clip_box.push_back(ClipperLib::IntPoint(0, side));
            clip_box.push_back(ClipperLib::IntPoint(0, 0));

            for (int j = 0; j < layer.features_size(); j++)
            {
                mapnik::vector::tile_feature const& feature = layer.features(j);

                int cmd = -1;
                const int cmd_bits = 3;
                unsigned length = 0;
                int32_t x = 0, y = 0;
                int32_t start_x = 0, start_y = 0;

                ClipperLib::Polygons geometry;
                ClipperLib::Polygon polygon;

                for (int k = 0; k < feature.geometry_size();)
                {
                    if (!length) {
                        unsigned cmd_length = feature.geometry(k++);
                        cmd = cmd_length & ((1 << cmd_bits) - 1);
                        length = cmd_length >> cmd_bits;
                    }

                    if (length > 0) {
                        length--;

                        if (cmd == mapnik::SEG_MOVETO || cmd == mapnik::SEG_LINETO)
                        {
                            int32_t dx = feature.geometry(k++);
                            int32_t dy = feature.geometry(k++);
                            x += ((dx >> 1) ^ (-(dx & 1)));
                            y += ((dy >> 1) ^ (-(dy & 1)));

                            // We can abort early if this feature has a vertex that is
                            // inside the bbox.
                            if ((x > 0 && x < static_cast<int>(side)) && (y > 0 && y < static_cast<int>(side))) {
                                return false;
                            }

                            if (cmd == mapnik::SEG_MOVETO) {
                                start_x = x;
                                start_y = y;
                                geometry.push_back(polygon);
                                polygon.clear();
                            }

                            polygon.push_back(ClipperLib::IntPoint(x, y));
                        }
                        else if (cmd == (mapnik::SEG_CLOSE & ((1 << cmd_bits) - 1)))
                        {
                            polygon.push_back(ClipperLib::IntPoint(start_x, start_y));
                            geometry.push_back(polygon);
                            polygon.clear();
                        }
                        else
                        {
                            throw std::runtime_error("Unknown command type");
                        }
                    }
                }

                ClipperLib::Polygons solution;

                clipper.Clear();
                clipper.AddPolygons(geometry, ClipperLib::ptSubject);
                clipper.AddPolygon(clip_box, ClipperLib::ptClip);
                clipper.Execute(ClipperLib::ctIntersection, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero);

                // If there are more than one result polygons, it can't be covered by
                // a single feature. Similarly, if there's no result, this geometry
                // is completely outside the bounding box.
                if (solution.size() != 1) {
                    return false;
                }

                // Once we have only one clipped result polygon, we can compare the
                // areas and return early if they don't match.
                double area = ClipperLib::Area(solution.front());
                if (area != extent_area) {
                    return false;
                }
                if (i == 0) {
                    key = layer.name();
                } else if (i > 0) {
                    key += std::string("-") + layer.name();
                }
            }
        }
        // It's either empty or doesn't have features that have vertices that are
        // not on the border of the bbox.
        return true;
    }

    bool is_solid_extent(mapnik::vector::tile const& tile, std::string & key)
    {
        for (int i = 0; i < tile.layers_size(); i++)
        {
            mapnik::vector::tile_layer const& layer = tile.layers(i);
            unsigned extent = layer.extent();
            unsigned side = extent - 1;
            double extent_area = side * side;
            for (int j = 0; j < layer.features_size(); j++)
            {
                mapnik::vector::tile_feature const& feature = layer.features(j);
                mapnik::eGeomType g_type = static_cast<mapnik::eGeomType>(feature.type());
                mapnik::geometry_type geom(g_type);
                int cmd = -1;
                const int cmd_bits = 3;
                unsigned length = 0;
                int32_t x = 0, y = 0;
                for (int k = 0; k < feature.geometry_size();)
                {
                    if (!length) {
                        unsigned cmd_length = feature.geometry(k++);
                        cmd = cmd_length & ((1 << cmd_bits) - 1);
                        length = cmd_length >> cmd_bits;
                    }

                    if (length > 0) {
                        length--;

                        if (cmd == mapnik::SEG_MOVETO || cmd == mapnik::SEG_LINETO)
                        {
                            int32_t dx = feature.geometry(k++);
                            int32_t dy = feature.geometry(k++);
                            x += ((dx >> 1) ^ (-(dx & 1)));
                            y += ((dy >> 1) ^ (-(dy & 1)));
                            // We can abort early if this feature has a vertex that is
                            // inside the bbox.
                            if ((x > 0 && x < static_cast<int>(side)) && (y > 0 && y < static_cast<int>(side))) {
                                return false;
                            }
                            geom.push_vertex(x, y, static_cast<mapnik::CommandType>(cmd));
                        }
                        else if (cmd == (mapnik::SEG_CLOSE & ((1 << cmd_bits) - 1)))
                        {
                            geom.push_vertex(0, 0, mapnik::SEG_CLOSE);
                        }
                        else
                        {
                            throw std::runtime_error("Unknown command type");
                        }
                    }
                }
                // Once we have only one clipped result polygon, we can compare the
                // areas and return early if they don't match.
                mapnik::box2d<double> box = geom.envelope();
                double geom_area = box.width() * box.height();
                if (geom_area < (extent_area - 32) )
                {
                    return false;
                }
                if (i == 0) {
                    key = layer.name();
                } else if (i > 0) {
                    key += std::string("-") + layer.name();
                }
            }
        }

        // It's either empty or doesn't have features that have vertices that are
        // not on the border of the bbox.
        return true;
    }

    }} // end ns

#endif // __MAPNIK_VECTOR_TILE_UTIL_H__
<commit_msg>only include clipper is_solid method if -DCONV_CLIPPER<commit_after>#ifndef __MAPNIK_VECTOR_TILE_UTIL_H__
#define __MAPNIK_VECTOR_TILE_UTIL_H__

#include "vector_tile.pb.h"
#include <mapnik/vertex.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry.hpp>
#include <stdexcept>
#include <string>

#ifdef CONV_CLIPPER
#include "clipper.hpp"
#endif

namespace mapnik { namespace vector {

#ifdef CONV_CLIPPER
    bool is_solid_clipper(mapnik::vector::tile const& tile, std::string & key)
    {
        ClipperLib::Clipper clipper;

        for (int i = 0; i < tile.layers_size(); i++)
        {
            mapnik::vector::tile_layer const& layer = tile.layers(i);
            unsigned extent = layer.extent();
            unsigned side = extent - 1;
            double extent_area = side * side;

            ClipperLib::Polygon clip_box;
            clip_box.push_back(ClipperLib::IntPoint(0, 0));
            clip_box.push_back(ClipperLib::IntPoint(side, 0));
            clip_box.push_back(ClipperLib::IntPoint(side, side));
            clip_box.push_back(ClipperLib::IntPoint(0, side));
            clip_box.push_back(ClipperLib::IntPoint(0, 0));

            for (int j = 0; j < layer.features_size(); j++)
            {
                mapnik::vector::tile_feature const& feature = layer.features(j);

                int cmd = -1;
                const int cmd_bits = 3;
                unsigned length = 0;
                int32_t x = 0, y = 0;
                int32_t start_x = 0, start_y = 0;

                ClipperLib::Polygons geometry;
                ClipperLib::Polygon polygon;

                for (int k = 0; k < feature.geometry_size();)
                {
                    if (!length) {
                        unsigned cmd_length = feature.geometry(k++);
                        cmd = cmd_length & ((1 << cmd_bits) - 1);
                        length = cmd_length >> cmd_bits;
                    }

                    if (length > 0) {
                        length--;

                        if (cmd == mapnik::SEG_MOVETO || cmd == mapnik::SEG_LINETO)
                        {
                            int32_t dx = feature.geometry(k++);
                            int32_t dy = feature.geometry(k++);
                            x += ((dx >> 1) ^ (-(dx & 1)));
                            y += ((dy >> 1) ^ (-(dy & 1)));

                            // We can abort early if this feature has a vertex that is
                            // inside the bbox.
                            if ((x > 0 && x < static_cast<int>(side)) && (y > 0 && y < static_cast<int>(side))) {
                                return false;
                            }

                            if (cmd == mapnik::SEG_MOVETO) {
                                start_x = x;
                                start_y = y;
                                geometry.push_back(polygon);
                                polygon.clear();
                            }

                            polygon.push_back(ClipperLib::IntPoint(x, y));
                        }
                        else if (cmd == (mapnik::SEG_CLOSE & ((1 << cmd_bits) - 1)))
                        {
                            polygon.push_back(ClipperLib::IntPoint(start_x, start_y));
                            geometry.push_back(polygon);
                            polygon.clear();
                        }
                        else
                        {
                            throw std::runtime_error("Unknown command type");
                        }
                    }
                }

                ClipperLib::Polygons solution;

                clipper.Clear();
                clipper.AddPolygons(geometry, ClipperLib::ptSubject);
                clipper.AddPolygon(clip_box, ClipperLib::ptClip);
                clipper.Execute(ClipperLib::ctIntersection, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero);

                // If there are more than one result polygons, it can't be covered by
                // a single feature. Similarly, if there's no result, this geometry
                // is completely outside the bounding box.
                if (solution.size() != 1) {
                    return false;
                }

                // Once we have only one clipped result polygon, we can compare the
                // areas and return early if they don't match.
                double area = ClipperLib::Area(solution.front());
                if (area != extent_area) {
                    return false;
                }
                if (i == 0) {
                    key = layer.name();
                } else if (i > 0) {
                    key += std::string("-") + layer.name();
                }
            }
        }
        // It's either empty or doesn't have features that have vertices that are
        // not on the border of the bbox.
        return true;
    }
#endif

    bool is_solid_extent(mapnik::vector::tile const& tile, std::string & key)
    {
        for (int i = 0; i < tile.layers_size(); i++)
        {
            mapnik::vector::tile_layer const& layer = tile.layers(i);
            unsigned extent = layer.extent();
            unsigned side = extent - 1;
            double extent_area = side * side;
            for (int j = 0; j < layer.features_size(); j++)
            {
                mapnik::vector::tile_feature const& feature = layer.features(j);
                mapnik::eGeomType g_type = static_cast<mapnik::eGeomType>(feature.type());
                mapnik::geometry_type geom(g_type);
                int cmd = -1;
                const int cmd_bits = 3;
                unsigned length = 0;
                int32_t x = 0, y = 0;
                for (int k = 0; k < feature.geometry_size();)
                {
                    if (!length) {
                        unsigned cmd_length = feature.geometry(k++);
                        cmd = cmd_length & ((1 << cmd_bits) - 1);
                        length = cmd_length >> cmd_bits;
                    }

                    if (length > 0) {
                        length--;

                        if (cmd == mapnik::SEG_MOVETO || cmd == mapnik::SEG_LINETO)
                        {
                            int32_t dx = feature.geometry(k++);
                            int32_t dy = feature.geometry(k++);
                            x += ((dx >> 1) ^ (-(dx & 1)));
                            y += ((dy >> 1) ^ (-(dy & 1)));
                            // We can abort early if this feature has a vertex that is
                            // inside the bbox.
                            if ((x > 0 && x < static_cast<int>(side)) && (y > 0 && y < static_cast<int>(side))) {
                                return false;
                            }
                            geom.push_vertex(x, y, static_cast<mapnik::CommandType>(cmd));
                        }
                        else if (cmd == (mapnik::SEG_CLOSE & ((1 << cmd_bits) - 1)))
                        {
                            geom.push_vertex(0, 0, mapnik::SEG_CLOSE);
                        }
                        else
                        {
                            throw std::runtime_error("Unknown command type");
                        }
                    }
                }
                // Once we have only one clipped result polygon, we can compare the
                // areas and return early if they don't match.
                mapnik::box2d<double> box = geom.envelope();
                double geom_area = box.width() * box.height();
                if (geom_area < (extent_area - 32) )
                {
                    return false;
                }
                if (i == 0) {
                    key = layer.name();
                } else if (i > 0) {
                    key += std::string("-") + layer.name();
                }
            }
        }

        // It's either empty or doesn't have features that have vertices that are
        // not on the border of the bbox.
        return true;
    }

    }} // end ns

#endif // __MAPNIK_VECTOR_TILE_UTIL_H__
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 damlaren

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 Implementation of perspective_camera.h.
 */

#include "renderer/perspective_camera.h"
#include "easylogging++.h"  // NOLINT
#include "geometry/transformation_matrix.h"

namespace ogle {

PerspectiveCamera::PerspectiveCamera(const float near_clip,
                                     const float far_clip,
                                     const Angle vertical_fov,
                                     const float aspect_ratio)
  : Camera(), near_clip_(near_clip), far_clip_(far_clip),
    vertical_fov_(vertical_fov), aspect_ratio_(aspect_ratio) {
  CHECK(near_clip_ < far_clip_) << "Near clip plane must be closer than far.";
  CHECK(near_clip_ >= 0) << "Near clip plane must be at positive distance.";
  CHECK(vertical_fov.radians() > 0) << "Vertical FOV must be > 0.";
  CHECK(aspect_ratio > 0) << "Aspect ratio must be > 0.";
}

PerspectiveCamera::~PerspectiveCamera() {
}

Matrix44f PerspectiveCamera::GetViewMatrix() const {
  return TransformationMatrix::ViewMatrix3D(
      transform_.world_position(),
      (transform_.world_orientation() * Transform::kFrontAxis).NormalizedCopy(),
      {0.f, 1.f, 0.f});
}

Matrix44f PerspectiveCamera::GetProjectionMatrix() const {
  return TransformationMatrix::PerspectiveMatrix3D(near_clip_, far_clip_,
                                                   vertical_fov_,
                                                   aspect_ratio_);
}

}  // namespace ogle
<commit_msg>Use a constant.<commit_after>/*
Copyright (c) 2015 damlaren

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 Implementation of perspective_camera.h.
 */

#include "renderer/perspective_camera.h"
#include "easylogging++.h"  // NOLINT
#include "geometry/transformation_matrix.h"

namespace ogle {

PerspectiveCamera::PerspectiveCamera(const float near_clip,
                                     const float far_clip,
                                     const Angle vertical_fov,
                                     const float aspect_ratio)
  : Camera(), near_clip_(near_clip), far_clip_(far_clip),
    vertical_fov_(vertical_fov), aspect_ratio_(aspect_ratio) {
  CHECK(near_clip_ < far_clip_) << "Near clip plane must be closer than far.";
  CHECK(near_clip_ >= 0) << "Near clip plane must be at positive distance.";
  CHECK(vertical_fov.radians() > 0) << "Vertical FOV must be > 0.";
  CHECK(aspect_ratio > 0) << "Aspect ratio must be > 0.";
}

PerspectiveCamera::~PerspectiveCamera() {
}

Matrix44f PerspectiveCamera::GetViewMatrix() const {
  return TransformationMatrix::ViewMatrix3D(
      transform_.world_position(),
      (transform_.world_orientation() * Transform::kFrontAxis).NormalizedCopy(),
      Transform::kUpAxis);
}

Matrix44f PerspectiveCamera::GetProjectionMatrix() const {
  return TransformationMatrix::PerspectiveMatrix3D(near_clip_, far_clip_,
                                                   vertical_fov_,
                                                   aspect_ratio_);
}

}  // namespace ogle
<|endoftext|>


<commit_before>// $Id: exception.C,v 1.10 2000/07/02 23:48:03 amoll Exp $

#include <BALL/COMMON/exception.h>
#include <BALL/COMMON/logStream.h>

#include <iostream>
#include <typeinfo>
#include <exception>
#include <stdio.h>
#include <stdlib.h>	// for getenv in terminate()
#include <sys/types.h>
#include <signal.h> // for SIGSEGV and kill
#include <unistd.h> // fot getpid

#define BALL_CORE_DUMP_ENVNAME "BALL_DUMP_CORE"

#define DEF_EXCEPTION(a,b) \
	a##::##a##(const char* file, int line)\
		: GeneralException(file, line, #a, b)\
	{\
	}\
\

using std::string;
using std::endl;

namespace BALL
{

	namespace Exception
	{

			GeneralException::GeneralException()
				:	file_("?"),
					line_(-1),
					name_("GeneralException"),
					message_("unspecified error")
			{
				globalHandler.set(file_, line_, name_, message_);
			}

			GeneralException::GeneralException(const char* file, int line, const string& name, const string& message)
				:	file_(file),
					line_(line),
					name_(name),
					message_(message)
			{
				globalHandler.set(file_, line_, name_, message_);
			}

			GeneralException::GeneralException(const GeneralException& exception)
				:	file_(exception.file_),
					line_(exception.line_),
					name_(exception.name_),
					message_(exception.message_)
			{
			}

			GeneralException::~GeneralException()
			{
			}

			string GeneralException::getName() const
			{
				return name_;
			}

			string GeneralException::getMessage() const
			{
				return message_;
			}

			string GeneralException::getFile() const
			{
				return file_;
			}

			int GeneralException::getLine() const
			{
				return line_;
			}

			IndexUnderflow::IndexUnderflow(const char* file, int line, Index index, Size size)
				: GeneralException(file, line, "IndexUnderflow", ""),
					size_(size),
					index_(index)
			{
				message_ = "the given index was too small: ";
				char buf[40];

				sprintf(buf, "%ld", (long)index);
				message_ += buf;
				message_ += " (size = ";

				sprintf(buf, "%ld", (long)size);
				message_ += buf;
				message_ += ")";

				globalHandler.setMessage(message_);
			}

			IndexOverflow::IndexOverflow(const char* file, int line, Index index, Size size)
				:	GeneralException(file, line, "IndexOverflow", "an index was too large"),
					size_(size),
					index_(index)
			{
				message_ = "the given index was too large: ";
				char buf[40];

				sprintf(buf, "%ld", (long)index);
				message_ += buf;
				message_ += " (size = ";

				sprintf(buf, "%ld", (long)size);
				message_ += buf;
				message_ += ")";

				globalHandler.setMessage(message_);
			}

			OutOfMemory::OutOfMemory(const char* file, int line, Size size)
				:	GeneralException(file, line, "OutOfMemory", "a memory allocation failed"),
					size_(size)
			{
				message_ = "unable to allocate enough memory (size = ";
				char buf[40];

				sprintf(buf, "%ld", (long)size_);
				message_ += buf;
				message_ += " bytes) ";

				globalHandler.setMessage(message_);
			}

			OutOfMemory::~OutOfMemory() throw()
			{
			}

			SizeUnderflow::SizeUnderflow(const char* file, int line, Size size)
				:	GeneralException(file, line, "SizeUnderflow", ""),
					size_(size)
			{
				message_ = "the given size was too small: ";
				char buf[40];
				sprintf(buf, "%ld", (long)size);

				message_ += buf;
				globalHandler.setMessage(message_);
			}

			FileNotFound::FileNotFound(const char* file, int line, const string& filename)
				:	GeneralException(file, line, "FileNotFound", ""),
					filename_(filename)
			{
				message_ = "the file " + filename + " could not be found";
				globalHandler.setMessage(message_);
			}

			string FileNotFound::getFilename() const
			{
				return filename_;
			}

			DEF_EXCEPTION(DivisionByZero, "a division by zero was requested")

			DEF_EXCEPTION(InvalidRange, "the range of the operation was invalid")

			DEF_EXCEPTION(InvalidFormat, "a conversion from a string to a numeric value failed")

			DEF_EXCEPTION(IllegalSelfOperation, "this operation may not be performed with the same object as argument")

			DEF_EXCEPTION(NullPointer, "a null pointer was specified")

			DEF_EXCEPTION(InvalidIterator, "the iterator is invalid - probably it is not bound to a container")

			DEF_EXCEPTION(IncompatibleIterators, "the iterator could not be assigned because it is bound to a different container")

			DEF_EXCEPTION(NotImplemented, "this method has not been implemented yet. Feel free to complain about it!")

			DEF_EXCEPTION(BufferOverflow, "the maximum buffersize has been reached")

			DEF_EXCEPTION(OutOfGrid, "a point was outside a grid")

			GlobalExceptionHandler::GlobalExceptionHandler()
			{
				std::set_terminate(terminate);
				std::set_unexpected(terminate);
				std::set_new_handler(newHandler);
			}

			void GlobalExceptionHandler::newHandler()
			{
				throw Exception::OutOfMemory(__FILE__, __LINE__);
			}

			void GlobalExceptionHandler::terminate()
			{
				// add cerr to the log stream
				// and write all available information on
				// the exception to the log stream (potentially with an assigned file!)
				// and cerr

				Log.insert(std::cerr);
				Log.error() << endl;
				Log.error() << "---------------------------------------------------" << endl;
				Log.error() << "FATAL: terminate called!" << endl;
				Log.error() << "---------------------------------------------------" << endl;
				if ((line_ != -1) && (name_ != "unknown"))
				{
					Log.error() << "last entry in the exception handler: " << endl;
					Log.error() << "exception of type " << name_.c_str() << " occured in line "
											<< line_ << " of " << file_.c_str() << endl;
					Log.error() << "error message: " << message_.c_str() << endl;
				}
				Log.error() << "---------------------------------------------------" << endl;

				// if the environment variable declared in BALL_CORE_DUMP_ENVNAME
				// is set, provoke a core dump (this is helpful to get s stack traceback)
				if (getenv(BALL_CORE_DUMP_ENVNAME) != 0)
				{
					Log.error() << "dumping core file.... (to avoid this, unset " << BALL_CORE_DUMP_ENVNAME
											<< " in your environment)" << endl;
					// provoke a core dump
					kill(getpid(), SIGSEGV);
				}

				// otherwise exit cleanly
				exit(1);
			}

			void GlobalExceptionHandler::set
				(const string& file, int line,
				 const string& name, const string& message)
			{
				name_ = name;
				line_ = line;
				message_ = message;
				file_ = file;
			}

			void GlobalExceptionHandler::setName(const string& name)
			{
				name_ = name;
			}

			void GlobalExceptionHandler::setMessage(const string& message)
			{
				message_ = message;
			}

			void GlobalExceptionHandler::setFile(const string& file)
			{
				file_ = file;
			}

			void GlobalExceptionHandler::setLine(int line)
			{
				line_ = line;
			}

			string	GlobalExceptionHandler::name_			= "unknown exception";
			int			GlobalExceptionHandler::line_			= -1;
			string	GlobalExceptionHandler::message_	= " - ";
			string	GlobalExceptionHandler::file_			= "unknown";

			// create a global instance of the exception handler
			GlobalExceptionHandler globalHandler;

	} // namespace Exception

} // namespace BALL
<commit_msg>added: support for third argument in InvalidFormat<commit_after>// $Id: exception.C,v 1.11 2000/07/17 13:45:48 oliver Exp $

#include <BALL/COMMON/exception.h>
#include <BALL/COMMON/logStream.h>

#include <iostream>
#include <typeinfo>
#include <exception>
#include <stdio.h>
#include <stdlib.h>	// for getenv in terminate()
#include <sys/types.h>
#include <signal.h> // for SIGSEGV and kill
#include <unistd.h> // fot getpid

#define BALL_CORE_DUMP_ENVNAME "BALL_DUMP_CORE"

#define DEF_EXCEPTION(a,b) \
	a##::##a##(const char* file, int line)\
		: GeneralException(file, line, #a, b)\
	{\
	}\
\

using std::string;
using std::endl;

namespace BALL
{

	namespace Exception
	{

			GeneralException::GeneralException()
				:	file_("?"),
					line_(-1),
					name_("GeneralException"),
					message_("unspecified error")
			{
				globalHandler.set(file_, line_, name_, message_);
			}

			GeneralException::GeneralException(const char* file, int line, const string& name, const string& message)
				:	file_(file),
					line_(line),
					name_(name),
					message_(message)
			{
				globalHandler.set(file_, line_, name_, message_);
			}

			GeneralException::GeneralException(const GeneralException& exception)
				:	file_(exception.file_),
					line_(exception.line_),
					name_(exception.name_),
					message_(exception.message_)
			{
			}

			GeneralException::~GeneralException()
			{
			}

			string GeneralException::getName() const
			{
				return name_;
			}

			string GeneralException::getMessage() const
			{
				return message_;
			}

			string GeneralException::getFile() const
			{
				return file_;
			}

			int GeneralException::getLine() const
			{
				return line_;
			}

			IndexUnderflow::IndexUnderflow(const char* file, int line, Index index, Size size)
				: GeneralException(file, line, "IndexUnderflow", ""),
					size_(size),
					index_(index)
			{
				message_ = "the given index was too small: ";
				char buf[40];

				sprintf(buf, "%ld", (long)index);
				message_ += buf;
				message_ += " (size = ";

				sprintf(buf, "%ld", (long)size);
				message_ += buf;
				message_ += ")";

				globalHandler.setMessage(message_);
			}

			IndexOverflow::IndexOverflow(const char* file, int line, Index index, Size size)
				:	GeneralException(file, line, "IndexOverflow", "an index was too large"),
					size_(size),
					index_(index)
			{
				message_ = "the given index was too large: ";
				char buf[40];

				sprintf(buf, "%ld", (long)index);
				message_ += buf;
				message_ += " (size = ";

				sprintf(buf, "%ld", (long)size);
				message_ += buf;
				message_ += ")";

				globalHandler.setMessage(message_);
			}

			OutOfMemory::OutOfMemory(const char* file, int line, Size size)
				:	GeneralException(file, line, "OutOfMemory", "a memory allocation failed"),
					size_(size)
			{
				message_ = "unable to allocate enough memory (size = ";
				char buf[40];

				sprintf(buf, "%ld", (long)size_);
				message_ += buf;
				message_ += " bytes) ";

				globalHandler.setMessage(message_);
			}

			OutOfMemory::~OutOfMemory() throw()
			{
			}

			SizeUnderflow::SizeUnderflow(const char* file, int line, Size size)
				:	GeneralException(file, line, "SizeUnderflow", ""),
					size_(size)
			{
				message_ = "the given size was too small: ";
				char buf[40];
				sprintf(buf, "%ld", (long)size);

				message_ += buf;
				globalHandler.setMessage(message_);
			}

			FileNotFound::FileNotFound(const char* file, int line, const string& filename)
				:	GeneralException(file, line, "FileNotFound", ""),
					filename_(filename)
			{
				message_ = "the file " + filename + " could not be found";
				globalHandler.setMessage(message_);
			}

			string FileNotFound::getFilename() const
			{
				return filename_;
			}

			InvalidFormat::InvalidFormat(const char* file, int line, const string& s)
				:	GeneralException(file, line, "InvalidFormat", ""),
					format_(s)
			{
				message_ = "problem converting " + s + " to a number.";
				globalHandler.setMessage(message_);
			}

			DEF_EXCEPTION(DivisionByZero, "a division by zero was requested")

			DEF_EXCEPTION(InvalidRange, "the range of the operation was invalid")

			DEF_EXCEPTION(NullPointer, "a null pointer was specified")

			DEF_EXCEPTION(InvalidIterator, "the iterator is invalid - probably it is not bound to a container")

			DEF_EXCEPTION(IncompatibleIterators, "the iterator could not be assigned because it is bound to a different container")

			DEF_EXCEPTION(NotImplemented, "this method has not been implemented yet. Feel free to complain about it!")

			DEF_EXCEPTION(BufferOverflow, "the maximum buffersize has been reached")

			DEF_EXCEPTION(OutOfGrid, "a point was outside a grid")

			GlobalExceptionHandler::GlobalExceptionHandler()
			{
				std::set_terminate(terminate);
				std::set_unexpected(terminate);
				std::set_new_handler(newHandler);
			}

			void GlobalExceptionHandler::newHandler()
			{
				throw Exception::OutOfMemory(__FILE__, __LINE__);
			}

			void GlobalExceptionHandler::terminate()
			{
				// add cerr to the log stream
				// and write all available information on
				// the exception to the log stream (potentially with an assigned file!)
				// and cerr

				Log.insert(std::cerr);
				Log.error() << endl;
				Log.error() << "---------------------------------------------------" << endl;
				Log.error() << "FATAL: terminate called!" << endl;
				Log.error() << "---------------------------------------------------" << endl;
				if ((line_ != -1) && (name_ != "unknown"))
				{
					Log.error() << "last entry in the exception handler: " << endl;
					Log.error() << "exception of type " << name_.c_str() << " occured in line "
											<< line_ << " of " << file_.c_str() << endl;
					Log.error() << "error message: " << message_.c_str() << endl;
				}
				Log.error() << "---------------------------------------------------" << endl;

				// if the environment variable declared in BALL_CORE_DUMP_ENVNAME
				// is set, provoke a core dump (this is helpful to get s stack traceback)
				if (getenv(BALL_CORE_DUMP_ENVNAME) != 0)
				{
					Log.error() << "dumping core file.... (to avoid this, unset " << BALL_CORE_DUMP_ENVNAME
											<< " in your environment)" << endl;
					// provoke a core dump
					kill(getpid(), SIGSEGV);
				}

				// otherwise exit cleanly
				exit(1);
			}

			void GlobalExceptionHandler::set
				(const string& file, int line,
				 const string& name, const string& message)
			{
				name_ = name;
				line_ = line;
				message_ = message;
				file_ = file;
			}

			void GlobalExceptionHandler::setName(const string& name)
			{
				name_ = name;
			}

			void GlobalExceptionHandler::setMessage(const string& message)
			{
				message_ = message;
			}

			void GlobalExceptionHandler::setFile(const string& file)
			{
				file_ = file;
			}

			void GlobalExceptionHandler::setLine(int line)
			{
				line_ = line;
			}

			string	GlobalExceptionHandler::name_			= "unknown exception";
			int			GlobalExceptionHandler::line_			= -1;
			string	GlobalExceptionHandler::message_	= " - ";
			string	GlobalExceptionHandler::file_			= "unknown";

			// create a global instance of the exception handler
			GlobalExceptionHandler globalHandler;

	} // namespace Exception

} // namespace BALL
<|endoftext|>


<commit_before>// $Id: property.C,v 1.21 2000/09/05 10:09:27 oliver Exp $

#include <BALL/CONCEPT/property.h>
#include <BALL/CONCEPT/persistenceManager.h>
#include <BALL/CONCEPT/textPersistenceManager.h>

using namespace std;

namespace BALL
{

	NamedProperty::NamedProperty(const NamedProperty& property)
		: PersistentObject(property),
			type_(property.type_),
			name_(property.name_)
	{
		if (type_ != STRING)
		{
			data_ = property.data_;
		}
		else
		{
			data_.s = new string(*property.data_.s);
		}
	}

	void NamedProperty::persistentWrite(PersistenceManager& pm, const char* name) const
	{
		pm.writeObjectHeader(this, name);
			pm.writePrimitive((int)type_, "type_");
			pm.writePrimitive(String(name_), "name_");

			switch (type_)
			{
				case	INT:					pm.writePrimitive(data_.i, "data_.i");		break;
				case	FLOAT:				pm.writePrimitive(data_.f, "data_.f");		break;
				case	DOUBLE:				pm.writePrimitive(data_.d, "data_.d");		break;
				case	UNSIGNED_INT:	pm.writePrimitive(data_.ui, "data_.ui"); break;
				case	BOOL:					pm.writePrimitive(data_.b, "data_.b");		break;
				case	OBJECT:				pm.writeObjectPointer(data_.object, "data_.object"); break;
				case	NONE:					break;
				case	STRING:				pm.writePrimitive(String(*data_.s), "data_.s");	break;
				default:
					Log.error() << "cannot write unknown property type: " << (int)type_ << endl;
			}
		pm.writeObjectTrailer(name);
	}

	void NamedProperty::persistentRead(PersistenceManager& pm)
	{
		int type;
		pm.readPrimitive(type, "type_");
		type_ = (Type)type;
		String s;
		pm.readPrimitive(s, "name_");
		name_ = s;

		switch (type_)
		{
			case	INT:					pm.readPrimitive(data_.i, "data_.i");		break;
			case	FLOAT:				pm.readPrimitive(data_.f, "data_.f");		break;
			case	DOUBLE:				pm.readPrimitive(data_.d, "data_.d");		break;
			case	UNSIGNED_INT:	pm.readPrimitive(data_.ui, "data_.ui"); break;
			case	BOOL:					pm.readPrimitive(data_.b, "data_.b");		break;
			case	NONE:	break;

			case	STRING:
				// we have to create a new string
				pm.readPrimitive(s, "data_.s");
				data_.s = new string(s);
				break;

			case	OBJECT:
				// the persistence manager will take care of
				// reading the object and will set this pointer afterwards
				pm.readObjectPointer(data_.object, "data_.object");
				break;

			default:
				Log.error() << "Unknown type while reading NamedProperty: " << (int)type_ << endl;
		}
	}

	/// Output operator
	ostream& operator << (std::ostream& s, const NamedProperty& property)
  {
		s << property.type_;
		s << endl;
		s << property.name_;
		s << endl;
		switch (property.type_)
		{
			case NamedProperty::BOOL:					s << property.data_.b; break;
			case NamedProperty::INT:					s << property.data_.i; break;
			case NamedProperty::UNSIGNED_INT: s << property.data_.ui; break;
			case NamedProperty::FLOAT:				s << property.data_.f; break;
			case NamedProperty::DOUBLE:				s << property.data_.d; break;
			case NamedProperty::STRING:				s << *property.data_.s; break;
			case NamedProperty::OBJECT:
				{
					TextPersistenceManager pm;
					pm.setOstream(s);
					pm.writeObjectPointer(property.data_.object, "data_.object");
					break;
				}
			case NamedProperty::NONE : break;
			default:
				Log.error() << "Unknown type while writing NamedProperty: " << (int)property.type_ << endl;
		}
		return s;
	}

	/// Input operator
	istream& operator >> (std::istream& s, NamedProperty& property)
  {
		s >> (int)property.type_;
		s >> property.name_;
		switch (property.type_)
		{
			case NamedProperty::BOOL : 	s >> property.data_.b; break;
			case NamedProperty::INT : 	s >> property.data_.i; break;
			case NamedProperty::UNSIGNED_INT : 	s >> property.data_.ui; break;
			case NamedProperty::FLOAT : s >> property.data_.f; break;
			case NamedProperty::DOUBLE :s >> property.data_.d; break;
			case NamedProperty::OBJECT :
			{
				TextPersistenceManager pm;
				pm.setIstream(s);
				pm.readObjectPointer(property.data_.object, "data_.object");
				break;
			}
			case NamedProperty::NONE : break;
			case NamedProperty::STRING :
			{
				string str;
				s >> str;
				property.data_.s = new string(str);
				break;
			}
			default:
				Log.error() << "Unknown type while reading NamedProperty: " << (int)property.type_ << endl;
		}
		return s;
	}

  ostream& operator << (ostream& s, const PropertyManager& property_manager)
  {
    s << property_manager.bitvector_;

		s << endl;
		s << property_manager.named_properties_.size();
		s << endl;
		vector<NamedProperty>::const_iterator it = property_manager.named_properties_.begin();
		for (; it != property_manager.named_properties_.end(); ++it)
		{
			s << *it << endl;
		}
		return s;
	}

  istream& operator >> (istream& s, PropertyManager& property_manager)
  {
		int size;
    s >> property_manager.bitvector_;
		s >> size;
		NamedProperty np;
		for (int i = 0; i < size; i++)
		{
			s >> np;
			property_manager.setProperty(np);
		}

		return s;
	}

  void PropertyManager::write(PersistenceManager& pm) const
  {
		pm.writeStorableObject(bitvector_, "bitvector_");
		Size size = named_properties_.size();
		pm.writePrimitive(size, "size");
		for (Size i = 0; i < size; i++)
		{
			named_properties_[i].persistentWrite(pm, "");
		}
	}

  bool PropertyManager::read(PersistenceManager& pm)
  {
		if (!pm.readStorableObject(bitvector_, "bitvector_"))
		{
			return false;
		}

		NamedProperty property("");
		named_properties_.clear();
		Size size = 0;
		pm.readPrimitive(size, "size");
		for (Size i = 0; i < size; i++)
		{
			pm.checkObjectHeader(property, "");
				property.persistentRead(pm);
			pm.checkObjectTrailer("");
			named_properties_.push_back(property);
		}

		return true;
	}

	void PropertyManager::set(const PropertyManager& property_manager, bool /* deep */)
	{
		bitvector_ = property_manager.bitvector_;
		named_properties_ = property_manager.named_properties_;
	}

	void PropertyManager::setProperty(const NamedProperty& property)
	{
		// search whether the property already exists
		vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
		{
			if (it->getName() == property.getName())
			{
				// yes, it exists. Erase the old content
				named_properties_.erase(it);
				break;
			}
		}

		// add the new content
		named_properties_.push_back(property);
	}

	void PropertyManager::setProperty(const string& name)
	{
		// search whether a property with the same name already exists
		vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
		{
			if (it->getName() == name)
			{
				// yes, it exists. Erase the old content
				named_properties_.erase(it);
				break;
			}
		}

		// add the new content
		named_properties_.push_back(NamedProperty(name));
	}

	const NamedProperty& PropertyManager::getProperty(const string& name) const
	{
		for (Size i = 0; i < named_properties_.size(); ++i)
		{
			if (named_properties_[i].getName() == name)
			{
				return named_properties_[i];
			}
		}

		return RTTI::getDefault<NamedProperty>();
	}

	void PropertyManager::clearProperty(const string& name)
	{
    vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
 		{
			if (it->getName() == name)
			{
				named_properties_.erase(it);
				break;
			}
		}
	}

	bool PropertyManager::hasProperty(const string& name) const
	{
		for (Size i = 0; i < named_properties_.size(); i++)
		{
			if (named_properties_[i].getName() == name)
			{
				return true;
			}
		}

		return false;
	}

	void PropertyManager::dump(ostream& s, Size depth) const
	{
		BALL_DUMP_STREAM_PREFIX(s);

		BALL_DUMP_DEPTH(s, depth);
		BALL_DUMP_CLASS_HEADER(s, PropertyManager, this);

		BALL_DUMP_DEPTH(s, depth);
		s << bitvector_ << endl;

		for (Size i = 0; i < named_properties_.size(); ++i)
		{
			BALL_DUMP_DEPTH(s, depth);
			s << "(" << named_properties_[i].getName();
			switch (named_properties_[i].getType())
			{
				case NamedProperty::NONE:
					s << "NONE: ";
					break;
				case NamedProperty::BOOL:
					s << "BOOL: " << named_properties_[i].getBool();
					break;
				case NamedProperty::INT:
					s << "INT: " << named_properties_[i].getInt();
					break;
				case NamedProperty::UNSIGNED_INT:
					s << "UNSIGNED_INT: " << named_properties_[i].getUnsignedInt();
					break;
				case NamedProperty::FLOAT:
					s << "FLOAT: " << named_properties_[i].getFloat();
					break;
				case NamedProperty::DOUBLE:
					s << "DOUBLE: " << named_properties_[i].getDouble();
					break;
				case NamedProperty::STRING:
					s << "STRING: " << (char)34 << named_properties_[i].getString().c_str() << (char)34;
					break;
				case NamedProperty::OBJECT:
					s << "OBJECT: " << named_properties_[i].getObject();
			}

			s << ")" << endl;
		}

		BALL_DUMP_STREAM_SUFFIX(s);
	}

#	ifdef BALL_NO_INLINE_FUNCTIONS
#		include <BALL/CONCEPT/property.iC>
#	endif

} // namespace BALL
<commit_msg>changed: moved default ctor from iC file to avoid problems related to   the inlining of a default ctor<commit_after>// $Id: property.C,v 1.22 2000/10/19 20:03:26 oliver Exp $

#include <BALL/CONCEPT/property.h>
#include <BALL/CONCEPT/persistenceManager.h>
#include <BALL/CONCEPT/textPersistenceManager.h>

using namespace std;

namespace BALL
{

	NamedProperty::NamedProperty()
		: PersistentObject(),
			type_(NONE),
			name_("")
	{
	}

	NamedProperty::NamedProperty(const NamedProperty& property)
		: PersistentObject(property),
			type_(property.type_),
			name_(property.name_)
	{
		if (type_ != STRING)
		{
			data_ = property.data_;
		}
		else
		{
			data_.s = new string(*property.data_.s);
		}
	}

	void NamedProperty::persistentWrite(PersistenceManager& pm, const char* name) const
	{
		pm.writeObjectHeader(this, name);
			pm.writePrimitive((int)type_, "type_");
			pm.writePrimitive(String(name_), "name_");

			switch (type_)
			{
				case	INT:					pm.writePrimitive(data_.i, "data_.i");		break;
				case	FLOAT:				pm.writePrimitive(data_.f, "data_.f");		break;
				case	DOUBLE:				pm.writePrimitive(data_.d, "data_.d");		break;
				case	UNSIGNED_INT:	pm.writePrimitive(data_.ui, "data_.ui"); break;
				case	BOOL:					pm.writePrimitive(data_.b, "data_.b");		break;
				case	OBJECT:				pm.writeObjectPointer(data_.object, "data_.object"); break;
				case	NONE:					break;
				case	STRING:				pm.writePrimitive(String(*data_.s), "data_.s");	break;
				default:
					Log.error() << "cannot write unknown property type: " << (int)type_ << endl;
			}
		pm.writeObjectTrailer(name);
	}

	void NamedProperty::persistentRead(PersistenceManager& pm)
	{
		int type;
		pm.readPrimitive(type, "type_");
		type_ = (Type)type;
		String s;
		pm.readPrimitive(s, "name_");
		name_ = s;

		switch (type_)
		{
			case	INT:					pm.readPrimitive(data_.i, "data_.i");		break;
			case	FLOAT:				pm.readPrimitive(data_.f, "data_.f");		break;
			case	DOUBLE:				pm.readPrimitive(data_.d, "data_.d");		break;
			case	UNSIGNED_INT:	pm.readPrimitive(data_.ui, "data_.ui"); break;
			case	BOOL:					pm.readPrimitive(data_.b, "data_.b");		break;
			case	NONE:	break;

			case	STRING:
				// we have to create a new string
				pm.readPrimitive(s, "data_.s");
				data_.s = new string(s);
				break;

			case	OBJECT:
				// the persistence manager will take care of
				// reading the object and will set this pointer afterwards
				pm.readObjectPointer(data_.object, "data_.object");
				break;

			default:
				Log.error() << "Unknown type while reading NamedProperty: " << (int)type_ << endl;
		}
	}

	/// Output operator
	ostream& operator << (std::ostream& s, const NamedProperty& property)
  {
		s << property.type_;
		s << endl;
		s << property.name_;
		s << endl;
		switch (property.type_)
		{
			case NamedProperty::BOOL:					s << property.data_.b; break;
			case NamedProperty::INT:					s << property.data_.i; break;
			case NamedProperty::UNSIGNED_INT: s << property.data_.ui; break;
			case NamedProperty::FLOAT:				s << property.data_.f; break;
			case NamedProperty::DOUBLE:				s << property.data_.d; break;
			case NamedProperty::STRING:				s << *property.data_.s; break;
			case NamedProperty::OBJECT:
				{
					TextPersistenceManager pm;
					pm.setOstream(s);
					pm.writeObjectPointer(property.data_.object, "data_.object");
					break;
				}
			case NamedProperty::NONE : break;
			default:
				Log.error() << "Unknown type while writing NamedProperty: " << (int)property.type_ << endl;
		}
		return s;
	}

	/// Input operator
	istream& operator >> (std::istream& s, NamedProperty& property)
  {
		s >> (int)property.type_;
		s >> property.name_;
		switch (property.type_)
		{
			case NamedProperty::BOOL : 	s >> property.data_.b; break;
			case NamedProperty::INT : 	s >> property.data_.i; break;
			case NamedProperty::UNSIGNED_INT : 	s >> property.data_.ui; break;
			case NamedProperty::FLOAT : s >> property.data_.f; break;
			case NamedProperty::DOUBLE :s >> property.data_.d; break;
			case NamedProperty::OBJECT :
			{
				TextPersistenceManager pm;
				pm.setIstream(s);
				pm.readObjectPointer(property.data_.object, "data_.object");
				break;
			}
			case NamedProperty::NONE : break;
			case NamedProperty::STRING :
			{
				string str;
				s >> str;
				property.data_.s = new string(str);
				break;
			}
			default:
				Log.error() << "Unknown type while reading NamedProperty: " << (int)property.type_ << endl;
		}
		return s;
	}

  ostream& operator << (ostream& s, const PropertyManager& property_manager)
  {
    s << property_manager.bitvector_;

		s << endl;
		s << property_manager.named_properties_.size();
		s << endl;
		vector<NamedProperty>::const_iterator it = property_manager.named_properties_.begin();
		for (; it != property_manager.named_properties_.end(); ++it)
		{
			s << *it << endl;
		}
		return s;
	}

  istream& operator >> (istream& s, PropertyManager& property_manager)
  {
		int size;
    s >> property_manager.bitvector_;
		s >> size;
		NamedProperty np;
		for (int i = 0; i < size; i++)
		{
			s >> np;
			property_manager.setProperty(np);
		}

		return s;
	}

  void PropertyManager::write(PersistenceManager& pm) const
  {
		pm.writeStorableObject(bitvector_, "bitvector_");
		Size size = named_properties_.size();
		pm.writePrimitive(size, "size");
		for (Size i = 0; i < size; i++)
		{
			named_properties_[i].persistentWrite(pm, "");
		}
	}

  bool PropertyManager::read(PersistenceManager& pm)
  {
		if (!pm.readStorableObject(bitvector_, "bitvector_"))
		{
			return false;
		}

		NamedProperty property("");
		named_properties_.clear();
		Size size = 0;
		pm.readPrimitive(size, "size");
		for (Size i = 0; i < size; i++)
		{
			pm.checkObjectHeader(property, "");
				property.persistentRead(pm);
			pm.checkObjectTrailer("");
			named_properties_.push_back(property);
		}

		return true;
	}

	void PropertyManager::set(const PropertyManager& property_manager, bool /* deep */)
	{
		bitvector_ = property_manager.bitvector_;
		named_properties_ = property_manager.named_properties_;
	}

	void PropertyManager::setProperty(const NamedProperty& property)
	{
		// search whether the property already exists
		vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
		{
			if (it->getName() == property.getName())
			{
				// yes, it exists. Erase the old content
				named_properties_.erase(it);
				break;
			}
		}

		// add the new content
		named_properties_.push_back(property);
	}

	void PropertyManager::setProperty(const string& name)
	{
		// search whether a property with the same name already exists
		vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
		{
			if (it->getName() == name)
			{
				// yes, it exists. Erase the old content
				named_properties_.erase(it);
				break;
			}
		}

		// add the new content
		named_properties_.push_back(NamedProperty(name));
	}

	const NamedProperty& PropertyManager::getProperty(const string& name) const
	{
		for (Size i = 0; i < named_properties_.size(); ++i)
		{
			if (named_properties_[i].getName() == name)
			{
				return named_properties_[i];
			}
		}

		return RTTI::getDefault<NamedProperty>();
	}

	void PropertyManager::clearProperty(const string& name)
	{
    vector<NamedProperty>::iterator it = named_properties_.begin();
		for (; it != named_properties_.end(); ++it)
 		{
			if (it->getName() == name)
			{
				named_properties_.erase(it);
				break;
			}
		}
	}

	bool PropertyManager::hasProperty(const string& name) const
	{
		for (Size i = 0; i < named_properties_.size(); i++)
		{
			if (named_properties_[i].getName() == name)
			{
				return true;
			}
		}

		return false;
	}

	void PropertyManager::dump(ostream& s, Size depth) const
	{
		BALL_DUMP_STREAM_PREFIX(s);

		BALL_DUMP_DEPTH(s, depth);
		BALL_DUMP_CLASS_HEADER(s, PropertyManager, this);

		BALL_DUMP_DEPTH(s, depth);
		s << bitvector_ << endl;

		for (Size i = 0; i < named_properties_.size(); ++i)
		{
			BALL_DUMP_DEPTH(s, depth);
			s << "(" << named_properties_[i].getName();
			switch (named_properties_[i].getType())
			{
				case NamedProperty::NONE:
					s << "NONE: ";
					break;
				case NamedProperty::BOOL:
					s << "BOOL: " << named_properties_[i].getBool();
					break;
				case NamedProperty::INT:
					s << "INT: " << named_properties_[i].getInt();
					break;
				case NamedProperty::UNSIGNED_INT:
					s << "UNSIGNED_INT: " << named_properties_[i].getUnsignedInt();
					break;
				case NamedProperty::FLOAT:
					s << "FLOAT: " << named_properties_[i].getFloat();
					break;
				case NamedProperty::DOUBLE:
					s << "DOUBLE: " << named_properties_[i].getDouble();
					break;
				case NamedProperty::STRING:
					s << "STRING: " << (char)34 << named_properties_[i].getString().c_str() << (char)34;
					break;
				case NamedProperty::OBJECT:
					s << "OBJECT: " << named_properties_[i].getObject();
			}

			s << ")" << endl;
		}

		BALL_DUMP_STREAM_SUFFIX(s);
	}

#	ifdef BALL_NO_INLINE_FUNCTIONS
#		include <BALL/CONCEPT/property.iC>
#	endif

} // namespace BALL
<|endoftext|>


<commit_before>/* +---------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)               |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2016, Individual contributors, see AUTHORS file        |
   | See: http://www.mrpt.org/Authors - All rights reserved.                   |
   | Released under BSD License. See details in http://www.mrpt.org/License    |
   +---------------------------------------------------------------------------+ */

#include "hwdrivers-precomp.h"   // Precompiled headers

#include <mrpt/system/os.h>
#include <mrpt/synch/CCriticalSection.h>
#include <mrpt/system/filesystem.h>
#include <mrpt/hwdrivers/CGPSInterface.h>

using namespace mrpt::hwdrivers;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace std;

const size_t MAX_NMEA_LINE_LENGTH = 1024;

bool  CGPSInterface::implement_parser_NMEA(size_t &out_minimum_rx_buf_to_decide)
{
	out_minimum_rx_buf_to_decide = 3;

	if (m_rx_buffer.size()<3)
		return true; // no need to skip a byte

	const size_t nBytesAval = m_rx_buffer.size();  // Available for read

	// If the string does not start with "$GP" it is not valid:
	uint8_t peek_buffer[3];
	m_rx_buffer.peek_many(&peek_buffer[0],3);
	if (peek_buffer[0]!='$' || peek_buffer[1]!='G' || peek_buffer[2]!='P') {
		// Not the start of a NMEA string, skip 1 char:
		return false;
	}
	else
	{
		// It starts OK: try to find the end of the line
		std::string  line;
		bool line_is_ended = false;
		for (size_t i=0;i<nBytesAval && i<MAX_NMEA_LINE_LENGTH;i++)
		{
			const char val = static_cast<char>(m_rx_buffer.peek(i));
			if (val=='\r' || val=='\n') {
				line_is_ended = true;
				break;
			}
			line.push_back(val);
		}
		if (line_is_ended)
		{
			// Pop from buffer:
			for (size_t i=0;i<line.size();i++) m_rx_buffer.pop();

			// Parse:
			const bool did_have_gga = m_just_parsed_messages.has_GGA_datum;
			if (CGPSInterface::parse_NMEA(line,m_just_parsed_messages, false /*verbose*/))
			{
				// Parsers must set only the part of the msg type:
				m_just_parsed_messages.sensorLabel = "NMEA";

				// Save GGA cache (useful for NTRIP,...)
				const bool now_has_gga = m_just_parsed_messages.has_GGA_datum;
				if (now_has_gga && !did_have_gga) {
					m_last_GGA = line;
				}
			}
			else
			{
				if (m_verbose)
					std::cerr << "[CGPSInterface::implement_parser_NMEA] Line of unknown format ignored: `"<<line<<"`\n";
			}
			return true;
		}
		else
		{
			// We still need to wait for more data to be read:
			out_minimum_rx_buf_to_decide = nBytesAval+1;
			return true;
		}
	}
}

/* -----------------------------------------------------
					parse_NMEA
----------------------------------------------------- */
bool CGPSInterface::parse_NMEA(const std::string &s, mrpt::obs::CObservationGPS &out_obs, const bool verbose)
{
	if (verbose)
		cout << "[CGPSInterface] GPS raw string: " << s << endl;

	// Firstly! If the string does not start with "$GP" it is not valid:
	if (s.size()<7) return false;
	if ( s[0]!='$' || s[1]!='G' ) return false;

	std::vector<std::string> lstTokens;
	mrpt::system::tokenize(s,"*,\t\r\n",lstTokens, false /* do not skip blank tokens */);
	if (lstTokens.size()<3) return false;

	for (size_t i=0;i<lstTokens.size();i++) lstTokens[i] = mrpt::system::trim(lstTokens[i]); // Trim whitespaces

	bool parsed_ok = false;
	// Try to determine the kind of command:
	if (lstTokens[0]=="$GPGGA" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GGA
		// ---------------------------------------------
		bool all_fields_ok=true;
		std::string  token;

		// Fill out the output structure:
		gnss::Message_NMEA_GGA gga;

		// Time:
		token = lstTokens[1];
		if (token.size()>=6)
		{
			gga.fields.UTCTime.hour		= 10 * (token[0]-'0') + token[1]-'0';
			gga.fields.UTCTime.minute	= 10 * (token[2]-'0') + token[3]-'0';
			gga.fields.UTCTime.sec		= atof( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Latitude:
		token = lstTokens[2];
		if (token.size()>=4)
		{
			double	lat = 10 * (token[0]-'0') + token[1]-'0';
			lat += atof( & (token.c_str()[2]) ) / 60.0;
			gga.fields.latitude_degrees = lat;
		}
		else all_fields_ok = false;

		// N/S:
		token = lstTokens[3];
		if (token.empty())
			all_fields_ok = false;
		else if (token[0]=='S')
			gga.fields.latitude_degrees = -gga.fields.latitude_degrees;

		// Longitude:
		token = lstTokens[4];
		if (token.size()>=5)
		{
			double	lat = 100 * (token[0]-'0') + 10 * (token[1]-'0')+ token[2]-'0';
			lat += atof( & (token.c_str()[3]) ) / 60.0;
			gga.fields.longitude_degrees = lat;
		}
		else all_fields_ok = false;

		// E_W:
		token = lstTokens[5];
		if (token.empty())
			all_fields_ok = false;
		else
		if (token[0]=='W')
			gga.fields.longitude_degrees = -gga.fields.longitude_degrees;

		// fix quality:
		token = lstTokens[6];
		if (!token.empty())
			gga.fields.fix_quality = (unsigned char)atoi(token.c_str());

		// sats:
		token = lstTokens[7];
		if (!token.empty())
			gga.fields.satellitesUsed = (unsigned char)atoi( token.c_str() );

		// HDOP:
		token = lstTokens[8];
		if (!token.empty())
		{
			gga.fields.HDOP = (float)atof( token.c_str() );
			gga.fields.thereis_HDOP = true;
		}

		// Altitude:
		token = lstTokens[9];
		if (token.empty()) all_fields_ok = false;
		else gga.fields.altitude_meters = atof( token.c_str() );

		// Units of the altitude:
//		token = lstTokens[10];
//		ASSERT_(token == "M");

		// Geoidal separation [B] (undulation)
		token = lstTokens[11];
		if (!token.empty())
			gga.fields.geoidal_distance = atof( token.c_str() );

		// Units of the geoidal separation:
//		token = lstTokens[12];
//		ASSERT_(token == "M");

		// Total altitude [A]+[B] and mmGPS Corrected total altitude Corr([A]+[B]):
		gga.fields.orthometric_altitude =
		gga.fields.corrected_orthometric_altitude =
		gga.fields.altitude_meters + gga.fields.geoidal_distance;

		if (all_fields_ok) {
			out_obs.setMsg(gga);
			out_obs.originalReceivedTimestamp = mrpt::system::now();
			out_obs.timestamp = gga.fields.UTCTime.getAsTimestamp( mrpt::system::now() );
			out_obs.has_satellite_timestamp = true;
		}
		parsed_ok = all_fields_ok;
	}
	else if ( lstTokens[0]=="$GPRMC" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPRMC
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_RMC rmc;

		// Time:
		token = lstTokens[1];
		if (token.size()>=6)
		{
			rmc.fields.UTCTime.hour		= 10 * (token[0]-'0') + token[1]-'0';
			rmc.fields.UTCTime.minute	= 10 * (token[2]-'0') + token[3]-'0';
			rmc.fields.UTCTime.sec		= atof( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Valid?
		token = lstTokens[2];
		if (token.empty()) all_fields_ok = false;
		else rmc.fields.validity_char = token.c_str()[0];

		// Latitude:
		token = lstTokens[3];
		if (token.size()>=4)
		{
			double	lat = 10 * (token[0]-'0') + token[1]-'0';
			lat += atof( & (token.c_str()[2]) ) / 60.0;
			rmc.fields.latitude_degrees = lat;
		}
		else all_fields_ok = false;

		// N/S:
		token = lstTokens[4];
		if (token.empty()) all_fields_ok = false;
		else if (token[0]=='S')
			rmc.fields.latitude_degrees = -rmc.fields.latitude_degrees;

		// Longitude:
		token = lstTokens[5];
		if (token.size()>=5)
		{
			double	lat = 100 * (token[0]-'0') + 10 * (token[1]-'0')+ token[2]-'0';
			lat += atof( & (token.c_str()[3]) ) / 60.0;
			rmc.fields.longitude_degrees = lat;
		}
		else all_fields_ok = false;

		// E/W:
		token = lstTokens[6];
		if (token.empty()) all_fields_ok = false;
		else if (token[0]=='W')
			rmc.fields.longitude_degrees = -rmc.fields.longitude_degrees;

		// Speed:
		token = lstTokens[7];
		if (!token.empty()) rmc.fields.speed_knots = atof( token.c_str() );

		// Direction:
		token = lstTokens[8];
		if (!token.empty()) rmc.fields.direction_degrees= atof( token.c_str() );

		// Date:
		token = lstTokens[9];
		if (token.size()>=6) {
			rmc.fields.date_day   = 10 * (token[0]-'0') + token[1]-'0';
			rmc.fields.date_month = 10 * (token[2]-'0') + token[3]-'0';
			rmc.fields.date_year  = atoi( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Magnetic var
		token = lstTokens[10];
		if (token.size()>=2)
		{
			rmc.fields.magnetic_dir = atof(token.c_str());
			// E/W:
			token = lstTokens[11];
			if (token.empty()) all_fields_ok = false;
			else if (token[0]=='W')
				rmc.fields.magnetic_dir = -rmc.fields.magnetic_dir;
		}

		// Mode ind.
		if (lstTokens.size()>=14) {
			// Only for NMEA 2.3
			token = lstTokens[12];
			if (token.empty()) all_fields_ok = false;
			else rmc.fields.positioning_mode = token.c_str()[0];
		} else rmc.fields.positioning_mode = 'A'; // Default for older receiver

		if (all_fields_ok) {
			out_obs.setMsg(rmc);
			out_obs.originalReceivedTimestamp = mrpt::system::now();
			out_obs.timestamp = rmc.fields.UTCTime.getAsTimestamp( rmc.getDateAsTimestamp() );
		}
		parsed_ok = all_fields_ok;
	}
	else if ( lstTokens[0]=="$GPGLL" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPGLL
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_GLL gll;
		// *** FIX lstTokens.size() above
		MRPT_TODO("Parse GLL")
	}
	else if ( lstTokens[0]=="$GPVTG" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPVTG
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_VTG vtg;
		// *** FIX lstTokens.size() above
		MRPT_TODO("Parse VTG")
	}
	else if ( lstTokens[0]=="$GPZDA" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPZDA
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_ZDA zda;
		// *** FIX lstTokens.size() above
		MRPT_TODO("Parse ZDA")
	}
	else
	{
		// other commands?
	}

	return parsed_ok;
}
<commit_msg>Progress with NMEA parsing<commit_after>/* +---------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)               |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2016, Individual contributors, see AUTHORS file        |
   | See: http://www.mrpt.org/Authors - All rights reserved.                   |
   | Released under BSD License. See details in http://www.mrpt.org/License    |
   +---------------------------------------------------------------------------+ */

#include "hwdrivers-precomp.h"   // Precompiled headers

#include <mrpt/system/os.h>
#include <mrpt/synch/CCriticalSection.h>
#include <mrpt/system/filesystem.h>
#include <mrpt/hwdrivers/CGPSInterface.h>

using namespace mrpt::hwdrivers;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace std;

const size_t MAX_NMEA_LINE_LENGTH = 1024;

bool  CGPSInterface::implement_parser_NMEA(size_t &out_minimum_rx_buf_to_decide)
{
	out_minimum_rx_buf_to_decide = 3;

	if (m_rx_buffer.size()<3)
		return true; // no need to skip a byte

	const size_t nBytesAval = m_rx_buffer.size();  // Available for read

	// If the string does not start with "$GP" it is not valid:
	uint8_t peek_buffer[3];
	m_rx_buffer.peek_many(&peek_buffer[0],3);
	if (peek_buffer[0]!='$' || peek_buffer[1]!='G' || peek_buffer[2]!='P') {
		// Not the start of a NMEA string, skip 1 char:
		return false;
	}
	else
	{
		// It starts OK: try to find the end of the line
		std::string  line;
		bool line_is_ended = false;
		for (size_t i=0;i<nBytesAval && i<MAX_NMEA_LINE_LENGTH;i++)
		{
			const char val = static_cast<char>(m_rx_buffer.peek(i));
			if (val=='\r' || val=='\n') {
				line_is_ended = true;
				break;
			}
			line.push_back(val);
		}
		if (line_is_ended)
		{
			// Pop from buffer:
			for (size_t i=0;i<line.size();i++) m_rx_buffer.pop();

			// Parse:
			const bool did_have_gga = m_just_parsed_messages.has_GGA_datum;
			if (CGPSInterface::parse_NMEA(line,m_just_parsed_messages, false /*verbose*/))
			{
				// Parsers must set only the part of the msg type:
				m_just_parsed_messages.sensorLabel = "NMEA";

				// Save GGA cache (useful for NTRIP,...)
				const bool now_has_gga = m_just_parsed_messages.has_GGA_datum;
				if (now_has_gga && !did_have_gga) {
					m_last_GGA = line;
				}
			}
			else
			{
				if (m_verbose)
					std::cerr << "[CGPSInterface::implement_parser_NMEA] Line of unknown format ignored: `"<<line<<"`\n";
			}
			return true;
		}
		else
		{
			// We still need to wait for more data to be read:
			out_minimum_rx_buf_to_decide = nBytesAval+1;
			return true;
		}
	}
}

/* -----------------------------------------------------
					parse_NMEA
----------------------------------------------------- */
bool CGPSInterface::parse_NMEA(const std::string &s, mrpt::obs::CObservationGPS &out_obs, const bool verbose)
{
	if (verbose)
		cout << "[CGPSInterface] GPS raw string: " << s << endl;

	// Firstly! If the string does not start with "$GP" it is not valid:
	if (s.size()<7) return false;
	if ( s[0]!='$' || s[1]!='G' ) return false;

	std::vector<std::string> lstTokens;
	mrpt::system::tokenize(s,"*,\t\r\n",lstTokens, false /* do not skip blank tokens */);
	if (lstTokens.size()<3) return false;

	for (size_t i=0;i<lstTokens.size();i++) lstTokens[i] = mrpt::system::trim(lstTokens[i]); // Trim whitespaces

	bool parsed_ok = false;
	// Try to determine the kind of command:
	if (lstTokens[0]=="$GPGGA" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GGA
		// ---------------------------------------------
		bool all_fields_ok=true;
		std::string  token;

		// Fill out the output structure:
		gnss::Message_NMEA_GGA gga;

		// Time:
		token = lstTokens[1];
		if (token.size()>=6)
		{
			gga.fields.UTCTime.hour		= 10 * (token[0]-'0') + token[1]-'0';
			gga.fields.UTCTime.minute	= 10 * (token[2]-'0') + token[3]-'0';
			gga.fields.UTCTime.sec		= atof( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Latitude:
		token = lstTokens[2];
		if (token.size()>=4)
		{
			double	lat = 10 * (token[0]-'0') + token[1]-'0';
			lat += atof( & (token.c_str()[2]) ) / 60.0;
			gga.fields.latitude_degrees = lat;
		}
		else all_fields_ok = false;

		// N/S:
		token = lstTokens[3];
		if (token.empty())
			all_fields_ok = false;
		else if (token[0]=='S')
			gga.fields.latitude_degrees = -gga.fields.latitude_degrees;

		// Longitude:
		token = lstTokens[4];
		if (token.size()>=5)
		{
			double	lat = 100 * (token[0]-'0') + 10 * (token[1]-'0')+ token[2]-'0';
			lat += atof( & (token.c_str()[3]) ) / 60.0;
			gga.fields.longitude_degrees = lat;
		}
		else all_fields_ok = false;

		// E_W:
		token = lstTokens[5];
		if (token.empty())
			all_fields_ok = false;
		else
		if (token[0]=='W')
			gga.fields.longitude_degrees = -gga.fields.longitude_degrees;

		// fix quality:
		token = lstTokens[6];
		if (!token.empty())
			gga.fields.fix_quality = (unsigned char)atoi(token.c_str());

		// sats:
		token = lstTokens[7];
		if (!token.empty())
			gga.fields.satellitesUsed = (unsigned char)atoi( token.c_str() );

		// HDOP:
		token = lstTokens[8];
		if (!token.empty())
		{
			gga.fields.HDOP = (float)atof( token.c_str() );
			gga.fields.thereis_HDOP = true;
		}

		// Altitude:
		token = lstTokens[9];
		if (token.empty()) all_fields_ok = false;
		else gga.fields.altitude_meters = atof( token.c_str() );

		// Units of the altitude:
//		token = lstTokens[10];
//		ASSERT_(token == "M");

		// Geoidal separation [B] (undulation)
		token = lstTokens[11];
		if (!token.empty())
			gga.fields.geoidal_distance = atof( token.c_str() );

		// Units of the geoidal separation:
//		token = lstTokens[12];
//		ASSERT_(token == "M");

		// Total altitude [A]+[B] and mmGPS Corrected total altitude Corr([A]+[B]):
		gga.fields.orthometric_altitude =
		gga.fields.corrected_orthometric_altitude =
		gga.fields.altitude_meters + gga.fields.geoidal_distance;

		if (all_fields_ok) {
			out_obs.setMsg(gga);
			out_obs.originalReceivedTimestamp = mrpt::system::now();
			out_obs.timestamp = gga.fields.UTCTime.getAsTimestamp( mrpt::system::now() );
			out_obs.has_satellite_timestamp = true;
		}
		parsed_ok = all_fields_ok;
	}
	else if ( lstTokens[0]=="$GPRMC" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPRMC
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_RMC rmc;

		// Time:
		token = lstTokens[1];
		if (token.size()>=6)
		{
			rmc.fields.UTCTime.hour		= 10 * (token[0]-'0') + token[1]-'0';
			rmc.fields.UTCTime.minute	= 10 * (token[2]-'0') + token[3]-'0';
			rmc.fields.UTCTime.sec		= atof( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Valid?
		token = lstTokens[2];
		if (token.empty()) all_fields_ok = false;
		else rmc.fields.validity_char = token.c_str()[0];

		// Latitude:
		token = lstTokens[3];
		if (token.size()>=4)
		{
			double	lat = 10 * (token[0]-'0') + token[1]-'0';
			lat += atof( & (token.c_str()[2]) ) / 60.0;
			rmc.fields.latitude_degrees = lat;
		}
		else all_fields_ok = false;

		// N/S:
		token = lstTokens[4];
		if (token.empty()) all_fields_ok = false;
		else if (token[0]=='S')
			rmc.fields.latitude_degrees = -rmc.fields.latitude_degrees;

		// Longitude:
		token = lstTokens[5];
		if (token.size()>=5)
		{
			double	lat = 100 * (token[0]-'0') + 10 * (token[1]-'0')+ token[2]-'0';
			lat += atof( & (token.c_str()[3]) ) / 60.0;
			rmc.fields.longitude_degrees = lat;
		}
		else all_fields_ok = false;

		// E/W:
		token = lstTokens[6];
		if (token.empty()) all_fields_ok = false;
		else if (token[0]=='W')
			rmc.fields.longitude_degrees = -rmc.fields.longitude_degrees;

		// Speed:
		token = lstTokens[7];
		if (!token.empty()) rmc.fields.speed_knots = atof( token.c_str() );

		// Direction:
		token = lstTokens[8];
		if (!token.empty()) rmc.fields.direction_degrees= atof( token.c_str() );

		// Date:
		token = lstTokens[9];
		if (token.size()>=6) {
			rmc.fields.date_day   = 10 * (token[0]-'0') + token[1]-'0';
			rmc.fields.date_month = 10 * (token[2]-'0') + token[3]-'0';
			rmc.fields.date_year  = atoi( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Magnetic var
		token = lstTokens[10];
		if (token.size()>=2)
		{
			rmc.fields.magnetic_dir = atof(token.c_str());
			// E/W:
			token = lstTokens[11];
			if (token.empty()) all_fields_ok = false;
			else if (token[0]=='W')
				rmc.fields.magnetic_dir = -rmc.fields.magnetic_dir;
		}

		// Mode ind.
		if (lstTokens.size()>=14) {
			// Only for NMEA 2.3
			token = lstTokens[12];
			if (token.empty()) all_fields_ok = false;
			else rmc.fields.positioning_mode = token.c_str()[0];
		} else rmc.fields.positioning_mode = 'A'; // Default for older receiver

		if (all_fields_ok) {
			out_obs.setMsg(rmc);
			out_obs.originalReceivedTimestamp = mrpt::system::now();
			out_obs.timestamp = rmc.fields.UTCTime.getAsTimestamp( rmc.getDateAsTimestamp() );
		}
		parsed_ok = all_fields_ok;
	}
	else if ( lstTokens[0]=="$GPGLL" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPGLL
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_GLL gll;
		// *** FIX lstTokens.size() above
		MRPT_TODO("Parse GLL")
	}
	else if ( lstTokens[0]=="$GPVTG" && lstTokens.size()>=13)
	{
		// ---------------------------------------------
		//					GPVTG
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_VTG vtg;
		// *** FIX lstTokens.size() above
		MRPT_TODO("Parse VTG")
	}
	else if ( lstTokens[0]=="$GPZDA" && lstTokens.size()>=5)
	{
		// ---------------------------------------------
		//					GPZDA
		// ---------------------------------------------
		bool all_fields_ok = true;
		std::string token;

		// Fill out the output structure:
		gnss::Message_NMEA_ZDA zda;
		//$--ZDA,hhmmss.ss,xx,xx,xxxx,xx,xx
		//hhmmss.ss = UTC
		//xx = Day, 01 to 31
		//xx = Month, 01 to 12
		//xxxx = Year
		//xx = Local zone description, 00 to +/- 13 hours
		//xx = Local zone minutes description (same sign as hours)

		// Time:
		token = lstTokens[1];
		if (token.size()>=6) {
			zda.fields.UTCTime.hour		= 10 * (token[0]-'0') + token[1]-'0';
			zda.fields.UTCTime.minute	= 10 * (token[2]-'0') + token[3]-'0';
			zda.fields.UTCTime.sec		= atof( & (token.c_str()[4]) );
		}
		else all_fields_ok = false;

		// Day:
		token = lstTokens[2];
		if (!token.empty())
			zda.fields.date_day = atoi(token.c_str());
		// Month:
		token = lstTokens[3];
		if (!token.empty())
			zda.fields.date_month = atoi(token.c_str());
		// Year:
		token = lstTokens[4];
		if (!token.empty())
			zda.fields.date_year = atoi(token.c_str());

		if (all_fields_ok) {
			out_obs.setMsg(zda);
			out_obs.originalReceivedTimestamp = mrpt::system::now();
			MRPT_TODO("Add zda.getDateAsTimestamp()")
			//out_obs.timestamp = zda.fields.UTCTime.getAsTimestamp( zda.getDateAsTimestamp() );
			out_obs.timestamp = zda.fields.UTCTime.getAsTimestamp( mrpt::system::now() );
		}
		parsed_ok = all_fields_ok;
	}
	else
	{
		// other commands?
	}

	return parsed_ok;
}
<|endoftext|>