File: angle.h

package info (click to toggle)
wsclean 2.8-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 2,196 kB
  • sloc: cpp: 34,504; ansic: 234; python: 174; makefile: 10
file content (142 lines) | stat: -rw-r--r-- 3,273 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#ifndef ANGLE_H
#define ANGLE_H

#include <string>
#include <sstream>
#include <stdexcept>
#include <cmath>

#include <boost/algorithm/string/case_conv.hpp>

class Angle
{
public:
	enum Unit { Radians, Degrees, Arcminutes, Arcseconds, Milliarcseconds };
	/**
	 * Parse the string as an angle, possibly with unit specification, and return in radians.
	 * @return The angle
	 */
	static double Parse(const std::string& s, const std::string& valueDescription, Unit defaultUnit);
	
	static std::string ToNiceString(double angleRad);
	
private:
	static size_t findNumberEnd(const std::string& s);
	static bool isDigit(const char c) { return c>='0' && c<='9'; }
	static bool isWhitespace(const char c) { return c==' ' || c=='\t'; }
};

inline std::string Angle::ToNiceString(double angleRad)
{
	std::ostringstream str;
	double degAngle = angleRad * 180.0 / M_PI;
	if(degAngle < 0.0)
	{
		str << "-";
		degAngle = -degAngle;
	}
	if(degAngle >= 2.0)
	{
		str << round(degAngle*100.0)/100.0 << " deg";
	}
	else {
		double minAngle = angleRad * 180.0 * 60.0 / M_PI;
		if(minAngle >= 2.0)
		{
			str << round(minAngle*100.0)/100.0 << "'";
		}
		else {
			double secAngle = angleRad * 180.0 * 60.0 * 60.0 / M_PI;
			if(secAngle >= 1.0)
			{
				str << round(secAngle*100.0)/100.0 << "''";
			}
			else {
				str << round (secAngle*100.0*1000.0)/100.0 << " masec";
			}
		}
	}
	return str.str();
}

inline double Angle::Parse(const std::string& s, const std::string& valueDescription, Unit defaultUnit)
{
  size_t end = findNumberEnd(s);
	if(end == 0)
		throw std::runtime_error("Error parsing " + valueDescription);
	std::string number = s.substr(0, end);
	double val = atof(number.c_str());
	// Skip whitespace after number
	const char *c = s.c_str();
	while(isWhitespace(c[end]))
		++end;
	std::string unitStr = std::string(&c[end]);
	boost::to_lower(unitStr);

	// Unit string empty? Than use default unit.
	if(unitStr.empty())
	{
		switch(defaultUnit)
		{
			case Radians:
				return val;
			case Degrees:
				return val * M_PI/180.0;
			case Arcminutes:
				return val * M_PI/(180.0*60.0);
			case Arcseconds:
				return val * M_PI/(180.0*60.0*60.0);
			case Milliarcseconds:
				return val * M_PI/(180.0*60.0*60.0*1000.0);
		}
	}
	
	// In degrees?
	else if(unitStr=="deg" || unitStr=="degrees")
		return val * M_PI/180.0;
	
	// In arcmin?
	else if(unitStr=="amin" || unitStr=="arcmin" || unitStr=="\'")
		return val * M_PI/(180.0*60.0);
	
	// In arcsec?
	else if(unitStr=="asec" || unitStr=="arcsec" || unitStr=="\'\'")
		return val * M_PI/(180.0*60.0*60.0);
	
	// In marcsec?
	else if(unitStr=="mas" || unitStr=="masec" || unitStr=="marcsec")
		return val * M_PI/(180.0*60.0*60.0*1000.0);
	
	// In radians
	else if(unitStr=="rad" || unitStr=="radians")
		return val;
	
	throw std::runtime_error("Invalid unit specification in angle given for " + valueDescription);
}

inline size_t Angle::findNumberEnd(const std::string& s)
{
	const char* c = s.c_str();
	size_t pos = 0;
	while(isWhitespace(c[pos]))
		++pos;
	if(c[pos] == '-')
		++pos;
	while(isDigit(c[pos]))
		++pos;
	if(c[pos]=='.')
		++pos;
	while(isDigit(c[pos]))
		++pos;
	if(c[pos]=='e' || c[pos]=='E')
	{
		++pos;
		if(c[pos]=='-' || c[pos]=='+')
			++pos;
		while(isDigit(c[pos]))
			++pos;
	}
	return pos;
}

#endif