<commit_before>// coding: utf-8
// ----------------------------------------------------------------------------
/* Copyright (c) 2009, Roboterclub Aachen e.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Roboterclub Aachen e.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ROBOTERCLUB AACHEN E.V. ''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 ROBOTERCLUB AACHEN E.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
// ----------------------------------------------------------------------------

#ifndef	XPCC__DELAY_HPP
#define	XPCC__DELAY_HPP

#ifdef __DOXYGEN__

namespace xpcc
{
	/**
	 * \brief	Delay us microseconds
	 * \ingroup	architecture
	 */
	void
	delayMicroseconds(uint32_t us);

	/**
	 * \brief	Delay ms milliseconds
	 * \ingroup	architecture
	 */
	void
	delayMilliseconds(uint32_t ms);
}

#else // !__DOXYGEN__

#include <xpcc/architecture/detect.hpp>
#include <xpcc/architecture/utils.hpp>

#if defined(XPCC__CPU_AVR)

	#include <util/delay.h>

	namespace xpcc
	{
		ALWAYS_INLINE void
		delayMicroseconds(uint32_t us)
		{
			_delay_us(us);
		}

		ALWAYS_INLINE void
		delayMilliseconds(uint32_t ms)
		{
			_delay_ms(ms);
		}
	}

#elif defined(XPCC__OS_UNIX) || defined(XPCC__OS_OSX)

	#include <unistd.h>

	namespace xpcc
	{
		ALWAYS_INLINE void
		delayMicroseconds(uint32_t us)
		{
			usleep(us);
		}

		ALWAYS_INLINE void
		delayMilliseconds(uint32_t ms)
		{
			usleep(ms*1000);
		}
	}

#elif defined(XPCC__OS_WIN32)

	namespace xpcc
	{
		/*inline void
		delayMicroseconds(int us)
		{
			int ms = us / 1000;
			if (ms <= 0) {
				ms = 1;
			}
			Sleep(ms);
		}

		inline void
		delay_ms(int ms)
		{
			Sleep(ms);
		}*/

		inline void
		delayMicroseconds(int)
		{
			// TODO
		}

		inline void
		delayMilliseconds(int)
		{
			// TODO
		}
	}

#elif defined(XPCC__CPU_ARM)

	extern "C" void _delay_us(uint32_t us);
	extern "C" void _delay_ms(uint32_t ms);

	namespace xpcc
	{
		static inline void
		delayMicroseconds(uint32_t us)
		{
			::_delay_us(us);
		}

		static inline void
		delayMilliseconds(uint32_t ms)
		{
			::_delay_ms(ms);
		}
	}
#else
	#error "Unknown architecture, please add some specific delay functions!"
#endif

#endif	// !__DOXYGEN__
#endif	// XPCC__DELAY_HPP
<commit_msg>delay: include stdint.h for uint32_t data type<commit_after>// coding: utf-8
// ----------------------------------------------------------------------------
/* Copyright (c) 2009, Roboterclub Aachen e.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Roboterclub Aachen e.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ROBOTERCLUB AACHEN E.V. ''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 ROBOTERCLUB AACHEN E.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
// ----------------------------------------------------------------------------

#ifndef	XPCC__DELAY_HPP
#define	XPCC__DELAY_HPP

#include <stdint.h>

#ifdef __DOXYGEN__

namespace xpcc
{
	/**
	 * \brief	Delay us microseconds
	 * \ingroup	architecture
	 */
	void
	delayMicroseconds(uint32_t us);

	/**
	 * \brief	Delay ms milliseconds
	 * \ingroup	architecture
	 */
	void
	delayMilliseconds(uint32_t ms);
}

#else // !__DOXYGEN__

#include <xpcc/architecture/detect.hpp>
#include <xpcc/architecture/utils.hpp>

#if defined(XPCC__CPU_AVR)

	#include <util/delay.h>

	namespace xpcc
	{
		ALWAYS_INLINE void
		delayMicroseconds(uint32_t us)
		{
			_delay_us(us);
		}

		ALWAYS_INLINE void
		delayMilliseconds(uint32_t ms)
		{
			_delay_ms(ms);
		}
	}

#elif defined(XPCC__OS_UNIX) || defined(XPCC__OS_OSX)

	#include <unistd.h>

	namespace xpcc
	{
		ALWAYS_INLINE void
		delayMicroseconds(uint32_t us)
		{
			usleep(us);
		}

		ALWAYS_INLINE void
		delayMilliseconds(uint32_t ms)
		{
			usleep(ms*1000);
		}
	}

#elif defined(XPCC__OS_WIN32)

	namespace xpcc
	{
		/*inline void
		delayMicroseconds(int us)
		{
			int ms = us / 1000;
			if (ms <= 0) {
				ms = 1;
			}
			Sleep(ms);
		}

		inline void
		delay_ms(int ms)
		{
			Sleep(ms);
		}*/

		inline void
		delayMicroseconds(int)
		{
			// TODO
		}

		inline void
		delayMilliseconds(int)
		{
			// TODO
		}
	}

#elif defined(XPCC__CPU_ARM)

	extern "C" void _delay_us(uint32_t us);
	extern "C" void _delay_ms(uint32_t ms);

	namespace xpcc
	{
		static inline void
		delayMicroseconds(uint32_t us)
		{
			::_delay_us(us);
		}

		static inline void
		delayMilliseconds(uint32_t ms)
		{
			::_delay_ms(ms);
		}
	}
#else
	#error "Unknown architecture, please add some specific delay functions!"
#endif

#endif	// !__DOXYGEN__
#endif	// XPCC__DELAY_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AutoBuffer.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 11:52:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _AUTO_BUFFER_HXX_
#define _AUTO_BUFFER_HXX_

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring>
#endif

//-------------------------------------------------------------
// A simple unicode buffer management class, the class itself
// is responsible for the allocated unicode buffer, any
// modification of the buffer size outside the class may lead
// to undefined behaviour
//-------------------------------------------------------------

class CAutoUnicodeBuffer
{
public:

    // if bLazyCreation is true the buffer will be created
    // when someone wants to fill the buffer
    CAutoUnicodeBuffer( size_t size, sal_Bool bLazyCreation = sal_False );
    ~CAutoUnicodeBuffer( );

    // resizes the buffer
    sal_Bool SAL_CALL resize( size_t new_size );

    // zeros the buffer
    void SAL_CALL empty( );

    // fills the buffer with a given content
    sal_Bool SAL_CALL fill( const sal_Unicode* pContent, size_t nLen );

    // returns the size of the buffer
    size_t SAL_CALL size( ) const;

    // conversion operator
    operator sal_Unicode*( );

    // address operator
    sal_Unicode* operator&( );

    const sal_Unicode* operator&( ) const;

private:
    void SAL_CALL init( );

private:
    size_t m_buffSize; // the number of unicode chars
    sal_Unicode* m_pBuff;
};

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.3.226); FILE MERGED 2008/04/01 16:00:04 thb 1.3.226.2: #i85898# Stripping all external header guards 2008/03/28 15:39:11 rt 1.3.226.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: AutoBuffer.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _AUTO_BUFFER_HXX_
#define _AUTO_BUFFER_HXX_

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------

#include <sal/types.h>

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring>
#endif

//-------------------------------------------------------------
// A simple unicode buffer management class, the class itself
// is responsible for the allocated unicode buffer, any
// modification of the buffer size outside the class may lead
// to undefined behaviour
//-------------------------------------------------------------

class CAutoUnicodeBuffer
{
public:

    // if bLazyCreation is true the buffer will be created
    // when someone wants to fill the buffer
    CAutoUnicodeBuffer( size_t size, sal_Bool bLazyCreation = sal_False );
    ~CAutoUnicodeBuffer( );

    // resizes the buffer
    sal_Bool SAL_CALL resize( size_t new_size );

    // zeros the buffer
    void SAL_CALL empty( );

    // fills the buffer with a given content
    sal_Bool SAL_CALL fill( const sal_Unicode* pContent, size_t nLen );

    // returns the size of the buffer
    size_t SAL_CALL size( ) const;

    // conversion operator
    operator sal_Unicode*( );

    // address operator
    sal_Unicode* operator&( );

    const sal_Unicode* operator&( ) const;

private:
    void SAL_CALL init( );

private:
    size_t m_buffSize; // the number of unicode chars
    sal_Unicode* m_pBuff;
};

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/make_unique.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/global.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/util/noncopyable.hpp>

namespace mapnik
{

struct wkb_reader : util::noncopyable
{
private:
    enum wkbByteOrder
    {
        wkbXDR=0,
        wkbNDR=1
    };

    const char* wkb_;
    std::size_t size_;
    std::size_t pos_;
    wkbByteOrder byteOrder_;
    bool needSwap_;
    wkbFormat format_;

public:

    enum wkbGeometryType {
        wkbPoint=1,
        wkbLineString=2,
        wkbPolygon=3,
        wkbMultiPoint=4,
        wkbMultiLineString=5,
        wkbMultiPolygon=6,
        wkbGeometryCollection=7,
        // Z
        wkbPointZ=1001,
        wkbLineStringZ=1002,
        wkbPolygonZ=1003,
        wkbMultiPointZ=1004,
        wkbMultiLineStringZ=1005,
        wkbMultiPolygonZ=1006,
        wkbGeometryCollectionZ=1007,
        // M
        wkbPointM=2001,
        wkbLineStringM=2002,
        wkbPolygonM=2003,
        wkbMultiPointM=2004,
        wkbMultiLineStringM=2005,
        wkbMultiPolygonM=2006,
        wkbGeometryCollectionM=2007,
        // ZM
        wkbPointZM=3001,
        wkbLineStringZM=3002,
        wkbPolygonZM=3003,
        wkbMultiPointZM=3004,
        wkbMultiLineStringZM=3005,
        wkbMultiPolygonZM=3006,
        wkbGeometryCollectionZM=3007
    };

    wkb_reader(const char* wkb, std::size_t size, wkbFormat format)
        : wkb_(wkb),
          size_(size),
          pos_(0),
          format_(format)
    {
        // try to determine WKB format automatically
        if (format_ == wkbAuto)
        {
            if (size_ >= 44
                && static_cast<unsigned char>(wkb_[0]) == static_cast<unsigned char>(0x00)
                && static_cast<unsigned char>(wkb_[38]) == static_cast<unsigned char>(0x7C)
                && static_cast<unsigned char>(wkb_[size_ - 1]) == static_cast<unsigned char>(0xFE))
            {
                format_ = wkbSpatiaLite;
            }
            else
            {
                format_ = wkbGeneric;
            }
        }

        switch (format_)
        {
        case wkbSpatiaLite:
            byteOrder_ = (wkbByteOrder) wkb_[1];
            pos_ = 39;
            break;

        case wkbGeneric:
        default:
            byteOrder_ = (wkbByteOrder) wkb_[0];
            pos_ = 1;
            break;
        }

        needSwap_ = byteOrder_ ? wkbXDR : wkbNDR;
    }

    mapnik::new_geometry::geometry read()
    {
        int type = read_integer();
        switch (type)
        {
        case wkbPoint:
            return std::move(mapnik::new_geometry::geometry(read_point()));
        case wkbLineString:
            return std::move(mapnik::new_geometry::geometry(read_linestring()));
        case wkbPolygon:
            return std::move(mapnik::new_geometry::geometry(read_polygon()));
        case wkbMultiPoint:
            return std::move(mapnik::new_geometry::geometry(read_multipoint()));
        case wkbMultiLineString:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring()));
        case wkbMultiPolygon:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon()));
        case wkbGeometryCollection:
            throw std::runtime_error("GeometryCollection");
            break; // TODO: should we drop geometry collection ?
        case wkbPointZ:
        case wkbPointM:
            return std::move(mapnik::new_geometry::geometry(read_point<true>()));
        case wkbPointZM:
            return std::move(mapnik::new_geometry::geometry(read_point<true,true>()));
        case wkbLineStringZ:
        case wkbLineStringM:
            return std::move(mapnik::new_geometry::geometry(read_linestring<true>()));
        case wkbLineStringZM:
            return std::move(mapnik::new_geometry::geometry(read_linestring<true,true>()));
        case wkbPolygonZ:
        case wkbPolygonM:
            return std::move(mapnik::new_geometry::geometry(read_polygon<true>()));
        case wkbPolygonZM:
            return std::move(mapnik::new_geometry::geometry(read_polygon<true,true>()));
        case wkbMultiPointZ:
        case wkbMultiPointM:
            return std::move(mapnik::new_geometry::geometry(read_multipoint<true>()));
        case wkbMultiPointZM:
            return std::move(mapnik::new_geometry::geometry(read_multipoint<true,true>()));
        case wkbMultiLineStringZ:
        case wkbMultiLineStringM:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring<true>()));
        case wkbMultiLineStringZM:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring<true,true>()));
        case wkbMultiPolygonZ:
        case wkbMultiPolygonM:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon<true>()));
        case wkbMultiPolygonZM:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon<true,true>()));
        case wkbGeometryCollectionZ:
        case wkbGeometryCollectionM:
        case wkbGeometryCollectionZM:
            // TODO ??
            throw std::runtime_error("GeometryCollection Z|M|ZM");
            break;
        default:
            break;
        }
        throw std::runtime_error("Uknown");
    }

private:

    int read_integer()
    {
        std::int32_t n;
        if (needSwap_)
        {
            read_int32_xdr(wkb_ + pos_, n);
        }
        else
        {
            read_int32_ndr(wkb_ + pos_, n);
        }
        pos_ += 4;

        return n;
    }

    double read_double()
    {
        double d;
        if (needSwap_)
        {
            read_double_xdr(wkb_ + pos_, d);
        }
        else
        {
            read_double_ndr(wkb_ + pos_, d);
        }
        pos_ += 8;

        return d;
    }

    template <typename Ring, bool Z = false, bool M = false>
    void read_coords(Ring & ring, std::size_t num_points)
    {
        double x,y;
        if (!needSwap_)
        {
            for (std::size_t i = 0; i < num_points; ++i)
            {
                read_double_ndr(wkb_ + pos_, x);
                read_double_ndr(wkb_ + pos_ + 8, y);
                ring.emplace_back(x,y);
                pos_ += 16; // skip XY
                if (Z) pos_ += 8;
                if (M) pos_ += 8;
            }
        }
        else
        {
            for (std::size_t i = 0; i < num_points; ++i)
            {
                read_double_xdr(wkb_ + pos_, x);
                read_double_xdr(wkb_ + pos_ + 8, y);
                ring.emplace_back(x,y);
                pos_ += 16; // skip XY
                if (Z) pos_ += 8;
                if (M) pos_ += 8;
            }
        }
    }

    template <bool Z = false, bool M = false>
    mapnik::new_geometry::point read_point()
    {
        double x = read_double();
        double y = read_double();
        if (Z) pos_ += 8;
        if (M) pos_ += 8;
        return mapnik::new_geometry::point(x, y);
    }

    template <bool Z = false, bool M = false>
    mapnik::new_geometry::multi_point read_multipoint()
    {
        mapnik::new_geometry::multi_point multi_point;
        int num_points = read_integer();
        multi_point.reserve(num_points);
        for (int i = 0; i < num_points; ++i)
        {
            pos_ += 5;
            multi_point.emplace_back(read_point<Z,M>());
        }
        return multi_point;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::line_string read_linestring()
    {
        mapnik::new_geometry::line_string line;
        int num_points = read_integer();
        if (num_points > 0)
        {
            line.reserve(num_points);
            read_coords<mapnik::new_geometry::line_string, M, Z>(line, num_points);
        }
        return line;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::multi_line_string read_multilinestring()
    {
        int num_lines = read_integer();
        mapnik::new_geometry::multi_line_string multi_line;
        multi_line.reserve(num_lines);
        for (int i = 0; i < num_lines; ++i)
        {
            pos_ += 5;
            multi_line.push_back(std::move(read_linestring<M, Z>()));
        }
        return multi_line;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::polygon3 read_polygon()
    {
        int num_rings = read_integer();
        mapnik::new_geometry::polygon3 poly;
        if (num_rings > 1)
        {
            poly.interior_rings.reserve(num_rings - 1);
        }

        for (int i = 0; i < num_rings; ++i)
        {
            mapnik::new_geometry::linear_ring ring;
            int num_points = read_integer();
            if (num_points > 0)
            {
                ring.reserve(num_points);
                read_coords<mapnik::new_geometry::linear_ring, M, Z>(ring, num_points);
            }
            if ( i == 0) poly.set_exterior_ring(std::move(ring));
            else poly.add_hole(std::move(ring));
        }
        return poly;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::multi_polygon read_multipolygon()
    {
        int num_polys = read_integer();
        mapnik::new_geometry::multi_polygon multi_poly;
        for (int i = 0; i < num_polys; ++i)
        {
            pos_ += 5;
            multi_poly.push_back(std::move(read_polygon<M, Z>()));
        }
        return multi_poly;
    }

    std::string wkb_geometry_type_string(int type)
    {
        std::stringstream s;

        switch (type)
        {
        case wkbPoint:               s << "Point"; break;
        case wkbPointZ:              s << "PointZ"; break;
        case wkbPointM:              s << "PointM"; break;
        case wkbPointZM:             s << "PointZM"; break;
        case wkbMultiPoint:          s << "MultiPoint"; break;
        case wkbMultiPointZ:         s << "MultiPointZ"; break;
        case wkbMultiPointM:         s << "MultiPointM"; break;
        case wkbMultiPointZM:        s << "MultiPointZM"; break;
        case wkbLineString:          s << "LineString"; break;
        case wkbLineStringZ:         s << "LineStringZ"; break;
        case wkbLineStringM:         s << "LineStringM"; break;
        case wkbLineStringZM:        s << "LineStringZM"; break;
        case wkbMultiLineString:     s << "MultiLineString"; break;
        case wkbMultiLineStringZ:    s << "MultiLineStringZ"; break;
        case wkbMultiLineStringM:    s << "MultiLineStringM"; break;
        case wkbMultiLineStringZM:   s << "MultiLineStringZM"; break;
        case wkbPolygon:             s << "Polygon"; break;
        case wkbPolygonZ:            s << "PolygonZ"; break;
        case wkbPolygonM:            s << "PolygonM"; break;
        case wkbPolygonZM:           s << "PolygonZM"; break;
        case wkbMultiPolygon:        s << "MultiPolygon"; break;
        case wkbMultiPolygonZ:       s << "MultiPolygonZ"; break;
        case wkbMultiPolygonM:       s << "MultiPolygonM"; break;
        case wkbMultiPolygonZM:      s << "MultiPolygonZM"; break;
        case wkbGeometryCollection:  s << "GeometryCollection"; break;
        case wkbGeometryCollectionZ: s << "GeometryCollectionZ"; break;
        case wkbGeometryCollectionM: s << "GeometryCollectionM"; break;
        case wkbGeometryCollectionZM:s << "GeometryCollectionZM"; break;
        default:                     s << "wkbUnknown(" << type << ")"; break;
        }

        return s.str();
    }

};

mapnik::new_geometry::geometry geometry_utils::from_wkb(const char* wkb,
                                                        unsigned size,
                                                        wkbFormat format)
{
    wkb_reader reader(wkb, size, format);
    return mapnik::new_geometry::geometry(reader.read());
}

} // namespace mapnik
<commit_msg>add support for reading geometry_collection<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/make_unique.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/global.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/util/noncopyable.hpp>

namespace mapnik
{

struct wkb_reader : util::noncopyable
{
private:
    enum wkbByteOrder
    {
        wkbXDR=0,
        wkbNDR=1
    };

    const char* wkb_;
    std::size_t size_;
    std::size_t pos_;
    wkbByteOrder byteOrder_;
    bool needSwap_;
    wkbFormat format_;

public:

    enum wkbGeometryType {
        wkbPoint=1,
        wkbLineString=2,
        wkbPolygon=3,
        wkbMultiPoint=4,
        wkbMultiLineString=5,
        wkbMultiPolygon=6,
        wkbGeometryCollection=7,
        // Z
        wkbPointZ=1001,
        wkbLineStringZ=1002,
        wkbPolygonZ=1003,
        wkbMultiPointZ=1004,
        wkbMultiLineStringZ=1005,
        wkbMultiPolygonZ=1006,
        wkbGeometryCollectionZ=1007,
        // M
        wkbPointM=2001,
        wkbLineStringM=2002,
        wkbPolygonM=2003,
        wkbMultiPointM=2004,
        wkbMultiLineStringM=2005,
        wkbMultiPolygonM=2006,
        wkbGeometryCollectionM=2007,
        // ZM
        wkbPointZM=3001,
        wkbLineStringZM=3002,
        wkbPolygonZM=3003,
        wkbMultiPointZM=3004,
        wkbMultiLineStringZM=3005,
        wkbMultiPolygonZM=3006,
        wkbGeometryCollectionZM=3007
    };

    wkb_reader(const char* wkb, std::size_t size, wkbFormat format)
        : wkb_(wkb),
          size_(size),
          pos_(0),
          format_(format)
    {
        // try to determine WKB format automatically
        if (format_ == wkbAuto)
        {
            if (size_ >= 44
                && static_cast<unsigned char>(wkb_[0]) == static_cast<unsigned char>(0x00)
                && static_cast<unsigned char>(wkb_[38]) == static_cast<unsigned char>(0x7C)
                && static_cast<unsigned char>(wkb_[size_ - 1]) == static_cast<unsigned char>(0xFE))
            {
                format_ = wkbSpatiaLite;
            }
            else
            {
                format_ = wkbGeneric;
            }
        }

        switch (format_)
        {
        case wkbSpatiaLite:
            byteOrder_ = (wkbByteOrder) wkb_[1];
            pos_ = 39;
            break;

        case wkbGeneric:
        default:
            byteOrder_ = (wkbByteOrder) wkb_[0];
            pos_ = 1;
            break;
        }

        needSwap_ = byteOrder_ ? wkbXDR : wkbNDR;
    }

    mapnik::new_geometry::geometry read()
    {
        int type = read_integer();
        switch (type)
        {
        case wkbPoint:
            return std::move(mapnik::new_geometry::geometry(read_point()));
        case wkbLineString:
            return std::move(mapnik::new_geometry::geometry(read_linestring()));
        case wkbPolygon:
            return std::move(mapnik::new_geometry::geometry(read_polygon()));
        case wkbMultiPoint:
            return std::move(mapnik::new_geometry::geometry(read_multipoint()));
        case wkbMultiLineString:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring()));
        case wkbMultiPolygon:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon()));
        case wkbGeometryCollection:
            return std::move(mapnik::new_geometry::geometry(read_collection()));
        case wkbPointZ:
        case wkbPointM:
            return std::move(mapnik::new_geometry::geometry(read_point<true>()));
        case wkbPointZM:
            return std::move(mapnik::new_geometry::geometry(read_point<true,true>()));
        case wkbLineStringZ:
        case wkbLineStringM:
            return std::move(mapnik::new_geometry::geometry(read_linestring<true>()));
        case wkbLineStringZM:
            return std::move(mapnik::new_geometry::geometry(read_linestring<true,true>()));
        case wkbPolygonZ:
        case wkbPolygonM:
            return std::move(mapnik::new_geometry::geometry(read_polygon<true>()));
        case wkbPolygonZM:
            return std::move(mapnik::new_geometry::geometry(read_polygon<true,true>()));
        case wkbMultiPointZ:
        case wkbMultiPointM:
            return std::move(mapnik::new_geometry::geometry(read_multipoint<true>()));
        case wkbMultiPointZM:
            return std::move(mapnik::new_geometry::geometry(read_multipoint<true,true>()));
        case wkbMultiLineStringZ:
        case wkbMultiLineStringM:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring<true>()));
        case wkbMultiLineStringZM:
            return std::move(mapnik::new_geometry::geometry(read_multilinestring<true,true>()));
        case wkbMultiPolygonZ:
        case wkbMultiPolygonM:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon<true>()));
        case wkbMultiPolygonZM:
            return std::move(mapnik::new_geometry::geometry(read_multipolygon<true,true>()));
        case wkbGeometryCollectionZ:
        case wkbGeometryCollectionM:
        case wkbGeometryCollectionZM:
            return std::move(mapnik::new_geometry::geometry(read_collection()));
        default:
            break;
        }
        throw std::runtime_error("Uknown WKB geometry type");
    }

private:

    int read_integer()
    {
        std::int32_t n;
        if (needSwap_)
        {
            read_int32_xdr(wkb_ + pos_, n);
        }
        else
        {
            read_int32_ndr(wkb_ + pos_, n);
        }
        pos_ += 4;

        return n;
    }

    double read_double()
    {
        double d;
        if (needSwap_)
        {
            read_double_xdr(wkb_ + pos_, d);
        }
        else
        {
            read_double_ndr(wkb_ + pos_, d);
        }
        pos_ += 8;

        return d;
    }

    template <typename Ring, bool Z = false, bool M = false>
    void read_coords(Ring & ring, std::size_t num_points)
    {
        double x,y;
        if (!needSwap_)
        {
            for (std::size_t i = 0; i < num_points; ++i)
            {
                read_double_ndr(wkb_ + pos_, x);
                read_double_ndr(wkb_ + pos_ + 8, y);
                ring.emplace_back(x,y);
                pos_ += 16; // skip XY
                if (Z) pos_ += 8;
                if (M) pos_ += 8;
            }
        }
        else
        {
            for (std::size_t i = 0; i < num_points; ++i)
            {
                read_double_xdr(wkb_ + pos_, x);
                read_double_xdr(wkb_ + pos_ + 8, y);
                ring.emplace_back(x,y);
                pos_ += 16; // skip XY
                if (Z) pos_ += 8;
                if (M) pos_ += 8;
            }
        }
    }

    template <bool Z = false, bool M = false>
    mapnik::new_geometry::point read_point()
    {
        double x = read_double();
        double y = read_double();
        if (Z) pos_ += 8;
        if (M) pos_ += 8;
        return mapnik::new_geometry::point(x, y);
    }

    template <bool Z = false, bool M = false>
    mapnik::new_geometry::multi_point read_multipoint()
    {
        mapnik::new_geometry::multi_point multi_point;
        int num_points = read_integer();
        multi_point.reserve(num_points);
        for (int i = 0; i < num_points; ++i)
        {
            pos_ += 5;
            multi_point.emplace_back(read_point<Z,M>());
        }
        return multi_point;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::line_string read_linestring()
    {
        mapnik::new_geometry::line_string line;
        int num_points = read_integer();
        if (num_points > 0)
        {
            line.reserve(num_points);
            read_coords<mapnik::new_geometry::line_string, M, Z>(line, num_points);
        }
        return line;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::multi_line_string read_multilinestring()
    {
        int num_lines = read_integer();
        mapnik::new_geometry::multi_line_string multi_line;
        multi_line.reserve(num_lines);
        for (int i = 0; i < num_lines; ++i)
        {
            pos_ += 5;
            multi_line.push_back(std::move(read_linestring<M, Z>()));
        }
        return multi_line;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::polygon3 read_polygon()
    {
        int num_rings = read_integer();
        mapnik::new_geometry::polygon3 poly;
        if (num_rings > 1)
        {
            poly.interior_rings.reserve(num_rings - 1);
        }

        for (int i = 0; i < num_rings; ++i)
        {
            mapnik::new_geometry::linear_ring ring;
            int num_points = read_integer();
            if (num_points > 0)
            {
                ring.reserve(num_points);
                read_coords<mapnik::new_geometry::linear_ring, M, Z>(ring, num_points);
            }
            if ( i == 0) poly.set_exterior_ring(std::move(ring));
            else poly.add_hole(std::move(ring));
        }
        return poly;
    }

    template <bool M = false, bool Z = false>
    mapnik::new_geometry::multi_polygon read_multipolygon()
    {
        int num_polys = read_integer();
        mapnik::new_geometry::multi_polygon multi_poly;
        for (int i = 0; i < num_polys; ++i)
        {
            pos_ += 5;
            multi_poly.push_back(std::move(read_polygon<M, Z>()));
        }
        return multi_poly;
    }

    mapnik::new_geometry::geometry_collection read_collection()
    {
        int num_geometries = read_integer();
        mapnik::new_geometry::geometry_collection collection;
        for (int i = 0; i < num_geometries; ++i)
        {
            pos_ += 1; // skip byte order
            collection.push_back(std::move(read()));
         }
        return collection;
     }

    std::string wkb_geometry_type_string(int type)
    {
        std::stringstream s;

        switch (type)
        {
        case wkbPoint:               s << "Point"; break;
        case wkbPointZ:              s << "PointZ"; break;
        case wkbPointM:              s << "PointM"; break;
        case wkbPointZM:             s << "PointZM"; break;
        case wkbMultiPoint:          s << "MultiPoint"; break;
        case wkbMultiPointZ:         s << "MultiPointZ"; break;
        case wkbMultiPointM:         s << "MultiPointM"; break;
        case wkbMultiPointZM:        s << "MultiPointZM"; break;
        case wkbLineString:          s << "LineString"; break;
        case wkbLineStringZ:         s << "LineStringZ"; break;
        case wkbLineStringM:         s << "LineStringM"; break;
        case wkbLineStringZM:        s << "LineStringZM"; break;
        case wkbMultiLineString:     s << "MultiLineString"; break;
        case wkbMultiLineStringZ:    s << "MultiLineStringZ"; break;
        case wkbMultiLineStringM:    s << "MultiLineStringM"; break;
        case wkbMultiLineStringZM:   s << "MultiLineStringZM"; break;
        case wkbPolygon:             s << "Polygon"; break;
        case wkbPolygonZ:            s << "PolygonZ"; break;
        case wkbPolygonM:            s << "PolygonM"; break;
        case wkbPolygonZM:           s << "PolygonZM"; break;
        case wkbMultiPolygon:        s << "MultiPolygon"; break;
        case wkbMultiPolygonZ:       s << "MultiPolygonZ"; break;
        case wkbMultiPolygonM:       s << "MultiPolygonM"; break;
        case wkbMultiPolygonZM:      s << "MultiPolygonZM"; break;
        case wkbGeometryCollection:  s << "GeometryCollection"; break;
        case wkbGeometryCollectionZ: s << "GeometryCollectionZ"; break;
        case wkbGeometryCollectionM: s << "GeometryCollectionM"; break;
        case wkbGeometryCollectionZM:s << "GeometryCollectionZM"; break;
        default:                     s << "wkbUnknown(" << type << ")"; break;
        }

        return s.str();
    }

};

mapnik::new_geometry::geometry geometry_utils::from_wkb(const char* wkb,
                                                        unsigned size,
                                                        wkbFormat format)
{
    wkb_reader reader(wkb, size, format);
    return mapnik::new_geometry::geometry(reader.read());
}

} // namespace mapnik
<|endoftext|>


<commit_before>#include "wsgi.h"
#include "server.h"
#include "base/definition.hpp"
#include "base/memory.hpp"

#include <uv.h>
#include "http_parser.h"

#include <algorithm>
#include <cassert>
#include <memory.h>
using namespace std;

#define _WSGI(p) ((hydrus::WSGIApplication*)(p->data))
#define _CLIENT(p) ((p->client()))
#define _CONNECTION(p) ((uv_tcp_t*)(p->connection()))

// ----------------------------------
//  Raise Output
// ----------------------------------
static const char kWSGIStatus_400[] = { "HTTP/1.1 400 Bad Request\r\nServer: hydrus\r\n\r\n[hydrus]Bad Request" };
static const char kWSGIStatus_404[] = { "HTTP/1.1 404 Not Found\r\nServer: hydrus\r\n\r\n[hydrus]Not Found" };
static const char kWSGIStatus_500[] = { "HTTP/1.1 500 Internal Server Error\r\nServer: hydrus\r\n\r\n[hydrus]Internal Server Error" };

#ifndef HY_SMALL_BUFFER

static hydrus::FixedMemoryPool<1024*1024> sWriteBuffer;
static const size_t kSendFileBuffer = 1024 * 1024;

#else

static hydrus::FixedMemoryPool<64*1024>   sWriteBuffer;
static const size_t kSendFileBuffer = 128 * 1024;

#endif

// -----------------------------------
//  helper functions
// -----------------------------------
static hydrus::WSGICallback sWSGIHandler = nullptr;
static http_parser_settings sParserSetting;

static const char * kHydrusServerName = "hydrus";

struct hydrus::WSGIClient
{
    uv_tcp_t*       tcp;
    http_parser     parser;
    bool            openning;
    std::string     tName;
    std::string     tValue;

    WSGIClient() :openning(false), tcp(new uv_tcp_t)
    {
        uv_tcp_init(uv_default_loop(), tcp);
    }
};

static inline bool
is_still_keepalive(hydrus::WSGIApplication * wa)
{
    auto client = _CLIENT(wa);
    bool should = wa->keepalive();
    printf("Is keep?\n");
    if (should)
    {
        // we know content-length, we can keepalive
        if (wa->contentLength() > 0)
        {
            printf("Content length:%d\n", wa->contentLength());
            return true;
        }
        else
        {
            // If `Content-Length` is not specified, HTTP 1.1 is default to keep-alive
            // HTTP 1.0 always close
            printf("Check is HTTP 1.1\n");
            return (client->parser.http_major > 0 && client->parser.http_minor > 0);
        }
    }
    else
    {
        // Connection: close on HTTP 1.1 or Missing Connection: keep-alive on HTTP 1.0
        printf("bye\n");
        return false;
    }
}

// -----------------------------------
//  UV callbacks
// -----------------------------------
static void
http_on_write(uv_write_t* req, int status)
{
    free(req);
}

static void
http_on_close(uv_handle_t * hnd)
{
    free(hnd);
}

static void
fs_on_sendfile(uv_fs_t * fs)
{
    uv_fs_req_cleanup(fs);
    free(fs);
}

// -----------------------------------
//  request parser
// -----------------------------------
static int
parser_on_begin(http_parser * pa)
{
    return 0;
}

static int
parser_on_url(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    wsgi->URL = string(at, length);
    return 0;
}

static int
parser_on_body(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    wsgi->BODY = string(at, length);
    return 0;
}

static int
parser_on_header_field(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    client->openning = true;
    client->tName = string(at, length);

    return 0;
}

static int
parser_on_header_value(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    if (!client->openning)
        return 0;

    client->tValue = string(at, length);
    client->openning = false;

    wsgi->HEADERS.push_back({ client->tName, client->tValue });
    return 0;
}

static int
parser_on_header_complete(http_parser* pa)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    if (client->openning)
    {
        return -1;
    }
    return 0;
}

static int
parser_on_complete(http_parser* pa)
{
    static char s_addr_buf[64];
    hydrus::WSGIApplication * wsgi = _WSGI(pa);
    uv_tcp_t * connection = _CONNECTION(wsgi);

    sockaddr_in ip;
    int len;
    uv_tcp_getpeername(connection, (sockaddr*)&ip, &len);
    uv_ip4_name(&ip, s_addr_buf, len);

    wsgi->REMOTE_ADDR = s_addr_buf;
    wsgi->REQUEST_METHOD = http_method_str((http_method)pa->method);

    // check this request is keep-alive or not
    wsgi->setKeepalive(http_should_keep_alive(pa) != 0);
    return 0;
}

// -----------------------------------
//  WSGIApplication impletation
// -----------------------------------
NS(hydrus)

void
WSGIReady(WSGICallback callback)
{
    if (sWSGIHandler)
        return;

    // setup callback
    sWSGIHandler = callback;

    // setup parser callback
    sParserSetting.on_message_begin = parser_on_begin;
    sParserSetting.on_url = parser_on_url;
    sParserSetting.on_body = parser_on_body;
    sParserSetting.on_header_field = parser_on_header_field;
    sParserSetting.on_header_value = parser_on_header_value;
    sParserSetting.on_headers_complete = parser_on_header_complete;
    sParserSetting.on_message_complete = parser_on_complete;
}

WSGIApplication::WSGIApplication() :
    SERVER_NAME(Server::host()),
    SERVER_PORT(Server::port()),
    contentLength_(0)
{
    // for headers
    HEADERS.reserve(16);

    // for libuv
    client_ = new WSGIClient();
    client_->tcp->data = this;

    // for http_parser
    client_->parser.data = (void*)this;
    http_parser_init(&(client_->parser), HTTP_REQUEST);
}

WSGIApplication::~WSGIApplication()
{
    uv_close((uv_handle_t*)client_->tcp, http_on_close);
    delete client_;
}

void
WSGIApplication::append(const char * buffer, size_t nread)
{
    rbuffer_.insert(rbuffer_.end(), buffer, buffer + nread);
}

bool
WSGIApplication::parse()
{
    const char * data = rbuffer_.data();
    size_t len = rbuffer_.size();
    if (len > 0)
    {
        size_t parsed = http_parser_execute(&(client_->parser), &sParserSetting, data, len);
        return parsed == len && client_->parser.http_errno == HPE_OK;
    }
    return false;
}

void
WSGIApplication::execute()
{
    sWSGIHandler(*this);

    this->setKeepalive(is_still_keepalive(this));
    rbuffer_.clear();
}

void
WSGIApplication::raiseUp(int statusCode)
{
    switch (statusCode)
    {
    case 400:
        // with out `\0` in HTTPResponse buffer
        this->send(kWSGIStatus_400, sizeof(kWSGIStatus_400) - 1);
        break;
    case 404:
        this->send(kWSGIStatus_404, sizeof(kWSGIStatus_404) - 1);
        break;
    case 500:
        this->send(kWSGIStatus_500, sizeof(kWSGIStatus_500) - 1);
        break;
    default:
        this->send("\r\n\r\n", 4);
        break;
    }
}

void *
WSGIApplication::connection()
{
    return client_->tcp;
}

WSGIClient*
WSGIApplication::client()
{
    return client_;
}

void
WSGIApplication::send(const char * data, size_t sz)
{
    size_t send_size = sz > sWriteBuffer.size() ? sWriteBuffer.size() : sz;
    size_t remain = sz - send_size;

    uv_write_t * w = new uv_write_t;
    w->data = this;

    sWriteBuffer.copy(data, send_size);
    uv_buf_t buf = uv_buf_init(sWriteBuffer.data(), send_size);
    uv_write(w, (uv_stream_t*)this->connection(), &buf, 1, http_on_write);

    if (remain > 0)
    {
        this->send(data + send_size, remain);
    }
}

void
WSGIApplication::sendFile(int file_fd, size_t sz)
{
    auto conn = _CONNECTION(this);
    uv_fs_t * fs = (uv_fs_t*)malloc(sizeof(uv_fs_t));

#if !defined(WIN32) && !defined(_WIN32)
    int sockfd = conn->io_watcher.fd;
#else
    int sockfd = conn->socket;
#endif

    if (sz < kSendFileBuffer)
    {
        uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, 0, sz, fs_on_sendfile);
    }
    else
    {
        int remain = sz;
        int offset= 0;
        do
        {
            uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, offset, kSendFileBuffer, fs_on_sendfile);
            remain -= kSendFileBuffer;
            offset += kSendFileBuffer;
        } while (remain >= kSendFileBuffer);
        if (remain > 0)
        {
            uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, offset, remain, fs_on_sendfile);
        }
    }
}

NS_END
<commit_msg>remove printf<commit_after>#include "wsgi.h"
#include "server.h"
#include "base/definition.hpp"
#include "base/memory.hpp"

#include <uv.h>
#include "http_parser.h"

#include <algorithm>
#include <cassert>
#include <memory.h>
using namespace std;

#define _WSGI(p) ((hydrus::WSGIApplication*)(p->data))
#define _CLIENT(p) ((p->client()))
#define _CONNECTION(p) ((uv_tcp_t*)(p->connection()))

// ----------------------------------
//  Raise Output
// ----------------------------------
static const char kWSGIStatus_400[] = { "HTTP/1.1 400 Bad Request\r\nServer: hydrus\r\n\r\n[hydrus]Bad Request" };
static const char kWSGIStatus_404[] = { "HTTP/1.1 404 Not Found\r\nServer: hydrus\r\n\r\n[hydrus]Not Found" };
static const char kWSGIStatus_500[] = { "HTTP/1.1 500 Internal Server Error\r\nServer: hydrus\r\n\r\n[hydrus]Internal Server Error" };

#ifndef HY_SMALL_BUFFER

static hydrus::FixedMemoryPool<1024*1024> sWriteBuffer;
static const size_t kSendFileBuffer = 1024 * 1024;

#else

static hydrus::FixedMemoryPool<64*1024>   sWriteBuffer;
static const size_t kSendFileBuffer = 128 * 1024;

#endif

// -----------------------------------
//  helper functions
// -----------------------------------
static hydrus::WSGICallback sWSGIHandler = nullptr;
static http_parser_settings sParserSetting;

static const char * kHydrusServerName = "hydrus";

struct hydrus::WSGIClient
{
    uv_tcp_t*       tcp;
    http_parser     parser;
    bool            openning;
    std::string     tName;
    std::string     tValue;

    WSGIClient() :openning(false), tcp(new uv_tcp_t)
    {
        uv_tcp_init(uv_default_loop(), tcp);
    }
};

static inline bool
is_still_keepalive(hydrus::WSGIApplication * wa)
{
    auto client = _CLIENT(wa);
    bool should = wa->keepalive();
    if (should)
    {
        // we know content-length, we can keepalive
        if (wa->contentLength() > 0)
        {
            return true;
        }
        else
        {
            // If `Content-Length` is not specified, HTTP 1.1 is default to keep-alive
            // HTTP 1.0 always close
            return (client->parser.http_major > 0 && client->parser.http_minor > 0);
        }
    }
    else
    {
        // Connection: close on HTTP 1.1 or Missing Connection: keep-alive on HTTP 1.0
        return false;
    }
}

// -----------------------------------
//  UV callbacks
// -----------------------------------
static void
http_on_write(uv_write_t* req, int status)
{
    free(req);
}

static void
http_on_close(uv_handle_t * hnd)
{
    free(hnd);
}

static void
fs_on_sendfile(uv_fs_t * fs)
{
    uv_fs_req_cleanup(fs);
    free(fs);
}

// -----------------------------------
//  request parser
// -----------------------------------
static int
parser_on_begin(http_parser * pa)
{
    return 0;
}

static int
parser_on_url(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    wsgi->URL = string(at, length);
    return 0;
}

static int
parser_on_body(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    wsgi->BODY = string(at, length);
    return 0;
}

static int
parser_on_header_field(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    client->openning = true;
    client->tName = string(at, length);

    return 0;
}

static int
parser_on_header_value(http_parser* pa, const char *at, size_t length)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    if (!client->openning)
        return 0;

    client->tValue = string(at, length);
    client->openning = false;

    wsgi->HEADERS.push_back({ client->tName, client->tValue });
    return 0;
}

static int
parser_on_header_complete(http_parser* pa)
{
    auto wsgi = _WSGI(pa);
    auto client = _CLIENT(wsgi);

    if (client->openning)
    {
        return -1;
    }
    return 0;
}

static int
parser_on_complete(http_parser* pa)
{
    static char s_addr_buf[64];
    hydrus::WSGIApplication * wsgi = _WSGI(pa);
    uv_tcp_t * connection = _CONNECTION(wsgi);

    sockaddr_in ip;
    int len;
    uv_tcp_getpeername(connection, (sockaddr*)&ip, &len);
    uv_ip4_name(&ip, s_addr_buf, len);

    wsgi->REMOTE_ADDR = s_addr_buf;
    wsgi->REQUEST_METHOD = http_method_str((http_method)pa->method);

    // check this request is keep-alive or not
    wsgi->setKeepalive(http_should_keep_alive(pa) != 0);
    return 0;
}

// -----------------------------------
//  WSGIApplication impletation
// -----------------------------------
NS(hydrus)

void
WSGIReady(WSGICallback callback)
{
    if (sWSGIHandler)
        return;

    // setup callback
    sWSGIHandler = callback;

    // setup parser callback
    sParserSetting.on_message_begin = parser_on_begin;
    sParserSetting.on_url = parser_on_url;
    sParserSetting.on_body = parser_on_body;
    sParserSetting.on_header_field = parser_on_header_field;
    sParserSetting.on_header_value = parser_on_header_value;
    sParserSetting.on_headers_complete = parser_on_header_complete;
    sParserSetting.on_message_complete = parser_on_complete;
}

WSGIApplication::WSGIApplication() :
    SERVER_NAME(Server::host()),
    SERVER_PORT(Server::port()),
    contentLength_(0)
{
    // for headers
    HEADERS.reserve(16);

    // for libuv
    client_ = new WSGIClient();
    client_->tcp->data = this;

    // for http_parser
    client_->parser.data = (void*)this;
    http_parser_init(&(client_->parser), HTTP_REQUEST);
}

WSGIApplication::~WSGIApplication()
{
    uv_close((uv_handle_t*)client_->tcp, http_on_close);
    delete client_;
}

void
WSGIApplication::append(const char * buffer, size_t nread)
{
    rbuffer_.insert(rbuffer_.end(), buffer, buffer + nread);
}

bool
WSGIApplication::parse()
{
    const char * data = rbuffer_.data();
    size_t len = rbuffer_.size();
    if (len > 0)
    {
        size_t parsed = http_parser_execute(&(client_->parser), &sParserSetting, data, len);
        return parsed == len && client_->parser.http_errno == HPE_OK;
    }
    return false;
}

void
WSGIApplication::execute()
{
    sWSGIHandler(*this);

    // recheck the connection should be keepalive or not
    this->setKeepalive(is_still_keepalive(this));
    rbuffer_.clear();
}

void
WSGIApplication::raiseUp(int statusCode)
{
    switch (statusCode)
    {
    case 400:
        // with out `\0` in HTTPResponse buffer
        this->send(kWSGIStatus_400, sizeof(kWSGIStatus_400) - 1);
        break;
    case 404:
        this->send(kWSGIStatus_404, sizeof(kWSGIStatus_404) - 1);
        break;
    case 500:
        this->send(kWSGIStatus_500, sizeof(kWSGIStatus_500) - 1);
        break;
    default:
        this->send("\r\n\r\n", 4);
        break;
    }
}

void *
WSGIApplication::connection()
{
    return client_->tcp;
}

WSGIClient*
WSGIApplication::client()
{
    return client_;
}

void
WSGIApplication::send(const char * data, size_t sz)
{
    size_t send_size = sz > sWriteBuffer.size() ? sWriteBuffer.size() : sz;
    size_t remain = sz - send_size;

    uv_write_t * w = new uv_write_t;
    w->data = this;

    sWriteBuffer.copy(data, send_size);
    uv_buf_t buf = uv_buf_init(sWriteBuffer.data(), send_size);
    uv_write(w, (uv_stream_t*)this->connection(), &buf, 1, http_on_write);

    if (remain > 0)
    {
        this->send(data + send_size, remain);
    }
}

void
WSGIApplication::sendFile(int file_fd, size_t sz)
{
    auto conn = _CONNECTION(this);
    uv_fs_t * fs = (uv_fs_t*)malloc(sizeof(uv_fs_t));

#if !defined(WIN32) && !defined(_WIN32)
    int sockfd = conn->io_watcher.fd;
#else
    int sockfd = conn->socket;
#endif

    if (sz < kSendFileBuffer)
    {
        uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, 0, sz, fs_on_sendfile);
    }
    else
    {
        int remain = sz;
        int offset= 0;
        do
        {
            uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, offset, kSendFileBuffer, fs_on_sendfile);
            remain -= kSendFileBuffer;
            offset += kSendFileBuffer;
        } while (remain >= kSendFileBuffer);
        if (remain > 0)
        {
            uv_fs_sendfile(uv_default_loop(), fs, sockfd, file_fd, offset, remain, fs_on_sendfile);
        }
    }
}

NS_END
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <ctime>

using namespace std;

const int qSize = 7;
const double gamma = 0.8;
float epsilon = 1;
const int iterations = 100;

int R[qSize][qSize] =
{
	{ -1, -1, -1, -1, 0, -1, -1 },
	{ -1, -1, -1, 0, -1, 100, 0 },
	{ -1, -1, -1, 0, -1, -1, 0 },
	{ -1, 0, 0, -1, 0, -1, 0 },
	{ 0, -1, -1, 0, -1, 100, 0 },
	{ -1, 0, -1, -1, 0, -1, 0 },
	{ -1, 0, 0, 0, 0, 100, -1 }

};

int Q[qSize][qSize];
int currentState;
int goalState = 5;
void episode(int initialState);
void chooseAnAction();
int getRandomAction(int upperBound, int lowerBound);
void initialize();
int maximum(int state, bool returnIndexOnly);
int reward(int action);
void printQMatrix();
int main()
{

	int newState;

	initialize();

	//Perform learning trials starting at all initial states.
	for (int i = 1; i <= iterations ; i++)
	{
		epsilon = sqrtf(1.0 / i);
		currentState = 0;

		episode(currentState);

		//printQMatrix();
	}

	//Perform tests, starting at all initial states.
	for (int i = 0; i <= (qSize - 1); i++)
	{
		currentState = i;
		newState = 0;
		while (currentState != goalState)
		{
			newState = maximum(currentState, true);
			cout << currentState << ", ";
			currentState = newState;
		}
		cout << goalState << endl;
	} // i

	return 0;
}
void printQMatrix()
{
	//Print out Q matrix.
	for (int i = 0; i <= (qSize - 1); i++)
	{
		for (int j = 0; j <= (qSize - 1); j++)
		{
			cout << setw(5) << Q[i][j];
			if (j < qSize - 1)
			{
				cout << ",";
			}
		} // j
		cout << "\n";
	} // i
	cout << "\n";
}

void episode(int initialState)
{
	for (int i = 0; i <= (qSize - 1); i++)
	{
		chooseAnAction();
	} // i
}

void chooseAnAction()
{

	int possibleAction;
	if (rand() / (RAND_MAX + 1.0) < epsilon)
	{
		//Randomly choose a possible action connected to the current state.
		possibleAction = getRandomAction(qSize, 0);
	}
	else
	{
		possibleAction = maximum(currentState, true);
		if (R[currentState][possibleAction] < 0)
		{

			possibleAction = getRandomAction(qSize, 0);
		}

	}

	Q[currentState][possibleAction] = reward(possibleAction);
	currentState = possibleAction;

}

int getRandomAction(int upperBound, int lowerBound)
{

	int action;
	bool choiceIsValid = false;
	int range = (upperBound - lowerBound) + 1;

	//Randomly choose a possible action connected to the current state.
	do
	{
		//Get a random value between 0 and 6.
		action = lowerBound + int(range * rand() / (RAND_MAX + 1.0));
		if (R[currentState][action] > -1)
		{
			choiceIsValid = true;
		}
	} while (choiceIsValid == false);

	return action;
}

void initialize()
{

	srand((unsigned)time(0));

	for (int i = 0; i <= (qSize - 1); i++)
	{
		for (int j = 0; j <= (qSize - 1); j++)
		{
			Q[i][j] = 0;
		} // j
	} // i
}

int maximum(int state, bool returnIndexOnly)
{
	// if returnIndexOnly = true, a Q matrix index is returned.
	// if returnIndexOnly = false, a Q matrix element is returned.

	int winner;
	bool foundNewWinner;
	bool done = false;

	winner = 0;

	do {
		foundNewWinner = false;
		for (int i = 0; i <= (qSize - 1); i++)
		{
			if ((i < winner) || (i > winner))
			{     //Avoid self-comparison.
				if (Q[state][i] > Q[state][winner])
				{
					winner = i;
					foundNewWinner = true;
				}
				if (Q[state][i] == Q[state][winner])
				{
					if (rand() / (RAND_MAX + 1.0) < 0.5)
					{
						winner = i;
						foundNewWinner = true;
					}
				}
			}
		} // i

		if (foundNewWinner == false)
		{
			done = true;
		}

	} while (done = false);

	if (returnIndexOnly == true)
	{
		return winner;
	}
	else
	{
		return Q[state][winner];
	}
}

int reward(int action)
{
	return static_cast<int>(R[currentState][action] + (gamma * maximum(action, false)));
}
<commit_msg>- modify  iterations count and episode step count<commit_after>#include <iostream>
#include <iomanip>
#include <ctime>

using namespace std;

const int qSize = 7;
const double gamma = 0.8;
float epsilon = 1;
const int iterations = 20;

int R[qSize][qSize] =
{
	{ -1, -1, -1, -1, 0, -1, -1 },
	{ -1, -1, -1, 0, -1, 100, 0 },
	{ -1, -1, -1, 0, -1, -1, 0 },
	{ -1, 0, 0, -1, 0, -1, 0 },
	{ 0, -1, -1, 0, -1, 100, 0 },
	{ -1, 0, -1, -1, 0, -1, 0 },
	{ -1, 0, 0, 0, 0, 100, -1 }

};

int Q[qSize][qSize];
int currentState;
int goalState = 5;
void episode(int initialState);
void chooseAnAction();
int getRandomAction(int upperBound, int lowerBound);
void initialize();
int maximum(int state, bool returnIndexOnly);
int reward(int action);
void printQMatrix();
int main()
{

	int newState;

	initialize();

	//Perform learning trials starting at all initial states.
	for (int i = 1; i <= iterations ; i++)
	{
		epsilon = sqrtf(1.0 / i);
		currentState = 0;

		episode(currentState);

		//printQMatrix();
	}

	//Perform tests, starting at all initial states.
	for (int i = 0; i <= (qSize - 1); i++)
	{
		currentState = i;
		newState = 0;
		while (currentState != goalState)
		{
			newState = maximum(currentState, true);
			cout << currentState << ", ";
			currentState = newState;
		}
		cout << goalState << endl;
	} // i

	return 0;
}
void printQMatrix()
{
	//Print out Q matrix.
	for (int i = 0; i <= (qSize - 1); i++)
	{
		for (int j = 0; j <= (qSize - 1); j++)
		{
			cout << setw(5) << Q[i][j];
			if (j < qSize - 1)
			{
				cout << ",";
			}
		} // j
		cout << "\n";
	} // i
	cout << "\n";
}

void episode(int initialState)
{
	for (int i = 0; i <= qSize * qSize; i++)
	{
		chooseAnAction();
	} // i
}

void chooseAnAction()
{

	int possibleAction;
	if (rand() / (RAND_MAX + 1.0) < epsilon)
	{
		//Randomly choose a possible action connected to the current state.
		possibleAction = getRandomAction(qSize, 0);
	}
	else
	{
		possibleAction = maximum(currentState, true);
		if (R[currentState][possibleAction] < 0)
		{

			possibleAction = getRandomAction(qSize, 0);
		}

	}

	Q[currentState][possibleAction] = reward(possibleAction);
	currentState = possibleAction;

}

int getRandomAction(int upperBound, int lowerBound)
{

	int action;
	bool choiceIsValid = false;
	int range = (upperBound - lowerBound) + 1;

	//Randomly choose a possible action connected to the current state.
	do
	{
		//Get a random value between 0 and 6.
		action = lowerBound + int(range * rand() / (RAND_MAX + 1.0));
		if (R[currentState][action] > -1)
		{
			choiceIsValid = true;
		}
	} while (choiceIsValid == false);

	return action;
}

void initialize()
{

	srand((unsigned)time(0));

	for (int i = 0; i <= (qSize - 1); i++)
	{
		for (int j = 0; j <= (qSize - 1); j++)
		{
			Q[i][j] = 0;
		} // j
	} // i
}

int maximum(int state, bool returnIndexOnly)
{
	// if returnIndexOnly = true, a Q matrix index is returned.
	// if returnIndexOnly = false, a Q matrix element is returned.

	int winner;
	bool foundNewWinner;
	bool done = false;

	winner = 0;

	do {
		foundNewWinner = false;
		for (int i = 0; i <= (qSize - 1); i++)
		{
			if ((i < winner) || (i > winner))
			{     //Avoid self-comparison.
				if (Q[state][i] > Q[state][winner])
				{
					winner = i;
					foundNewWinner = true;
				}
				if (Q[state][i] == Q[state][winner])
				{
					if (rand() / (RAND_MAX + 1.0) < 0.5)
					{
						winner = i;
						foundNewWinner = true;
					}
				}
			}
		} // i

		if (foundNewWinner == false)
		{
			done = true;
		}

	} while (done = false);

	if (returnIndexOnly == true)
	{
		return winner;
	}
	else
	{
		return Q[state][winner];
	}
}

int reward(int action)
{
	return static_cast<int>(R[currentState][action] + (gamma * maximum(action, false)));
}
<|endoftext|>


<commit_before>#include "autopilot_tester.h"
#include <iostream>
#include <future>

std::string connection_url {"udp://"};

void AutopilotTester::connect(const std::string uri)
{
    ConnectionResult ret = _mavsdk.add_any_connection(uri);
    REQUIRE(ret == ConnectionResult::SUCCESS);

    std::cout << "Waiting for system connect" << std::endl;
    REQUIRE(poll_condition_with_timeout(
        [this]() { return _mavsdk.is_connected(); }, std::chrono::seconds(25)));

    auto& system = _mavsdk.system();

    _telemetry.reset(new Telemetry(system));
    _action.reset(new Action(system));
    _mission.reset(new Mission(system));
    _offboard.reset(new Offboard(system));
}

void AutopilotTester::wait_until_ready()
{
    std::cout << "Waiting for system to be ready" << std::endl;
    CHECK(poll_condition_with_timeout(
        [this]() { return _telemetry->health_all_ok(); }, std::chrono::seconds(20)));
}

void AutopilotTester::wait_until_ready_local_position_only()
{
    std::cout << "Waiting for system to be ready" << std::endl;
    CHECK(poll_condition_with_timeout(
        [this]() {
	return
	    (_telemetry->health().gyrometer_calibration_ok &&
	     _telemetry->health().accelerometer_calibration_ok &&
	     _telemetry->health().magnetometer_calibration_ok &&
	     _telemetry->health().level_calibration_ok &&
	     _telemetry->health().local_position_ok);
	}, std::chrono::seconds(20)));
}

void AutopilotTester::store_home()
{
    request_ground_truth();
    _home = get_ground_truth_position();
}

void AutopilotTester::check_home_within(float acceptance_radius_m)
{
    CHECK(ground_truth_horizontal_position_close_to(_home, acceptance_radius_m));
}

void AutopilotTester::set_takeoff_altitude(const float altitude_m)
{
    CHECK(Action::Result::SUCCESS == _action->set_takeoff_altitude(altitude_m));
    const auto result = _action->get_takeoff_altitude();
    CHECK(result.first == Action::Result::SUCCESS);
    CHECK(result.second == Approx(altitude_m));
}

void AutopilotTester::arm()
{
    const auto result = _action->arm();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::takeoff()
{
    const auto result = _action->takeoff();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::land()
{
    const auto result = _action->land();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::transition_to_fixedwing()
{
    const auto result = _action->transition_to_fixedwing();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::transition_to_multicopter()
{
    const auto result = _action->transition_to_multicopter();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::wait_until_disarmed()
{
    REQUIRE(poll_condition_with_timeout(
        [this]() { return !_telemetry->armed(); }, std::chrono::seconds(60)));
}

void AutopilotTester::wait_until_hovering()
{
    REQUIRE(poll_condition_with_timeout(
        [this]() { return _telemetry->landed_state() == Telemetry::LandedState::IN_AIR; }, std::chrono::seconds(20)));
}

void AutopilotTester::prepare_square_mission(MissionOptions mission_options)
{
    const auto ct = get_coordinate_transformation();

    std::vector<std::shared_ptr<MissionItem>> mission_items {};
    mission_items.push_back(create_mission_item({mission_options.leg_length_m, 0.}, mission_options, ct));
    mission_items.push_back(create_mission_item({mission_options.leg_length_m, mission_options.leg_length_m}, mission_options, ct));
    mission_items.push_back(create_mission_item({0., mission_options.leg_length_m}, mission_options, ct));

    _mission->set_return_to_launch_after_mission(mission_options.rtl_at_end);

    std::promise<void> prom;
    auto fut = prom.get_future();

    _mission->upload_mission_async(mission_items, [&prom](Mission::Result result) {
        REQUIRE(Mission::Result::SUCCESS == result);
        prom.set_value();
    });

    REQUIRE(fut.wait_for(std::chrono::seconds(2)) == std::future_status::ready);
}

void AutopilotTester::execute_mission()
{
    std::promise<void> prom;
    auto fut = prom.get_future();

    _mission->start_mission_async([&prom](Mission::Result result) {
        REQUIRE(Mission::Result::SUCCESS == result);
        prom.set_value();
    });

    // TODO: Adapt time limit based on mission size, flight speed, sim speed factor, etc.

    REQUIRE(poll_condition_with_timeout(
        [this]() { return _mission->mission_finished(); }, std::chrono::seconds(60)));

    REQUIRE(fut.wait_for(std::chrono::seconds(1)) == std::future_status::ready);
}

CoordinateTransformation AutopilotTester::get_coordinate_transformation()
{
    const auto home = _telemetry->home_position();
    REQUIRE(std::isfinite(home.latitude_deg));
    REQUIRE(std::isfinite(home.longitude_deg));
    return CoordinateTransformation({home.latitude_deg, home.longitude_deg});
}

std::shared_ptr<MissionItem>  AutopilotTester::create_mission_item(
    const CoordinateTransformation::LocalCoordinate& local_coordinate,
    const MissionOptions& mission_options,
    const CoordinateTransformation& ct)
{
    auto mission_item = std::make_shared<MissionItem>();
    const auto pos_north = ct.global_from_local(local_coordinate);
    mission_item->set_position(pos_north.latitude_deg, pos_north.longitude_deg);
    mission_item->set_relative_altitude(mission_options.relative_altitude_m);
    return mission_item;
}

void AutopilotTester::execute_rtl()
{
    REQUIRE(Action::Result::SUCCESS == _action->return_to_launch());
}

void AutopilotTester::offboard_goto(const Offboard::PositionNEDYaw& target, float acceptance_radius_m, std::chrono::seconds timeout_duration)
{
    _offboard->set_position_ned(target);
    REQUIRE(_offboard->start() == Offboard::Result::SUCCESS);
    REQUIRE(poll_condition_with_timeout(
        [=]() { return estimated_position_close_to(target, acceptance_radius_m); }, timeout_duration));
    std::cout << "Target position reached" << std::endl;
}

void AutopilotTester::offboard_land()
{
    Offboard::VelocityNEDYaw land_velocity;
    land_velocity.north_m_s = 0.0f;
    land_velocity.east_m_s = 0.0f;
    land_velocity.down_m_s = 1.0f;
    land_velocity.yaw_deg = 0.0f;
    _offboard->set_velocity_ned(land_velocity);
}

bool AutopilotTester::estimated_position_close_to(const Offboard::PositionNEDYaw& target_pos, float acceptance_radius_m)
{
    Telemetry::PositionNED est_pos = _telemetry->position_velocity_ned().position;
    return sq(est_pos.north_m - target_pos.north_m) +
           sq(est_pos.east_m - target_pos.east_m) +
           sq(est_pos.down_m - target_pos.down_m)  < sq(acceptance_radius_m);
}

bool AutopilotTester::estimated_horizontal_position_close_to(const Offboard::PositionNEDYaw& target_pos, float acceptance_radius_m)
{
    Telemetry::PositionNED est_pos = _telemetry->position_velocity_ned().position;
    return sq(est_pos.north_m - target_pos.north_m) +
           sq(est_pos.east_m - target_pos.east_m) < sq(acceptance_radius_m);
}

void AutopilotTester::request_ground_truth()
{
    REQUIRE(_telemetry->set_rate_ground_truth(15) == Telemetry::Result::SUCCESS);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

Telemetry::GroundTruth AutopilotTester::get_ground_truth_position()
{
    return _telemetry->ground_truth();
}

bool AutopilotTester::ground_truth_horizontal_position_close_to(const Telemetry::GroundTruth& target_pos, float acceptance_radius_m)
{
    REQUIRE(std::isfinite(target_pos.latitude_deg));
    REQUIRE(std::isfinite(target_pos.longitude_deg));
    using GlobalCoordinate = CoordinateTransformation::GlobalCoordinate;
    using LocalCoordinate = CoordinateTransformation::LocalCoordinate;
    CoordinateTransformation ct(GlobalCoordinate{target_pos.latitude_deg, target_pos.longitude_deg});

    Telemetry::GroundTruth current_pos = _telemetry->ground_truth();
    REQUIRE(std::isfinite(current_pos.latitude_deg));
    REQUIRE(std::isfinite(current_pos.longitude_deg));
    LocalCoordinate local_pos= ct.local_from_global(GlobalCoordinate{current_pos.latitude_deg, current_pos.longitude_deg});

    return sq(local_pos.north_m) + sq(local_pos.east_m) < sq(acceptance_radius_m);
}
<commit_msg>mavsdk_tests: use CHECK if we don't need to abort<commit_after>#include "autopilot_tester.h"
#include <iostream>
#include <future>

std::string connection_url {"udp://"};

void AutopilotTester::connect(const std::string uri)
{
    ConnectionResult ret = _mavsdk.add_any_connection(uri);
    REQUIRE(ret == ConnectionResult::SUCCESS);

    std::cout << "Waiting for system connect" << std::endl;
    REQUIRE(poll_condition_with_timeout(
        [this]() { return _mavsdk.is_connected(); }, std::chrono::seconds(25)));

    auto& system = _mavsdk.system();

    _telemetry.reset(new Telemetry(system));
    _action.reset(new Action(system));
    _mission.reset(new Mission(system));
    _offboard.reset(new Offboard(system));
}

void AutopilotTester::wait_until_ready()
{
    std::cout << "Waiting for system to be ready" << std::endl;
    CHECK(poll_condition_with_timeout(
        [this]() { return _telemetry->health_all_ok(); }, std::chrono::seconds(20)));
}

void AutopilotTester::wait_until_ready_local_position_only()
{
    std::cout << "Waiting for system to be ready" << std::endl;
    CHECK(poll_condition_with_timeout(
        [this]() {
	return
	    (_telemetry->health().gyrometer_calibration_ok &&
	     _telemetry->health().accelerometer_calibration_ok &&
	     _telemetry->health().magnetometer_calibration_ok &&
	     _telemetry->health().level_calibration_ok &&
	     _telemetry->health().local_position_ok);
	}, std::chrono::seconds(20)));
}

void AutopilotTester::store_home()
{
    request_ground_truth();
    _home = get_ground_truth_position();
}

void AutopilotTester::check_home_within(float acceptance_radius_m)
{
    CHECK(ground_truth_horizontal_position_close_to(_home, acceptance_radius_m));
}

void AutopilotTester::set_takeoff_altitude(const float altitude_m)
{
    CHECK(Action::Result::SUCCESS == _action->set_takeoff_altitude(altitude_m));
    const auto result = _action->get_takeoff_altitude();
    CHECK(result.first == Action::Result::SUCCESS);
    CHECK(result.second == Approx(altitude_m));
}

void AutopilotTester::arm()
{
    const auto result = _action->arm();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::takeoff()
{
    const auto result = _action->takeoff();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::land()
{
    const auto result = _action->land();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::transition_to_fixedwing()
{
    const auto result = _action->transition_to_fixedwing();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::transition_to_multicopter()
{
    const auto result = _action->transition_to_multicopter();
    REQUIRE(result == Action::Result::SUCCESS);
}

void AutopilotTester::wait_until_disarmed()
{
    REQUIRE(poll_condition_with_timeout(
        [this]() { return !_telemetry->armed(); }, std::chrono::seconds(60)));
}

void AutopilotTester::wait_until_hovering()
{
    REQUIRE(poll_condition_with_timeout(
        [this]() { return _telemetry->landed_state() == Telemetry::LandedState::IN_AIR; }, std::chrono::seconds(20)));
}

void AutopilotTester::prepare_square_mission(MissionOptions mission_options)
{
    const auto ct = get_coordinate_transformation();

    std::vector<std::shared_ptr<MissionItem>> mission_items {};
    mission_items.push_back(create_mission_item({mission_options.leg_length_m, 0.}, mission_options, ct));
    mission_items.push_back(create_mission_item({mission_options.leg_length_m, mission_options.leg_length_m}, mission_options, ct));
    mission_items.push_back(create_mission_item({0., mission_options.leg_length_m}, mission_options, ct));

    _mission->set_return_to_launch_after_mission(mission_options.rtl_at_end);

    std::promise<void> prom;
    auto fut = prom.get_future();

    _mission->upload_mission_async(mission_items, [&prom](Mission::Result result) {
        REQUIRE(Mission::Result::SUCCESS == result);
        prom.set_value();
    });

    REQUIRE(fut.wait_for(std::chrono::seconds(2)) == std::future_status::ready);
}

void AutopilotTester::execute_mission()
{
    std::promise<void> prom;
    auto fut = prom.get_future();

    _mission->start_mission_async([&prom](Mission::Result result) {
        REQUIRE(Mission::Result::SUCCESS == result);
        prom.set_value();
    });

    // TODO: Adapt time limit based on mission size, flight speed, sim speed factor, etc.

    REQUIRE(poll_condition_with_timeout(
        [this]() { return _mission->mission_finished(); }, std::chrono::seconds(60)));

    REQUIRE(fut.wait_for(std::chrono::seconds(1)) == std::future_status::ready);
}

CoordinateTransformation AutopilotTester::get_coordinate_transformation()
{
    const auto home = _telemetry->home_position();
    CHECK(std::isfinite(home.latitude_deg));
    CHECK(std::isfinite(home.longitude_deg));
    return CoordinateTransformation({home.latitude_deg, home.longitude_deg});
}

std::shared_ptr<MissionItem>  AutopilotTester::create_mission_item(
    const CoordinateTransformation::LocalCoordinate& local_coordinate,
    const MissionOptions& mission_options,
    const CoordinateTransformation& ct)
{
    auto mission_item = std::make_shared<MissionItem>();
    const auto pos_north = ct.global_from_local(local_coordinate);
    mission_item->set_position(pos_north.latitude_deg, pos_north.longitude_deg);
    mission_item->set_relative_altitude(mission_options.relative_altitude_m);
    return mission_item;
}

void AutopilotTester::execute_rtl()
{
    REQUIRE(Action::Result::SUCCESS == _action->return_to_launch());
}

void AutopilotTester::offboard_goto(const Offboard::PositionNEDYaw& target, float acceptance_radius_m, std::chrono::seconds timeout_duration)
{
    _offboard->set_position_ned(target);
    REQUIRE(_offboard->start() == Offboard::Result::SUCCESS);
    CHECK(poll_condition_with_timeout(
        [=]() { return estimated_position_close_to(target, acceptance_radius_m); }, timeout_duration));
    std::cout << "Target position reached" << std::endl;
}

void AutopilotTester::offboard_land()
{
    Offboard::VelocityNEDYaw land_velocity;
    land_velocity.north_m_s = 0.0f;
    land_velocity.east_m_s = 0.0f;
    land_velocity.down_m_s = 1.0f;
    land_velocity.yaw_deg = 0.0f;
    _offboard->set_velocity_ned(land_velocity);
}

bool AutopilotTester::estimated_position_close_to(const Offboard::PositionNEDYaw& target_pos, float acceptance_radius_m)
{
    Telemetry::PositionNED est_pos = _telemetry->position_velocity_ned().position;
    return sq(est_pos.north_m - target_pos.north_m) +
           sq(est_pos.east_m - target_pos.east_m) +
           sq(est_pos.down_m - target_pos.down_m)  < sq(acceptance_radius_m);
}

bool AutopilotTester::estimated_horizontal_position_close_to(const Offboard::PositionNEDYaw& target_pos, float acceptance_radius_m)
{
    Telemetry::PositionNED est_pos = _telemetry->position_velocity_ned().position;
    return sq(est_pos.north_m - target_pos.north_m) +
           sq(est_pos.east_m - target_pos.east_m) < sq(acceptance_radius_m);
}

void AutopilotTester::request_ground_truth()
{
    CHECK(_telemetry->set_rate_ground_truth(15) == Telemetry::Result::SUCCESS);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

Telemetry::GroundTruth AutopilotTester::get_ground_truth_position()
{
    return _telemetry->ground_truth();
}

bool AutopilotTester::ground_truth_horizontal_position_close_to(const Telemetry::GroundTruth& target_pos, float acceptance_radius_m)
{
    CHECK(std::isfinite(target_pos.latitude_deg));
    CHECK(std::isfinite(target_pos.longitude_deg));
    using GlobalCoordinate = CoordinateTransformation::GlobalCoordinate;
    using LocalCoordinate = CoordinateTransformation::LocalCoordinate;
    CoordinateTransformation ct(GlobalCoordinate{target_pos.latitude_deg, target_pos.longitude_deg});

    Telemetry::GroundTruth current_pos = _telemetry->ground_truth();
    CHECK(std::isfinite(current_pos.latitude_deg));
    CHECK(std::isfinite(current_pos.longitude_deg));
    LocalCoordinate local_pos= ct.local_from_global(GlobalCoordinate{current_pos.latitude_deg, current_pos.longitude_deg});

    return sq(local_pos.north_m) + sq(local_pos.east_m) < sq(acceptance_radius_m);
}
<|endoftext|>


<commit_before>// This program demonstrates the use ports by setting up a simple
// pipeline. All processes create an identical pipeline:
// vtkImageReader -> vtkContourFilter -> vtkElevationFilter
// In addition, the first (root) process creates n input ports
// (where n=nProcs-1), each attached to an output port on the other
// processes. It then appends the polygonal output from all input
// ports and it's own pipeline and renders the result ISO_NUM times,
// each time setting a different scalar value to be contoured.

#include "vtkImageReader.h"
#include "vtkContourFilter.h"
#include "vtkAppendPolyData.h"
#include "vtkOutputPort.h"
#include "vtkInputPort.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkElevationFilter.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkTimerLog.h"
#include "vtkMath.h"
#include "vtkWindowToImageFilter.h"
#include "vtkTIFFWriter.h"
#include "vtkMultiProcessController.h"

static const float ISO_START=4250.0;
static const float ISO_STEP=-1250.0;
static const int ISO_NUM=3;
// Just pick a tag which is available
static const int ISO_VALUE_RMI_TAG=300;
static const int PORT_TAG=999;

// call back to set the iso surface value.
void SetIsoValueRMI(void *localArg, void *remoteArg,
		  int remoteArgLen, int id)
{
  float val;

  vtkContourFilter *iso;
  iso = (vtkContourFilter *)localArg;
  val = iso->GetValue(0);
  iso->SetValue(0, val + ISO_STEP);
}

// This will be called by all processes
void MyMain( vtkMultiProcessController *controller, void *arg )
{
  vtkImageReader *reader;
  vtkContourFilter *iso;
  vtkElevationFilter *elev;
  int myid, numProcs;
  float val;
  int numTris;
  char *save_filename = (char*)arg;

  // Obtain the id of the running process and the total
  // number of processes
  myid = controller->GetLocalProcessId();
  numProcs = controller->GetNumberOfProcesses();

  // Create the reader, the data file name might have
  // to be changed depending on where the data files are.
  reader = vtkImageReader::New();
  reader->SetDataByteOrderToLittleEndian();
  reader->SetDataExtent(0, 127, 0, 127, 1, 93);
  reader->SetFilePrefix("../../../../vtkdata/headsq/half");
  reader->SetDataSpacing(1.6, 1.6, 1.5);

  // Iso-surface.
  iso = vtkContourFilter::New();
  iso->SetInput(reader->GetOutput());
  iso->SetValue(0, ISO_START);
  iso->ComputeScalarsOff();
  iso->ComputeGradientsOff();

  // Compute a different color for each process.
  elev = vtkElevationFilter::New();
  elev->SetInput(iso->GetOutput());
  vtkMath::RandomSeed(myid * 100);
  val = vtkMath::Random();
  elev->SetScalarRange(val, val+0.001);

  if (myid != 0)
    {
    // If I am not the root process

    // Satellite process! Send data through port.
    vtkOutputPort *upPort = vtkOutputPort::New();

    // Last, set up a RMI call back to change the iso surface value.
    // This is done so that the root process can let this process
    // know that it wants the contour value to change.
    controller->AddRMI(SetIsoValueRMI, (void *)iso, ISO_VALUE_RMI_TAG);

    // connect the port to the output of the pipeline
    upPort->SetInput(elev->GetPolyDataOutput());

    // Multiple ports can go through the same connection.
    // This is used to differentiate ports
    upPort->SetTag(PORT_TAG);

    // Loop which processes RMI requests.
    // Use vtkMultiProcessController::BREAK_RMI_TAG to break it.
    // The root process with send a ISO_VALUE_RMI_TAG to make this
    // process change it's contour value.
    upPort->WaitForUpdate();

    // We are done. Clean up.
    upPort->Delete();
    }
  else
    {
    // If I am the root process

    int i, j;
    vtkAppendPolyData *app = vtkAppendPolyData::New();
    vtkInputPort *downPort;
    vtkRenderer *ren = vtkRenderer::New();
    vtkRenderWindow *renWindow = vtkRenderWindow::New();
    vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
    vtkActor *actor = vtkActor::New();
    vtkTimerLog *timer = vtkTimerLog::New();
    vtkCamera *cam = vtkCamera::New();

    // Add my pipeline's output to the append filter
    app->AddInput(elev->GetPolyDataOutput());

    // ###################### important ####################
    // # This tells the append filter to request pieces from
    // # each of its inputs.  Since each of its inputs comes from
    // # a different process,  each process generates a separate
    // # piece of the data (data parallelism).
    // # If this is not used, all processes will iso-surface
    // # all the data.
    app->ParallelStreamingOn();

    // This is the main thread: Collect the data and render it.
    for (i = 1; i < numProcs; ++i)
      {
      downPort = vtkInputPort::New();
      downPort->SetRemoteProcessId(i);

      // Multiple ports can go through the same connection.
      // This is used to differentiate ports
      downPort->SetTag(PORT_TAG);

      app->AddInput(downPort->GetPolyDataOutput());

      // Reference already incremented by AddInput(). Delete()
      // will only decrement the count, not destroy the object.
      // The ports will be destroyed when the append filter
      // goes away.
      downPort->Delete();
      downPort = NULL;
      }

    // Create the rendering part of the pipeline
    renWindow->AddRenderer(ren);
    iren->SetRenderWindow(renWindow);
    ren->SetBackground(0.9, 0.9, 0.9);
    renWindow->SetSize( 400, 400);

    mapper->SetInput(app->GetOutput());
    actor->SetMapper(mapper);

    ren->AddActor(actor);

    cam->SetFocalPoint(100, 100, 65);
    cam->SetPosition(100, 450, 65);
    cam->SetViewUp(0, 0, -1);
    cam->SetViewAngle(30);

    cam->SetClippingRange(177.0, 536.0);
    ren->SetActiveCamera(cam);

    // loop through some iso surface values.
    for (j = 0; j < ISO_NUM; ++j)
      {
      // set the local value
      SetIsoValueRMI((void*)iso, NULL, 0, 0);
      for (i = 1; i < numProcs; ++i)
	{
	// trigger the RMI to change the iso surface value.
	controller->TriggerRMI(i, ISO_VALUE_RMI_TAG);
	}

      // Time the rendering. Note that the execution on all processes
      // start only after Update()
      timer->StartTimer();
      app->Update();
      timer->StopTimer();
      numTris = iso->GetOutput()->GetNumberOfCells();
      val = iso->GetValue(0);
      cerr << "Update " << val << " took " << timer->GetElapsedTime()
	   << " seconds to produce " << numTris << " triangles\n";

      // now render the results
      renWindow->Render();
      }

    if (save_filename[0] != '\0')
      {
      // Save an image if we need to for regression test.
      vtkWindowToImageFilter *w2if = vtkWindowToImageFilter::New();
      vtkTIFFWriter *rttiffw = vtkTIFFWriter::New();
      w2if->SetInput(renWindow);
      rttiffw->SetInput(w2if->GetOutput());
      rttiffw->SetFileName(save_filename);
      rttiffw->Write();
      }
    else
      {
      //  Begin mouse interaction
      iren->Start();
      }

    // Tell the other processors to stop processing RMIs.
    for (i = 1; i < numProcs; ++i)
      {
      controller->TriggerRMI(i, vtkMultiProcessController::BREAK_RMI_TAG);
      }

    // Clean up
    app->Delete();
    ren->Delete();
    renWindow->Delete();
    iren->Delete();
    mapper->Delete();
    actor->Delete();
    }

  // clean up objects in all processes.
  reader->Delete();
  iso->Delete();
  elev->Delete();
}

int main( int argc, char *argv[] )
{
  vtkMultiProcessController *controller;
  char save_filename[100];

  save_filename[0] = '\0';

  if( (argc >= 2) && (strcmp("-S", argv[argc-1]) == 0) )
    {
    sprintf( save_filename, "%s.cxx.tif", argv[0] );
    }

  // Note that this will create a vtkMPIController if MPI
  // is configured, vtkThreadedController otherwise.
  controller = vtkMultiProcessController::New();

  controller->Initialize(&argc, &argv);

  controller->SetSingleMethod(MyMain, save_filename);

  // When using MPI, the number of processes is determined
  // by the external program which launches this application.
  // However, when using threads, we need to set it ourselves.
  if (controller->IsA("vtkThreadedController"))
    {
    // Set the number of processes to 2 for this example.
    controller->SetNumberOfProcesses(2);
    }
  controller->SingleMethodExecute();

  controller->Finalize();
  controller->Delete();
  return 0;
}

<commit_msg>Forgot to remove unnecessary code.<commit_after>// This program demonstrates the use ports by setting up a simple
// pipeline. All processes create an identical pipeline:
// vtkImageReader -> vtkContourFilter -> vtkElevationFilter
// In addition, the first (root) process creates n input ports
// (where n=nProcs-1), each attached to an output port on the other
// processes. It then appends the polygonal output from all input
// ports and it's own pipeline and renders the result ISO_NUM times,
// each time setting a different scalar value to be contoured.

#include "vtkImageReader.h"
#include "vtkContourFilter.h"
#include "vtkAppendPolyData.h"
#include "vtkOutputPort.h"
#include "vtkInputPort.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkElevationFilter.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkTimerLog.h"
#include "vtkMath.h"
#include "vtkWindowToImageFilter.h"
#include "vtkTIFFWriter.h"
#include "vtkMultiProcessController.h"
#include "vtkGetDataRoot.h"

static const float ISO_START=4250.0;
static const float ISO_STEP=-1250.0;
static const int ISO_NUM=3;
// Just pick a tag which is available
static const int ISO_VALUE_RMI_TAG=300;
static const int PORT_TAG=999;

// call back to set the iso surface value.
void SetIsoValueRMI(void *localArg, void *remoteArg,
		  int remoteArgLen, int id)
{
  float val;

  vtkContourFilter *iso;
  iso = (vtkContourFilter *)localArg;
  val = iso->GetValue(0);
  iso->SetValue(0, val + ISO_STEP);
}

// This will be called by all processes
void MyMain( vtkMultiProcessController *controller, void *arg )
{
  vtkImageReader *reader;
  vtkContourFilter *iso;
  vtkElevationFilter *elev;
  int myid, numProcs;
  float val;
  int numTris;
  char* fname = reinterpret_cast<char*>(arg);

  // Obtain the id of the running process and the total
  // number of processes
  myid = controller->GetLocalProcessId();
  numProcs = controller->GetNumberOfProcesses();

  // Create the reader, the data file name might have
  // to be changed depending on where the data files are.
  reader = vtkImageReader::New();
  reader->SetDataByteOrderToLittleEndian();
  reader->SetDataExtent(0, 63, 0, 63, 1, 93);
  reader->SetFilePrefix(fname);
  reader->SetDataSpacing(3.2, 3.2, 1.5);

  // Iso-surface.
  iso = vtkContourFilter::New();
  iso->SetInput(reader->GetOutput());
  iso->SetValue(0, ISO_START);
  iso->ComputeScalarsOff();
  iso->ComputeGradientsOff();

  // Compute a different color for each process.
  elev = vtkElevationFilter::New();
  elev->SetInput(iso->GetOutput());
  vtkMath::RandomSeed(myid * 100);
  val = vtkMath::Random();
  elev->SetScalarRange(val, val+0.001);

  if (myid != 0)
    {
    // If I am not the root process

    // Satellite process! Send data through port.
    vtkOutputPort *upPort = vtkOutputPort::New();

    // Last, set up a RMI call back to change the iso surface value.
    // This is done so that the root process can let this process
    // know that it wants the contour value to change.
    controller->AddRMI(SetIsoValueRMI, (void *)iso, ISO_VALUE_RMI_TAG);

    // connect the port to the output of the pipeline
    upPort->SetInput(elev->GetPolyDataOutput());

    // Multiple ports can go through the same connection.
    // This is used to differentiate ports
    upPort->SetTag(PORT_TAG);

    // Loop which processes RMI requests.
    // Use vtkMultiProcessController::BREAK_RMI_TAG to break it.
    // The root process with send a ISO_VALUE_RMI_TAG to make this
    // process change it's contour value.
    upPort->WaitForUpdate();

    // We are done. Clean up.
    upPort->Delete();
    }
  else
    {
    // If I am the root process

    int i, j;
    vtkAppendPolyData *app = vtkAppendPolyData::New();
    vtkInputPort *downPort;
    vtkRenderer *ren = vtkRenderer::New();
    vtkRenderWindow *renWindow = vtkRenderWindow::New();
    vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
    vtkActor *actor = vtkActor::New();
    vtkTimerLog *timer = vtkTimerLog::New();
    vtkCamera *cam = vtkCamera::New();

    // Add my pipeline's output to the append filter
    app->AddInput(elev->GetPolyDataOutput());

    // ###################### important ####################
    // # This tells the append filter to request pieces from
    // # each of its inputs.  Since each of its inputs comes from
    // # a different process,  each process generates a separate
    // # piece of the data (data parallelism).
    // # If this is not used, all processes will iso-surface
    // # all the data.
    app->ParallelStreamingOn();

    // This is the main thread: Collect the data and render it.
    for (i = 1; i < numProcs; ++i)
      {
      downPort = vtkInputPort::New();
      downPort->SetRemoteProcessId(i);

      // Multiple ports can go through the same connection.
      // This is used to differentiate ports
      downPort->SetTag(PORT_TAG);

      app->AddInput(downPort->GetPolyDataOutput());

      // Reference already incremented by AddInput(). Delete()
      // will only decrement the count, not destroy the object.
      // The ports will be destroyed when the append filter
      // goes away.
      downPort->Delete();
      downPort = NULL;
      }

    // Create the rendering part of the pipeline
    renWindow->AddRenderer(ren);
    iren->SetRenderWindow(renWindow);
    ren->SetBackground(0.9, 0.9, 0.9);
    renWindow->SetSize( 400, 400);

    mapper->SetInput(app->GetOutput());
    actor->SetMapper(mapper);

    ren->AddActor(actor);

    cam->SetFocalPoint(100, 100, 65);
    cam->SetPosition(100, 450, 65);
    cam->SetViewUp(0, 0, -1);
    cam->SetViewAngle(30);

    cam->SetClippingRange(177.0, 536.0);
    ren->SetActiveCamera(cam);

    // loop through some iso surface values.
    for (j = 0; j < ISO_NUM; ++j)
      {
      // set the local value
      SetIsoValueRMI((void*)iso, NULL, 0, 0);
      for (i = 1; i < numProcs; ++i)
	{
	// trigger the RMI to change the iso surface value.
	controller->TriggerRMI(i, ISO_VALUE_RMI_TAG);
	}

      // Time the rendering. Note that the execution on all processes
      // start only after Update()
      timer->StartTimer();
      app->Update();
      timer->StopTimer();
      numTris = iso->GetOutput()->GetNumberOfCells();
      val = iso->GetValue(0);
      cerr << "Update " << val << " took " << timer->GetElapsedTime()
	   << " seconds to produce " << numTris << " triangles\n";

      // now render the results
      renWindow->Render();
      }

    // Tell the other processors to stop processing RMIs.
    for (i = 1; i < numProcs; ++i)
      {
      controller->TriggerRMI(i, vtkMultiProcessController::BREAK_RMI_TAG);
      }

    // Clean up
    app->Delete();
    ren->Delete();
    renWindow->Delete();
    iren->Delete();
    mapper->Delete();
    actor->Delete();
    cam->Delete();
    timer->Delete();
    }

  // clean up objects in all processes.
  reader->Delete();
  iso->Delete();
  elev->Delete();
}

int main( int argc, char* argv[] )
{
  vtkMultiProcessController *controller;

  // Note that this will create a vtkMPIController if MPI
  // is configured, vtkThreadedController otherwise.
  controller = vtkMultiProcessController::New();

  controller->Initialize(&argc, &argv);

  // Use this method to get the place of the data directory.
  char* fname = vtkExpandDataFileName(argc, argv, "Data/headsq/quarter");

  controller->SetSingleMethod(MyMain, reinterpret_cast<void*>(fname));

  // When using MPI, the number of processes is determined
  // by the external program which launches this application.
  // However, when using threads, we need to set it ourselves.
  if (controller->IsA("vtkThreadedController"))
    {
    // Set the number of processes to 2 for this example.
    controller->SetNumberOfProcesses(2);
    }
  controller->SingleMethodExecute();

  delete[] fname;

  controller->Finalize();
  controller->Delete();

  return 0;
}

<|endoftext|>