Пробелы в линии при попытке нарисовать их с помощью мыши - PullRequest
2 голосов
/ 30 мая 2019

Я написал программу для рисования функции греха так, что ее нелегко объяснить, но действительно легко ее увидеть, так что в этом вся

import pygame
import math
import fractions

window = pygame.display.set_mode((0, 0))#, pygame.FULLSCREEN)
pygame.font.init()
running = True
w, h = pygame.display.get_surface().get_size()
myfont = pygame.font.SysFont("monospace", 12)
myfont2 = pygame.font.SysFont("monospace", 30)

white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
green = (0, 255, 0)
wCol = (100, 100, 100)
yellow = (0, 0, 255)

#temp
last = [0, 0]
lastQ = 0
q = 0

unit = 50
radius = 100
xa = int(w/3)
ya1 = 0
ya2 = int(h)
xb1 = 0
xb2 = int(w)        
yb = int(h/2)
xc = int(xa - radius)
yc = int(yb)
subtraction = 2
rotCount = 0
points = []

def check4points(angleC, sinC):
    isInArr = False
    for i in points:
        if i[0] == angleC and i[1] == sinC:
            isInArr = True
        else:
            isInArr = False
    return(isInArr)

def draw():
    global points
    window.fill(white)
    #axis and units
    pygame.draw.line(window, black, (xa, ya1), (xa, ya2), 2) # OY
    pygame.draw.line(window, black, (xb1, yb), (xb2, yb), 2) # OX
    #x units
    deltaU = 0
    for i in range(xa, w, 50):
        pygame.draw.line(window, black, (i, (yb - 5)), (i, (yb + 5)), 1)
        text = myfont.render(str(fractions.Fraction(deltaU).limit_denominator()) + "PI", 1, black)
        window.blit(text, (i - 15, yb + 5))
        deltaU += 1/6
    deltaU = 0
    for i in range(xa, 0, -50):
        pygame.draw.line(window, black, (i, (yb - 5)), (i, (yb + 5)), 1)
        text = myfont.render(str(fractions.Fraction(deltaU).limit_denominator()) + "PI", 1, black)
        window.blit(text, ((i) - 15, yb + 5))
        deltaU -= 1/6
    #y units
    deltaU = 0
    for i in range(yb, h, 50):
        pygame.draw.line(window, black, ((xa - 5), i), ((xa + 5), i), 1)
        text = myfont.render(str(deltaU), 1, black)
        window.blit(text, (xa + 10, i - 10))
        deltaU -= 0.5
    deltaU = 0
    for i in range(yb, 0, -50):
        pygame.draw.line(window, black, ((xa - 5), i), ((xa + 5), i), 1)
        text = myfont.render(str(deltaU), 1, black)
        window.blit(text, (xa + 10, i - 10))
        deltaU += 0.5
    text1 = myfont2.render("Kąt: " + str(angle), 2, black)
    text2 = myfont2.render("Sinus kąta: " + str(sinFinal), 2, black)
    text3 = myfont2.render("R - Reset", 2, black)
    window.blit(text1, (50, 100))
    window.blit(text2, (50, 130))
    window.blit(text3, (w*0.9, h*0.9))

    #circle thingy
    pygame.draw.circle(window, black, (xc, yc), radius, 2)
    pygame.draw.line(window, wCol, (xa - (2*unit), yb), satelliteCenter, 3)
    #pygame.draw.line(window, wCol, (mouse_xPos, mouse_yPos), (mouse_xPos, yb), 2)
    #pygame.draw.line(window, wCol, (mouse_xPos, mouse_yPos), (xa, mouse_yPos), 2)


    #point/sin graph
    pygame.draw.line(window, yellow, satelliteCenter, (satelliteCenter[0], yb), 2)
    pygame.draw.line(window, wCol, satelliteCenter, (w, satelliteCenter[1]), 2)
    pygame.draw.line(window, wCol, (0, satelliteCenter[1]), satelliteCenter, 2)
    pygame.draw.circle(window, red, satelliteCenter, 6)

    sinC = int(yb - (sinFinal * 100))
    angleC = (int(angle*(5/9)*3) + xa)

    point = [angleC, sinC]

    if check4points(angleC, sinC) == False:
        points.append(point)

    for i in range(len(points) - 1):
        pygame.draw.circle(window, red, (points[i][0], points[i][1]), 6, 0)

    pygame.draw.line(window, yellow, (angleC, sinC), (angleC, yb), 2)

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            quit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                running = False
                quit()
            if event.key == pygame.K_LEFT:
                rotCount -= 1
            if event.key == pygame.K_RIGHT:
                rotCount += 1
            if event.key == pygame.K_r:
                points = []
                rotCount = 0

    mouse_xPos = pygame.mouse.get_pos()[0]
    mouse_yPos = pygame.mouse.get_pos()[1]

    satelliteCenter = (xc+radius, yb)
    vector = (mouse_xPos-xc, mouse_yPos-yb)
    distance = (vector[0]**2 + vector[1]**2)**0.5

    if distance > 0:
        scalar = radius/distance
        satelliteCenter = (int(round(xc + vector[0]*scalar)),
                           int(round(yb + vector[1]*scalar)) )

    if q == 1 and lastQ == 4:    
        rotCount += 1
    elif q == 4 and lastQ == 1:
        rotCount -= 1

    lastQ = q


    last = satelliteCenter

    xrel = (mouse_xPos - xa)/50
    yrel = -(mouse_yPos - yb)/50
    xcircle = -2

    x = xrel - xcircle
    y = yrel
    hypotenuse = math.sqrt(x**2 + y**2)

    sin = y/hypotenuse
    angle = math.degrees(math.asin(sin))
    if x >= 0 and y > 0:
        angle = angle + (rotCount*360)
        q = 1
    elif x > 0 and y <= 0:
        angle = angle + 360 + (rotCount*360)
        q = 4
    elif x <= 0 and y < 0:
        angle = 180 - angle + (rotCount*360)
        q = 3
    elif x < 0 and y >= 0:
        angle = 180 - angle + (rotCount*360)
        q = 2

    sinFinal = math.sin(math.radians(angle))

    draw()

    pygame.display.flip()

Я попытался вычесть координату x последней нарисованной точки и координату x текущей нарисованной точки и проверить, больше ли она заданного числа (например, 2 пикселя). Кажется, что он не работает и действительно неэффективен

Это линии, рисующие точки:


    sinC = int(yb - (sinFinal * 100))
    angleC = (int(angle*(5/9)*3) + xa)

    point = [angleC, sinC]

    if check4points(angleC, sinC) == False:
        points.append(point)

    for i in range(len(points) - 1):
        pygame.draw.circle(window, red, (points[i][0], points[i][1]), 6, 0)

    pygame.draw.line(window, yellow, (angleC, sinC), (angleC, yb), 2)

Если бы вы могли, пожалуйста, скажите мне, как я мог бы воспринимать плавную линию. Заранее спасибо:)

Кстати, не судите меня за мой код спагетти, я только начинающий: D

1 Ответ

0 голосов
/ 30 мая 2019

Используйте round вместо int:

sinC   = round(yb - (sinFinal * 100))
angleC = round(angle*(5/9)*3 + xa)

Чтобы найти существующие точки в списке (points), достаточно найти any точку с той же x координатой:

any([x for x in points if x==point[0]])

Сортировка (sorted) списка точек после добавления новой точки:

point = [angleC, sinC]
if not any([x for x in points if x==point[0]]):
    points.append(point)
    points = sorted(points, key = lambda p : p[0])

Когда кривая нарисована, вычислите x расстояние точки до ее преемника и предшественника:

dist_p = 0 if i==0 else points[i][0]-points[i-1][0]
dist_s = 0 if i>len(points)-2 else points[i+1][0]-points[i][0]

Нарисуйте точку, когда расстояние до преемника и предшественника достигнет определенного threshold, и проведите линию еще:

sinC   = round(yb - (sinFinal * 100))
angleC = round(angle*(5/9)*3 + xa)

point = [angleC, sinC]
if not any([x for x in points if x==point[0]]):
    points.append(point)
    points = sorted(points, key = lambda p : p[0])

threshold = 10
for i in range(len(points)):
    dist_p = 0 if i==0 else points[i][0]-points[i-1][0]
    dist_s = 0 if i>len(points)-2 else points[i+1][0]-points[i][0]
    if dist_p > threshold and dist_s > threshold: 
        pygame.draw.circle(window, red, points[i], 6, 0)
    elif 0 < dist_p < threshold:
        pygame.draw.line(window, red, points[i-1], points[i], 2)
...