Exemple #1
0
float min_rotation_step(Image* image) {
	int width  = image_width(image);
	int height = image_height(image);
	int mid_x  = width / 2;
	int mid_y  = height / 2;

	float degrees   = 45;
	float radians   = degrees_to_radians(45);
	float x         = 0;
	float y         = 0;
	float current_x = 0;
	float current_y = 0;
	float next_x    = cos(radians)*(x - mid_x) + sin(radians)*(y - mid_y) + mid_x;
	float next_y    = -sin(radians)*(x - mid_x) + cos(radians)*(y - mid_y) + mid_y;

	do {
		current_x = next_x;
		current_y = next_y;

		degrees /= 2.0;
		radians = degrees_to_radians(degrees);

		next_x = cos(radians)*(x - mid_x) + sin(radians)*(y - mid_y) + mid_x;
		next_y = -sin(radians)*(x - mid_x) + cos(radians)*(y - mid_y) + mid_y;
	} while (abs(next_x - current_x) > 1 || abs(next_y - current_y) > 1);

	return degrees;
}
Exemple #2
0
transform transform::rotate(float degrees, float rx, float ry, float rz)
{
  float4x4 A;
  float length = std::sqrt((rx*rx) + (ry*ry) + (rz*rz));
  float a = rx / length;
  float b = ry / length;
  float c = rz / length;
  float aa = a * a;
  float bb = b * b;
  float cc = c * c;
  float sine = std::sin(degrees_to_radians(-degrees));
  float cosine = std::cos(degrees_to_radians(-degrees));
  float omcos = 1.0f - cosine;

  A(0,0) = aa + (1.0f - aa) * cosine;
  A(1,1) = bb + (1.0f - bb) * cosine;
  A(2,2) = cc + (1.0f - cc) * cosine;
  A(0,1) = a * b * omcos + c * sine;
  A(0,2) = a * c * omcos - b * sine;
  A(1,0) = a * b * omcos - c * sine;
  A(1,2) = b * c * omcos + a * sine;
  A(2,0) = a * c * omcos + b * sine;
  A(2,1) = b * c * omcos - a * sine;
  A(0,3) = A(1,3) = A(2,3) = A(3,0) = A(3,1) = A(3,2) = 0.0f;
  A(3,3) = 1.0f;
   
  return transform(A);
} // end transform::rotate()
Exemple #3
0
struct matrix * rotate_z(double theta){
  struct matrix *trans;
  
  trans = new_matrix(4,4);
  trans = create_identity_matrix(trans);
  
  trans->m[0][0] = cos(degrees_to_radians(theta));
  trans->m[0][1] = -1 * sin(degrees_to_radians(theta));
  trans->m[1][0] = sin(degrees_to_radians(theta));
  trans->m[1][1] = cos(degrees_to_radians(theta));
  
  print_trans_matrix(trans);
  return trans;
}
Exemple #4
0
Vector::Vector(double magnitude, double direction)
{

    x_component_ = magnitude * cos(degrees_to_radians(direction));
    y_component_ = magnitude * sin(degrees_to_radians(direction));
    set_component_signs(direction);

    magnitude_ = magnitude;
    direction_ = direction;

    Logger::write(Logger::string_stream << "creating vector:");
    Logger::write(Logger::string_stream << "\t\tmagnitude: " << magnitude_);
    Logger::write(Logger::string_stream << "\t\tdirection: " << direction_);
    Logger::write(Logger::string_stream << "\t\tx_component: " << x_component_);
    Logger::write(Logger::string_stream << "\t\ty_component: " << y_component_);
}
Exemple #5
0
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
// make input point
void futile_lnglat_to_coord(double lng_deg, double lat_deg, int zoom, futile_coord_s *out) {
    double lat_rad = degrees_to_radians(lat_deg);
    double n = pow(2.0, zoom);
    out->x = (lng_deg + 180.0) / 360.0 * n;
    out->y = (1.0 - log(tan(lat_rad) + (1 / cos(lat_rad))) / M_PI) / 2.0 * n;
    out->z = zoom;
}
Exemple #6
0
Image* image_rotate(Image* image, float angle, int padding) {
	int width     = image_width(image);
	int height    = image_height(image);
	Image* output = image_blank_copy(image, width, height);

	float radians = degrees_to_radians(angle);
	int mid_x     = width / 2;
	int mid_y     = height / 2;

	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {
			float original_x = cos(radians)*(x - mid_x) + sin(radians)*(y - mid_y) + mid_x;
			float original_y = -sin(radians)*(x - mid_x) + cos(radians)*(y - mid_y) + mid_y;

			if (original_x >= width || original_y >= height || original_x < 0 || original_y < 0) {
				image_set_pixel_intensity(output, x, y, padding);
			} else {
				// int intensity = image_get_pixel_intensity(image, original_x, original_y);
				int intensity = bilinear_intensity(image, original_x, original_y, padding);

				image_set_pixel_intensity(output, x, y, intensity);
			}
		}
	}

	return output;
}
void test002 ( )

/******************************************************************************/
/*
  Purpose:

    TEST002 tests ANGLE_DEG_2D and ANGLE_RAD_ND.

  Licensing:

    This code is distributed under the GNU LGPL license. 

  Modified:

    14 April 2013

  Author:

    John Burkardt
*/
{
  int angle_num = 12;
  int i;
  double temp1;
  double temp2;
  double temp3;
  double thetad;
  double thetar;
  double v1[2] = { 1.0, 0.0 };
  double v2[2];
  double v3[2] = { 0.0, 0.0 };

  printf ( "\n" );
  printf ( "TEST002\n" );
  printf ( "  ANGLE_DEG_2D computes an angle,\n" );
  printf ( "  ANGLE_RAD_ND computes an angle.\n" );
  printf ( "\n" );
  printf ( "  X  Y  Theta  ATAN2(y, x), ANGLE_RAD_ND, ANGLE_DEG_2D\n" );
  printf ( "\n" );

  for ( i = 0; i <= angle_num; i++ )
  {
    thetad = ( double ) ( i ) * 360.0 / ( double ) ( angle_num );
    thetar = degrees_to_radians ( thetad );

    v2[0] = cos ( thetar );
    v2[1] = sin ( thetar );

    temp1 = radians_to_degrees ( atan2 ( v2[1], v2[0] ) );

    temp2 = angle_rad_nd ( 2, v1, v2 );

    temp3 = angle_deg_2d ( v1, v3, v2 );

    printf ( "  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f\n",
    v2[0], v2[1], thetad, temp1, temp2, temp3 );
  } 
  return;
}
Exemple #8
0
static void wolf_raycast(struct point2 *position, double angle, draw_wall_fn draw_wall)
{
	double fov = degrees_to_radians(FOV) * 640.0/480.0;
	double ray_step = fov / (double) 640.0;

	for (int i = 0; i < 640; i++) {
		struct vector2 ray_direction;
		double next_x, next_y;
		double step_x, step_y;
		double max_x, max_y;
		double ray_angle;
		double dx, dy;
		int x, y;

		ray_angle = angle + -fov/2.0 + ray_step * i;
		ray_direction.x = cos(ray_angle);
		ray_direction.y = sin(ray_angle);

		x = position->x;
		y = position->y;

		step_x = sign(ray_direction.x);
		step_y = sign(ray_direction.y);

		next_x = x + (step_x > 0 ? 1 : 0);
		next_y = y + (step_y > 0 ? 1 : 0);

		max_x = (next_x - position->x) / ray_direction.x;
		max_y = (next_y - position->y) / ray_direction.y;

		if (isnan(max_x))
			max_x = INFINITY;
		if (isnan(max_y))
			max_y = INFINITY;

		dx = step_x / ray_direction.x;
		dy = step_y / ray_direction.y;

		if (isnan(dx))
			dx = INFINITY;
		if (isnan(dy))
			dy = INFINITY;

		for (;;) {
			if (map[x][y] != 0)
				break;

			if (max_x < max_y) {
				max_x += dx;
				x += step_x;
			} else {
				max_y += dy;
				y += step_y;
			}
		}

		draw_wall(position, x, y);
	}
}
Exemple #9
0
		void updateTransform ()
		{
			m_transform.localToParent() = Matrix4::getIdentity();
			m_transform.localToParent().translateBy(m_origin);
			m_ray.direction = matrix4_transformed_direction(matrix4_rotation_for_z(degrees_to_radians(m_angle)),
					Vector3(1, 0, 0));
			m_transformChanged();
		}
Exemple #10
0
void Camera::setCameraOrbitLocation(float yawDegrees, float pitchDegrees, float radius)
{
    m_cameraOrbitYawDegrees= wrap_degrees(yawDegrees);
    m_cameraOrbitPitchDegrees= clampf(pitchDegrees, 0.f, 60.f);
    m_cameraOrbitRadius= fmaxf(radius, k_camera_min_zoom);

    const float yawRadians= degrees_to_radians(m_cameraOrbitYawDegrees);
    const float pitchRadians= degrees_to_radians(m_cameraOrbitPitchDegrees);
    const float xzRadiusAtPitch= m_cameraOrbitRadius*cosf(pitchRadians);

    m_cameraPosition= 
        glm::vec3(
            xzRadiusAtPitch*sinf(yawRadians),
            m_cameraOrbitRadius*sinf(pitchRadians),
            xzRadiusAtPitch*cosf(yawRadians))
        + glm::vec3(0.f, k_camera_y_offset, 0.f);

    publishCameraViewMatrix();
}
Exemple #11
0
void Camera::moveUpdateAxes() {
	double ya = degrees_to_radians(_angles[CAMERA_YAW]);

	// the movement matrix is kept 2d
	forward[0] = static_cast<float>(cos(ya));
	forward[1] = static_cast<float>(sin(ya));
	forward[2] = 0;
	right[0] = forward[1];
	right[1] = -forward[0];
}
Matrix4 RenderPreview::getProjectionMatrix(float near_z, float far_z, float fieldOfView, int width, int height)
{
    const float half_width = near_z * tan(degrees_to_radians(fieldOfView * 0.5f));
    const float half_height = half_width * (static_cast<float>(height) / static_cast<float>(width));

    return Matrix4::getProjectionForFrustum(
        -half_width,
        half_width,
        -half_height,
        half_height,
        near_z,
        far_z
    );
}
Exemple #13
0
double hyperbolic_tangent(double angle, enum angle_type atype)
{
      switch (atype)
      {
      case RAD:
            normalize_radians(&angle);
            return tanh(angle);
            break;

      case DEG:
            return tanh(degrees_to_radians(angle));
            break;

      case GRAD:
            return tanh(grade_to_radians(angle));
      }
}
Exemple #14
0
double sine(double angle, enum angle_type atype)
{
      switch (atype)
      {
      case RAD:
            normalize_radians(&angle);
            return sin(angle);
            break;

      case DEG:
            return sin(degrees_to_radians(angle));
            break;

      case GRAD:
            return sin(grade_to_radians(angle));
      }
}
Exemple #15
0
static void wolf_frame(struct point2 *position, struct vector2 *direction, float angle)
{
	glClearColor(0,0,0,0); 
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

	mat4x4 project;
	mat4x4_identity(project);
	mat4x4_perspective(project, degrees_to_radians(FOV), 640.0/480.0, 0.1f, 64.0f);

	mat4x4_identity(model_view);
	vec3 eye;
	eye[0] = position->x;
	eye[1] = 0.3;
	eye[2] = position->y;
	vec3 center;
	center[0] = position->x+direction->x;
	center[1] = 0.3;
	center[2] = position->y+direction->y;
	vec3 up;
	up[0] = 0.0;
	up[1] = 1.0;
	up[2] = 0.0;
	mat4x4_look_at(model_view, eye, center, up);

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf((const GLfloat*) project);

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf((const GLfloat*) model_view);

	glEnable(GL_DEPTH_TEST);

	wolf_draw_floor();

	wolf_raycast(position, angle, wolf_draw_wall);
}
bool LevellerDataset::compute_elev_scaling
(
	const OGRSpatialReference& sr
)
{
	const char* pszGroundUnits;

	if(!sr.IsGeographic())
	{
		// For projected or local CS, the elev scale is
		// the average ground scale.
		m_dElevScale = average(m_adfTransform[1], m_adfTransform[5]);

		const double dfLinear = sr.GetLinearUnits();
		const measurement_unit* pu = this->get_uom(dfLinear);
		if(pu == NULL)
			return false;

		pszGroundUnits = pu->pszID;
	}
	else
	{
		pszGroundUnits = "m";

		const double kdEarthCircumPolar = 40007849;
		const double kdEarthCircumEquat = 40075004;

		double xr, yr;
		xr = 0.5 * this->nRasterXSize;
		yr = 0.5 * this->nRasterYSize;

		double xg[2], yg[2];
		this->raw_to_proj(xr, yr, xg[0], yg[0]);
		this->raw_to_proj(xr+1, yr+1, xg[1], yg[1]);
		
		// The earths' circumference shrinks using a sin()
		// curve as we go up in latitude.
		const double dLatCircum = kdEarthCircumEquat 
			* sin(degrees_to_radians(90.0 - yg[0]));

		// Derive meter distance between geolongitudes
		// in xg[0] and xg[1].
		double dx = fabs(xg[1] - xg[0]) / 360.0 * dLatCircum;
		double dy = fabs(yg[1] - yg[0]) / 360.0 * kdEarthCircumPolar;

		m_dElevScale = average(dx, dy);
	}

	m_dElevBase = m_dLogSpan[0];

	// Convert from ground units to elev units.
	const measurement_unit* puG = this->get_uom(pszGroundUnits);
	const measurement_unit* puE = this->get_uom(m_szElevUnits);

	if(puG == NULL || puE == NULL)
		return false;

	const double g_to_e = puG->dScale / puE->dScale;

	m_dElevScale *= g_to_e;
	return true;
}
void	Angle::degrees(double degrees) {
	_angle = degrees_to_radians(degrees);
}
bool TerragenDataset::write_header()
{
	char szHeader[16];
	memcpy(szHeader, "TERRAGENTERRAIN ", sizeof(szHeader));

    if(1 != VSIFWriteL( (void *) szHeader, sizeof(szHeader), 1, m_fp ))
	{
        CPLError( CE_Failure, CPLE_FileIO, 
                  "Couldn't write to Terragen file %s.\n"
                  "Is file system full?",
                  m_pszFilename );
        VSIFCloseL( m_fp );

        return false;
    }

    
// -------------------------------------------------------------------- 
//      Write out the heightfield dimensions, etc.
// -------------------------------------------------------------------- 

	const int nXSize = this->GetRasterXSize();
	const int nYSize = this->GetRasterYSize();

	this->write_next_tag("SIZE");
	this->put((GInt16)(min(nXSize, nYSize)-1));
	this->pad(sizeof(GInt16));

	if(nXSize != nYSize)
	{
		this->write_next_tag("XPTS");
		this->put((GInt16)nXSize); this->pad(sizeof(GInt16));
		this->write_next_tag("YPTS");
		this->put((GInt16)nYSize); this->pad(sizeof(GInt16));
	}

	if(m_bIsGeo)
	{
		/*
			With a geographic projection (degrees),
			m_dGroundScale will be in degrees and
			m_dMetersPerGroundUnit is undefined.
			So we're going to estimate a m_dMetersPerGroundUnit
			value here (i.e., meters per degree).

			We figure out the degree size of one 
			pixel, and then the latitude degrees 
			of the heightfield's center. The circumference of
			the latitude's great circle lets us know how
			wide the pixel is in meters, and we 
			average that with the pixel's meter breadth,
			which is based on the polar circumference.
		*/

		/*const double m_dDegLongPerPixel = 
			fabs(m_adfTransform[1]);*/

		const double m_dDegLatPerPixel = 
			fabs(m_adfTransform[5]);

		/*const double m_dCenterLongitude =
			m_adfTransform[0] + 
			(0.5 * m_dDegLongPerPixel * (nXSize-1));*/

		const double m_dCenterLatitude =
			m_adfTransform[3] + 
			(0.5 * m_dDegLatPerPixel * (nYSize-1));


		const double dLatCircum = kdEarthCircumEquat 
			* sin(degrees_to_radians(90.0 - m_dCenterLatitude));

		const double dMetersPerDegLongitude = dLatCircum / 360;
		/*const double dMetersPerPixelX = 
			(m_dDegLongPerPixel / 360) * dLatCircum;*/

		const double dMetersPerDegLatitude = 
			kdEarthCircumPolar / 360;
		/*const double dMetersPerPixelY = 
			(m_dDegLatPerPixel / 360) * kdEarthCircumPolar;*/

		m_dMetersPerGroundUnit = 
			average(dMetersPerDegLongitude, dMetersPerDegLatitude);

	}
		
	m_dSCAL = m_dGroundScale * m_dMetersPerGroundUnit;

	if(m_dSCAL != 30.0)
	{
		const float sc = (float)m_dSCAL;
		this->write_next_tag("SCAL");
		this->put(sc);
		this->put(sc);
		this->put(sc);
	}

	if(!this->write_next_tag("ALTW"))
	{
        CPLError( CE_Failure, CPLE_FileIO, 
                  "Couldn't write to Terragen file %s.\n"
                  "Is file system full?",
                  m_pszFilename );
        VSIFCloseL( m_fp );

        return false;
	}

	// Compute physical scales and offsets.
	m_span_m[0] = m_dLogSpan[0] * m_dMetersPerElevUnit;
	m_span_m[1] = m_dLogSpan[1] * m_dMetersPerElevUnit;

	m_span_px[0] = m_span_m[0] / m_dSCAL;
	m_span_px[1] = m_span_m[1] / m_dSCAL;

	const double span_px = m_span_px[1] - m_span_px[0];
	m_nHeightScale = (GInt16)span_px;
	if(m_nHeightScale == 0)
		m_nHeightScale++;

	#define P2L_PX(n, hs, bh)	\
		((double)(n) / 65536.0 * (hs) + (bh))

	#define L2P_PX(n, hs, bh)	\
		((int)(((n)-(bh)) * 65536.0 / (hs)))

	// Increase the heightscale until the physical span
	// fits within a 16-bit range. The smaller the logical span,
	// the more necessary this becomes.
	int hs, bh;
	for(hs = m_nHeightScale; hs <= 32767; hs++)
	{
		double prevdelta = 1.0e30;
		for(bh = -32768; bh <= 32767; bh++)
		{
			int nValley = L2P_PX(m_span_px[0], hs, bh);
			if(nValley < -32768) continue;
			int nPeak = L2P_PX(m_span_px[1], hs, bh);
			if(nPeak > 32767) continue;

			// now see how closely the baseheight gets
			// to the pixel span.
			double d = P2L_PX(nValley, hs, bh);
			double delta = fabs(d - m_span_px[0]);
			if(delta < prevdelta) // Converging?
				prevdelta = delta;
			else 
			{
				// We're diverging, so use the previous bh
				// and stop looking.
				bh--;
				break;
			}
		}
		if(bh != 32768) break;
	}
	if(hs == 32768)
	{
        CPLError( CE_Failure, CPLE_FileIO, 
                  "Couldn't write to Terragen file %s.\n"
                  "Cannot find adequate heightscale/baseheight combination.",
                  m_pszFilename );
        VSIFCloseL( m_fp );

        return false;
	}
		
	m_nHeightScale = hs;
	m_nBaseHeight = bh;


	// m_nHeightScale is the one that gives us the 
	// widest use of the 16-bit space. However, there
	// might be larger heightscales that, even though
	// the reduce the space usage, give us a better fit
	// for preserving the span extents.


	return (this->put(m_nHeightScale) &&
			this->put(m_nBaseHeight));
}
Exemple #19
0
int main(int argc,char** argv)
{
 Nodes       *OSMNodes;
 Segments    *OSMSegments;
 Ways        *OSMWays;
 Relations   *OSMRelations;
 Results     *results[NWAYPOINTS+1]={NULL};
 int          point_used[NWAYPOINTS+1]={0};
 double       point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
 index_t      point_node[NWAYPOINTS+1]={NO_NODE};
 double       heading=-999;
 int          help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0;
 char        *dirname=NULL,*prefix=NULL;
 char        *profiles=NULL,*profilename=NULL;
 char        *translations=NULL,*language=NULL;
 int          exactnodes=0,reverse=0,loop=0;
 Transport    transport=Transport_None;
 Profile     *profile=NULL;
 Translation *translation=NULL;
 index_t      start_node,finish_node=NO_NODE;
 index_t      join_segment=NO_SEGMENT;
 int          arg,nresults=0;
 waypoint_t   start_waypoint,finish_waypoint=NO_WAYPOINT;
 waypoint_t   first_waypoint=NWAYPOINTS,last_waypoint=1,waypoint;
 int          inc_dec_waypoint=1;

 printf_program_start();

 /* Parse the command line arguments */

 if(argc<2)
    print_usage(0,NULL,NULL);

 /* Get the non-routing, general program options */

 for(arg=1;arg<argc;arg++)
   {
    if(!strcmp(argv[arg],"--version"))
       print_usage(-1,NULL,NULL);
    else if(!strcmp(argv[arg],"--help"))
       print_usage(1,NULL,NULL);
    else if(!strcmp(argv[arg],"--help-profile"))
       help_profile=1;
    else if(!strcmp(argv[arg],"--help-profile-xml"))
       help_profile_xml=1;
    else if(!strcmp(argv[arg],"--help-profile-json"))
       help_profile_json=1;
    else if(!strcmp(argv[arg],"--help-profile-perl"))
       help_profile_pl=1;
    else if(!strncmp(argv[arg],"--dir=",6))
       dirname=&argv[arg][6];
    else if(!strncmp(argv[arg],"--prefix=",9))
       prefix=&argv[arg][9];
    else if(!strncmp(argv[arg],"--profiles=",11))
       profiles=&argv[arg][11];
    else if(!strncmp(argv[arg],"--translations=",15))
       translations=&argv[arg][15];
    else if(!strcmp(argv[arg],"--exact-nodes-only"))
       exactnodes=1;
    else if(!strncmp(argv[arg],"--reverse",9))
      {
       if(argv[arg][9]=='=')
          reverse=atoi(&argv[arg][10]);
       else
          reverse=1;
      }
    else if(!strncmp(argv[arg],"--loop",6))
      {
       if(argv[arg][6]=='=')
          loop=atoi(&argv[arg][7]);
       else
          loop=1;
      }
    else if(!strcmp(argv[arg],"--quiet"))
       option_quiet=1;
    else if(!strcmp(argv[arg],"--loggable"))
       option_loggable=1;
    else if(!strcmp(argv[arg],"--logtime"))
       option_logtime=2;
    else if(!strcmp(argv[arg],"--logmemory"))
       option_logmemory=1;
    else if(!strcmp(argv[arg],"--output-html"))
       option_file_html=1;
    else if(!strcmp(argv[arg],"--output-gpx-track"))
       option_file_gpx_track=1;
    else if(!strcmp(argv[arg],"--output-gpx-route"))
       option_file_gpx_route=1;
    else if(!strcmp(argv[arg],"--output-text"))
       option_file_text=1;
    else if(!strcmp(argv[arg],"--output-text-all"))
       option_file_text_all=1;
    else if(!strcmp(argv[arg],"--output-none"))
       option_file_none=1;
    else if(!strcmp(argv[arg],"--output-stdout"))
      { option_file_stdout=1; option_quiet=1; }
    else if(!strncmp(argv[arg],"--profile=",10))
       profilename=&argv[arg][10];
    else if(!strncmp(argv[arg],"--language=",11))
       language=&argv[arg][11];
    else if(!strcmp(argv[arg],"--shortest"))
       option_quickest=0;
    else if(!strcmp(argv[arg],"--quickest"))
       option_quickest=1;
    else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
      {
       int point;
       char *p=&argv[arg][6];

       while(isdigit(*p)) p++;
       if(*p++!='=')
          print_usage(0,argv[arg],NULL);

       point=atoi(&argv[arg][5]);
       if(point>NWAYPOINTS || point_used[point]&1)
          print_usage(0,argv[arg],NULL);

       point_lon[point]=degrees_to_radians(atof(p));
       point_used[point]+=1;

       if(point<first_waypoint)
          first_waypoint=point;
       if(point>last_waypoint)
          last_waypoint=point;
      }
    else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
      {
       int point;
       char *p=&argv[arg][6];

       while(isdigit(*p)) p++;
       if(*p++!='=')
          print_usage(0,argv[arg],NULL);

       point=atoi(&argv[arg][5]);
       if(point>NWAYPOINTS || point_used[point]&2)
          print_usage(0,argv[arg],NULL);

       point_lat[point]=degrees_to_radians(atof(p));
       point_used[point]+=2;

       if(point<first_waypoint)
          first_waypoint=point;
       if(point>last_waypoint)
          last_waypoint=point;
      }
    else if(!strncmp(argv[arg],"--heading=",10))
      {
       double h=atof(&argv[arg][10]);

       if(h>=-360 && h<=360)
         {
          heading=h;

          if(heading<0) heading+=360;
         }
      }
    else if(!strncmp(argv[arg],"--transport=",12))
      {
       transport=TransportType(&argv[arg][12]);

       if(transport==Transport_None)
          print_usage(0,argv[arg],NULL);
      }
    else
       continue;

    argv[arg]=NULL;
   }

 /* Check the specified command line options */

 if(option_file_stdout && (option_file_html+option_file_gpx_track+option_file_gpx_route+option_file_text+option_file_text_all)!=1)
   {
    fprintf(stderr,"Error: The '--output-stdout' option requires exactly one other output option (but not '--output-none').\n");
    exit(EXIT_FAILURE);
   }

 if(option_file_html==0 && option_file_gpx_track==0 && option_file_gpx_route==0 && option_file_text==0 && option_file_text_all==0 && option_file_none==0)
    option_file_html=option_file_gpx_track=option_file_gpx_route=option_file_text=option_file_text_all=1;

 /* Load in the selected profiles */

 if(transport==Transport_None)
    transport=Transport_Motorcar;

 if(profiles)
   {
    if(!ExistsFile(profiles))
      {
       fprintf(stderr,"Error: The '--profiles' option specifies a file '%s' that does not exist.\n",profiles);
       exit(EXIT_FAILURE);
      }
   }
 else
   {
    profiles=FileName(dirname,prefix,"profiles.xml");

    if(!ExistsFile(profiles))
      {
       char *defaultprofiles=FileName(ROUTINO_DATADIR,NULL,"profiles.xml");

       if(!ExistsFile(defaultprofiles))
         {
          fprintf(stderr,"Error: The '--profiles' option was not used and the files '%s' and '%s' do not exist.\n",profiles,defaultprofiles);
          exit(EXIT_FAILURE);
         }

       free(profiles);
       profiles=defaultprofiles;
      }
   }

 if(!profilename)
    profilename=(char*)TransportName(transport);

 if(ParseXMLProfiles(profiles,profilename,(help_profile_xml|help_profile_json|help_profile_pl)))
   {
    fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
    exit(EXIT_FAILURE);
   }

 profile=GetProfile(profilename);

 if(!profile)
   {
    fprintf(stderr,"Error: Cannot find a profile called '%s' in the file '%s'.\n",profilename,profiles);

    profile=(Profile*)calloc(1,sizeof(Profile));
    profile->transport=transport;
   }

 /* Parse the other command line arguments that modify the profile */

 for(arg=1;arg<argc;arg++)
   {
    if(!argv[arg])
       continue;
    else if(!strncmp(argv[arg],"--highway-",10))
      {
       Highway highway;
       char *equal=strchr(argv[arg],'=');
       char *string;
       double p;

       if(!equal)
           print_usage(0,argv[arg],NULL);

       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10);
       string[equal-argv[arg]-10]=0;

       highway=HighwayType(string);

       if(highway==Highway_None)
          print_usage(0,argv[arg],NULL);

       p=atof(equal+1);

       if(p<0 || p>100)
          print_usage(0,argv[arg],NULL);

       profile->highway[highway]=(score_t)(p/100);

       free(string);
      }
    else if(!strncmp(argv[arg],"--speed-",8))
      {
       Highway highway;
       char *equal=strchr(argv[arg],'=');
       char *string;
       double s;

       if(!equal)
          print_usage(0,argv[arg],NULL);

       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8);
       string[equal-argv[arg]-8]=0;

       highway=HighwayType(string);

       if(highway==Highway_None)
          print_usage(0,argv[arg],NULL);

       s=atof(equal+1);

       if(s<0)
          print_usage(0,argv[arg],NULL);

       profile->speed[highway]=kph_to_speed(s);

       free(string);
      }
    else if(!strncmp(argv[arg],"--property-",11))
      {
       Property property;
       char *equal=strchr(argv[arg],'=');
       char *string;
       double p;

       if(!equal)
          print_usage(0,argv[arg],NULL);

       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11);
       string[equal-argv[arg]-11]=0;

       property=PropertyType(string);

       if(property==Property_None)
          print_usage(0,argv[arg],NULL);

       p=atof(equal+1);

       if(p<0 || p>100)
          print_usage(0,argv[arg],NULL);

       profile->props[property]=(score_t)(p/100);

       free(string);
      }
    else if(!strncmp(argv[arg],"--oneway=",9))
       profile->oneway=!!atoi(&argv[arg][9]);
    else if(!strncmp(argv[arg],"--turns=",8))
       profile->turns=!!atoi(&argv[arg][8]);
    else if(!strncmp(argv[arg],"--weight=",9))
       profile->weight=tonnes_to_weight(atof(&argv[arg][9]));
    else if(!strncmp(argv[arg],"--height=",9))
       profile->height=metres_to_height(atof(&argv[arg][9]));
    else if(!strncmp(argv[arg],"--width=",8))
       profile->width=metres_to_width(atof(&argv[arg][8]));
    else if(!strncmp(argv[arg],"--length=",9))
       profile->length=metres_to_length(atof(&argv[arg][9]));
    else
       print_usage(0,argv[arg],NULL);
   }

 /* Print one of the profiles if requested */

 if(help_profile)
   {
    PrintProfile(profile);

    exit(EXIT_SUCCESS);
   }
 else if(help_profile_xml)
   {
    PrintProfilesXML();

    exit(EXIT_SUCCESS);
   }
 else if(help_profile_json)
   {
    PrintProfilesJSON();

    exit(EXIT_SUCCESS);
   }
 else if(help_profile_pl)
   {
    PrintProfilesPerl();

    exit(EXIT_SUCCESS);
   }

 /* Load in the selected translation */

 if(option_file_html || option_file_gpx_route || option_file_gpx_track || option_file_text || option_file_text_all)
   {
    if(translations)
      {
       if(!ExistsFile(translations))
         {
          fprintf(stderr,"Error: The '--translations' option specifies a file '%s' that does not exist.\n",translations);
          exit(EXIT_FAILURE);
         }
      }
    else
      {
       translations=FileName(dirname,prefix,"translations.xml");

       if(!ExistsFile(translations))
         {
          char *defaulttranslations=FileName(ROUTINO_DATADIR,NULL,"translations.xml");

          if(!ExistsFile(defaulttranslations))
            {
             fprintf(stderr,"Error: The '--translations' option was not used and the files '%s' and '%s' do not exist.\n",translations,defaulttranslations);
             exit(EXIT_FAILURE);
            }

          free(translations);
          translations=defaulttranslations;
         }
      }

    if(ParseXMLTranslations(translations,language,0))
      {
       fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
       exit(EXIT_FAILURE);
      }

    if(language)
      {
       translation=GetTranslation(language);

       if(!translation)
         {
          fprintf(stderr,"Warning: Cannot find a translation called '%s' in the file '%s'.\n",language,translations);
          exit(EXIT_FAILURE);
         }
      }
    else
      {
       translation=GetTranslation("");

       if(!translation)
         {
          fprintf(stderr,"Warning: No translations in '%s'.\n",translations);
          exit(EXIT_FAILURE);
         }
      }
   }

 /* Check the waypoints are valid */

 for(waypoint=1;waypoint<=NWAYPOINTS;waypoint++)
    if(point_used[waypoint]==1 || point_used[waypoint]==2)
       print_usage(0,NULL,"All waypoints must have latitude and longitude.");

 if(first_waypoint>=last_waypoint)
    print_usage(0,NULL,"At least two waypoints must be specified.");

 /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */

 if(!option_quiet)
    printf_first("Loading Files:");

 OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem"));

 OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem"));

 OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem"));

 OSMRelations=LoadRelationList(FileName(dirname,prefix,"relations.mem"));

 if(!option_quiet)
    printf_last("Loaded Files: nodes, segments, ways & relations");

 /* Check the profile is valid for use with this database */

 if(UpdateProfile(profile,OSMWays))
   {
    fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
    exit(EXIT_FAILURE);
   }

 /* Find all waypoints */

 for(waypoint=first_waypoint;waypoint<=last_waypoint;waypoint++)
   {
    distance_t distmax=km_to_distance(MAXSEARCH);
    distance_t distmin;
    index_t segment=NO_SEGMENT;
    index_t node1,node2,node=NO_NODE;

    if(point_used[waypoint]!=3)
       continue;

    /* Find the closest point */

    if(!option_quiet)
       printf_first("Finding Closest Point: Waypoint %d",waypoint);

    if(exactnodes)
       node=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin);
    else
      {
       distance_t dist1,dist2;

       segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2);

       if(segment!=NO_SEGMENT)
          node=CreateFakes(OSMNodes,OSMSegments,waypoint,LookupSegment(OSMSegments,segment,1),node1,node2,dist1,dist2);
      }

    if(!option_quiet)
       printf_last("Found Closest Point: Waypoint %d",waypoint);

    if(node==NO_NODE)
      {
       fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint);
       exit(EXIT_FAILURE);
      }

    if(!option_quiet)
      {
       double lat,lon;

       if(IsFakeNode(node))
          GetFakeLatLong(node,&lat,&lon);
       else
          GetLatLong(OSMNodes,node,NULL,&lat,&lon);

       if(IsFakeNode(node))
          printf("Waypoint %d is segment %"Pindex_t" (node %"Pindex_t" -> %"Pindex_t"): %3.6f %4.6f = %2.3f km\n",waypoint,segment,node1,node2,
                 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
       else
          printf("Waypoint %d is node %"Pindex_t": %3.6f %4.6f = %2.3f km\n",waypoint,node,
                 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
      }

    point_node[waypoint]=node;
   }

 /* Check for reverse direction */

 if(reverse)
   {
    waypoint_t temp;

    temp=first_waypoint;
    first_waypoint=last_waypoint;
    last_waypoint=temp;

    inc_dec_waypoint=-1;
   }

 /* Loop through all pairs of waypoints */

 if(loop && reverse)
   {
    finish_node=point_node[last_waypoint];

    finish_waypoint=last_waypoint;
   }

 for(waypoint=first_waypoint;waypoint!=(last_waypoint+inc_dec_waypoint);waypoint+=inc_dec_waypoint)
   {
    if(point_used[waypoint]!=3)
       continue;

    start_node=finish_node;
    finish_node=point_node[waypoint];

    start_waypoint=finish_waypoint;
    finish_waypoint=waypoint;

    if(start_node==NO_NODE)
       continue;

    if(heading!=-999 && join_segment==NO_SEGMENT)
       join_segment=FindClosestSegmentHeading(OSMNodes,OSMSegments,OSMWays,start_node,heading,profile);

    /* Calculate the route */

    if(!option_quiet)
       printf("Routing from waypoint %d to waypoint %d\n",start_waypoint,finish_waypoint);

    results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);

    if(!results[nresults])
       exit(EXIT_FAILURE);

    join_segment=results[nresults]->last_segment;

    nresults++;
   }

 if(loop && !reverse)
   {
    start_node=finish_node;
    finish_node=point_node[first_waypoint];

    start_waypoint=finish_waypoint;
    finish_waypoint=first_waypoint;

    /* Calculate the route */

    if(!option_quiet)
       printf("Routing from waypoint %d to waypoint %d\n",start_waypoint,finish_waypoint);

    results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);

    if(!results[nresults])
       exit(EXIT_FAILURE);

    nresults++;
   }

 if(!option_quiet)
   {
    printf("Routed OK\n");
    fflush(stdout);
   }

 /* Print out the combined route */

 if(!option_quiet)
    printf_first("Generating Result Outputs");

 if(!option_file_none)
    PrintRoute(results,nresults,OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,translation);

 if(!option_quiet)
    printf_last("Generated Result Outputs");

 /* Destroy the remaining results lists and data structures */

#ifdef DEBUG_MEMORY_LEAK

 for(waypoint=0;waypoint<nresults;waypoint++)
    FreeResultsList(results[waypoint]);

 DestroyNodeList(OSMNodes);
 DestroySegmentList(OSMSegments);
 DestroyWayList(OSMWays);
 DestroyRelationList(OSMRelations);

 FreeXMLProfiles();

 FreeXMLTranslations();

#endif

 if(!option_quiet)
    printf_program_end();

 exit(EXIT_SUCCESS);
}
void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode)
{
 transports_t allow=Transports_ALL;
 nodeflags_t flags=0;
 node_t id;
 int i;

 /* Convert id */

 id=(node_t)node_id;
 logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */

 /* Delete */

 if(mode==MODE_DELETE)
   {
    AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,NODE_DELETED);

    return;
   }

 /* Parse the tags */

 for(i=0;i<tags->ntags;i++)
   {
    int recognised=0;
    char *k=tags->k[i];
    char *v=tags->v[i];

    switch(*k)
      {
      case 'b':
       if(!strcmp(k,"bicycle"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Bicycle;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'bicycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'f':
       if(!strcmp(k,"foot"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Foot;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'foot' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'g':
       if(!strcmp(k,"goods"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Goods;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'goods' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'h':
       if(!strcmp(k,"horse"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Horse;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'horse' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       if(!strcmp(k,"hgv"))
         {
          if(ISFALSE(v))
             allow&=~Transports_HGV;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'hgv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'm':
       if(!strcmp(k,"moped"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Moped;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'moped' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       if(!strcmp(k,"motorcycle"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Motorcycle;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'motorcycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       if(!strcmp(k,"motorcar"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Motorcar;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'motorcar' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'p':
       if(!strcmp(k,"psv"))
         {
          if(ISFALSE(v))
             allow&=~Transports_PSV;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'psv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      case 'r':
       if(!strcmp(k,"roundabout"))
         {
          if(ISTRUE(v))
             flags|=NODE_MINIRNDBT;
          else
             logerror("Node %"Pnode_t" has an unrecognised tag 'roundabout' = '%s' (after tagging rules); using 'no'.\n",id,v);
          recognised=1; break;
         }

       break;

      case 'w':
       if(!strcmp(k,"wheelchair"))
         {
          if(ISFALSE(v))
             allow&=~Transports_Wheelchair;
          else if(!ISTRUE(v))
             logerror("Node %"Pnode_t" has an unrecognised tag 'wheelchair' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
          recognised=1; break;
         }

       break;

      default:
       break;
      }

    if(!recognised)
       logerror("Node %"Pnode_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_node(id),k,v);
   }

 /* Create the node */

 AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags);
}