0.2.0 Angle

This commit is contained in:
Rob Tillaart 2024-04-06 11:38:00 +02:00
parent bd77c35574
commit 9711a7c55f
14 changed files with 232 additions and 153 deletions

View File

@ -1,4 +1,5 @@
# These are supported funding model platforms
github: RobTillaart
github: RobTillaart
custom: "https://www.paypal.me/robtillaart"

View File

@ -1,12 +1,12 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update

View File

@ -1,4 +1,3 @@
---
name: Arduino CI
on: [push, pull_request]
@ -6,9 +5,10 @@ on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6

View File

@ -9,10 +9,11 @@ on:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
uses: limitusus/json-syntax-check@v2
with:
pattern: "\\.json$"

View File

@ -1,7 +1,7 @@
//
// FILE: Angle.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.15
// VERSION: 0.2.0
// PURPOSE: library for Angle math for Arduino
// URL: https://github.com/RobTillaart/Angle
// http://forum.arduino.cc/index.php?topic=339402
@ -11,7 +11,7 @@
AngleFormat::AngleFormat( const Angle &ref, AngleFormatMode format )
: angle(ref), mode(format)
: angle(ref), mode(format)
{
}
@ -24,104 +24,113 @@ size_t AngleFormat::printTo(Print& p) const
Angle::Angle(int dd, int mm, int ss, int tt)
{
neg = false;
d = dd;
m = mm;
s = ss;
t = tt;
_negative = false;
_degrees = dd;
_minutes = mm;
_seconds = ss;
_tenths = tt;
// normalize();
// assume only one (largest) parameter is negative at most...
if (d < 0) { d = -d; neg = true; }
if (m < 0) { m = -m; neg = true; }
if (s < 0) { s = -s; neg = true; }
if (t < 0) { t = -t; neg = true; }
if (_degrees < 0) { _degrees = -_degrees; _negative = true; }
if (_minutes < 0) { _minutes = -_minutes; _negative = true; }
if (_seconds < 0) { _seconds = -_seconds; _negative = true; }
if (_tenths < 0) { _tenths = -_tenths ; _negative = true; }
// modulo might be faster
while (t >= 10000) { s++; t -= 10000; }
while (s >= 60) { m++; s -= 60; }
while (m >= 60) { d++; m -= 60; }
while (_tenths >= 10000) { _seconds++; _tenths -= 10000; }
while (_seconds >= 60) { _minutes++; _seconds -= 60; }
while (_minutes >= 60) { _degrees++; _minutes -= 60; }
// check special case 0
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
if (_degrees == 0 && _minutes == 0 && _seconds == 0 && _tenths == 0)
{
_negative = false;
}
}
Angle::Angle(const double alpha)
{
double a = alpha;
neg = (alpha < 0);
if (neg) a = -a;
double angle = alpha;
_negative = (alpha < 0);
if (_negative) angle = -angle;
d = int(a);
a = a - d;
// unsigned long p = a * 3600000L;
_degrees = int(angle);
angle = angle - _degrees;
// unsigned long p = angle * 3600000L;
// 3600 000 = 2^7 • 3^2 • 5^5 = 128 * 28125
// 2^7 = 128 will only affect exponent - no loss precision
// 28125 is less digits so less loss of significant digits.
// upgraded to 4 decimal seconds
// 36 000 000L = 256 * 140625
a = a * 256;
unsigned long p = round(a * 140625.0);
t = p % 10000UL;
angle = angle * 256;
unsigned long p = round(angle * 140625.0);
_tenths = p % 10000UL;
p = p / 10000UL;
s = p % 60UL;
m = p / 60UL;
_seconds = p % 60UL;
_minutes = p / 60UL;
// check special case 0
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
if (_degrees == 0 && _minutes == 0 && _seconds == 0 && _tenths == 0)
{
_negative = false;
}
}
Angle::Angle(const char * str)
{
uint32_t yy = 0;
uint8_t d_cnt = 0;
neg = false;
uint8_t decimals = 0;
_negative = false;
// parse whole degrees
char *p = (char *) str;
d = 0;
_degrees = 0;
// skip crap
while (!isdigit(*p) && (*p != '-')) p++;
// process sign
if (*p == '-')
{
neg = true;
_negative = true;
p++;
}
if (*p == '+') p++;
// parse whole part into degrees;
// parse whole part into degrees
while (isdigit(*p))
{
d *= 10;
d += (*p - '0');
_degrees *= 10;
_degrees += (*p - '0');
p++;
}
// parse decimal part into an uint32_t
if (*p != '\0')
{
p++; // skip .
while (isdigit(*p) && d_cnt < 9)
p++; // skip decimal point .
while (isdigit(*p) && decimals < 9)
{
d_cnt++;
decimals++;
yy *= 10;
yy += (*p - '0');
p++;
}
}
// make sure we have 9 decimal places.
while (d_cnt < 9)
while (decimals < 9)
{
d_cnt++;
decimals++;
yy *= 10;
}
// convert float to degrees. 1000000000 ~> 36000000 -> /250 * 9
// yy = yy * 4 / 125 + yy / 250; // just keeps the maths within 32 bits
yy = yy * 4 / 125;
yy = yy + (yy + 4)/ 8; // just keeps the maths within 32 bits
// split yy in m, s, tt
t = yy % 10000UL;
// split yy in minutes, seconds, tenThousands
_tenths = yy % 10000UL;
yy = yy / 10000UL;
s = yy % 60;
m = yy / 60;
_seconds = yy % 60;
_minutes = yy / 60;
// check special case 0
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
if (_degrees == 0 && _minutes == 0 && _seconds == 0 && _tenths == 0)
{
_negative = false;
}
}
@ -132,25 +141,25 @@ size_t Angle::printTo(Print& p, AngleFormatMode mode) const
char separator[4] = ".\'\""; // "..."; // ALT-0176 = ° 179.59.59.9999
size_t n = 0;
if (neg) n += p.print('-');
n += p.print(d);
if (_negative) n += p.print('-');
n += p.print(_degrees);
n += p.print(separator[0]);
if( --c )
{
if (m < 10) n += p.print('0');
n += p.print(m);
if (_minutes < 10) n += p.print('0');
n += p.print(_minutes);
n += p.print(separator[1]);
if( --c )
{
if (s < 10) n += p.print('0');
n += p.print(s);
if (_seconds < 10) n += p.print('0');
n += p.print(_seconds);
n += p.print(separator[2]);
if( --c )
{
if (t < 1000) n += p.print('0');
if (t < 100) n += p.print('0');
if (t < 10) n += p.print('0');
n += p.print(t);
if (_tenths < 1000) n += p.print('0');
if (_tenths < 100) n += p.print('0');
if (_tenths < 10) n += p.print('0');
n += p.print(_tenths);
}
}
}
@ -160,10 +169,10 @@ size_t Angle::printTo(Print& p, AngleFormatMode mode) const
double Angle::toDouble(void)
{
long v = t + s * 10000UL + m * 600000UL;
double val = ((1.0 / 140625.0) / 256) * v + d;
if (neg) val = -val;
return val;
long v = _tenths + _seconds * 10000UL + _minutes * 600000UL;
double value = ((1.0 / 140625.0) / 256) * v + _degrees;
if (_negative) value = -value;
return value;
}
@ -171,48 +180,48 @@ double Angle::toDouble(void)
Angle Angle::operator - ()
{
Angle temp = *this;
if (temp.d == 0 && temp.m == 0 && temp.s == 0 && temp.t == 0)
if (temp._degrees == 0 && temp._minutes == 0 && temp._seconds == 0 && temp._tenths == 0)
{
temp.neg = false;
temp._negative = false;
}
else
{
temp.neg = !neg;
temp._negative = !_negative;
}
return temp;
};
// BASIC MATH
Angle Angle::operator + (const Angle &a) // TOCHECK
Angle Angle::operator + (const Angle &a) // TOCHECK
{
return addHelper(a);
}
Angle& Angle::operator += (const Angle &a) // TOCHECK
Angle& Angle::operator += (const Angle &a) // TOCHECK
{
*this = addHelper(a);
return *this;
}
Angle Angle::addHelper(const Angle &a) // TOCHECK
Angle Angle::addHelper(const Angle &a) // TOCHECK
{
Angle temp = *this;
if (temp.neg == a.neg)
if (temp._negative == a._negative)
{
temp.d += a.d;
temp.m += a.m;
temp.s += a.s;
temp.t += a.t;
temp._degrees += a._degrees;
temp._minutes += a._minutes;
temp._seconds += a._seconds;
temp._tenths += a._tenths ;
}
else
{
temp.d -= a.d;
temp.m -= a.m;
temp.s -= a.s;
temp.t -= a.t;
temp._degrees -= a._degrees;
temp._minutes -= a._minutes;
temp._seconds -= a._seconds;
temp._tenths -= a._tenths ;
}
temp.normalize();
@ -220,35 +229,35 @@ Angle Angle::addHelper(const Angle &a) // TOCHECK
}
Angle Angle::operator - (const Angle &a) // TOCHECK
Angle Angle::operator - (const Angle &a) // TOCHECK
{
return subHelper(a);
}
Angle& Angle::operator -= (const Angle &a) // TOCHECK
Angle& Angle::operator -= (const Angle &a) // TOCHECK
{
*this = subHelper(a);
return *this;
}
Angle Angle::subHelper(const Angle &a) // TOCHECK
Angle Angle::subHelper(const Angle &a) // TOCHECK
{
Angle temp = *this;
if (temp.neg == a.neg)
if (temp._negative == a._negative)
{
temp.d -= a.d;
temp.m -= a.m;
temp.s -= a.s;
temp.t -= a.t;
temp._degrees -= a._degrees;
temp._minutes -= a._minutes;
temp._seconds -= a._seconds;
temp._tenths -= a._tenths ;
}
else
{
temp.d += a.d;
temp.m += a.m;
temp.s += a.s;
temp.t += a.t;
temp._degrees += a._degrees;
temp._minutes += a._minutes;
temp._seconds += a._seconds;
temp._tenths += a._tenths ;
}
temp.normalize();
return temp;
@ -286,7 +295,7 @@ double Angle::operator / (Angle& a)
{
double f = this->toDouble();
double g = a.toDouble();
return f/g;
return f / g;
}
@ -297,55 +306,58 @@ double Angle::operator / (Angle& a)
int Angle::compare(const Angle &a, const Angle &b)
{
// check sign first
if (!a.neg && b.neg) return 1;
if (a.neg && !b.neg) return -1;
if (!a._negative && b._negative) return 1;
if (a._negative && !b._negative) return -1;
// check abs value
int rv = 0;
if (a.d > b.d) rv = 1;
else if (a.d < b.d) rv = -1;
else if (a.m > b.m) rv = 1;
else if (a.m < b.m) rv = -1;
else if (a.s > b.s) rv = 1;
else if (a.s < b.s) rv = -1;
else if (a.t > b.t) rv = 1;
else if (a.t < b.t) rv = -1;
if (a._degrees > b._degrees) rv = 1;
else if (a._degrees < b._degrees) rv = -1;
else if (a._minutes > b._minutes) rv = 1;
else if (a._minutes < b._minutes) rv = -1;
else if (a._minutes > b._minutes) rv = 1;
else if (a._minutes < b._minutes) rv = -1;
else if (a._tenths > b._tenths) rv = 1;
else if (a._tenths < b._tenths) rv = -1;
if (rv != 0 && a.neg) rv = -rv;
if (rv != 0 && a._negative) rv = -rv;
return rv;
}
void Angle::normalize()
{
while (t < 0) { s--; t += 10000; }
while (t >= 10000) { s++; t -= 10000; }
while (s < 0) { m--; s += 60; }
while (s >= 60) { m++; s -= 60; }
while (m < 0) { d--; m += 60; }
while (m >= 60) { d++; m -= 60; }
while (_tenths < 0) { _seconds--; _tenths += 10000; }
while (_tenths >= 10000) { _seconds++; _tenths -= 10000; }
while (_seconds < 0) { _minutes--; _seconds += 60; }
while (_seconds >= 60) { _minutes++; _seconds -= 60; }
while (_minutes < 0) { _degrees--; _minutes += 60; }
while (_minutes >= 60) { _degrees++; _minutes -= 60; }
if (d < 0)
if (_degrees < 0)
{
if (t != 0)
if (_tenths != 0)
{
t = 10000 - t;
s++;
_tenths = 10000 - _tenths;
_seconds++;
}
if (s != 0)
if (_seconds != 0)
{
s = (60 - s) % 60;
m++;
_seconds = (60 - _seconds) % 60;
_minutes++;
}
if (m != 0)
if (_minutes != 0)
{
m = (60 - m) % 60;
d++;
_minutes = (60 - _minutes) % 60;
_degrees++;
}
d = -d;
neg = !neg;
_degrees = -_degrees;
_negative = !_negative;
}
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
if (_degrees == 0 && _minutes == 0 && _seconds == 0 && _tenths == 0)
{
_negative = false;
}
}

View File

@ -2,13 +2,12 @@
//
// FILE: Angle.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.15
// VERSION: 0.2.0
// PURPOSE: angle library for Arduino
// URL: https://github.com/RobTillaart/Angle
// http://forum.arduino.cc/index.php?topic=339402
//
// AngleFormat proxy added 03/03/15 by Christoper Andrews.
//
// AngleFormat proxy added 03/03/15 by Christopher Andrews.
#include "math.h"
@ -16,18 +15,19 @@
#include "Printable.h"
#define ANGLE_LIB_VERSION (F("0.1.15"))
#define ANGLE_LIB_VERSION (F("0.2.0"))
class Angle;
enum AngleFormatMode{
enum AngleFormatMode
{
D = 1, M, S, T
};
struct AngleFormat : Printable{
struct AngleFormat : Printable
{
AngleFormat( const Angle &ref, AngleFormatMode format );
size_t printTo(Print& p) const;
@ -43,11 +43,11 @@ public:
Angle(double alpha);
Angle(const char * str);
int sign() { return neg ? -1 : 1; };
int degree() { return d; };
int minute() { return m; };
int second() { return s; };
int tenthousand() { return t; };
int sign() { return _negative ? -1 : 1; };
int degree() { return _degrees; };
int minute() { return _minutes; };
int second() { return _seconds; };
int tenthousand() { return _tenths; };
size_t printTo(Print& p) const { return printTo( p, T ); }
size_t printTo(Print& p, AngleFormatMode mode) const;
@ -55,8 +55,8 @@ public:
AngleFormat format( AngleFormatMode format ) { return AngleFormat( *this, format ); }
double toDouble();
double toRadians() { return toDouble() * PI / 180.0; };
void fromRadians(double rad) { *this = rad * 180.0/PI; };
double toRadians() { return toDouble() * (PI / 180.0); };
void fromRadians(double radians) { *this = radians * (180.0 / PI); };
// EQUALITIES
bool operator == (const Angle& a) { return compare(*this, a) == 0; };
@ -90,11 +90,11 @@ private:
Angle addHelper(const Angle &a);
Angle subHelper(const Angle &a);
bool neg; // angle is negative
int d; // whole degrees
int m; // minutes
int s; // seconds
int t; // ten thousands
bool _negative; // angle is negative
int _degrees;
int _minutes;
int _seconds;
int _tenths; // ten thousands
};

View File

@ -6,10 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.0] - 2024-04-06
- update GitHub actions
- give internal variables descriptive names
- minor edits
----
## [0.1.15] - 2023-10-17
- update readme (badges)
## [0.1.14] - 2023-01-31
- update GitHub actions
- update license 2023

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2015-2023 Rob Tillaart
Copyright (c) 2015-2024 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -107,7 +107,6 @@ Especially the constructor does not check input so use it carefully.
- test more
- TOCHECK in code
- improve code quality
- use better variable names in code
#### Could

View File

@ -3,7 +3,6 @@
// AUTHOR: Rob Tillaart
// PURPOSE: demo sketch to test angle class
// URL: https://github.com/RobTillaart/Angle.git
//
#include "Angle.h"

View File

@ -0,0 +1,63 @@
Arduino UNO
IDE 1.8.19
Angle_performance.ino
ANGLE_LIB_VERSION: 0.2.0
testConstructors
212
-45.59'15"5555
212
-45.59'15"5555
testToDouble
40
1.0341668
36
-1.0341678
164
360.00'00"0000
testParts
4
1.0000000
8
2.0000000
8
3.0000000
8
4.0000000
8
5.0000000
testNegate
8
45.30'00"0000
testCompare
4
1
testAdd
52
44.27'56"9996
268
-12.57'50"9740
testMultiply
220
28.52'30"0000
300
360.38'56"0230
testDivide
236
0.57'16"3636
316
0.01'24"3694
testRatio
100
0.13
Done...

View File

@ -2,9 +2,7 @@
// FILE: test_angle01.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo sketch to test angle class
// DATE: 2015-07-30
// URL: https://github.com/RobTillaart/Angle.git
//
#include "Angle.h"
@ -438,10 +436,10 @@ void testRatio()
Serial.println(b);
Serial.println(b / a, 7);
a = 180;
b = 57.295779513082320876798154814105; // one radian
b = 57.295779513082320876798154814105; // one radian
Serial.println(a);
Serial.println(b);
Serial.println(a / b, 7); // should be PI
Serial.println(a / b, 7); // should be PI
}
@ -472,5 +470,5 @@ void loop()
}
// -- END OF FILE --
// -- END OF FILE --

View File

@ -20,7 +20,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/Angle.git"
},
"version": "0.1.15",
"version": "0.2.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=Angle
version=0.1.15
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to convert between floating point angle to minutes hours representation.