shapes.py

Created by airopi

Created on March 22, 2022

5.3 KB

Un script python pour dessiner des figures géométriques ! (Cercles, triangles, hexagones, étoiles… shurikens ?)

Même ce que vous voulez enfaite !

Utilisation :

Les fonctions de dessins :

polygone(x,y,nb_sides,side?,r?,orient?,co?) : dessiner un polygone régulier
figure(points,co?) : dessiner une figure avec des points
line(pt1,pt2,co?) : dessiner une ligne
lines(points,close?,co?) : dessiner des ligne entre plusieurs points
circle(x,y,r,inside_r,co?) : tracer un cercle
rectangle(x,y,width,height,co?) : tracer un rectangle
triangle(x,y,side,orient?,co?) : tracer un triangle
etoile(x,y,nb_sides,outside_r,inside_r,orient?) : tracer une étoile
shuriken(x,y,nb_sides,outside_r,inside_r,orient?) : tracer un shuriken
random(co?) : tracer une forme aléatoire

Quelques variables à connaitre :

y int : coordonnée y
x int : coordonée x
width int : largeur du rectangle
height int : hauteur du rectangle
side int : longueur d’un coté
r int : le rayon d’un cercle ou d’un polygone
outside_r int : le rayon du cercle extérieur
inside_r int : le rayon du cercle intérieur
nb_sides int : le nombre de cotés d’un polygone
orient int : l’orientation d’un polygone
co tuple[int] : la couleur d’une figure
pt tuple[int] : un point
points tuple[int] | tuple[tuple[int]] : une liste de points
close bool : si la figure est fermée ou no

Quelques exemples :

etoile(160,111,5,100,30,45,(255,100,100))
shuriken(160,111,5,100,-30,45)
circle(160,111,100,50,(100,255,100))

Les fonctions bonus :

Ces commandes peuvent être supprimées du programme.

help_shapes() : afficher les fonctions de dessin
exemples() : afficher des exemples


from kandinsky import *
from math import *
from random import randint

default_co=(100,100,100)

# Utility functions

def _radius(side,nb_sides):
  alpha=radians(360/nb_sides)
  return (side/2)/sin(alpha/2)

def _lenght_side(r,nb_sides):
  alpha=radians(360/nb_sides)
  return 2*r*sin(alpha/2)

def _diagonal_from_side(side,nb_sides):
  r=_radius(side,nb_sides)
  if nb_sides%2==0:
    return r*2
  q=sqrt(r**2-(side/2)**2)
  return q+r

def _diagonal_from_radius(r,nb_sides):
  if nb_sides%2==0:
    return r*2
  ln_s=_lenght_side(r,nb_sides)
  q=sqrt(r**2-(ln_s/2)**2)
  return q+r

def _minmax(array):
  return min(array), max(array)

def _line_eq(pt1,pt2,from_x=True):
  if from_x:
    return lambda x:round(pt1[1]+(pt2[1]-pt1[1])*(x-pt1[0])/(pt2[0]-pt1[0])) if pt2[0]-pt1[0] else pt1[0]
  else:
    return lambda y:round(pt1[0]+(pt2[0]-pt1[0])*(y-pt1[1])/(pt2[1]-pt1[1])) if pt2[1]-pt1[1] else pt1[1]


# Base functions :

def figure(points,co=default_co):
  _co=color(*co)

  vectors=[]

  def _append_vectors(pts):
    vectors.extend((pts[i-1], pts[i]) for i in range(len(pts)))

  if isinstance(points[0][0], int):  # ((x,y),(x,y),...)
    _append_vectors(points)
  else:  # (((x,y),(x,y),...),((x,y),(x,y),...),...)
    for sub_points in points:
      _append_vectors(sub_points)
    points=[p for pts in points for p in pts]

  x_values=tuple(p[0] for p in points)
  min_x=min(x_values)
  max_x=max(x_values)

  for x in range(min_x,max_x):
    if (x-1) in x_values or x == min_x:
      precedent=None
      path_vectors=[]
      for vector in vectors:
        if not min(vector[0][0], vector[1][0]) <= x <= max(vector[0][0],vector[1][0]):continue
        if precedent and precedent[1][0]==vector[0][0]:
          if not ((precedent[0][0]<vector[0][0] and vector[1][0]<vector[0][0])
            or (precedent[0][0]>vector[0][0] and vector[1][0]>vector[0][0])):continue
        precedent=vector
        path_vectors.append(precedent)

    path=tuple(sorted(_line_eq(*vector)(x) for vector in path_vectors))

    for i in range(0, len(path), 2):
      try:fill_rect(x,path[i],1,path[i+1]-path[i],_co)
      except:pass #sometimes something messup idk why

def _polygone_points(x,y,nb_sides,side=None,r=None,orient=0):
  if side and r:
    raise ValueError("You can't give both side and r")
  elif side:
    h=_diagonal_from_side(side,nb_sides)
    r=_radius(side,nb_sides)
  elif r:
    h=_diagonal_from_radius(r,nb_sides)
  else:
    raise ValueError("Missing side or r")

  orient=radians(orient)
  alpha=radians(360/nb_sides)

  points=[]
  for i in range(nb_sides):
    points.append(
      (round(x+r*cos(orient+i*alpha+pi/nb_sides)),
      round(y-r*sin(orient+i*alpha+pi/nb_sides)))
    )

  return points

def polygone(x,y,nb_sides,side=None,r=None,orient=0,co=default_co):
  points=_polygone_points(x,y,nb_sides,side,r,orient)
  figure(points,co)

def line(pt1,pt2,co=default_co):
  _co=color(*co)

  xy=_line_eq(pt1,pt2)
  yx=_line_eq(pt1,pt2,False)

  for x in range(min(pt1[0],pt2[0]),max(pt1[0],pt2[0])):
    set_pixel(x,xy(x),_co)
  for y in range(min(pt1[1],pt2[1]),max(pt1[1],pt2[1])):
    set_pixel(yx(y),y,_co)

def lines(points,close=False,co=default_co):
  if close:
    points=tuple(points)+(points[0],)
  for i in range(len(points)-1):
    line(points[i],points[i+1],co)


# Child functions

def rectangle(x,y,width,height,co=default_co):
  _co=color(*co)
  fill_rect(x,y,width,height,_co)

def triangle(x,y,side,orient=0,co=default_co):
  polygone(x,y,3,side=side,orient=orient,co=co)

def shuriken(x,y,nb_sides,outside_r,inside_r,orient=0,co=default_co):
  points_out=_polygone_points(x,y,nb_sides,r=outside_r,orient=orient)
  points_in=_polygone_points(x,y,nb_sides,r=inside_r,orient=360/nb_sides+orient)
  points=[x for y in zip(points_out,points_in) for x in y]
  figure(points,co)

def etoile(x,y,nb_sides,outside_r,inside_r,orient=0,co=default_co):
  points_out=_polygone_points(x,y,nb_sides,r=outside_r,orient=orient)
  points_in=_polygone_points(x,y,nb_sides,r=inside_r,orient=180/nb_sides+orient)
  points=[x for y in zip(points_out,points_in) for x in y]
  figure(points,co)

def circle(x,y,r,inside_r=0,co=default_co):
  _co=color(100,100,100)

  if not inside_r:
    for i in range(r):
      h=int(r*sin(acos(i/r)))
      fill_rect(x+i,y-h,1,h*2,_co)
      fill_rect(x-i,y-h,1,h*2,_co)
  else:
    for i in range(r):
      h=int(r*sin(acos(i/r)))
      ih=int(inside_r*sin(acos(i/inside_r))) if i<=inside_r else 0

      fill_rect(x+i,y-h,1,h-ih,_co)
      fill_rect(x+i,y+h,1,-h+ih,_co)
      fill_rect(x-i,y-h,1,h-ih,_co)
      fill_rect(x-i,y+h,1,-h+ih,_co)

def random(co=default_co):
  points=[]
  for i in range(randint(20,30)):
    points.append((randint(0,320),randint(0,222)))

  lines(points,True,co)
  figure(points,co)


# Other functions

def help_shapes():
  print("polygone(x,y,nb_sides,side?,r?,orient?,co?)")
  print("figure(points,co?)")
  print("line(pt1,pt2,co?)")
  print("lines(points,close?,co?)")
  print()
  print("circle(x,y,r,inside_r,co?)")
  print("rectangle(x,y,width,height,co?)")
  print("triangle(x,y,side,orient=0,co?)")
  print("etoile(x,y,nb_sides,outside_r,inside_r,orient=0,co?)")
  print("shuriken(x,y,nb_sides,outside_r,inside_r,orient=0,co?)")
  print("random(co?)")

def exemples():
  print("etoile(160,111,5,100,30,45,(255,100,100))")
  print("shuriken(160,111,5,100,-30,45)")
  print("circle(160,111,100,50,(100,255,100))")