Skip to content

Suggestion: Angle (Degrees) to N-S-E-W, #585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
TheMightyPope opened this issue Jan 23, 2019 · 14 comments
Closed

Suggestion: Angle (Degrees) to N-S-E-W, #585

TheMightyPope opened this issue Jan 23, 2019 · 14 comments

Comments

@TheMightyPope
Copy link

When using for example the National Weather Data API you will see data for Wind Direction expressed in Degrees, like this:

[https://api.weather.gov/gridpoints/LWX/100,60

...

"windDirection": {
"sourceUnit": "degrees",
"uom": "unit:degree_(angle)",
"values": [
{
"validTime": "2019-01-23T02:00:00+00:00/PT1H",
"value": 160
},
{
"validTime": "2019-01-23T03:00:00+00:00/PT2H",
"value": 170

It would be useful to convert this to a wind direction expressed as North or N, North North-East (NNE), etc, and of course the other way too.

@angularsen
Copy link
Owner

angularsen commented Jan 23, 2019

Hmm. I don't know enough about this domain. Is North 0 degrees and West 90 degrees, or something like that? Is that definition standardized worldwide, or does it vary for different countries/usage domains?

At first I thought, sure, let's just add them as angle units. But then I saw some issues:

  1. You can't meaningfully parse double whatDoesThisEvenMean = Angle.Parse("5 NNE");
  2. You can't meaningfully convert from other angle units: double val = Angle.FromDegrees(90).As(AngleUnit.NNE); // 1??

It took me a moment, but I'm now realizing that NNE is not a unit. It's a quantity of angle.

We can, however, add something like this:

Angle nnw = Angle.NorthNorthWest; // Static readonly getter property for new Angle(22.5, AngleUnit.Degree) or whatever the value is
double nnwDegrees = nnw.As(AngleUnit.Degree); // 22.5
string nnwText = nnw.ToString("Wind is blowing {0} {1}."); // "Wind is blowing 22.5 º."

I don't think we should add logic to convert say 22.5 to NNW or to whatever the nearest wind direction is, that is application specific use and should be defined per app.

Am I understanding this right?
Does this match what you thought of adding to the library or did you think of something else?

@angularsen
Copy link
Owner

angularsen commented Jan 23, 2019

We might also be be able to add something like this, which is probably more what you asked:

WindDirection wd = Angle.GetWindDirection(90); // WindDirection.West enum value

It does, however, smell like app-specific code to me. Some only care about N,W,E,S, others want N,NW,W,SW,S etc.. I can imagine others want three-letter directions.
I'm not sure if this kind of logic belongs in a generic-purpose units library, but I am open to discuss it.

Let me hear what you think first and maybe I misunderstood some things :-)

@TheMightyPope
Copy link
Author

That would be great.
My 2c would be that while this might seem app-specific, these compass directions have existed for hundreds of years and are quite standard when navigating, for wind-directions, and probably other things I haven't thought off. I.e. the conversion from degrees to 'compass direction' is pretty standard stuff. There are many questions about it when searching, and even a few github libraries just for this problem. I would vote to include it. An Enum Value would be fine, and even better with a ToString(..) to make it NNW, or SSW, etc...

Perhaps like FeetInches it could contain subvalues, like compas.major = North, compas.minor = NorthWest, compas.full = NorthNorthWest

Just a thought, I have only used your library for 10 minutes, so I think you're better qualified to implement it the best way, if you agree it should be include.

Btw, Great library !!

@TheMightyPope
Copy link
Author

@TheMightyPope
Copy link
Author

One more thing, IF you decide to do it... Perhaps consider adding a 'reverse' direction, so if I have for example SSE, the reverse would be NNW. Useful if you are figuring out for example a wind blowing in a SSE direction, that means it's coming from a NNW direction. Yeah, I'm into wind these days, what can I say :)

@angularsen
Copy link
Owner

angularsen commented Jan 26, 2019

Ok, I'm sold. Let's add this thing and I want you to add it :-)

We need to come up with a design proposal first. I'll toss in what I can think of from the top of my head, but please revise this and change as you see fit. Nothing long or fancy, just paint a picture for how it will be used and what new methods, properties or types we need.

Angle.ToString(CompassType)

Added via Angle.extra.cs.

Angle a = Angle.FromDegrees(33.8);
a.ToString(CompassType.Points32)` // NEbN
a.ToString(CompassType.Points16)` // NNE
a.ToString(CompassType.Points8)` // NE
a.ToString(CompassType.Points4)` // N

Angle factory methods

Added via Angle.extra.cs.

Angle a = Angle.FromCompassPoint(CompassPoint.NNE); // 22.5 degrees

Reverse compass angle

Note: All compass angles should be 0-360 degrees, not negative nor larger than 360.

Angle nne = Angle.FromCompassPoint(CompassPoint.NNE); // 22.5 degrees
Angle ssw = nne.ReverseCompassAngle(); // 202.5 degrees - is there more generic term/name we can use here that is not restricted to "compass" but circles in general?

New types

  • enum CompassPoint { NNE, NbE /* etc... */ }
  • enum CompassType { Points32, Points16, Points8, Points4 }

@TheMightyPope
Copy link
Author

How about this?

Angle.ToString(CompassType)

What you suggested is great, but any reason we can't also add this?
C = Cardinal Direction (N/S/E/W)
c = cardinal Ordinal direction
S = secondary-intercadirnal direction
s = Not sure about the name, but lowercase s seems to make sense given above, = below

-- These may be too domain specific ? :
D = Degrees
T = Terms (From WikiPedia - Mariners Compass Rose section)

So, with a ToString(string) function:

Angle a = Angle.FromDegrees(33.8);
a.ToString("Ccbs") // NEbN
a.ToString("Cc-s") // NE-N
a.ToString("CcS") // NNE
a.ToString("Cc") // NE
a.ToString("C-c") // N-E
a.ToString("C") // N
a.ToString("D") // 33.8° (See Wikipedia Link) - This may be too domain specific...
a.ToString('T")` // Greco (See Wikipedia Link) - This may be too domain specific...

Otherwise your suggestion is fine too, I guess I like the option so people can format it the way they want it.

Opposite compass angle

The Opposite side of a circle I believe the term is after some googling..

Angle nne = Angle.FromCompassPoint(CompassPoint.NNE); // 22.5 degrees
Angle ssw = nne.OppositeCompassAngle();

New types

enum CompassPoint { NNE, NbE /* etc... */ }
enum CompassType { Points32, Points16, Points8, Points4 }

See also: https://en.wikipedia.org/wiki/Compass_rose

I think that's pretty much my suggestions... Feel free to kill the ones that may not fit the package.

@angularsen
Copy link
Owner

Sure, I guess we can add format pattern support. We haven't done that before, so you might have to pave some new road here.

Basically, all ToString() methods are generated by PowerShell scripts, so I think we'll have to modify the code generator to insert something like this:

        public string ToString([CanBeNull] IFormatProvider provider, [NotNull] string format, [NotNull] params object[] args)
        {
            if (format == null) throw new ArgumentNullException(nameof(format));
            if (args == null) throw new ArgumentNullException(nameof(args));

            // BEGIN NEW CODE
            foreach (var formatter in _toStringFormatters)
            {
                format = formatter.Format(format, args);
            }
            // END NEW CODE

            provider = provider ?? GlobalConfiguration.DefaultCulture;

            var value = Convert.ToDouble(Value);
            var formatArgs = UnitFormatter.GetFormatArgs(Unit, value, provider, args);
            return string.Format(provider, format, formatArgs);
        }

Then we can in Angle.extra.cs add some custom formatters to the _toStringFormatters field, which also does not exist yet. The idea is to replace C with N, replace c with E etc. as in your example.

We also need to document these format patterns, at minimum in the xmldoc so you can see all options with intellisense when coding. It's also possible there are some hints we can give to ReSharper and other tooling to understand that some characters are format pattern characters, not sure, maybe they just hard coded support for dates and time patterns. Just look into it and see what the best practices are.

Snipped from:

public string ToString([CanBeNull] IFormatProvider provider, [NotNull] string format, [NotNull] params object[] args)
{
if (format == null) throw new ArgumentNullException(nameof(format));
if (args == null) throw new ArgumentNullException(nameof(args));
provider = provider ?? GlobalConfiguration.DefaultCulture;
var value = Convert.ToDouble(Value);
var formatArgs = UnitFormatter.GetFormatArgs(Unit, value, provider, args);
return string.Format(provider, format, formatArgs);
}

@tmilnthorp
Copy link
Collaborator

Cross-reference #579

@angularsen
Copy link
Owner

@TheMightyPope Please take a look at #579 as that PR is nearing completion now, for a reference on how to do format strings. Do you still intend to follow up with a PR on this issue?

@TheMightyPope
Copy link
Author

TheMightyPope commented Feb 26, 2019 via email

@angularsen
Copy link
Owner

I understand, I'll leave it open for a few weeks and check back if I don't hear anything.
Let me know if you need any assistance on GitHub and git in general, I'm happy to help!

@angularsen
Copy link
Owner

It's been a few weeks now, do you still intend to follow up on this or is it better to close it for now?

@angularsen
Copy link
Owner

Closing due to inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants