如何在Pygame或Matplotlib中绘制天文正确的新月形

问题描述

Pyephem以[0.0,1.0]中的数字为我提供亮度,> 0刚好在新月之后,

我正在创建月球的图形表示,因此,我试图呈现天文学上正确的月牙(或月球?)。

我的系统使用Pygame进行音频和图形处理,但是看起来填充区域在matplotlib中更容易使用,并且我为这两种技术都提供了连接器,因此解决方案可以使用这两种技术。

到目前为止,我的方法是渲染一个白色圆圈和一个黑色圆圈,将其涂在临时曲面上,在该曲面上调整Alpha。稍后,我将计算当前月球的名称,并根据月球名称(例如,狼月,血月等)来选择背景。

我当前的代码有点像月相,但是看起来不太正确。我不确定从哪里开始寻找正确的参数...我认为主要的问题是找出食偏圆的比例,然后找出其中心的正确偏移量。

def arc_patch (ax,lunacity): # https://stackoverflow.com/questions/58263608/fill-between-arc-patches-matplotlib
    ax.grid (False)
    xmin = -85 # Todo don't use magic numbers
    xmax = +85
    xrng = xmax - xmin
    ymin = -85
    ymax = +85
    yrng = ymax - ymin
    ax.set_xlim (xmin,xmax)
    ax.set_ylim (ymin,ymax)
    
    # Use a predefined colormap
    colormap = []
    
    # Draw multiple ellipses with different colors and style. All are perfectly superposed
    ellipse = mpl.patches.Ellipse (  # Base one,with big black line for reference
        ORIGIN,xrng,yrng,color='k',fill=False,zorder=100) # Todo what is zorder ?

    # Define some clipping paths
    # One for each area
    clips = [
        mpl.patches.Arc ( # the moon,both light and dark
            ORIGIN,theta1=0,theta2=360,visible=False  # We do not need to display it,just to use it for clipping
        ),]
    colormap.append ('purple') # invisible
    
    if lunacity < .25:       # 0,.25 => new moon,first quarter moon
        print ("q0-q1")
        
        lun = lunacity * 4   # 0,1.
        lun = 1 - lun        # 1,0.
        lun = 1 / lun        # 1,inf

        rx,ry = xrng,yrng * lun
    
        X,Y = ORIGIN        # center of light circle
        X = X - (rx / 2) * ((lunacity - 0) * 4)
        x,y = X,Y          # center of dark circle
        Arc1_xy = x,y
        
        # draw light circle,then dark circle
        light_patch = mpl.patches.Ellipse (
            ORIGIN,visible=False)
        dark_patch = mpl.patches.Ellipse (
            Arc1_xy,rx,ry,visible=False)
        colormap.append ('white')
        colormap.append ('black')
        clips.append (light_patch)
        clips.append ( dark_patch)
        
    elif lunacity < .5:       #  .25,.5  => first quarter moon,full moon
        print ("q1-q2")
        
        assert .25 <= lunacity
        lun = lunacity - .25 # 0.,.25
        assert lun >= 0
        assert lun < .25
        lun = lun * 4        # 0.,1.
        assert lun >= 0
        assert lun < 1
        lun = 1 / lun        # inf,1.
        assert lun >= 1
        print ("lun: %s" % (lun,))
        
        rx,Y = ORIGIN        # center of dark circle
        X = X + (rx / 2) * (1 - ((lunacity - .25) * 4))
        x,Y          # center of light circle
        Arc1_xy = x,y
        
        print ("(x: %s,y: %s),(w: %s,h: %s)" % (x,y,ry))
        
        # draw dark circle,then light circle
        dark_patch = mpl.patches.Ellipse (
            ORIGIN,visible=False)
        light_patch = mpl.patches.Ellipse (
            Arc1_xy,visible=False)
        colormap.append ('black')
        colormap.append ('white')
        clips.append ( dark_patch)
        clips.append (light_patch)
    elif lunacity < .75:     #  .5,.75 => full moon,third quarter moon
        print ("q2-q3")
        
        assert .5 <= lunacity
        lun = lunacity - .5  # 0.,1.
        assert lun >= 0
        assert lun < 1
        lun = 1 - lun        # 1.,0.
        assert lun > 0
        assert lun <= 1
        lun = 1 / lun        # 1.,inf
        assert lun >= 1
        print ("lun: %s" % (lun,Y = ORIGIN        # center of light circle
        X = X - (rx / 2) * ((lunacity - .5) * 4)
        x,visible=False)
        colormap.append ('black')
        colormap.append ('white')
        clips.append ( dark_patch)
        clips.append (light_patch)
    elif lunacity < 1.0:     #  .75,1.   => third quarter moon,full moon
        print ("q3-q4")

        assert .75 <= lunacity
        lun = lunacity - .75 # 0.,1.
        assert lun > 1
        print ("lun: %s" % (lun,Y = ORIGIN        # center of light circle
        X = X + (rx / 2) * (1 - ((lunacity - .75) * 4))
        x,ry))
        
        # draw light circle,visible=False)
        colormap.append ('white')
        colormap.append ('black')
        clips.append (light_patch)
        clips.append ( dark_patch)
    
    n = len (clips)
    # Ellipses for your sub-areas.
    # Add more if you want more areas
    # Apply the style of your areas here (colors,alpha,hatch,etc.)
    areas = [
        mpl.patches.Ellipse (
            ORIGIN,# Perfectly fit your base ellipse
            color=colormap [i],fill=True,alpha=1.0,# Add some style,fill,color,alpha
            zorder=i)
        for i in range (n)  # Here,we have 4 areas
    ]

    # Add all your components to your axe
    ax.add_patch (ellipse)
    for area,clip in zip (areas,clips):
        ax.add_patch (area)
        ax.add_patch (clip)
        area.set_clip_path (clip)  # Use clipping paths to clip you areas

更多地研究了问题之后,我发现我正在向后看椭圆的轴。修改后,我有了这个,但是圆弧的起始/结束角度出了点问题(看来matplotlib遵守了theta1和theta2)或剪辑顺序:

if lunacity < .25:       # 0,0.
        
        rx,ry = xrng * lun,yrng
        
        # dark left,dark middle,light right
        light_patch = mpl.patches.Ellipse ( # right half
            ORIGIN,visible=False) # theta1=-90,theta2=+90
        dark_patch = mpl.patches.Ellipse ( # center
            ORIGIN,visible=False)
        dark_patch2 = mpl.patches.Arc ( # left half
            ORIGIN,theta1=+90,theta2=+270,visible=False)
        colormap.append ('black')
        colormap.append ('white')
        colormap.append ('black')
        clips.append ( dark_patch2)
        clips.append (light_patch)
        clips.append ( dark_patch)
        
    elif lunacity < .5:       #  .25,1.
        assert lun >= 0
        assert lun < 1
        
        rx,light middle,light right
        light_patch2 = mpl.patches.Ellipse (  # right
            ORIGIN,theta2=+90
        dark_patch = mpl.patches.Arc (  # left
            ORIGIN,visible=False)
        light_patch = mpl.patches.Ellipse (  # middle
            ORIGIN,visible=False)
        colormap.append ('white')
        colormap.append ('black')
        colormap.append ('white')
        clips.append (light_patch2)
        clips.append ( dark_patch)
        clips.append (light_patch)
    elif lunacity < .75:     #  .5,0.
        assert lun > 0
        assert lun <= 1
        rx,yrng
    
        # light left,dark right
        light_patch2 = mpl.patches.Ellipse (  # left
            ORIGIN,visible=False) # theta1=+90,dark_patch = mpl.patches.Arc (  # right
            ORIGIN,theta1=-90,theta2=+90,visible=False)
        colormap.append ('white')
        colormap.append ('black')
        colormap.append ('white')
        clips.append (light_patch2)
        clips.append ( dark_patch)
        clips.append (light_patch)
    elif lunacity < 1.0:     #  .75,yrng
        
        # light left,dark right
        dark_patch2 = mpl.patches.Ellipse (  # right
            ORIGIN,theta2=+90
        light_patch = mpl.patches.Arc (  # left
            ORIGIN,visible=False)
        dark_patch = mpl.patches.Ellipse (  # middle
            ORIGIN,visible=False)
        colormap.append ('black')
        colormap.append ('white')
        colormap.append ('black')
        clips.append ( dark_patch2)
        clips.append (light_patch)
        clips.append ( dark_patch)

解决方法

几何:

“观察者所看到的球形物体(最显着的是月亮)的发光面的形状似乎少于被太阳照亮的一半,而形状不同于通常称为平面的月牙形几何:假设终结器位于一个大圆上,那么新月形月亮实际上将以半椭圆和半圆为界,椭圆的长轴与半圆的直径重合。” >

https://en.wikipedia.org/wiki/Crescent#Shape

我不知道为什么要打补丁.Arc没有使用theta1和theta2,所以我切换到了patch.Rectangle:

light_patch2 = mpl.patches.Rectangle (  # right
            *rrect,visible=False)
        dark_patch = mpl.patches.Rectangle (  # left
            *lrect,visible=False)
        light_patch = mpl.patches.Ellipse (  # middle
            ORIGIN,rx,ry,visible=False)
        colormap.append ('white')
        colormap.append ('black')
        colormap.append ('white')
        clips.append (light_patch2)
        clips.append ( dark_patch)
        clips.append (light_patch)