It is currently February 29th, 2020, 12:43 am

## [Solved][Lots of Math] Moon Icon Rotation on a Sky Dial

Help with creating, editing & fixing problems with skins
raiguard
Posts: 653
Joined: June 25th, 2015, 7:02 pm
Location: The Sky, USA

### [Solved][Lots of Math] Moon Icon Rotation on a Sky Dial

EDIT 2: THIS PROBLEM IS NOW OBSELETE. SEE THIS POST. THANKS TO ALL WHO HELPED!

EDIT: I have created a very long and very detailed explanation of exactly what is going on. If you wish to dive in and try to help me solve this, click here. Thanks!

Hello everyone. I am attempting to create a sky dial using shape meters, and while I have done a basic one before, the one I am currently creating is very complicated and convoluted. I am creating this thread because I am bound to have many math-related issues with path shapes.

Here is my first problem:

For the moon icon, I would like to be able to display the current moon phase, as well as the angle of the illuminated side as you would see it in the sky. I have done both of these things before, that is not my problem. My problem arises when I attempt to implement them on the sky dial:
atrodial PROBLEMS.gif
That's not right at all!

My only hypothesis so far is that when the moon limb shape (the white illuminated part) is at certain angles, it's changing where the top-left of the limb's bounding box is, and therefore, the arc rotation anchor point moves as well. However, I have absolutely no clue how to fix it. I need to somehow create a function of the moon's limb rotation that will move the arc rotation anchor back to where it is supposed to be (signified by the green dot).

Does anybody have any ideas? Much appreciated.

AstroDial.ini:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Colors
colorBg=15,15,15
colorDialArc=150,150,150
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70
colorSun=250,222,110
; Dial settings
dialStartX=3
dialArcThickness=6
; Moon settings
moonBorderThickness=3

; =========================
; DEBUG TESTING VARIABLES
; =========================
; Sun / Moon Angles on the Dial (degrees)
sunDialAngle=-1
moonDialAngle=0
; Angle that the illuminated limb of the moon will face (degrees, starts North, counterclockwise)
moonViewAngle=0
; If set to 1, the moon will orient based on the value above. If set to 0, waxing will display on the right, and waning will display on the left.
showMoonAngle=1
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.12

; ==================================================
; MEASURES
; ==================================================

[MeasureSunDialVisibility]
Measure=Calc
Formula=#sunDialAngle#
IfCondition=(MeasureSunDialVisibility > 180) || (MeasureSunDialVisibility < 0)
IfTrueAction=[!SetVariable sunDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable sunDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

[MeasureMoonDialVisibility]
Measure=Calc
Formula=#moonDialAngle#
IfCondition=(MeasureMoonDialVisibility > 180) || (MeasureMoonDialVisibility < 0)
IfTrueAction=[!SetVariable moonDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable moonDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1

; TEMPORARY DEBUG
[MeasureActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 180
ActionList2=ResetMove | Repeat Move, 16, 180
ActionList3=ResetMove | Repeat Both, 16, 180
Increase=[!SetVariable moonViewAngle "(#moonViewAngle# + 2)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Move=[!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Both=[!SetVariable moonViewAngle "(#moonViewAngle# + 2)"][!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
ResetMove=[!SetVariable moonDialAngle 0][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
DynamicVariables=1

; ==================================================
; METERS
; ==================================================

[MeterAstroDial]
Meter=Shape
; Arc
; Sun
; Moon
Shape6=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate (((#showMoonAngle# = 1) ? (-#moonViewAngle#) : ((#moonPhase# > 0.5) ? -90 : 90)) - #moonDialAngle#),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round

SolidColor=#colorBg#
DynamicVariables=1

[MeterDebugLimbRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 1"]
Antialias=1

[MeterDebugDialRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Dial Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 2"]
Antialias=1

[MeterDebugBoth]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Both Rotations
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 3"]
Antialias=1``````
And here is a standalone version of the moon shape, in case it is helpful:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.0
; Angle that the illuminated limb of the moon will be displayed at (starting at north, going clockwise)
moonViewAngle=0
; Set to 1 to use moonViewAngle, 0 to display horizontally
showMoonAngle=0
; Internal moon variables
moonBorderThickness=2
; Colors
colorBg=15,15,15
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1

[MeterMoonShape]
Meter=Shape
Shape3=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate ((#showMoonAngle# = 1) ? (-#moonViewAngle# + 180) : ((#moonPhase# > 0.5) ? -90 : 90)),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round
SolidColor=#colorBg#
DynamicVariables=1
LeftMouseUpAction=[!CommandMeasure MeasureMoonShapeActionTimer "Execute 1"]

; Temporary measure for debug purposes - animates between new moon and full moon, then back
[MeasureMoonShapeActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 100 | Wait 1000 | Repeat Increase, 16, 100 | Reset
Increase=[!SetVariable moonPhase "(#moonPhase# + 0.005)"][!UpdateMeasure MeasureMoonShapePhaseCalc][!UpdateMeter MeterMoonShape][!UpdateMeasure MeasureMoonShapeActionTimer][!Redraw]
Reset=[!SetVariable moonPhase 0][!UpdateMeasure MeasureMoonShapePhaseCalc][!UpdateMeter MeterMoonShape][!UpdateMeasure MeasureMoonShapeActionTimer][!Redraw]
DynamicVariables=1``````
You do not have the required permissions to view the files attached to this post.
Last edited by raiguard on June 22nd, 2019, 4:10 pm, edited 2 times in total.
”We are pretty sure that r2922 resolves the regression in resolution caused by a reversion to a revision.” - jsmorley, 2017
raiguard
Posts: 653
Joined: June 25th, 2015, 7:02 pm
Location: The Sky, USA

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

So, I have made some progress! I realized that I could use the sine and cosine of the moon limb's rotation angle to figure out how much the limb's bounding box has moved, and has therefore allowed me to fix the issue:
astrodial less-than-half fixed.gif
It works beautifully!

...NOT.

It only works if the moon phase is less than half a moon!
astrodial more-than-half broken.gif
If the moon phase is more than half a moon, then it behaves completely differently. I can't simply use the trigonometry that I used before, because now instead of being a nice semicircle, the shape is an irregularly shaped ellipse...

This would be so much easier if you could somehow retrieve the X and Y positions of shapes within a shape meter, not just the meter itself...

Edit: Or better yet, this would be completely 100% painless if you could 'group' shapes together without actually combining them, so I could move the entire moon icon as a single unit, rather than as three separate shapes.

Anyone have any input?

AstroDial.ini:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Colors
colorBg=15,15,15
colorDialArc=150,150,150
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70
colorSun=250,222,110
; Dial settings
dialStartX=3
dialArcThickness=6
; Moon settings
moonBorderThickness=3
moonViewAngle=((#rawMVA# + #moonDialAngle#) % 360)

; =========================
; DEBUG TESTING VARIABLES
; =========================
; Sun / Moon Angles on the Dial (degrees)
sunDialAngle=-1
moonDialAngle=0
; Angle that the illuminated limb of the moon will face (degrees, starts North, counterclockwise)
rawMVA=0
; If set to 1, the moon will orient based on the value above. If set to 0, waxing will display on the right, and waning will display on the left.
showMoonAngle=1
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.12

; ==================================================
; MEASURES
; ==================================================

[MeasureSunDialVisibility]
Measure=Calc
Formula=#sunDialAngle#
IfCondition=(MeasureSunDialVisibility > 180) || (MeasureSunDialVisibility < 0)
IfTrueAction=[!SetVariable sunDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable sunDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

[MeasureMoonDialVisibility]
Measure=Calc
Formula=#moonDialAngle#
IfCondition=(MeasureMoonDialVisibility > 180) || (MeasureMoonDialVisibility < 0)
IfTrueAction=[!SetVariable moonDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable moonDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1
Group=MoonShape

; Adjusts the center of arc rotation for the moon limb shape in the X direction
[MeasureMoonLimbArcRotationXOffsetCalc]
Measure=Calc
DynamicVariables=1
Group=MoonShape

; Adjusts the center of arc rotation for the moon limb shape in the Y direction
[MeasureMoonLimbArcRotationYOffsetCalc]
Measure=Calc
DynamicVariables=1
Group=MoonShape

; TEMPORARY DEBUG - rotates the moon's illuminated limb 360 degrees
[MeasureActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 180
ActionList2=ResetMove | Repeat Move, 16, 180
ActionList3=ResetMove | Repeat Both, 16, 180
ActionList4=Repeat Increase, 16, 5
Increase=[!SetVariable rawMVA "(#rawMVA# + 2)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Move=[!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Both=[!SetVariable rawMVA "(#rawMVA# + 2)"][!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
ResetMove=[!SetVariable moonDialAngle 0][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
DynamicVariables=1

; ==================================================
; METERS
; ==================================================

[MeterAstroDial]
Meter=Shape
; Arc
; Sun
; Moon
Shape6=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate (((#showMoonAngle# = 1) ? (-#moonViewAngle#) : ((#moonPhase# > 0.5) ? -90 : 90))),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round

Shape7=Combine Shape5 | Intersect Shape6 | Rotate #moonDialAngle#,(#dialRadius# + [MeasureMoonLimbArcRotationXOffsetCalc:]),([MeasureMoonLimbArcRotationYOffsetCalc:])

SolidColor=#colorBg#
DynamicVariables=1

[MeterDebugLimbRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 1"]
Antialias=1

[MeterDebugDialRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Dial Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 2"]
Antialias=1

[MeterDebugBoth]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Both Rotations
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 3"]
Antialias=1

[MeterDebugStepLimb]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Step Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 4"]
Antialias=1``````
You do not have the required permissions to view the files attached to this post.
”We are pretty sure that r2922 resolves the regression in resolution caused by a reversion to a revision.” - jsmorley, 2017
SparkShredder
Posts: 50
Joined: November 17th, 2017, 12:00 pm

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

Honestly, I'm not that of a pro coder, So, I'd have taken help from Photoshop.
I may create various icons and and leave transparent space on right side
and Used:
Meter=Rotator
MeasureName=HowMuchItShouldRotate
Image?=[WhichIconItshouldUseMeasure]

Blah Blah Blah
GTI.H
Posts: 75
Joined: December 15th, 2018, 3:35 am

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

Hi raiguard,

I like math and am currently interested in orbital movements with Rainmeter.

I've been looking at your code in my spare time, but I do not know if I understood your wish. For me to understand your math I need to first study and familiarize with measures Shape and ActionTimer, but I can already feel the lack of trigonometric functions to solve a trigonometric issue.

I suspect that you have rewrote part of trigonometry (eg. x.cos=y) and that the error in AstroDial.ini starts in the second quadrant which leads us to suspect one of its conditions in Shape6 = Path MoonArc

To solve this issue, the first way that comes to my mind is to use a meter Rotator moving with Sin/Cos functions by setting its X and Y positions.

--
Regards
GTI
raiguard wrote:
December 30th, 2018, 3:22 am
Hello everyone. I am attempting to create a sky dial using shape meters, and while I have done a basic one before, the one I am currently creating is very complicated and convoluted. I am creating this thread because I am bound to have many math-related issues with path shapes.

Here is my first problem:

For the moon icon, I would like to be able to display the current moon phase, as well as the angle of the illuminated side as you would see it in the sky. I have done both of these things before, that is not my problem. My problem arises when I attempt to implement them on the sky dial:

atrodial PROBLEMS.gif

That's not right at all!

My only hypothesis so far is that when the moon limb shape (the white illuminated part) is at certain angles, it's changing where the top-left of the limb's bounding box is, and therefore, the arc rotation anchor point moves as well. However, I have absolutely no clue how to fix it. I need to somehow create a function of the moon's limb rotation that will move the arc rotation anchor back to where it is supposed to be (signified by the green dot).

Does anybody have any ideas? Much appreciated.

AstroDial.ini:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Colors
colorBg=15,15,15
colorDialArc=150,150,150
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70
colorSun=250,222,110
; Dial settings
dialStartX=3
dialArcThickness=6
; Moon settings
moonBorderThickness=3

; =========================
; DEBUG TESTING VARIABLES
; =========================
; Sun / Moon Angles on the Dial (degrees)
sunDialAngle=-1
moonDialAngle=0
; Angle that the illuminated limb of the moon will face (degrees, starts North, counterclockwise)
moonViewAngle=0
; If set to 1, the moon will orient based on the value above. If set to 0, waxing will display on the right, and waning will display on the left.
showMoonAngle=1
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.12

; ==================================================
; MEASURES
; ==================================================

[MeasureSunDialVisibility]
Measure=Calc
Formula=#sunDialAngle#
IfCondition=(MeasureSunDialVisibility > 180) || (MeasureSunDialVisibility < 0)
IfTrueAction=[!SetVariable sunDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable sunDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

[MeasureMoonDialVisibility]
Measure=Calc
Formula=#moonDialAngle#
IfCondition=(MeasureMoonDialVisibility > 180) || (MeasureMoonDialVisibility < 0)
IfTrueAction=[!SetVariable moonDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable moonDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1

; TEMPORARY DEBUG
[MeasureActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 180
ActionList2=ResetMove | Repeat Move, 16, 180
ActionList3=ResetMove | Repeat Both, 16, 180
Increase=[!SetVariable moonViewAngle "(#moonViewAngle# + 2)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Move=[!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Both=[!SetVariable moonViewAngle "(#moonViewAngle# + 2)"][!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
ResetMove=[!SetVariable moonDialAngle 0][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
DynamicVariables=1

; ==================================================
; METERS
; ==================================================

[MeterAstroDial]
Meter=Shape
; Arc
; Sun
; Moon
Shape6=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate (((#showMoonAngle# = 1) ? (-#moonViewAngle#) : ((#moonPhase# > 0.5) ? -90 : 90)) - #moonDialAngle#),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round

SolidColor=#colorBg#
DynamicVariables=1

[MeterDebugLimbRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 1"]
Antialias=1

[MeterDebugDialRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Dial Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 2"]
Antialias=1

[MeterDebugBoth]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Both Rotations
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 3"]
Antialias=1``````
And here is a standalone version of the moon shape, in case it is helpful:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.0
; Angle that the illuminated limb of the moon will be displayed at (starting at north, going clockwise)
moonViewAngle=0
; Set to 1 to use moonViewAngle, 0 to display horizontally
showMoonAngle=0
; Internal moon variables
moonBorderThickness=2
; Colors
colorBg=15,15,15
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1

[MeterMoonShape]
Meter=Shape
Shape3=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate ((#showMoonAngle# = 1) ? (-#moonViewAngle# + 180) : ((#moonPhase# > 0.5) ? -90 : 90)),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round
SolidColor=#colorBg#
DynamicVariables=1
LeftMouseUpAction=[!CommandMeasure MeasureMoonShapeActionTimer "Execute 1"]

; Temporary measure for debug purposes - animates between new moon and full moon, then back
[MeasureMoonShapeActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 100 | Wait 1000 | Repeat Increase, 16, 100 | Reset
Increase=[!SetVariable moonPhase "(#moonPhase# + 0.005)"][!UpdateMeasure MeasureMoonShapePhaseCalc][!UpdateMeter MeterMoonShape][!UpdateMeasure MeasureMoonShapeActionTimer][!Redraw]
Reset=[!SetVariable moonPhase 0][!UpdateMeasure MeasureMoonShapePhaseCalc][!UpdateMeter MeterMoonShape][!UpdateMeasure MeasureMoonShapeActionTimer][!Redraw]
DynamicVariables=1``````
Last edited by GTI.H on December 31st, 2018, 5:56 pm, edited 2 times in total.
GTI.H
Posts: 75
Joined: December 15th, 2018, 3:35 am

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

Oh . . . Great, Good job!

Thank you for sharing the code, went through my head in making a skin similar to yours for any Astros (Moon/Sun/Earth/Etc.).

This would be better if the beginning and end of the arc represented the rising and setting of the Astro and that the arc represented the true orbit of the Astro and for this we need the equation that describes the orbit of the Astro!
It would be nice to have the equation that describes the phases of the moon, do you have this equation?

As I said before:
To solve this issue, the first way that come to my mind is to use meter Rotator moving with Sin/Cos functions by setting its X and Y positions.

--
Regards
GTI
raiguard wrote:
December 31st, 2018, 6:12 am
So, I have made some progress! I realized that I could use the sine and cosine of the moon limb's rotation angle to figure out how much the limb's bounding box has moved, and has therefore allowed me to fix the issue:

astrodial less-than-half fixed.gif

It works beautifully!

...NOT.

It only works if the moon phase is less than half a moon!

astrodial more-than-half broken.gif
If the moon phase is more than half a moon, then it behaves completely differently. I can't simply use the trigonometry that I used before, because now instead of being a nice semicircle, the shape is an irregularly shaped ellipse...

This would be so much easier if you could somehow retrieve the X and Y positions of shapes within a shape meter, not just the meter itself...

Edit: Or better yet, this would be completely 100% painless if you could 'group' shapes together without actually combining them, so I could move the entire moon icon as a single unit, rather than as three separate shapes.

Anyone have any input?

AstroDial.ini:

Code: Select all

``````[Rainmeter]
MiddleMouseUpAction=[!Refresh]
AccurateText=1

[Variables]
; Colors
colorBg=15,15,15
colorDialArc=150,150,150
colorMoon=200,200,200
colorMoonBg=30,30,30
colorMoonBorder=70,70,70
colorSun=250,222,110
; Dial settings
dialStartX=3
dialArcThickness=6
; Moon settings
moonBorderThickness=3
moonViewAngle=((#rawMVA# + #moonDialAngle#) % 360)

; =========================
; DEBUG TESTING VARIABLES
; =========================
; Sun / Moon Angles on the Dial (degrees)
sunDialAngle=-1
moonDialAngle=0
; Angle that the illuminated limb of the moon will face (degrees, starts North, counterclockwise)
rawMVA=0
; If set to 1, the moon will orient based on the value above. If set to 0, waxing will display on the right, and waning will display on the left.
showMoonAngle=1
; Moon phase value: 0.0 (new) -> 0.5 (full) -> 1.0 (new)
moonPhase=0.12

; ==================================================
; MEASURES
; ==================================================

[MeasureSunDialVisibility]
Measure=Calc
Formula=#sunDialAngle#
IfCondition=(MeasureSunDialVisibility > 180) || (MeasureSunDialVisibility < 0)
IfTrueAction=[!SetVariable sunDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable sunDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

[MeasureMoonDialVisibility]
Measure=Calc
Formula=#moonDialAngle#
IfCondition=(MeasureMoonDialVisibility > 180) || (MeasureMoonDialVisibility < 0)
IfTrueAction=[!SetVariable moonDialVisibility 0][!UpdateMeter MeterAstroDial][!Redraw]
IfFalseAction=[!SetVariable moonDialVisibility 255][!UpdateMeter MeterAstroDial][!Redraw]
DynamicVariables=1

; Converts the moon phase value into a radius value usable by the arc shape
[MeasureMoonShapePhaseCalc]
Measure=Calc
Formula=clamp(abs((#moonInnerRadius# * 4 * ((#moonPhase# > 0.5) ? (0.5 - (#moonPhase# - 0.5)) : #moonPhase#)) - #moonInnerRadius#),0,#moonInnerRadius#)
DynamicVariables=1
Group=MoonShape

; Adjusts the center of arc rotation for the moon limb shape in the X direction
[MeasureMoonLimbArcRotationXOffsetCalc]
Measure=Calc
DynamicVariables=1
Group=MoonShape

; Adjusts the center of arc rotation for the moon limb shape in the Y direction
[MeasureMoonLimbArcRotationYOffsetCalc]
Measure=Calc
DynamicVariables=1
Group=MoonShape

; TEMPORARY DEBUG - rotates the moon's illuminated limb 360 degrees
[MeasureActionTimer]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat Increase, 16, 180
ActionList2=ResetMove | Repeat Move, 16, 180
ActionList3=ResetMove | Repeat Both, 16, 180
ActionList4=Repeat Increase, 16, 5
Increase=[!SetVariable rawMVA "(#rawMVA# + 2)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Move=[!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
Both=[!SetVariable rawMVA "(#rawMVA# + 2)"][!SetVariable moonDialAngle "(#moonDialAngle# + 1)"][!SetVariable moonViewAngle "((#rawMVA# + #moonDialAngle#) % 360)"][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
ResetMove=[!SetVariable moonDialAngle 0][!UpdateMeasureGroup MoonShape][!UpdateMeter MeterAstroDial][!UpdateMeasure MeasureActionTimer][!Redraw]
DynamicVariables=1

; ==================================================
; METERS
; ==================================================

[MeterAstroDial]
Meter=Shape
; Arc
; Sun
; Moon
Shape6=Path MoonArc | StrokeWidth 0 | Fill Color #colorMoon# | Rotate (((#showMoonAngle# = 1) ? (-#moonViewAngle#) : ((#moonPhase# > 0.5) ? -90 : 90))),#moonInnerRadius#,#moonInnerRadius# | Offset #moonBorderThickness#,#moonBorderThickness# | StrokeLineJoin Round

Shape7=Combine Shape5 | Intersect Shape6 | Rotate #moonDialAngle#,(#dialRadius# + [MeasureMoonLimbArcRotationXOffsetCalc:]),([MeasureMoonLimbArcRotationYOffsetCalc:])

SolidColor=#colorBg#
DynamicVariables=1

[MeterDebugLimbRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 1"]
Antialias=1

[MeterDebugDialRotation]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Dial Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 2"]
Antialias=1

[MeterDebugBoth]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Both Rotations
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 3"]
Antialias=1

[MeterDebugStepLimb]
Meter=String
FontFace=Arial
FontSize=12
FontColor=230,230,230
SolidColor=#colorBg#
Y=R
Text=Debug Step Limb Rotation
LeftMouseUpAction=[!CommandMeasure MeasureActionTimer "Execute 4"]
Antialias=1``````
raiguard
Posts: 653
Joined: June 25th, 2015, 7:02 pm
Location: The Sky, USA

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

SparkShredder wrote:
December 31st, 2018, 8:26 am
Honestly, I'm not that of a pro coder, So, I'd have taken help from Photoshop.
I may create various icons and and leave transparent space on right side
and Used:
Meter=Rotator
MeasureName=HowMuchItShouldRotate
Image?=[WhichIconItshouldUseMeasure]

Blah Blah Blah
Unfortunately, since I am using a shape meter, using a rotator meter is not an option to me. I don't want to use static images for the moon phase - I have a script that very accurately calculates the moon phase, and I created a shape meter that can dynamically show that phase without needing to use images.

Thanks for the input though!
”We are pretty sure that r2922 resolves the regression in resolution caused by a reversion to a revision.” - jsmorley, 2017
raiguard
Posts: 653
Joined: June 25th, 2015, 7:02 pm
Location: The Sky, USA

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

GTI.H wrote:
December 31st, 2018, 4:00 pm
Hi raiguard,

I like math and am currently interested in orbital movements with Rainmeter.

I've been looking at your code in my spare time, but I do not know if I understood your wish. For me to understand your math I need to first study and familiarize with measures Shape and ActionTimer, but I can already feel the lack of trigonometric functions to solve a trigonometric issue.

I suspect that you have rewrote part of trigonometry (eg. x.cos=y) and that the error in AstroDial.ini starts in the second quadrant which leads us to suspect one of its conditions in Shape6 = Path MoonArc

To solve this issue, the first way that comes to my mind is to use a meter Rotator moving with Sin/Cos functions by setting its X and Y positions.

--
Regards
GTI
Unfortunately, once again, I can't use a rotator meter here. My moon icon is a dynamically created shape that matches a moon phase value from a LUA script. If I were to use a rotator meter, I would need to use images, which I do not want to do.

I'll fire up MS paint and try to explain the exact issue I'm encountering in more detail, so you (and others) can analyse it properly. Stay tuned.
GTI.H wrote:
December 31st, 2018, 5:54 pm
Oh . . . Great, Good job!

Thank you for sharing the code, went through my head in making a skin similar to yours for any Astros (Moon/Sun/Earth/Etc.).

This would be better if the beginning and end of the arc represented the rising and setting of the Astro and that the arc represented the true orbit of the Astro and for this we need the equation that describes the orbit of the Astro!
It would be nice to have the equation that describes the phases of the moon, do you have this equation?

As I said before:
To solve this issue, the first way that come to my mind is to use meter Rotator moving with Sin/Cos functions by setting its X and Y positions.

--
Regards
GTI
As it currently stands, the arc will represent the actual rising/setting of the sun and moon. It will not display the actual orbit of the objects, but simply be a representation of elapsed time between rising/setting. My eventual plan is to also represent the times for dawn/dusk, golden hours, meridian crossings, etc. in another arc below the dial. All of this information is gathered through a LUA script that I translated from JavaScript, called SunCalc. You can find the original JavaScript code here

Here is the script translated to LUA, with additions to make it work with Rainmeter skins:

Code: Select all

``````--[[
----------------------------------------------------------------------------------------------------
SUNCALC.LUA
raiguard
v1.0.5

This script is a form of 'SunCalc' by mourner, translated to LUA and adapted for Rainmeter
The original source code of SunCalc can be found at https://github.com/mourner/suncalc
See below to view SunCalc's source code license
----------------------------------------------------------------------------------------------------
CHANGELOG:
v1.0.5 - 2018-12-30
- Removed code from the Update() function to facilitate invoking the script multiple times
with different parameters through !CommandMeasure bangs
- Updated documentation
v1.0.4 - 2018-11-21
- Corrected timestamp conversion issues when monitoring a different timezone from the one the
PC is located in
v1.0.3 - 2018-11-09
- Removed suntime and moontime exports, FormatTimeString() function
v1.0.2 - 2018-11-02
- Improved moon phase name function
v1.0.1 - 2018-11-01
- Fixed crash when moonrise is nil
v1.0.0 - 2018-10-26
- Initial release
----------------------------------------------------------------------------------------------------
]]--

debug = false -- set to true to enable debug logging
data = { moonViewAngle = 0, moonPhase = 0, moonPhaseName = 'New Moon' } -- set default values

function Initialize() end

function Update() end

-- generates all of the data and translates it into a format usable by the skin.
-- invoke through a !CommandMeasure bang.
-- all data table outputs that have to do with time are given as Windows FILETIME values.
function GenerateData(timestamp, latitude, longitude, tzOffset)

-- setup timestamps
local timestamp, mDate, zDate, ysDate, tmDate = SetupTimestamps(timestamp, tzOffset)

-- retrieve data tables from SunCalc script
sunTimes = SunCalc.getTimes(mDate, latitude, longitude)
moonTimes = SunCalc.getMoonTimes(zDate, latitude, longitude)
sunPosition = SunCalc.getPosition(mDate, latitude, longitude)
moonPosition = SunCalc.getMoonPosition(mDate, latitude, longitude)
moonIllumination = SunCalc.getMoonIllumination(mDate, latitude, longitude)
-- debug logging
RmLog('getTimes():')
PrintTable(sunTimes)
RmLog('getMoonTimes():')
PrintTable(moonTimes)
RmLog('getPosition():')
PrintTable(sunPosition)
RmLog('getMoonPosition():')
PrintTable(moonPosition)
RmLog('getMoonIllumination():')
PrintTable(moonIllumination)

-- fix moonrise / moonset times if necessary
if moonTimes.rise ~= nil and (moonTimes.set == nil or moonTimes.set < moonTimes.rise and mDate > moonTimes.set) then
-- set moonset to that of the next day
moonTimes.set = SunCalc.getMoonTimes(tmDate, latitude, longitude)['set']
elseif moonTimes.rise == nil or (moonTimes.set < moonTimes.rise and mDate < moonTimes.set) then
-- set moonrise to that of the previous day
moonTimes.rise = SunCalc.getMoonTimes(ysDate, latitude, longitude)['rise']
end
-- calculate suntime and moontime in minutes
suntime = GetDifference(sunTimes.sunset, sunTimes.sunrise)
moontime = GetDifference(moonTimes.set, moonTimes.rise)

-- translate the data into the formats used by the skin
data.sunrise = UnixToFiletime(CorrectTimestamp(sunTimes.sunrise), tzOffset)
data.sunset = UnixToFiletime(CorrectTimestamp(sunTimes.sunset), tzOffset)
data.moonrise = UnixToFiletime(CorrectTimestamp(moonTimes.rise), tzOffset)
data.moonset = UnixToFiletime(CorrectTimestamp(moonTimes.set), tzOffset)
data.moonViewAngle = math.deg(moonIllumination.angle - moonPosition.parallacticAngle)
data.moonPhase = moonIllumination.phase
data.moonPhaseName = GetMoonPhaseName(data.moonPhase)

-- calculate sun and moon dial angles
data.sunDialAngle = (GetDifference(mDate, sunTimes.sunrise) / suntime) * 180
data.moonDialAngle = (GetDifference(mDate, moonTimes.rise) / moontime) * 180
-- brute-force reset angle to -1 if things get wacky or if the object is set
if data.sunDialAngle > 180 or data.sunDialAngle < 0 then data.sunDialAngle = -1 end
if data.moonDialAngle > 180 or data.moonDialAngle < 0 then data.moonDialAngle = -1 end
-- debug logging
RmLog('data:')
PrintTable(data)
SKIN:Bang('!UpdateMeasureGroup', 'SunCalc')
SKIN:Bang('!UpdateMeterGroup', 'SunCalc')
SKIN:Bang('!Redraw')

end

-- converts a Windows FILETIME timestamp into a Unix epoch timestamp, accounting for timezone and DST, then returns several useful timestamps
function SetupTimestamps(timestamp, tzOffset)

tzOffset = tzOffset or 0
local localTz = (GetTimeOffset() / 3600)
RmLog(localTz .. ' | ' .. tzOffset)
tDate = os.date("!*t", timestamp)
tDate.year = tDate.year - (1970 - 1601)
timestamp = os.time(tDate) - (os.date('*t')['isdst'] and 3600 or 0)
RmLog(timestamp)
mDate = tonumber(tostring(timestamp) .. '000')
zDate = tonumber(tostring(os.time{ year = tDate.year, month = tDate.month, day = tDate.day, hour = 0, min = 0, sec = 0 }) .. '000')
ysDate = zDate - 86400000
tmDate =  zDate + 86400000
RmLog('zDate: ' .. zDate)

return timestamp, -- current unix epoch timestamp value
mDate,     -- 'millisecond date' (timestamp with three extra zeroes)
zDate,     -- timestamp at current day, 0:00:00 (12:00 AM)
ysDate,    -- timestamp at yesterday, 0:00:00 (12:00 AM)
tmDate     -- timestamp at tomorrow, 0:00:00 (12:00 AM)

end

-- retrieves data from the data table using inline LUA in the skin
function GetData(key) return data[key] or '' end

-- ----- Utilities -----

moonPhases = {
{ 0.00, 0.03, 'New Moon'        },
{ 0.03, 0.23, 'Waxing Crescent' },
{ 0.23, 0.27, 'First Quarter'   },
{ 0.27, 0.48, 'Waxing Gibbous'  },
{ 0.48, 0.52, 'Full Moon'       },
{ 0.52, 0.73, 'Waning Gibbous'  },
{ 0.73, 0.77, 'Last Quarter'    },
{ 0.77, 0.98, 'Waning Crescent' },
{ 0.98, 1.01, 'New Moon'        }
}

function GetMoonPhaseName(phase)

for i,v in pairs(moonPhases) do
if phase >= v[1] and phase < v[2] then return v[3] end
end

return 'WTF?'

end

function UnixToFiletime(timestamp, tzOffset)

local tDate = os.date("*t", timestamp)
tDate.year = tDate.year + (1970 - 1601)
tDate.hour = tDate.hour + tzOffset
timestamp = os.time(tDate)
return timestamp

end

function GetTimeOffset() return (os.time() - os.time(os.date('!*t')) + (os.date('*t')['isdst'] and 3600 or 0)) end

function GetDifference(a1, a2) return ((a1 - a2) / 60000) end

-- function to make logging messages less cluttered
function RmLog(message, type)

if type == nil then type = 'Debug' end

if debug == true then
SKIN:Bang("!Log", message, type)
elseif type ~= 'Debug' then
SKIN:Bang("!Log", message, type)
end

end

printIndent = '     '

-- prints the entire contents of a table to the Rainmeter log
function PrintTable(table)
for k,v in pairs(table) do
if type(v) == 'table' then
local pI = printIndent
RmLog(printIndent .. tostring(k) .. ':')
printIndent = printIndent .. '  '
PrintTable(v)
printIndent = pI
else
RmLog(printIndent .. tostring(k) .. ': ' .. tostring(v))
end
end
end

-- ------------------------------------------------------------------------------------------------------------------------
-- ------------------------------------------------------------------------------------------------------------------------
-- ------------------------------------------------------------------------------------------------------------------------

--[[
SunCalc is a JavaScript library for calculating sun/moon position and light phases.
https://github.com/mourner/suncalc

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.

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 HOLDER 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.
]]--

-- shortcuts for easier to read formulas

PI   = math.pi
sin  = math.sin
cos  = math.cos
tan  = math.tan
asin = math.asin
atan = math.atan2
acos = math.acos

-- sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas

-- date/time constants and conversions

dayMs = 1000 * 60 * 60 * 24
J1970 = 2440588
J2000 = 2451545

function toJulian(date)  return date / dayMs - 0.5 + J1970  end
function fromJulian(j)   return (j + 0.5 - J1970) * dayMs  end

-- general calculations for position

e = rad * 23.4397 -- obliquity of the Earth

function rightAscension(l, b)  return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));  end
function declination(l, b)     return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));  end

function azimuth(H, phi, dec)   return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi));  end
function altitude(H, phi, dec)  return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));  end

function siderealTime(d, lw)  return rad * (280.16 + 360.9856235 * d) - lw;  end

function astroRefraction(h)
if (h < 0) then -- the following formula works for positive altitudes only.
h = 0 -- if h = -0.08901179 a div/0 would occur.
end

-- formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
-- 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / math.tan(h + 0.00312536 / (h + 0.08901179))

end

-- general sun calculations

function solarMeanAnomaly(d)  return rad * (357.5291 + 0.98560028 * d)  end

function eclipticLongitude(M)

local C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)) -- equation of center
local P = rad * 102.9372 -- perihelion of the Earth

return M + C + P + PI
end

function sunCoords(d)

M = solarMeanAnomaly(d)
L = eclipticLongitude(M)

return {
dec = declination(L, 0),
ra = rightAscension(L, 0)
}

end

SunCalc = {}

-- calculates sun position for a given date and latitude/longitude

SunCalc.getPosition = function (date, lat, lng)

d   = toDays(date)
c  = sunCoords(d)
H  = siderealTime(d, lw) - c.ra

return {
azimuth = azimuth(H, phi, c.dec),
altitude = altitude(H, phi, c.dec)
}

end

-- sun times configuration (angle, morning name, evening name)

times = {
{-0.833, 'sunrise',       'sunset'      },
{  -0.3, 'sunriseEnd',    'sunsetStart' },
{    -6, 'dawn',          'dusk'        },
{   -12, 'nauticalDawn',  'nauticalDusk'},
{   -18, 'nightEnd',      'night'       },
{     6, 'goldenHourEnd', 'goldenHour'  }
}

-- adds a custom time to the times config

SunCalc.addTime = function (angle, riseName, setName)
table.insert(times, {angle, riseName, setName})
end

-- calculations for sun times

J0 = 0.0009

function julianCycle(d, lw)  return math.round(d - J0 - lw / (2 * PI))  end

function approxTransit(Ht, lw, n)  return J0 + (Ht + lw) / (2 * PI) + n  end
function solarTransitJ(ds, M, L)   return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L)  end

function hourAngle(h, phi, d)  return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d)))  end

-- returns set time for the given sun altitude
function getSetJ(h, lw, phi, dec, n, M, L)

w = hourAngle(h, phi, dec)
a = approxTransit(w, lw, n)
return solarTransitJ(a, M, L)

end

-- calculates sun times for a given date and latitude/longitude

SunCalc.getTimes = function (date, lat, lng)

d = toDays(date)
n = julianCycle(d, lw)
ds = approxTransit(0, lw, n)

M = solarMeanAnomaly(ds)
L = eclipticLongitude(M)
dec = declination(L, 0)

Jnoon = solarTransitJ(ds, M, L)

i, len, time, Jset, Jrise = nil

result = {
solarNoon = fromJulian(Jnoon),
}

for i = 1,table.length(times) do
time = times[i]

Jset = getSetJ(time[1] * rad, lw, phi, dec, n, M, L)
Jrise = Jnoon - (Jset - Jnoon)

result[time[2]] = fromJulian(Jrise)
result[time[3]] = fromJulian(Jset)
end

return result

end

-- moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas

function moonCoords(d) -- geocentric ecliptic coordinates of the moon

L = rad * (218.316 + 13.176396 * d) -- ecliptic longitude
M = rad * (134.963 + 13.064993 * d) -- mean anomaly
F = rad * (93.272 + 13.229350 * d)  -- mean distance

l  = L + rad * 6.289 * sin(M) -- longitude
b  = rad * 5.128 * sin(F)    -- latitude
dt = 385001 - 20905 * cos(M)  -- distance to the moon in km

return {
ra = rightAscension(l, b),
dec = declination(l, b),
dist = dt
}

end

SunCalc.getMoonPosition = function (date, lat, lng)

d   = toDays(date)

c = moonCoords(d)
H = siderealTime(d, lw) - c.ra
h = altitude(H, phi, c.dec)
-- formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H))

h = h + astroRefraction(h) -- altitude correction for refraction

return {
azimuth = azimuth(H, phi, c.dec),
altitude = h,
distance = c.dist,
parallacticAngle = pa
}

end

-- calculations for illumination parameters of the moon,
-- based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
-- Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.

SunCalc.getMoonIllumination = function (date)

d = toDays(date)
s = sunCoords(d)
m = moonCoords(d)

sdist = 149598000 -- distance from Earth to Sun in km

phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra))
inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi))
angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra))

return {
fraction = (1 + cos(inc)) / 2,
phase = 0.5 + 0.5 * inc * (angle < 0 and -1 or 1) / math.pi,
angle = angle
}

end

function hoursLater(date, h)
return date + h * dayMs / 24
end

-- calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article

SunCalc.getMoonTimes = function (date, lat, lng)

t = date
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx = nil

-- go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
for i=1,24,2 do
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc

a = (h0 + h2) / 2 - h1
b = (h2 - h0) / 2
xe = -b / (2 * a)
ye = (a * xe + b) * xe + h1
d = b * b - 4 * a * h1
roots = 0

if d >= 0 then
dx = math.sqrt(d) / (math.abs(a) * 2)
x1 = xe - dx
x2 = xe + dx
if math.abs(x1) <= 1 then roots = roots + 1 end
if math.abs(x2) <= 1 then roots = roots + 1 end
if x1 < -1 then x1 = x2 end
end

if roots == 1 then
if h0 < 0 then rise = i + x1
else set = i + x1 end

elseif roots == 2 then
rise = i + (ye < 0 and x2 or x1)
set = i + (ye < 0 and x1 or x2)
end

if rise and set then break end

h0 = h2
end

result = {}

if rise then result.rise = hoursLater(t, rise) end
if set then result.set = hoursLater(t, set) end

if not rise and not set then result[ye > 0 and 'alwaysUp' or 'alwaysDown'] = true end

return result

end

-- ---------- NOT PART OF THE ORIGINAL SCRIPT - HAD TO BE ADDED FOR THE SCRIPT TO WORK IN LUA ----------

function math.round(x)
if x%2 ~= 0.5 then
return math.floor(x+0.5)
end
return x-0.5
end

function table.length(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end``````
”We are pretty sure that r2922 resolves the regression in resolution caused by a reversion to a revision.” - jsmorley, 2017
balala
Rainmeter Sage
Posts: 9799
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

Please pack the whole config (with all needed files - like the .lua - and resources) and upload it.
raiguard
Posts: 653
Joined: June 25th, 2015, 7:02 pm
Location: The Sky, USA

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

balala wrote:
December 31st, 2018, 9:06 pm
Please pack the whole config (with all needed files - like the .lua - and resources) and upload it.
I actually removed tons of irrelevant code from the skin and merged it all into one file to simplify debugging the moon icon. The skin right now doesn't use SunCalc, and doesn't require any external files to work. Would you still like me to package the original?
”We are pretty sure that r2922 resolves the regression in resolution caused by a reversion to a revision.” - jsmorley, 2017
balala
Rainmeter Sage
Posts: 9799
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

### Re: [Lots of Math] Moon Icon Rotation on a Sky Dial

raiguard wrote:
December 31st, 2018, 9:12 pm
I actually removed tons of irrelevant code from the skin and merged it all into one file to simplify debugging the moon icon. The skin right now doesn't use SunCalc, and doesn't require any external files to work. Would you still like me to package the original?
You've posted the content of a .lua file, that's why I asked to upload it. How does the latest code look like? If you've changed the lastly posted code, please post / upload it.