<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013 Estimation and Control Library (ECL). All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name ECL nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file gps_checks.cpp
 * Perform pre-flight and in-flight GPS quality checks
 *
 * @author Paul Riseborough <p_riseborough@live.com.au>
 *
 */

#include "ekf.h"

#include <ecl.h>
#include <geo_lookup/geo_mag_declination.h>
#include <mathlib/mathlib.h>

// GPS pre-flight check bit locations
#define MASK_GPS_NSATS  (1<<0)
#define MASK_GPS_PDOP   (1<<1)
#define MASK_GPS_HACC   (1<<2)
#define MASK_GPS_VACC   (1<<3)
#define MASK_GPS_SACC   (1<<4)
#define MASK_GPS_HDRIFT (1<<5)
#define MASK_GPS_VDRIFT (1<<6)
#define MASK_GPS_HSPD   (1<<7)
#define MASK_GPS_VSPD   (1<<8)

bool Ekf::collect_gps(const gps_message &gps)
{
	// Run GPS checks always
	_gps_checks_passed = gps_is_good(gps);
	if (!_NED_origin_initialised && _gps_checks_passed) {
		// If we have good GPS data set the origin's WGS-84 position to the last gps fix
		double lat = gps.lat / 1.0e7;
		double lon = gps.lon / 1.0e7;
		map_projection_init_timestamped(&_pos_ref, lat, lon, _time_last_imu);

		// if we are already doing aiding, correct for the change in position since the EKF started navigationg
		if (_control_status.flags.opt_flow || _control_status.flags.gps || _control_status.flags.ev_pos || _control_status.flags.ev_vel) {
			double est_lat, est_lon;
			map_projection_reproject(&_pos_ref, -_state.pos(0), -_state.pos(1), &est_lat, &est_lon);
			map_projection_init_timestamped(&_pos_ref, est_lat, est_lon, _time_last_imu);
		}

		// Take the current GPS height and subtract the filter height above origin to estimate the GPS height of the origin
		_gps_alt_ref = 1e-3f * (float)gps.alt + _state.pos(2);
		_NED_origin_initialised = true;
		_last_gps_origin_time_us = _time_last_imu;

		// set the magnetic field data returned by the geo library using the current GPS position
		_mag_declination_gps = math::radians(get_mag_declination(lat, lon));
		_mag_inclination_gps = math::radians(get_mag_inclination(lat, lon));
		_mag_strength_gps = 0.01f * get_mag_strength(lat, lon);

		// request a reset of the yaw using the new declination
		_mag_yaw_reset_req = true;
		// save the horizontal and vertical position uncertainty of the origin
		_gps_origin_eph = gps.eph;
		_gps_origin_epv = gps.epv;

		// if the user has selected GPS as the primary height source, switch across to using it
		if (_params.vdist_sensor_type == VDIST_SENSOR_GPS) {
			ECL_INFO_TIMESTAMPED("EKF GPS checks passed (WGS-84 origin set, using GPS height)");
			_control_status.flags.baro_hgt = false;
			_control_status.flags.gps_hgt = true;
			_control_status.flags.rng_hgt = false;
			// zero the sensor offset
			_hgt_sensor_offset = 0.0f;
		} else {
			ECL_INFO_TIMESTAMPED("EKF GPS checks passed (WGS-84 origin set)");
		}
	}

	// start collecting GPS if there is a 3D fix and the NED origin has been set
	return _NED_origin_initialised && (gps.fix_type >= 3);
}

/*
 * Return true if the GPS solution quality is adequate to set an origin for the EKF
 * and start GPS aiding.
 * All activated checks must pass for 10 seconds.
 * Checks are activated using the EKF2_GPS_CHECK bitmask parameter
 * Checks are adjusted using the EKF2_REQ_* parameters
*/
bool Ekf::gps_is_good(const gps_message &gps)
{
	// Check the fix type
	_gps_check_fail_status.flags.fix = (gps.fix_type < 3);

	// Check the number of satellites
	_gps_check_fail_status.flags.nsats = (gps.nsats < _params.req_nsats);

	// Check the position dilution of precision
	_gps_check_fail_status.flags.pdop = (gps.pdop > _params.req_pdop);

	// Check the reported horizontal and vertical position accuracy
	_gps_check_fail_status.flags.hacc = (gps.eph > _params.req_hacc);
	_gps_check_fail_status.flags.vacc = (gps.epv > _params.req_vacc);

	// Check the reported speed accuracy
	_gps_check_fail_status.flags.sacc = (gps.sacc > _params.req_sacc);

	// check if GPS quality is degraded
	_gps_error_norm = fmaxf((gps.eph / _params.req_hacc) , (gps.epv / _params.req_vacc));
	_gps_error_norm = fmaxf(_gps_error_norm , (gps.sacc / _params.req_sacc));

	// Calculate time lapsed since last update, limit to prevent numerical errors and calculate a lowpass filter coefficient
	const float filt_time_const = 10.0f;
	float dt = fminf(fmaxf(float(_time_last_imu - _gps_pos_prev.timestamp) * 1e-6f, 0.001f), filt_time_const);
	float filter_coef = dt / filt_time_const;

	// The following checks are only valid when the vehicle is at rest
	double lat = gps.lat * 1.0e-7;
	double lon = gps.lon * 1.0e-7;
	if (!_control_status.flags.in_air && _vehicle_at_rest) {
		// Calculate position movement since last measurement
		float delta_posN = 0.0f;
		float delta_PosE = 0.0f;

		// calculate position movement since last GPS fix
		if (_gps_pos_prev.timestamp > 0) {
			map_projection_project(&_gps_pos_prev, lat, lon, &delta_posN, &delta_PosE);

		} else {
			// no previous position has been set
			map_projection_init_timestamped(&_gps_pos_prev, lat, lon, _time_last_imu);
			_gps_alt_prev = 1e-3f * (float)gps.alt;

		}

		// Calculate the horizontal drift velocity components and limit to 10x the threshold
		float vel_limit = 10.0f * _params.req_hdrift;
		float velN = fminf(fmaxf(delta_posN / dt, -vel_limit), vel_limit);
		float velE = fminf(fmaxf(delta_PosE / dt, -vel_limit), vel_limit);

		// Apply a low pass filter
		_gpsDriftVelN = velN * filter_coef + _gpsDriftVelN * (1.0f - filter_coef);
		_gpsDriftVelE = velE * filter_coef + _gpsDriftVelE * (1.0f - filter_coef);

		// Calculate the horizontal drift speed and fail if too high
		_gps_drift_metrics[0] = sqrtf(_gpsDriftVelN * _gpsDriftVelN + _gpsDriftVelE * _gpsDriftVelE);
		_gps_check_fail_status.flags.hdrift = (_gps_drift_metrics[0] > _params.req_hdrift);

		// Calculate the vertical drift velocity and limit to 10x the threshold
		float vz_drift_limit = 10.0f * _params.req_vdrift;
		float gps_alt_m = 1e-3f * (float)gps.alt;
		float velD = math::constrain(((_gps_alt_prev - gps_alt_m) / dt), -vz_drift_limit, vz_drift_limit);

		// Apply a low pass filter to the vertical velocity
		_gps_drift_velD = velD * filter_coef + _gps_drift_velD * (1.0f - filter_coef);

		// Fail if the vertical drift speed is too high
		_gps_drift_metrics[1] = fabsf(_gps_drift_velD);
		_gps_check_fail_status.flags.vdrift = (_gps_drift_metrics[1] > _params.req_vdrift);

		// Check the magnitude of the filtered horizontal GPS velocity
		float vxy_drift_limit = 10.0f * _params.req_hdrift;
		float gps_velN = fminf(fmaxf(gps.vel_ned[0], -vxy_drift_limit), vxy_drift_limit);
		float gps_velE = fminf(fmaxf(gps.vel_ned[1], -vxy_drift_limit), vxy_drift_limit);
		_gps_velN_filt = gps_velN * filter_coef + _gps_velN_filt * (1.0f - filter_coef);
		_gps_velE_filt  = gps_velE * filter_coef + _gps_velE_filt  * (1.0f - filter_coef);
		_gps_drift_metrics[2] = sqrtf(_gps_velN_filt * _gps_velN_filt + _gps_velE_filt * _gps_velE_filt);
		_gps_check_fail_status.flags.hspeed = (_gps_drift_metrics[2] > _params.req_hdrift);

		_gps_drift_updated = true;

	} else if (_control_status.flags.in_air) {
		// These checks are always declared as passed when flying
		// If on ground and moving, the last result before movement commenced is kept
		_gps_check_fail_status.flags.hdrift = false;
		_gps_check_fail_status.flags.vdrift = false;
		_gps_check_fail_status.flags.hspeed = false;
		_gps_drift_updated = false;

	} else {
		// This is the case where the vehicle is on ground and IMU movement is blocking the drift calculation
		_gps_drift_updated = true;

	}

	// save GPS fix for next time
	map_projection_init_timestamped(&_gps_pos_prev, lat, lon, _time_last_imu);
	_gps_alt_prev = 1e-3f * (float)gps.alt;

	// Check  the filtered difference between GPS and EKF vertical velocity
	float vz_diff_limit = 10.0f * _params.req_vdrift;
	float vertVel = fminf(fmaxf((gps.vel_ned[2] - _state.vel(2)), -vz_diff_limit), vz_diff_limit);
	_gps_velD_diff_filt = vertVel * filter_coef + _gps_velD_diff_filt * (1.0f - filter_coef);
	_gps_check_fail_status.flags.vspeed = (fabsf(_gps_velD_diff_filt) > _params.req_vdrift);

	// assume failed first time through
	if (_last_gps_fail_us == 0) {
		_last_gps_fail_us = _time_last_imu;
	}

	// if any user selected checks have failed, record the fail time
	if (
		_gps_check_fail_status.flags.fix ||
		(_gps_check_fail_status.flags.nsats   && (_params.gps_check_mask & MASK_GPS_NSATS)) ||
		(_gps_check_fail_status.flags.pdop    && (_params.gps_check_mask & MASK_GPS_PDOP)) ||
		(_gps_check_fail_status.flags.hacc    && (_params.gps_check_mask & MASK_GPS_HACC)) ||
		(_gps_check_fail_status.flags.vacc    && (_params.gps_check_mask & MASK_GPS_VACC)) ||
		(_gps_check_fail_status.flags.sacc    && (_params.gps_check_mask & MASK_GPS_SACC)) ||
		(_gps_check_fail_status.flags.hdrift  && (_params.gps_check_mask & MASK_GPS_HDRIFT)) ||
		(_gps_check_fail_status.flags.vdrift  && (_params.gps_check_mask & MASK_GPS_VDRIFT)) ||
		(_gps_check_fail_status.flags.hspeed  && (_params.gps_check_mask & MASK_GPS_HSPD)) ||
		(_gps_check_fail_status.flags.vspeed  && (_params.gps_check_mask & MASK_GPS_VSPD))
	) {
		_last_gps_fail_us = _time_last_imu;
	} else {
		_last_gps_pass_us = _time_last_imu;
	}

	// continuous period without fail of x seconds required to return a healthy status
	return _time_last_imu - _last_gps_fail_us > (uint64_t)_min_gps_health_time_us;
}
<commit_msg>Use helper function to switch to gps height<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013 Estimation and Control Library (ECL). All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name ECL nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file gps_checks.cpp
 * Perform pre-flight and in-flight GPS quality checks
 *
 * @author Paul Riseborough <p_riseborough@live.com.au>
 *
 */

#include "ekf.h"

#include <ecl.h>
#include <geo_lookup/geo_mag_declination.h>
#include <mathlib/mathlib.h>

// GPS pre-flight check bit locations
#define MASK_GPS_NSATS  (1<<0)
#define MASK_GPS_PDOP   (1<<1)
#define MASK_GPS_HACC   (1<<2)
#define MASK_GPS_VACC   (1<<3)
#define MASK_GPS_SACC   (1<<4)
#define MASK_GPS_HDRIFT (1<<5)
#define MASK_GPS_VDRIFT (1<<6)
#define MASK_GPS_HSPD   (1<<7)
#define MASK_GPS_VSPD   (1<<8)

bool Ekf::collect_gps(const gps_message &gps)
{
	// Run GPS checks always
	_gps_checks_passed = gps_is_good(gps);
	if (!_NED_origin_initialised && _gps_checks_passed) {
		// If we have good GPS data set the origin's WGS-84 position to the last gps fix
		double lat = gps.lat / 1.0e7;
		double lon = gps.lon / 1.0e7;
		map_projection_init_timestamped(&_pos_ref, lat, lon, _time_last_imu);

		// if we are already doing aiding, correct for the change in position since the EKF started navigationg
		if (_control_status.flags.opt_flow || _control_status.flags.gps || _control_status.flags.ev_pos || _control_status.flags.ev_vel) {
			double est_lat, est_lon;
			map_projection_reproject(&_pos_ref, -_state.pos(0), -_state.pos(1), &est_lat, &est_lon);
			map_projection_init_timestamped(&_pos_ref, est_lat, est_lon, _time_last_imu);
		}

		// Take the current GPS height and subtract the filter height above origin to estimate the GPS height of the origin
		_gps_alt_ref = 1e-3f * (float)gps.alt + _state.pos(2);
		_NED_origin_initialised = true;
		_last_gps_origin_time_us = _time_last_imu;

		// set the magnetic field data returned by the geo library using the current GPS position
		_mag_declination_gps = math::radians(get_mag_declination(lat, lon));
		_mag_inclination_gps = math::radians(get_mag_inclination(lat, lon));
		_mag_strength_gps = 0.01f * get_mag_strength(lat, lon);

		// request a reset of the yaw using the new declination
		_mag_yaw_reset_req = true;
		// save the horizontal and vertical position uncertainty of the origin
		_gps_origin_eph = gps.eph;
		_gps_origin_epv = gps.epv;

		// if the user has selected GPS as the primary height source, switch across to using it
		if (_params.vdist_sensor_type == VDIST_SENSOR_GPS) {
			ECL_INFO_TIMESTAMPED("EKF GPS checks passed (WGS-84 origin set, using GPS height)");
			setControlGPSHeight();
			// zero the sensor offset
			_hgt_sensor_offset = 0.0f;
		} else {
			ECL_INFO_TIMESTAMPED("EKF GPS checks passed (WGS-84 origin set)");
		}
	}

	// start collecting GPS if there is a 3D fix and the NED origin has been set
	return _NED_origin_initialised && (gps.fix_type >= 3);
}

/*
 * Return true if the GPS solution quality is adequate to set an origin for the EKF
 * and start GPS aiding.
 * All activated checks must pass for 10 seconds.
 * Checks are activated using the EKF2_GPS_CHECK bitmask parameter
 * Checks are adjusted using the EKF2_REQ_* parameters
*/
bool Ekf::gps_is_good(const gps_message &gps)
{
	// Check the fix type
	_gps_check_fail_status.flags.fix = (gps.fix_type < 3);

	// Check the number of satellites
	_gps_check_fail_status.flags.nsats = (gps.nsats < _params.req_nsats);

	// Check the position dilution of precision
	_gps_check_fail_status.flags.pdop = (gps.pdop > _params.req_pdop);

	// Check the reported horizontal and vertical position accuracy
	_gps_check_fail_status.flags.hacc = (gps.eph > _params.req_hacc);
	_gps_check_fail_status.flags.vacc = (gps.epv > _params.req_vacc);

	// Check the reported speed accuracy
	_gps_check_fail_status.flags.sacc = (gps.sacc > _params.req_sacc);

	// check if GPS quality is degraded
	_gps_error_norm = fmaxf((gps.eph / _params.req_hacc) , (gps.epv / _params.req_vacc));
	_gps_error_norm = fmaxf(_gps_error_norm , (gps.sacc / _params.req_sacc));

	// Calculate time lapsed since last update, limit to prevent numerical errors and calculate a lowpass filter coefficient
	const float filt_time_const = 10.0f;
	float dt = fminf(fmaxf(float(_time_last_imu - _gps_pos_prev.timestamp) * 1e-6f, 0.001f), filt_time_const);
	float filter_coef = dt / filt_time_const;

	// The following checks are only valid when the vehicle is at rest
	double lat = gps.lat * 1.0e-7;
	double lon = gps.lon * 1.0e-7;
	if (!_control_status.flags.in_air && _vehicle_at_rest) {
		// Calculate position movement since last measurement
		float delta_posN = 0.0f;
		float delta_PosE = 0.0f;

		// calculate position movement since last GPS fix
		if (_gps_pos_prev.timestamp > 0) {
			map_projection_project(&_gps_pos_prev, lat, lon, &delta_posN, &delta_PosE);

		} else {
			// no previous position has been set
			map_projection_init_timestamped(&_gps_pos_prev, lat, lon, _time_last_imu);
			_gps_alt_prev = 1e-3f * (float)gps.alt;

		}

		// Calculate the horizontal drift velocity components and limit to 10x the threshold
		float vel_limit = 10.0f * _params.req_hdrift;
		float velN = fminf(fmaxf(delta_posN / dt, -vel_limit), vel_limit);
		float velE = fminf(fmaxf(delta_PosE / dt, -vel_limit), vel_limit);

		// Apply a low pass filter
		_gpsDriftVelN = velN * filter_coef + _gpsDriftVelN * (1.0f - filter_coef);
		_gpsDriftVelE = velE * filter_coef + _gpsDriftVelE * (1.0f - filter_coef);

		// Calculate the horizontal drift speed and fail if too high
		_gps_drift_metrics[0] = sqrtf(_gpsDriftVelN * _gpsDriftVelN + _gpsDriftVelE * _gpsDriftVelE);
		_gps_check_fail_status.flags.hdrift = (_gps_drift_metrics[0] > _params.req_hdrift);

		// Calculate the vertical drift velocity and limit to 10x the threshold
		float vz_drift_limit = 10.0f * _params.req_vdrift;
		float gps_alt_m = 1e-3f * (float)gps.alt;
		float velD = math::constrain(((_gps_alt_prev - gps_alt_m) / dt), -vz_drift_limit, vz_drift_limit);

		// Apply a low pass filter to the vertical velocity
		_gps_drift_velD = velD * filter_coef + _gps_drift_velD * (1.0f - filter_coef);

		// Fail if the vertical drift speed is too high
		_gps_drift_metrics[1] = fabsf(_gps_drift_velD);
		_gps_check_fail_status.flags.vdrift = (_gps_drift_metrics[1] > _params.req_vdrift);

		// Check the magnitude of the filtered horizontal GPS velocity
		float vxy_drift_limit = 10.0f * _params.req_hdrift;
		float gps_velN = fminf(fmaxf(gps.vel_ned[0], -vxy_drift_limit), vxy_drift_limit);
		float gps_velE = fminf(fmaxf(gps.vel_ned[1], -vxy_drift_limit), vxy_drift_limit);
		_gps_velN_filt = gps_velN * filter_coef + _gps_velN_filt * (1.0f - filter_coef);
		_gps_velE_filt  = gps_velE * filter_coef + _gps_velE_filt  * (1.0f - filter_coef);
		_gps_drift_metrics[2] = sqrtf(_gps_velN_filt * _gps_velN_filt + _gps_velE_filt * _gps_velE_filt);
		_gps_check_fail_status.flags.hspeed = (_gps_drift_metrics[2] > _params.req_hdrift);

		_gps_drift_updated = true;

	} else if (_control_status.flags.in_air) {
		// These checks are always declared as passed when flying
		// If on ground and moving, the last result before movement commenced is kept
		_gps_check_fail_status.flags.hdrift = false;
		_gps_check_fail_status.flags.vdrift = false;
		_gps_check_fail_status.flags.hspeed = false;
		_gps_drift_updated = false;

	} else {
		// This is the case where the vehicle is on ground and IMU movement is blocking the drift calculation
		_gps_drift_updated = true;

	}

	// save GPS fix for next time
	map_projection_init_timestamped(&_gps_pos_prev, lat, lon, _time_last_imu);
	_gps_alt_prev = 1e-3f * (float)gps.alt;

	// Check  the filtered difference between GPS and EKF vertical velocity
	float vz_diff_limit = 10.0f * _params.req_vdrift;
	float vertVel = fminf(fmaxf((gps.vel_ned[2] - _state.vel(2)), -vz_diff_limit), vz_diff_limit);
	_gps_velD_diff_filt = vertVel * filter_coef + _gps_velD_diff_filt * (1.0f - filter_coef);
	_gps_check_fail_status.flags.vspeed = (fabsf(_gps_velD_diff_filt) > _params.req_vdrift);

	// assume failed first time through
	if (_last_gps_fail_us == 0) {
		_last_gps_fail_us = _time_last_imu;
	}

	// if any user selected checks have failed, record the fail time
	if (
		_gps_check_fail_status.flags.fix ||
		(_gps_check_fail_status.flags.nsats   && (_params.gps_check_mask & MASK_GPS_NSATS)) ||
		(_gps_check_fail_status.flags.pdop    && (_params.gps_check_mask & MASK_GPS_PDOP)) ||
		(_gps_check_fail_status.flags.hacc    && (_params.gps_check_mask & MASK_GPS_HACC)) ||
		(_gps_check_fail_status.flags.vacc    && (_params.gps_check_mask & MASK_GPS_VACC)) ||
		(_gps_check_fail_status.flags.sacc    && (_params.gps_check_mask & MASK_GPS_SACC)) ||
		(_gps_check_fail_status.flags.hdrift  && (_params.gps_check_mask & MASK_GPS_HDRIFT)) ||
		(_gps_check_fail_status.flags.vdrift  && (_params.gps_check_mask & MASK_GPS_VDRIFT)) ||
		(_gps_check_fail_status.flags.hspeed  && (_params.gps_check_mask & MASK_GPS_HSPD)) ||
		(_gps_check_fail_status.flags.vspeed  && (_params.gps_check_mask & MASK_GPS_VSPD))
	) {
		_last_gps_fail_us = _time_last_imu;
	} else {
		_last_gps_pass_us = _time_last_imu;
	}

	// continuous period without fail of x seconds required to return a healthy status
	return _time_last_imu - _last_gps_fail_us > (uint64_t)_min_gps_health_time_us;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/app/AppFactory.h"
#include "monarch/crypto/MessageDigest.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/data/json/JsonLd.h"
#include "monarch/data/rdfa/RdfaReader.h"
#include "monarch/http/HttpClient.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/logging/Logging.h"
#include "monarch/net/Url.h"
#include "monarch/util/StringTools.h"

#include <cstdio>

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::crypto;
using namespace monarch::data::json;
using namespace monarch::data::rdfa;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::util;

#define APP_NAME "monarch.apps.rdfa2jsonld.Rdfa2JsonLd"

namespace monarch
{
namespace apps
{
namespace rdfa2jsonld
{

static bool _processStream(
   InputStream* is, const char* srcName, const char* baseUri)
{
   bool rval;

   // read in rdfa
   RdfaReader reader;
   reader.setBaseUri(baseUri);
   DynamicObject dyno;
   rval = reader.start(dyno) && reader.read(is) && reader.finish();

   if(rval)
   {
      // normalize and hash output
      DynamicObject normalized;
      JsonLd::normalize(dyno, normalized);
      // digest normalized data
      MessageDigest md;
      string json = JsonWriter::writeToString(normalized, true, false);
      rval = md.start("SHA1") && md.update(json.c_str(), json.length());
      if(rval)
      {
         // print output
         if(srcName != NULL)
         {
            printf("RDFa to JSON-LD: '%s'\n", srcName);
         }
         else
         {
            printf("RDFa to JSON-LD:\n");
         }
         printf("Normalized SHA-1 hash: %s\n", md.getDigest().c_str());
         // output
         rval = JsonWriter::writeToStdOut(dyno, false, false);
      }
   }

   return rval;
}

static bool _processFile(const char* inFile, const char* baseUri)
{
   bool rval;

   string _baseUri = baseUri;
   if(_baseUri.length() == 0)
   {
      // set base URI based on file name
      string path;
      if(!File::getAbsolutePath(inFile, path))
      {
         MO_CAT_ERROR(MO_APP_CAT,
            "Error getting absolute path for '%s'.", inFile);
      }
      _baseUri = StringTools::format("file://%s", path.c_str());
   }
   string _srcName = ((inFile != NULL) ? inFile : "");
   if(_srcName.length() == 0)
   {
      _srcName = "stdin";
   }

   // prepare input stream
   File file((FileImpl*)NULL);
   FileInputStream* fis;
   if(inFile == NULL)
   {
      fis = new FileInputStream(FileInputStream::StdIn);
   }
   else
   {
      file = inFile;
      fis = new FileInputStream(file);
   }

   rval = _processStream(fis, _srcName.c_str(), _baseUri.c_str());

   // close input stream
   fis->close();
   delete fis;

   return rval;
}

static bool _processHttp(Url& url, const char* baseUri)
{
   bool rval;

   string _baseUri = baseUri;
   if(_baseUri.length() == 0)
   {
      // default to URL
      _baseUri = url.toString();
   }

   HttpClient client;

   rval = client.connect(&url);
   if(rval)
   {
      string content;
      HttpResponse* response = client.get(&url);
      if(response != NULL)
      {
         if(client.receiveContent(content))
         {
            ByteArrayInputStream is(content.c_str(), content.length());
            rval = _processStream(&is, _baseUri.c_str(), _baseUri.c_str());
         }
         else
         {
            MO_CAT_ERROR(MO_APP_CAT,
               "IO Exception for URL '%s'.", url.toString().c_str());
         }
      }
   }
   else
   {
      MO_CAT_ERROR(MO_APP_CAT,
         "Connection problem for URL '%s'.", url.toString().c_str());
   }

   client.disconnect();

   return rval;
}

class Rdfa2JsonLdApp : public App
{
public:
   Rdfa2JsonLdApp() {};
   virtual ~Rdfa2JsonLdApp() {};
   virtual DynamicObject getCommandLineSpec(Config& cfg)
   {
      // initialize config
      Config& c = cfg[ConfigManager::MERGE][APP_NAME];
      c["baseUri"] = "";

      DynamicObject spec;
      spec["help"] =
"Rdfa2JsonLd Options\n"
"      --base-uri      The base URI to use.\n"
"\n";

      DynamicObject opt(NULL);

      // create option to set base URI
      opt = spec["options"]->append();
      opt["long"] = "--base-uri";
      opt["argError"] = "Base URI must be a string.";
      opt["arg"]["root"] = c;
      opt["arg"]["path"] = "baseUri";

      // use extra options as files to process
      opt = spec["options"]->append();
      opt["extra"]["root"] = c;
      opt["extra"]["path"] = "urls";

      return spec;
   };

   /**
    * Runs the app.
    *
    * @return true if successful, false if an exception occurred.
    */
   virtual bool run()
   {
      Config cfg = getConfig()[APP_NAME];
      const char* baseUri = cfg["baseUri"];

      // process files
      DynamicObject& urls = cfg["urls"];
      if(urls->length() == 0)
      {
         printf("Reading RDFa from standard input...\n");

         if(strlen(baseUri) == 0)
         {
            // set a fake stdin base URI
            baseUri = "stdin";
         }

         // create file from std input
         _processFile(NULL, baseUri);
      }
      else
      {
         printf("Reading RDFa from URLs or files...\n");

         DynamicObjectIterator i = urls.getIterator();
         bool success = true;
         while(success && i->hasNext())
         {
            const char* next = i->next()->getString();

            Url url;
            if(url.setUrl(next))
            {
               string scheme = url.getScheme();
               if(scheme == "")
               {
                  // assume a regular file
                  success = _processFile(next, baseUri);
               }
               else if(scheme == "file")
               {
                  success = _processFile(url.getPath().c_str(), baseUri);
               }
               else if(scheme == "http" || scheme == "https")
               {
                  success = _processHttp(url, baseUri);
               }
               else
               {
                  MO_CAT_ERROR(MO_APP_CAT,
                     "Unknown URL scheme for '%s'.", next);
                  success = false;
               }
            }
            else
            {
               // failed to set as URL, assume a simple file string
               Exception::clear();
               success = _processFile(next, baseUri);
            }
         }
      }

      return !Exception::isSet();
   };
};

class Rdfa2JsonLdAppFactory : public AppFactory
{
public:
   Rdfa2JsonLdAppFactory() : AppFactory(APP_NAME, "1.0") {}
   virtual ~Rdfa2JsonLdAppFactory() {}
   virtual App* createApp()
   {
      return new Rdfa2JsonLdApp();
   }
};

} // end namespace rdfa2jsonld
} // end namespace apps
} // end namespace monarch

Module* createModestModule()
{
   return new monarch::apps::rdfa2jsonld::Rdfa2JsonLdAppFactory();
}

void freeModestModule(Module* m)
{
   delete m;
}
<commit_msg>Add options for filtering and normalization.<commit_after>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/app/AppFactory.h"
#include "monarch/crypto/MessageDigest.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/data/json/JsonLd.h"
#include "monarch/data/rdfa/RdfaReader.h"
#include "monarch/http/HttpClient.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/logging/Logging.h"
#include "monarch/net/Url.h"
#include "monarch/util/StringTools.h"

#include <cstdio>

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::crypto;
using namespace monarch::data::json;
using namespace monarch::data::rdfa;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::util;

#define APP_NAME "monarch.apps.rdfa2jsonld.Rdfa2JsonLd"

namespace monarch
{
namespace apps
{
namespace rdfa2jsonld
{

static bool _processStream(
   DynamicObject& options, InputStream* is, const char* srcName,
   const char* baseUri)
{
   bool rval;

   // options
   bool doFilter = options["filter"]->getBoolean();
   bool doNormalize = options["normalize"]->getBoolean();
   bool doHash = options["hash"]->getBoolean();
   bool doDump = options["dump"]->getBoolean();
   bool verbose = true;

   // read in rdfa
   RdfaReader reader;
   reader.setBaseUri(baseUri);
   DynamicObject dyno;
   rval = reader.start(dyno) && reader.read(is) && reader.finish();

   // pipe data as requested
   DynamicObject output = dyno;

   if(rval && doFilter)
   {
      DynamicObject& input = output;
      DynamicObject filtered;
      DynamicObject context(NULL);
      if(output->hasMember("#"))
      {
         // context from normalized data
         context = output["#"];
      }
      else
      {
         // empty context
         context = DynamicObject();
         context->setType(Map);
      }
      DynamicObject filter;
      filter["@"] = srcName;
      rval = JsonLd::filter(context, filter, input, filtered);
      if(rval)
      {
         output = filtered;
      }
   }

   if(rval && doNormalize)
   {
      DynamicObject& input = output;
      DynamicObject normalized;
      rval = JsonLd::normalize(input, normalized);
      if(rval)
      {
         output = normalized;
      }
   }

   string hash;
   if(rval && doHash)
   {
      // digest normalized data
      MessageDigest md;
      string json = JsonWriter::writeToString(output, true, false);
      rval = md.start("SHA1") && md.update(json.c_str(), json.length());
      if(rval)
      {
         hash = md.getDigest().c_str();
      }
   }

   if(rval)
   {
      if(verbose)
      {
         // print output
         printf("* RDFa to JSON-LD\n");
         printf("* <source>:\n%s\n",
            (srcName != NULL) ? srcName : "(unknown)");
      }
   }

   if(rval && doHash)
   {
      if(verbose)
      {
         // output info
         printf("* <source>|RDFa|JSON-LD|%s%s%s<stdout>:\n",
            doFilter ? "filter|" : "",
            doNormalize ? "normalize|" : "",
            doHash ? "SHA-1|" : "");
      }
      // output hash
      printf("%s\n", hash.c_str());
   }

   if(rval && doDump)
   {
      if(verbose)
      {
         // output info
         printf("* <source>|RDFa|JSON-LD|%s%s<stdout>:\n",
            doFilter ? "filter|" : "",
            doNormalize ? "normalize|" : "");
      }
      // output JSON-LD
      rval = JsonWriter::writeToStdOut(output, false, false);
   }

   return rval;
}

static bool _processFile(
   DynamicObject& options, const char* inFile, const char* baseUri)
{
   bool rval;

   string _baseUri = baseUri;
   if(_baseUri.length() == 0)
   {
      // set base URI based on file name
      string path;
      if(!File::getAbsolutePath(inFile, path))
      {
         MO_CAT_ERROR(MO_APP_CAT,
            "Error getting absolute path for '%s'.", inFile);
      }
      _baseUri = StringTools::format("file://%s", path.c_str());
   }
   string _srcName = ((inFile != NULL) ? inFile : "");
   if(_srcName.length() == 0)
   {
      _srcName = "stdin";
   }

   // prepare input stream
   File file((FileImpl*)NULL);
   FileInputStream* fis;
   if(inFile == NULL)
   {
      fis = new FileInputStream(FileInputStream::StdIn);
   }
   else
   {
      file = inFile;
      fis = new FileInputStream(file);
   }

   rval = _processStream(options, fis, _srcName.c_str(), _baseUri.c_str());

   // close input stream
   fis->close();
   delete fis;

   return rval;
}

static bool _processHttp(
   DynamicObject& options, Url& url, const char* baseUri)
{
   bool rval;

   string _baseUri = baseUri;
   if(_baseUri.length() == 0)
   {
      // default to URL
      _baseUri = url.toString();
   }

   HttpClient client;

   rval = client.connect(&url);
   if(rval)
   {
      string content;
      HttpResponse* response = client.get(&url);
      if(response != NULL)
      {
         if(client.receiveContent(content))
         {
            ByteArrayInputStream is(content.c_str(), content.length());
            rval = _processStream(
               options, &is, _baseUri.c_str(), _baseUri.c_str());
         }
         else
         {
            MO_CAT_ERROR(MO_APP_CAT,
               "IO Exception for URL '%s'.", url.toString().c_str());
         }
      }
   }
   else
   {
      MO_CAT_ERROR(MO_APP_CAT,
         "Connection problem for URL '%s'.", url.toString().c_str());
   }

   client.disconnect();

   return rval;
}

class Rdfa2JsonLdApp : public App
{
public:
   Rdfa2JsonLdApp() {};
   virtual ~Rdfa2JsonLdApp() {};
   virtual DynamicObject getCommandLineSpec(Config& cfg)
   {
      // initialize config
      Config& c = cfg[ConfigManager::MERGE][APP_NAME];
      c["baseUri"] = "";
      c["filter"] = false;
      c["normalize"] = false;
      c["hash"] = true;
      c["dump"] = true;
      c["verbose"] = true;

      DynamicObject spec;
      spec["help"] =
"Rdfa2JsonLd Options\n"
"      --base-uri      The base URI to use.\n"
"      --filter        Filter for source URI properties.\n"
"      --no-filter     Do not filter on source URI. (default)\n"
"      --normalize     Normalize JSON-LD.\n"
"      --no-normalize  Do not normalize JSON-LD. (default)\n"
"      --hash          Hash JSON-LD. (default).\n"
"      --no-hash       Do not hash JSON-LD.\n"
"      --dump          Dump JSON-LD. (default).\n"
"      --no-dump       Do not dump JSON-LD.\n"
"      --verbose       Verbose output. (default).\n"
"      --quiet         Quieter output.\n"
"\n";

      DynamicObject opt(NULL);

      // create option to set base URI
      opt = spec["options"]->append();
      opt["long"] = "--base-uri";
      opt["argError"] = "Base URI must be a string.";
      opt["arg"]["root"] = c;
      opt["arg"]["path"] = "baseUri";

      // simple boolean options
      DynamicObject bools;
      bools->append("filter");
      bools->append("normalize");
      bools->append("hash");
      bools->append("dump");

      DynamicObjectIterator i = bools.getIterator();
      while(i->hasNext())
      {
         DynamicObject& next = i->next();
         const char* name = next->getString();

         // do it
         opt = spec["options"]->append();
         opt["long"]->format("--%s", name);
         opt["setTrue"]["root"] = c;
         opt["setTrue"]["path"] = name;

         // do not do it
         opt = spec["options"]->append();
         opt["long"]->format("--no-%s", name);
         opt["setFalse"]["root"] = c;
         opt["setFalse"]["path"] = name;
      }

      // verbose output
      opt = spec["options"]->append();
      opt["long"] = "--verbose";
      opt["setTrue"]["root"] = c;
      opt["setTrue"]["path"] = "verbose";

      // quiet output
      opt = spec["options"]->append();
      opt["long"] = "--quiet";
      opt["setFalse"]["root"] = c;
      opt["setFalse"]["path"] = "verbose";

      // use extra options as files to process
      opt = spec["options"]->append();
      opt["extra"]["root"] = c;
      opt["extra"]["path"] = "urls";

      return spec;
   };

   /**
    * Runs the app.
    *
    * @return true if successful, false if an exception occurred.
    */
   virtual bool run()
   {
      Config cfg = getConfig()[APP_NAME];
      const char* baseUri = cfg["baseUri"];

      // process files
      DynamicObject& urls = cfg["urls"];
      if(urls->length() == 0)
      {
         printf("Reading RDFa from standard input...\n");

         if(strlen(baseUri) == 0)
         {
            // set a fake stdin base URI
            baseUri = "stdin";
         }

         // create file from std input
         _processFile(cfg, NULL, baseUri);
      }
      else
      {
         printf("Reading RDFa from URLs or files...\n");

         DynamicObjectIterator i = urls.getIterator();
         bool success = true;
         while(success && i->hasNext())
         {
            const char* next = i->next()->getString();

            Url url;
            if(url.setUrl(next))
            {
               string scheme = url.getScheme();
               if(scheme == "")
               {
                  // assume a regular file
                  success = _processFile(cfg, next, baseUri);
               }
               else if(scheme == "file")
               {
                  success = _processFile(cfg, url.getPath().c_str(), baseUri);
               }
               else if(scheme == "http" || scheme == "https")
               {
                  success = _processHttp(cfg, url, baseUri);
               }
               else
               {
                  MO_CAT_ERROR(MO_APP_CAT,
                     "Unknown URL scheme for '%s'.", next);
                  success = false;
               }
            }
            else
            {
               // failed to set as URL, assume a simple file string
               Exception::clear();
               success = _processFile(cfg, next, baseUri);
            }
         }
      }

      return !Exception::isSet();
   };
};

class Rdfa2JsonLdAppFactory : public AppFactory
{
public:
   Rdfa2JsonLdAppFactory() : AppFactory(APP_NAME, "1.0") {}
   virtual ~Rdfa2JsonLdAppFactory() {}
   virtual App* createApp()
   {
      return new Rdfa2JsonLdApp();
   }
};

} // end namespace rdfa2jsonld
} // end namespace apps
} // end namespace monarch

Module* createModestModule()
{
   return new monarch::apps::rdfa2jsonld::Rdfa2JsonLdAppFactory();
}

void freeModestModule(Module* m)
{
   delete m;
}
<|endoftext|>


<commit_before>
/* We would like to have a tool that extracts translations for given
   authority data
   The german term is found in Field 150
   Currently there are two different kinds of translations:
   TxTheo-Translations with the following definitions:

   710: Körperschaft - fremdsprachige Äquivalenz
   711: Konferenz - fremdsprachige Äquivalenz
   700: Person - fremdsprachige Äquivalenz
   730: Titel - fremdsprachige Äquivalenz
   750: Sachbegriff - fremdsprachige Äquivalenz
   751: Geografikum - fremdsprachige Äquivalenz

   LoC/Rameau Translations:

   700: Person - Bevorzugter Name in einem anderen Datenbestand
   710: Körperschaft - Bevorzugter Name in einem anderen Datenbestand
   711: Konferenz - Bevorzugte Benennung in einem anderen Datenbestand
   730: Einheitstitel - Bevorzugter Name in einem anderen Datenbestand
   750: Sachbegriff - Bevorzugte Benennung in einem anderen Datenbestand
   751: Geografikum - Bevorzugter Name in einem anderen Datenbestand

*/

#include <iostream>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

// Languages to handle
//enum languages { "en","fr" };

const unsigned int NUMBER_OF_LANGUAGES = 2;
const std::string languages_to_create_str = "en, fr";
enum languages { en, fr };

void Usage() {
    std::cerr << "Usage: " << ::progname << " norm_data_marc_input extracted_translations\n";
    std::exit(EXIT_FAILURE);
}

void augment_ixtheo_tag_with_language(const MarcUtil::Record &record, const std::string tag, std::vector<std::string> &translations) {
    auto ixtheo_pos = std::find(translations.begin(), translations.end(), "IxTheo");
    if (ixtheo_pos != translations.end()) {
        std::vector<std::string> ixtheo_lang_code;
        record.extractSubfields(tag, "9" , &ixtheo_lang_code);
        for (auto lang_code : ixtheo_lang_code) {
            if (lang_code.find("eng") != std::string::npos && *ixtheo_pos != "IxTheo_eng")
               *ixtheo_pos = *ixtheo_pos + "_eng";
            // FIXME: There are currently no french translations...
            else if (lang_code.find("fra") != std::string::npos && *ixtheo_pos != "IxTheo_fra")
               *ixtheo_pos = *ixtheo_pos + "_fra";
        }
    }
}

void ExtractTranslations(File* const marc_norm_input,
                         const std::string german_term_field_spec,
                         const std::string translation_field_spec,
                         std::map<std::string,std::string> term_to_translation_map[]) {

    std::set<std::string> german_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(german_term_field_spec, ':', &german_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    std::set<std::string> translation_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(translation_field_spec, ':', &translation_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    unsigned count(0);

    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_norm_input)) {

        std::vector<std::string> german_term;

        // Determine the german term we will have translations for

        for (auto tag_and_subfields : german_tags_and_subfield_codes) {
             const std::string tag(tag_and_subfields.substr(0, 3));
             const std::string subfields(tag_and_subfields.substr(3));

             std::vector<std::string> german_term_for_one_field;
             record.extractSubfields(tag, subfields, &german_term_for_one_field);

             // We may get the german term from only one field
             if (german_term.size() > 1)
                 Warning("We have german terms in more than one field for PPN: " + record.getFields()[0]);

             if (not german_term_for_one_field.empty())
                 german_term = german_term_for_one_field;
        }

        std::vector<std::string> all_translations;

        // Extract all additional translations

        for (auto tag_and_subfields : translation_tags_and_subfield_codes) {
            const std::string tag(tag_and_subfields.substr(0, 3));
            const std::string subfields(tag_and_subfields.substr(3));

            std::vector<std::string> translations;
            record.extractSubfields(tag, subfields, &translations);

            // For IxTheo-Translations add the language code in the same field
            augment_ixtheo_tag_with_language(record, tag, translations);

            all_translations.insert(std::end(all_translations), std::begin(translations), std::end(translations));
        }

        for (auto it = all_translations.begin(); it != all_translations.end(); it++) {
            if (*it == "IxTheo_eng") {
                term_to_translation_map[en].emplace(StringUtil::Join(german_term, ' '), *(it+1));
                ++it;
            }
            else if (*it == "IxTheo_fra") {
                term_to_translation_map[fr].emplace(StringUtil::Join(german_term, ' '), *(it+1));
                ++it;
            }

            else if (*it == "lcsh") {
                term_to_translation_map[en].emplace(StringUtil::Join(german_term, ' '), *(it+1));
                ++it;
            }
            else if (*it == "ram") {
                term_to_translation_map[fr].emplace(StringUtil::Join(german_term, ' '), *(it+1));
                ++it;
            }

        }

    }

    count++;

}

std::unique_ptr<File> OpenInputFile(const std::string &filename) {
    std::string mode("r");
    mode += MediaTypeUtil::GetFileMediaType(filename) == "application/lz4" ? "u" : "m";
    std::unique_ptr<File> file(new File(filename, mode));
    if (file == nullptr)
        Error("can't open \"" + filename + "\" for reading!");

    return file;
}

int main(int argc, char **argv) {
    progname = argv[0];

    if (argc != 3)
        Usage();

    const std::string norm_data_marc_input_filename(argv[1]);
    std::unique_ptr<File> norm_data_marc_input(OpenInputFile(norm_data_marc_input_filename));

    const std::string extracted_translations_filename(argv[2]);
    if (unlikely(norm_data_marc_input_filename == extracted_translations_filename))
        Error("Norm data input file name equals output file name!");

    std::string output_mode("w");
    if (norm_data_marc_input->isCompressingOrUncompressing())
        output_mode += 'c';

    // Create a file for each language
    std::vector<std::string> output_file_components;
    if (unlikely(StringUtil::Split(extracted_translations_filename, ".", &output_file_components) < 1))
        Error("extracted_translations_filename " + extracted_translations_filename + " is not valid");

    std::vector<std::string> languages_to_create;
    if (unlikely(StringUtil::Split(languages_to_create_str, ',', &languages_to_create) < 1))
        Error("String " + languages_to_create_str + " is not valid");

    File* lang_file[NUMBER_OF_LANGUAGES];
    unsigned i(0);

    // Derive output components from given input filename
    std::string extension = (output_file_components.size() > 1) ? output_file_components.back() : "";
    std::string basename;
    if (extension != "")
        output_file_components.pop_back();
    basename = StringUtil::Join(output_file_components, ".");

    // Assemble output filename
    for (auto lang : languages_to_create) {
         lang = StringUtil::Trim(lang);

         std::string lang_file_name_str =
             (extension != "") ? basename + "_" + lang + "." + extension : basename + "_" + lang;

         lang_file[i++] = new File(lang_file_name_str, output_mode);
         if (lang_file[i] == NULL)
             Error("can't open \"" + lang_file_name_str + "\" for writing!");
    }

    try {
        std::map<std::string, std::string> term_to_translation_map[NUMBER_OF_LANGUAGES];

        ExtractTranslations(norm_data_marc_input.get(), "100a:150a", "750a2", term_to_translation_map);
        for (auto line : term_to_translation_map[en]) {

             *(lang_file[en]) << line.first << "|" << line.second << "\n";
        }

        for (auto line : term_to_translation_map[fr]) {
             *(lang_file[fr]) << line.first << "|" << line.second << "\n";
        }

    } catch (const std::exception &x) {
      Error("caught exception: " + std::string(x.what()));
    }

}

<commit_msg>Changes as desired<commit_after>/** \file    extract_normdata_translations.cc
 *  \brief   Extract IxTheo and MACS translations from the normdata file and write it to
 *           language specific text files
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* The German term is found in Field 150
   Currently there are two different kinds of translations:
   IxTheo-Translations with the following definitions:

   710: Körperschaft - fremdsprachige Äquivalenz
   711: Konferenz - fremdsprachige Äquivalenz
   700: Person - fremdsprachige Äquivalenz
   730: Titel - fremdsprachige Äquivalenz
   750: Sachbegriff - fremdsprachige Äquivalenz
   751: Geografikum - fremdsprachige Äquivalenz

   LoC/Rameau Translations:
   700: Person - Bevorzugter Name in einem anderen Datenbestand
   710: Körperschaft - Bevorzugter Name in einem anderen Datenbestand
   711: Konferenz - Bevorzugte Benennung in einem anderen Datenbestand
   730: Einheitstitel - Bevorzugter Name in einem anderen Datenbestand
   750: Sachbegriff - Bevorzugte Benennung in einem anderen Datenbestand
   751: Geografikum - Bevorzugter Name in einem anderen Datenbestand
*/
#include <iostream>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

// Languages to handle
const unsigned int NUMBER_OF_LANGUAGES = 2;
const std::vector<std::string> languages_to_create{ "en", "fr" };
enum languages { en, fr };

void Usage() {
    std::cerr << "Usage: " << ::progname << " norm_data_marc_input extracted_translations\n";
    std::exit(EXIT_FAILURE);
}

void augmentIxTheoTagWithLanguage(const MarcUtil::Record &record, const std::string &tag, std::vector<std::string> * const translations) {
    auto ixtheo_pos = std::find(translations->begin(), translations->end(), "IxTheo");
    if (ixtheo_pos != translations->end()) {
        std::vector<std::string> ixtheo_lang_code;
        record.extractSubfields(tag, "9" , &ixtheo_lang_code);
        for (auto lang_code : ixtheo_lang_code) {
            if (lang_code.find("eng") != std::string::npos and *ixtheo_pos != "IxTheo_eng")
               *ixtheo_pos += "_eng";
            else if (lang_code.find("fra") != std::string::npos and *ixtheo_pos != "IxTheo_fra")
               *ixtheo_pos += "_fra";
            else
                Warning("Unsupported language code " + lang_code);
        }
    }
}

void ExtractTranslations(File* const marc_norm_input,
                         const std::string german_term_field_spec,
                         const std::string translation_field_spec,
                         std::map<std::string,std::string> term_to_translation_map[])
{
    std::set<std::string> german_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(german_term_field_spec, ':', &german_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    std::set<std::string> translation_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(translation_field_spec, ':', &translation_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    unsigned count(0);

    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_norm_input)) {
        std::vector<std::string> german_term;

        // Determine the German term we will have translations for
        for (const auto tag_and_subfields : german_tags_and_subfield_codes) {
             const std::string tag(tag_and_subfields.substr(0, 3));
             const std::string subfields(tag_and_subfields.substr(3));

             std::vector<std::string> german_term_for_one_field;
             record.extractSubfields(tag, subfields, &german_term_for_one_field);

             // We may get the german term from only one field
             if (german_term.size() > 1)
                 Warning("We have german terms in more than one field for PPN: " + record.getFields()[0]);

             if (not german_term_for_one_field.empty())
                 german_term = german_term_for_one_field;
        }

        std::vector<std::string> all_translations;

        // Extract all additional translations
        for (auto tag_and_subfields : translation_tags_and_subfield_codes) {
            const std::string tag(tag_and_subfields.substr(0, 3));
            const std::string subfields(tag_and_subfields.substr(3));

            std::vector<std::string> translations;
            record.extractSubfields(tag, subfields, &translations);

            // For IxTheo-Translations add the language code in the same field
            augmentIxTheoTagWithLanguage(record, tag, &translations);

            all_translations.insert(all_translations.end(), translations.begin(), translations.end());
        }

        for (auto it = all_translations.begin(); it != all_translations.end(); ++it) {
            if (*it == "IxTheo_eng") {
                term_to_translation_map[en].emplace(StringUtil::Join(german_term, ' '), *(it + 1));
                ++it;
            } else if (*it == "IxTheo_fra") {
                term_to_translation_map[fr].emplace(StringUtil::Join(german_term, ' '), *(it + 1));
                ++it;
            } else if (*it == "lcsh") {
                term_to_translation_map[en].emplace(StringUtil::Join(german_term, ' '), *(it + 1));
                ++it;
            } else if (*it == "ram") {
                term_to_translation_map[fr].emplace(StringUtil::Join(german_term, ' '), *(it + 1));
                ++it;
            }
        }
    }
    ++count;
}

std::unique_ptr<File> OpenInputFile(const std::string &filename) {
    std::string mode("r");
    if (MediaTypeUtil::GetFileMediaType(filename) == "application/lz4")
        mode += "u";
    std::unique_ptr<File> file(new File(filename, mode));
    if (file->fail())
        Error("can't open \"" + filename + "\" for reading!");

    return file;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    const std::string norm_data_marc_input_filename(argv[1]);
    std::unique_ptr<File> norm_data_marc_input(OpenInputFile(norm_data_marc_input_filename));

    const std::string extracted_translations_filename(argv[2]);
    if (unlikely(norm_data_marc_input_filename == extracted_translations_filename))
        Error("Norm data input file name equals output file name!");

    std::string output_mode("w");
    if (norm_data_marc_input->isCompressingOrUncompressing())
        output_mode += 'c';

    // Create a file for each language
    std::vector<std::string> output_file_components;
    if (unlikely(StringUtil::Split(extracted_translations_filename, ".", &output_file_components) < 1))
        Error("extracted_translations_filename " + extracted_translations_filename + " is not valid");

    File *lang_files[NUMBER_OF_LANGUAGES];
    unsigned i(0);

    // Derive output components from given input filename
    std::string extension = (output_file_components.size() > 1) ? output_file_components.back() : "";
    std::string basename;
    if (not extension.empty())
        output_file_components.pop_back();
    basename = StringUtil::Join(output_file_components, ".");

    // Assemble output filename
    for (auto lang : languages_to_create) {
         lang = StringUtil::Trim(lang);

         std::string lang_file_name_str =
             (extension != "") ? basename + "_" + lang + "." + extension : basename + "_" + lang;

         lang_files[i++] = new File(lang_file_name_str, output_mode);
         if (lang_files[i]->fail())
             Error("can't open \"" + lang_file_name_str + "\" for writing!");
    }

    try {
        std::map<std::string, std::string> term_to_translation_map[NUMBER_OF_LANGUAGES];

        ExtractTranslations(norm_data_marc_input.get(), "100a:150a", "750a2", term_to_translation_map);
        for (auto line : term_to_translation_map[en]) {

             *(lang_files[en]) << line.first << "|" << line.second << "\n";
        }

        for (auto line : term_to_translation_map[fr]) {
             *(lang_files[fr]) << line.first << "|" << line.second << "\n";
        }

    } catch (const std::exception &x) {
      Error("caught exception: " + std::string(x.what()));
    }
}

<|endoftext|>


<commit_before>#include <server/server_interface.hpp>
#include <iostream>

ServerInterface::ServerInterface(zmq::context_t& context,
                                    std::string const& commandServer,
                                    std::string const& stateServer,
                                    std::string const& matchToken)
    : m_command(context, ZMQ_REQ), m_state(context, ZMQ_SUB),
        m_matchToken(matchToken)
{
    std::cout << "Connecting to command server " << commandServer << std::endl;
    m_command.connect(commandServer.c_str());
    std::cout << "Connecting to state server " << stateServer << std::endl;
    m_state.connect(stateServer.c_str());
}

ServerInterface::~ServerInterface() {
    std::cout << "Closing sockets." << std::endl;
    m_command.close();
    m_state.close();
}

bool ServerInterface::Initialize() {
    // Sends initial message to command server
    std::cout << "Initiating handshake... ";
    std::string const* requestS = m_factory.CreateInitMessage(m_matchToken);
    zmq::message_t request (requestS->size());
    memcpy(static_cast<void*>(request.data()), requestS->data(), requestS->size());
    delete requestS;
    m_command.send(request);

    // Subscribes to state server
    m_state.setsockopt(ZMQ_SUBSCRIBE, m_matchToken.c_str(), m_matchToken.size());

    zmq::message_t reply;
    m_command.recv(&reply);
    std::string replyS (static_cast<char const*>(reply.data()), reply.size());
    bool success = m_factory.ParseInitReply(replyS);
    if (success)
        std::cout << "Success!" << std::endl;
    else
        std::cout << "Failure." << std::endl;
    return success;
}

State const* ServerInterface::GetState() {
    zmq::message_t address;
    zmq::message_t state;
    m_state.recv(&address);
    m_state.recv(&state);
    std::string stateS (static_cast<char const*>(state.data()), state.size());
    return m_factory.ParseStateMessage(stateS);
}

bool ServerInterface::SendMove(enum Tetromino::Move move, int pieceId) {
    std::string const* moveCommandS = m_factory.CreateMoveMessage(move, pieceId);
    zmq::message_t moveCommand (moveCommandS->size());
    memcpy(static_cast<void*>(moveCommand.data()), moveCommandS->data(),
                                moveCommandS->size());
    delete moveCommandS;
    m_command.send(moveCommand);

    zmq::message_t reply;
    int error = m_command.recv(&reply, ZMQ_NOBLOCK);
    if (error != -1) {
        std::string replyS (static_cast<char const*>(reply.data()), reply.size());
        return m_factory.ParseMoveReply(replyS);
    }
    else {
        return NULL;
    }
}

<commit_msg>Fixed infinite loop. #3<commit_after>#include <server/server_interface.hpp>
#include <iostream>

ServerInterface::ServerInterface(zmq::context_t& context,
                                    std::string const& commandServer,
                                    std::string const& stateServer,
                                    std::string const& matchToken)
    : m_command(context, ZMQ_REQ), m_state(context, ZMQ_SUB),
        m_matchToken(matchToken)
{
    std::cout << "Connecting to command server " << commandServer << std::endl;
    m_command.connect(commandServer.c_str());
    std::cout << "Connecting to state server " << stateServer << std::endl;
    m_state.connect(stateServer.c_str());
}

ServerInterface::~ServerInterface() {
    std::cout << "Closing sockets." << std::endl;
    m_command.close();
    m_state.close();
}

bool ServerInterface::Initialize() {
    // Sends initial message to command server
    std::cout << "Initiating handshake... ";
    std::string const* requestS = m_factory.CreateInitMessage(m_matchToken);
    zmq::message_t request (requestS->size());
    memcpy(static_cast<void*>(request.data()), requestS->data(), requestS->size());
    delete requestS;
    m_command.send(request);

    // Subscribes to state server
    m_state.setsockopt(ZMQ_SUBSCRIBE, m_matchToken.c_str(), m_matchToken.size());

    zmq::message_t reply;
    m_command.recv(&reply);
    std::string replyS (static_cast<char const*>(reply.data()), reply.size());
    bool success = m_factory.ParseInitReply(replyS);
    if (success)
        std::cout << "Success!" << std::endl;
    else
        std::cout << "Failure." << std::endl;
    return success;
}

State const* ServerInterface::GetState() {
    zmq::message_t address;
    zmq::message_t state;
    int error = m_state.recv(&address, ZMQ_NOBLOCK);
    if (error != -1) {
        m_state.recv(&state);
        std::string stateS (static_cast<char const*>(state.data()), state.size());
        return m_factory.ParseStateMessage(stateS);
    }
    else {
        return NULL;
    }
}

bool ServerInterface::SendMove(enum Tetromino::Move move, int pieceId) {
    std::string const* moveCommandS = m_factory.CreateMoveMessage(move, pieceId);
    zmq::message_t moveCommand (moveCommandS->size());
    memcpy(static_cast<void*>(moveCommand.data()), moveCommandS->data(),
                                moveCommandS->size());
    delete moveCommandS;
    m_command.send(moveCommand);

    zmq::message_t reply;
    m_command.recv(&reply);
    std::string replyS (static_cast<char const*>(reply.data()), reply.size());
    return m_factory.ParseMoveReply(replyS);
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 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
 *
 *****************************************************************************/
// $Id$

#include <mapnik/map.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/image_util.hpp>

#include <iostream>

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <plugins_dir>\n";
        return EXIT_SUCCESS;
    }

    std::cout << " running demo ... \n";
    using namespace mapnik;
    datasource_cache::instance()->register_datasources(argv[1]);
    freetype_engine::register_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");

    Map m(800,600);
    m.set_background(color_factory::from_string("white"));

    // create styles

    // Provinces (polygon)
    feature_type_style provpoly_style;

    rule_type provpoly_rule_on;
    provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
    provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
    provpoly_style.add_rule(provpoly_rule_on);

    rule_type provpoly_rule_qc;
    provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
    provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
    provpoly_style.add_rule(provpoly_rule_qc);

    m.insert_style("provinces",provpoly_style);

    // Provinces (polyline)
    feature_type_style provlines_style;

    stroke provlines_stk (Color(0,0,0),1.0);
    provlines_stk.add_dash(8, 4);
    provlines_stk.add_dash(2, 2);
    provlines_stk.add_dash(2, 2);

    rule_type provlines_rule;
    provlines_rule.append(line_symbolizer(provlines_stk));
    provlines_style.add_rule(provlines_rule);

    m.insert_style("provlines",provlines_style);

    // Drainage
    feature_type_style qcdrain_style;

    rule_type qcdrain_rule;
    qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
    qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
    qcdrain_style.add_rule(qcdrain_rule);

    m.insert_style("drainage",qcdrain_style);

    // Roads 3 and 4 (The "grey" roads)
    feature_type_style roads34_style;
    rule_type roads34_rule;
    roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
    stroke roads34_rule_stk(Color(171,158,137),2.0);
    roads34_rule_stk.set_line_cap(ROUND_CAP);
    roads34_rule_stk.set_line_join(ROUND_JOIN);
    roads34_rule.append(line_symbolizer(roads34_rule_stk));
    roads34_style.add_rule(roads34_rule);

    m.insert_style("smallroads",roads34_style);

    // Roads 2 (The thin yellow ones)
    feature_type_style roads2_style_1;
    rule_type roads2_rule_1;
    roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_1(Color(171,158,137),4.0);
    roads2_rule_stk_1.set_line_cap(ROUND_CAP);
    roads2_rule_stk_1.set_line_join(ROUND_JOIN);
    roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
    roads2_style_1.add_rule(roads2_rule_1);

    m.insert_style("road-border", roads2_style_1);

    feature_type_style roads2_style_2;
    rule_type roads2_rule_2;
    roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_2(Color(255,250,115),2.0);
    roads2_rule_stk_2.set_line_cap(ROUND_CAP);
    roads2_rule_stk_2.set_line_join(ROUND_JOIN);
    roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
    roads2_style_2.add_rule(roads2_rule_2);

    m.insert_style("road-fill", roads2_style_2);

    // Roads 1 (The big orange ones, the highways)
    feature_type_style roads1_style_1;
    rule_type roads1_rule_1;
    roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_1(Color(188,149,28),7.0);
    roads1_rule_stk_1.set_line_cap(ROUND_CAP);
    roads1_rule_stk_1.set_line_join(ROUND_JOIN);
    roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
    roads1_style_1.add_rule(roads1_rule_1);
    m.insert_style("highway-border", roads1_style_1);

    feature_type_style roads1_style_2;
    rule_type roads1_rule_2;
    roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_2(Color(242,191,36),5.0);
    roads1_rule_stk_2.set_line_cap(ROUND_CAP);
    roads1_rule_stk_2.set_line_join(ROUND_JOIN);
    roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
    roads1_style_2.add_rule(roads1_rule_2);
    m.insert_style("highway-fill", roads1_style_2);

    // Populated Places

    feature_type_style popplaces_style;
    rule_type popplaces_rule;
    text_symbolizer popplaces_text_symbolizer("GEONAME","DejaVu Sans Book",10,Color(0,0,0));
    popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
    popplaces_text_symbolizer.set_halo_radius(1);
    popplaces_rule.append(popplaces_text_symbolizer);
    popplaces_style.add_rule(popplaces_rule);

    m.insert_style("popplaces",popplaces_style );

    // Layers
    // Provincial  polygons
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries";

        Layer lyr("Provinces");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provinces");
        m.addLayer(lyr);
    }

    // Drainage
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/qcdrainage";
        Layer lyr("Quebec Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/ontdrainage";

        Layer lyr("Ontario Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    // Provincial boundaries
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries_l";
        Layer lyr("Provincial borders");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provlines");
        m.addLayer(lyr);
    }

    // Roads
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/roads";
        Layer lyr("Roads");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("smallroads");
        lyr.add_style("road-border");
        lyr.add_style("road-fill");
        lyr.add_style("highway-border");
        lyr.add_style("highway-fill");

        m.addLayer(lyr);
    }
    // popplaces
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/popplaces";
        p["encoding"] = "latin1";
        Layer lyr("Populated Places");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("popplaces");
        m.addLayer(lyr);
    }

    m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,
                                 1706357.31328276,-25098.593149577));

    Image32 buf(m.getWidth(),m.getHeight());
    agg_renderer<Image32> ren(m,buf);
    ren.apply();

    save_to_file<ImageData32>("demo.jpg","jpeg",buf.data());
    save_to_file<ImageData32>("demo.png","png",buf.data());

    std::cout << "Two maps have been rendered in the current directory:\n"
        "- demo.jpg\n"
        "- demo.png\n"
        "Have a look!\n";

    return EXIT_SUCCESS;
}
<commit_msg> - added exception handling<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 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
 *
 *****************************************************************************/
// $Id$

#include <mapnik/map.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/config_error.hpp>

#include <iostream>

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <plugins_dir>\n";
        return EXIT_SUCCESS;
    }

    using namespace mapnik;
    try {
        std::cout << " running demo ... \n";
        datasource_cache::instance()->register_datasources(argv[1]);
        freetype_engine::register_font("/usr/local/lib/mapnik/fonts/DejaVuSans.ttf");

        Map m(800,600);
        m.set_background(color_factory::from_string("white"));

        // create styles

        // Provinces (polygon)
        feature_type_style provpoly_style;

        rule_type provpoly_rule_on;
        provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
        provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
        provpoly_style.add_rule(provpoly_rule_on);

        rule_type provpoly_rule_qc;
        provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
        provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
        provpoly_style.add_rule(provpoly_rule_qc);

        m.insert_style("provinces",provpoly_style);

        // Provinces (polyline)
        feature_type_style provlines_style;

        stroke provlines_stk (Color(0,0,0),1.0);
        provlines_stk.add_dash(8, 4);
        provlines_stk.add_dash(2, 2);
        provlines_stk.add_dash(2, 2);

        rule_type provlines_rule;
        provlines_rule.append(line_symbolizer(provlines_stk));
        provlines_style.add_rule(provlines_rule);

        m.insert_style("provlines",provlines_style);

        // Drainage
        feature_type_style qcdrain_style;

        rule_type qcdrain_rule;
        qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
        qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
        qcdrain_style.add_rule(qcdrain_rule);

        m.insert_style("drainage",qcdrain_style);

        // Roads 3 and 4 (The "grey" roads)
        feature_type_style roads34_style;
        rule_type roads34_rule;
        roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
        stroke roads34_rule_stk(Color(171,158,137),2.0);
        roads34_rule_stk.set_line_cap(ROUND_CAP);
        roads34_rule_stk.set_line_join(ROUND_JOIN);
        roads34_rule.append(line_symbolizer(roads34_rule_stk));
        roads34_style.add_rule(roads34_rule);

        m.insert_style("smallroads",roads34_style);

        // Roads 2 (The thin yellow ones)
        feature_type_style roads2_style_1;
        rule_type roads2_rule_1;
        roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_1(Color(171,158,137),4.0);
        roads2_rule_stk_1.set_line_cap(ROUND_CAP);
        roads2_rule_stk_1.set_line_join(ROUND_JOIN);
        roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
        roads2_style_1.add_rule(roads2_rule_1);

        m.insert_style("road-border", roads2_style_1);

        feature_type_style roads2_style_2;
        rule_type roads2_rule_2;
        roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_2(Color(255,250,115),2.0);
        roads2_rule_stk_2.set_line_cap(ROUND_CAP);
        roads2_rule_stk_2.set_line_join(ROUND_JOIN);
        roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
        roads2_style_2.add_rule(roads2_rule_2);

        m.insert_style("road-fill", roads2_style_2);

        // Roads 1 (The big orange ones, the highways)
        feature_type_style roads1_style_1;
        rule_type roads1_rule_1;
        roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_1(Color(188,149,28),7.0);
        roads1_rule_stk_1.set_line_cap(ROUND_CAP);
        roads1_rule_stk_1.set_line_join(ROUND_JOIN);
        roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
        roads1_style_1.add_rule(roads1_rule_1);
        m.insert_style("highway-border", roads1_style_1);

        feature_type_style roads1_style_2;
        rule_type roads1_rule_2;
        roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_2(Color(242,191,36),5.0);
        roads1_rule_stk_2.set_line_cap(ROUND_CAP);
        roads1_rule_stk_2.set_line_join(ROUND_JOIN);
        roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
        roads1_style_2.add_rule(roads1_rule_2);
        m.insert_style("highway-fill", roads1_style_2);

        // Populated Places

        feature_type_style popplaces_style;
        rule_type popplaces_rule;
        text_symbolizer popplaces_text_symbolizer("GEONAME","DejaVu Sans Book",10,Color(0,0,0));
        popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
        popplaces_text_symbolizer.set_halo_radius(1);
        popplaces_rule.append(popplaces_text_symbolizer);
        popplaces_style.add_rule(popplaces_rule);

        m.insert_style("popplaces",popplaces_style );

        // Layers
        // Provincial  polygons
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries";

            Layer lyr("Provinces");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provinces");
            m.addLayer(lyr);
        }

        // Drainage
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/qcdrainage";
            Layer lyr("Quebec Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/ontdrainage";

            Layer lyr("Ontario Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        // Provincial boundaries
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries_l";
            Layer lyr("Provincial borders");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provlines");
            m.addLayer(lyr);
        }

        // Roads
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/roads";
            Layer lyr("Roads");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("smallroads");
            lyr.add_style("road-border");
            lyr.add_style("road-fill");
            lyr.add_style("highway-border");
            lyr.add_style("highway-fill");

            m.addLayer(lyr);
        }
        // popplaces
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/popplaces";
            p["encoding"] = "latin1";
            Layer lyr("Populated Places");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("popplaces");
            m.addLayer(lyr);
        }

        m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,
                                     1706357.31328276,-25098.593149577));

        Image32 buf(m.getWidth(),m.getHeight());
        agg_renderer<Image32> ren(m,buf);
        ren.apply();

        save_to_file<ImageData32>("demo.jpg","jpeg",buf.data());
        save_to_file<ImageData32>("demo.png","png",buf.data());

        std::cout << "Two maps have been rendered in the current directory:\n"
            "- demo.jpg\n"
            "- demo.png\n"
            "Have a look!\n";

    }
    catch ( const mapnik::config_error & ex )
    {
        std::cerr << "### Configuration error: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( const std::exception & ex )
    {
        std::cerr << "### std::exception: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( ... )
    {
        std::cerr << "### Unknown exception." << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<|endoftext|>