From 95231b375e27af8994e9790cabb19d245fd7e826 Mon Sep 17 00:00:00 2001 From: Discusser <47938380+Discusser@users.noreply.github.com> Date: Wed, 11 Jun 2025 07:58:11 +0200 Subject: [PATCH 1/5] Fix list comprehension issue with fill_rectangle --- src/visual/visual.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/visual/visual.py b/src/visual/visual.py index 6299e88..d5d3eb7 100644 --- a/src/visual/visual.py +++ b/src/visual/visual.py @@ -64,7 +64,9 @@ def fill_polygone(n,rayon,coord,color='0',c_map=None,alpha=1): for p,c in zip(connect_points(points,True),[color for _ in range(len(points))] if not isinstance(c_map,list) else c_map):fill_triangles([([coord,p[0],p[1]])],c,alpha) def draw_rectangle(P1,P4,color='0'):fill_rect(P1.x,P1.y,P4.x-P1.x,1,color);fill_rect(P4.x,P1.y,1,P4.y-P1.y+1,color);fill_rect(P1.x,P4.y,P4.x-P1.x,1,color);fill_rect(P1.x,P1.y,1,P4.y-P1.y,color) def fill_rectangle(P1,P4,color='0',alpha=1): - for x,y in [(x,y) for x in range(P4.x-P1.x if P4.x>P1.x else P1.x-P4.x) for y in range(P4.y-P1.y if P4.y>P1.y else P1.y-P4.y)]:alpha_pixel(P1.x+x,P1.y+y,color,alpha) + for x in range(P4.x-P1.x if P4.x>P1.x else P1.x-P4.x): + for y in range(P4.y-P1.y if P4.y>P1.y else P1.y-P4.y): + alpha_pixel(P1.x+x,P1.y+y,color,alpha) def draw_circle(center,rayon,color='0'): for x in range(-abs(rayon),abs(rayon)): l=round((abs(rayon)**2-x**2)**0.5) @@ -77,4 +79,4 @@ def bezier_curve(liste,color='0',thickness=1,N=1500): for _t in range(N): x,y,t=0,0,_t/N for i in range(len(liste)):x+=((perm(len(liste)-1,i)/factorial(i))*(t**i)*((1-t)**(len(liste)-1-i)))*liste[i].x;y+=((perm(len(liste)-1,i)/factorial(i))*(t**i)*((1-t)**(len(liste)-1-i)))*liste[i].y - P=Point(round(x),round(y));set_pixel(P.x,P.y,color) if thickness==1 else fill_circle(P,thickness,color,1) \ No newline at end of file + P=Point(round(x),round(y));set_pixel(P.x,P.y,color) if thickness==1 else fill_circle(P,thickness,color,1) From 228cdaa2cb27700cc70cba03cbca22b3a2781359 Mon Sep 17 00:00:00 2001 From: Discusser <47938380+Discusser@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:04:36 +0200 Subject: [PATCH 2/5] Add python-minifer dependency --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ebafcfc..e785f68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ kandinsky==2.7.2 -ion-numworks==2.1 \ No newline at end of file +ion-numworks==2.1 +python-minifier==2.11.3 From 9b54c7744007fd65eb7cee3c751d3cb182466dd7 Mon Sep 17 00:00:00 2001 From: Discusser <47938380+Discusser@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:23:35 +0200 Subject: [PATCH 3/5] Add script to minify python files --- minify.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 minify.py diff --git a/minify.py b/minify.py new file mode 100644 index 0000000..40c08fe --- /dev/null +++ b/minify.py @@ -0,0 +1,28 @@ +import os +import python_minifier + +SOURCE_DIRECTORY = "src" +EXCLUDED_DIRECTORIES = ["src/visual/examples"] + + +# Iterate through every file in our source directory +for subdirs, dirs, files in os.walk(SOURCE_DIRECTORY): + canContinue = True + for excluded in EXCLUDED_DIRECTORIES: + # If subdir is inside of one of the excluded directories, skip it + if os.path.commonpath([subdirs, excluded]) == excluded: + canContinue = False + break + + if not canContinue: + continue + + for file in files: + # We only care about minifying .py files that aren't already minified + if file.split(".")[-1] == "py" and not file.endswith(".min.py"): + outputFilename = file.split(".") + outputFilename.insert(len(outputFilename) - 1, "min") + outputFilename = ".".join(outputFilename) + inputFp = open(os.path.join(subdirs, file)) + outputFp = open(os.path.join(subdirs, outputFilename), "w") + outputFp.write(python_minifier.minify(inputFp.read())) From 9ad91ed4cf1c82d41a2b2df5fdc734cfa89edf1e Mon Sep 17 00:00:00 2001 From: Discusser <47938380+Discusser@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:23:50 +0200 Subject: [PATCH 4/5] Add .min.py files generated by script --- src/visual/__init__.min.py | 1 + src/visual/extensions/__init__.min.py | 0 .../extensions/ellipses/__init__.min.py | 1 + .../ellipses/ellipses_example.min.py | 9 + .../extensions/ellipses/ext_ellipses.min.py | 14 + src/visual/extensions/grapher/__init__.min.py | 1 + .../extensions/grapher/ext_grapher.min.py | 192 ++++++++ src/visual/extensions/lines/__init__.min.py | 1 + src/visual/extensions/lines/ext_lines.min.py | 25 + .../extensions/lines/lines_example.min.py | 15 + src/visual/extensions/turtle/__init__.min.py | 1 + .../extensions/turtle/ext_turtle.min.py | 77 +++ .../turtle/ext_turtle_for_computer.min.py | 77 +++ .../extensions/turtle/turtle_example.min.py | 15 + src/visual/visual.min.py | 85 ++++ src/visual/visual.py | 464 +++++++++++++++--- 16 files changed, 898 insertions(+), 80 deletions(-) create mode 100644 src/visual/__init__.min.py create mode 100644 src/visual/extensions/__init__.min.py create mode 100644 src/visual/extensions/ellipses/__init__.min.py create mode 100644 src/visual/extensions/ellipses/ellipses_example.min.py create mode 100644 src/visual/extensions/ellipses/ext_ellipses.min.py create mode 100644 src/visual/extensions/grapher/__init__.min.py create mode 100644 src/visual/extensions/grapher/ext_grapher.min.py create mode 100644 src/visual/extensions/lines/__init__.min.py create mode 100644 src/visual/extensions/lines/ext_lines.min.py create mode 100644 src/visual/extensions/lines/lines_example.min.py create mode 100644 src/visual/extensions/turtle/__init__.min.py create mode 100644 src/visual/extensions/turtle/ext_turtle.min.py create mode 100644 src/visual/extensions/turtle/ext_turtle_for_computer.min.py create mode 100644 src/visual/extensions/turtle/turtle_example.min.py create mode 100644 src/visual/visual.min.py diff --git a/src/visual/__init__.min.py b/src/visual/__init__.min.py new file mode 100644 index 0000000..7bc5dc3 --- /dev/null +++ b/src/visual/__init__.min.py @@ -0,0 +1 @@ +from visual.visual import* \ No newline at end of file diff --git a/src/visual/extensions/__init__.min.py b/src/visual/extensions/__init__.min.py new file mode 100644 index 0000000..e69de29 diff --git a/src/visual/extensions/ellipses/__init__.min.py b/src/visual/extensions/ellipses/__init__.min.py new file mode 100644 index 0000000..e683410 --- /dev/null +++ b/src/visual/extensions/ellipses/__init__.min.py @@ -0,0 +1 @@ +from.ext_ellipses import* \ No newline at end of file diff --git a/src/visual/extensions/ellipses/ellipses_example.min.py b/src/visual/extensions/ellipses/ellipses_example.min.py new file mode 100644 index 0000000..811ff17 --- /dev/null +++ b/src/visual/extensions/ellipses/ellipses_example.min.py @@ -0,0 +1,9 @@ +from visual import Point +from ext_ellipses import draw_ellipses,fill_ellipses +A=Point(50,50) +B=Point(270,172) +def example_1():fill_ellipses(A,B,'red',alpha=.5);draw_ellipses(A,B,'black') +example_1() +A=Point(125,50) +B=Point(195,172) +def example_2():fill_ellipses(A,B,'red',alpha=.5);draw_ellipses(A,B,'black') \ No newline at end of file diff --git a/src/visual/extensions/ellipses/ext_ellipses.min.py b/src/visual/extensions/ellipses/ext_ellipses.min.py new file mode 100644 index 0000000..a48ebb8 --- /dev/null +++ b/src/visual/extensions/ellipses/ext_ellipses.min.py @@ -0,0 +1,14 @@ +from visual import Point,set_pixel,alpha_pixel +def draw_ellipses(P1,P2,color='0'): + D=color;B=P2;A=P1;C,E=abs(B.x-A.x),abs(B.y-A.y);F=E&1;H,G=4*(1-C)*E*E,4*(F+1)*C*C;I=H+G+F*C*C + if A.x>B.x:A.x,B.x=B.x,A.x+C + if A.y>B.y:A.y=B.y + A.y+=(E+1)//2;B.y=A.y-F;C*=8*C;F=8*E*E + while A.x<=B.x: + set_pixel(B.x,A.y,D);set_pixel(A.x,A.y,D);set_pixel(A.x,B.y,D);set_pixel(B.x,B.y,D);J=2*I + if J<=G:A.y+=1;B.y-=1;I+=G;G+=C + if J>=H or 2*I>G:A.x+=1;B.x-=1;I+=H;H+=F + while A.y-B.yA.C.x-A.Lxg+Screen.p and round(A._C.x+x*A.p)A.C.y-A.Lyh+Screen.p and round(A._C.y-y*A.p)A.C.x-A.Lxg and round(A._C.x+B*A.p)A.C.y-A.Lyh and round(A._C.y-C*A.p)=B[0].y else set_lines([(B[0],E)],C) + elif G==1 and F[1]!=_D:set_lines([(D,B[0])],C)if D.y<=B[0].y else set_lines([(B[0],E)],C) + elif G==1 and F[2]!=_D:set_lines([(D,B[0])],C)if D.x>=B[0].x else set_lines([(B[0],E)],C) + elif G==1 and F[3]!=_D:set_lines([(D,B[0])],C)if D.x<=B[0].x else set_lines([(B[0],E)],C) + elif D in I:set_lines([(D,E)],C) + fill_rect(A.C.x-A.Lxg,A.C.y+A.Lyh,A.Lxd+A.Lxg,1,Screen.palette[_G]);fill_rect(A.C.x+A.Lxg,A.C.y-A.Lyb,1,A.Lyb+A.Lyh,Screen.palette[_G]) + def set_points(A,liste,color=Screen.palette[_F],style='O'): + D=style;C=color;B=liste + if not{_A:B,_E:C,_I:D}in A.liste_point:A._liste_point.append({_A:B,_E:C,_I:D});A.liste_point.append({_A:B,_E:C,_I:D}) + else:draw_points([Point(round(A._C.x+B.x*A.p),round(A._C.y-B.y*A.p))for B in B if A.check(B.x,B.y)],C,D,_M) + def set_lines(A,liste,color=Screen.palette[_F]): + F=liste;C=color + if not{_A:F,_E:C}in A.liste_line:A._liste_line.append({_A:F,_E:C});A.liste_line.append({_A:F,_E:C}) + else: + I=[(Point(A.C.x-A.Lxd,A.C.y-A.Lyb),Point(A.C.x+A.Lxg,A.C.y-A.Lyb)),(Point(A.C.x-A.Lxd,A.C.y+A.Lyh),Point(A.C.x+A.Lxg,A.C.y+A.Lyh)),(Point(A.C.x-A.Lxd,A.C.y-A.Lyb),Point(A.C.x-A.Lxd,A.C.y+A.Lyh)),(Point(A.C.x+A.Lxg,A.C.y-A.Lyb),Point(A.C.x+A.Lxg,A.C.y+A.Lyh))];J=connect_points([Point(round(A._C.x+B.x*A.p),round(A._C.y-B.y*A.p))for B in F if round(A._C.x+B.x*A.p)>A.C.x-A.Lxg and round(A._C.x+B.x*A.p)A.C.y-A.Lyh and round(A._C.y-B.y*A.p)=B[0].y else set_lines([(B[0],E)],C) + elif H==1 and G[1]!=_D:set_lines([(D,B[0])],C)if D.y<=B[0].y else set_lines([(B[0],E)],C) + elif H==1 and G[2]!=_D:set_lines([(D,B[0])],C)if D.x>=B[0].x else set_lines([(B[0],E)],C) + elif H==1 and G[3]!=_D:set_lines([(D,B[0])],C)if D.x<=B[0].x else set_lines([(B[0],E)],C) + elif(D,E)in J:set_lines([(D,E)],C) + fill_rect(A.C.x-A.Lxg,A.C.y+A.Lyh,A.Lxd+A.Lxg+1,1,Screen.palette[_G]);fill_rect(A.C.x+A.Lxg,A.C.y-A.Lyb,1,A.Lyb+A.Lyh,Screen.palette[_G]) + def set_vectors(A,P,V,color=Screen.palette[_F]): + C=color + if not{_A:[P,V+P],_E:C}in A.liste_vector:A._liste_vector.append({_A:[P,V+P],_E:C});A.liste_vector.append({_A:[P,V+P],_E:C}) + else: + H=[(Point(A.C.x-A.Lxd,A.C.y-A.Lyb),Point(A.C.x+A.Lxg,A.C.y-A.Lyb)),(Point(A.C.x-A.Lxd,A.C.y+A.Lyh),Point(A.C.x+A.Lxg,A.C.y+A.Lyh)),(Point(A.C.x-A.Lxd,A.C.y-A.Lyb),Point(A.C.x-A.Lxd,A.C.y+A.Lyh)),(Point(A.C.x+A.Lxg,A.C.y-A.Lyb),Point(A.C.x+A.Lxg,A.C.y+A.Lyh))];I=connect_points([Point(round(A._C.x+B.x*A.p),round(A._C.y-B.y*A.p))for B in[P,V+P]if round(A._C.x+B.x*A.p)>A.C.x-A.Lxg and round(A._C.x+B.x*A.p)A.C.y-A.Lyh and round(A._C.y-B.y*A.p)=B[0].y else draw_vector(B[0],Vector(x=E.x-B[0].x,y=E.y-B[0].y),C) + elif G==1 and F[1]!=_D:set_lines([(D,B[0])],C)if D.y<=B[0].y else draw_vector(B[0],Vector(x=E.x-B[0].x,y=E.y-B[0].y),C) + elif G==1 and F[2]!=_D:set_lines([(D,B[0])],C)if D.x>=B[0].x else draw_vector(B[0],Vector(x=E.x-B[0].x,y=E.y-B[0].y),C) + elif G==1 and F[3]!=_D:set_lines([(D,B[0])],C)if D.x<=B[0].x else draw_vector(B[0],Vector(x=E.x-B[0].x,y=E.y-B[0].y),C) + elif(D,E)in I:draw_vector(D,Vector(x=E.x-D.x,y=E.y-D.y),C) + fill_rect(A.C.x-A.Lxg,A.C.y+A.Lyh,A.Lxd+A.Lxg+1,1,Screen.palette[_G]);fill_rect(A.C.x+A.Lxg,A.C.y-A.Lyb,1,A.Lyb+A.Lyh,Screen.palette[_G]) + def set_droite(C,A,B,color=Screen.palette[_F]): + D=color + if not{_A:[A,B],_E:D}in C.liste_droite:C._liste_droite.append({_A:[A,B],_E:D});C.liste_droite.append({_A:[A,B],_E:D}) + else: + F=[(Point(C.C.x-C.Lxd,C.C.y-C.Lyb),Point(C.C.x+C.Lxg,C.C.y-C.Lyb)),(Point(C.C.x-C.Lxd,C.C.y+C.Lyh),Point(C.C.x+C.Lxg,C.C.y+C.Lyh)),(Point(C.C.x-C.Lxd,C.C.y-C.Lyb),Point(C.C.x-C.Lxd,C.C.y+C.Lyh)),(Point(C.C.x+C.Lxg,C.C.y-C.Lyb),Point(C.C.x+C.Lxg,C.C.y+C.Lyh))] + for(G,H)in connect_points([Point(round(C._C.x+A.x*C.p),round(C._C.y-A.y*C.p))for A in[A,B]]):I=C.find_intersections(G,H,F,_L);E=[Point(round(A.x),round(A.y))for A in I if A!=_D];set_lines([(E[0],E[1])],D)if len(E)==2 else _D + fill_rect(C.C.x-C.Lxg,C.C.y+C.Lyh,C.Lxd+C.Lxg+1,1,Screen.palette[_G]);fill_rect(C.C.x+C.Lxg,C.C.y-C.Lyb,1,C.Lyb+C.Lyh,Screen.palette[_G]) + def clean(A):A._liste_scatter,A._liste_plot,A._liste_point,A._liste_line,A._liste_droite,A._liste_vector,A.liste_scatter,A.liste_plot,A.liste_point,A.liste_line,A.liste_droite,A.liste_vector=[],[],[],[],[],[],[],[],[],[],[],[];fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes() + def set_axes(A): + if A.background: + for D in range(A._Lyh,0,-A.p):fill_rect(A.C.x-A.Lxg,A._C.y-A._Lyh+round(D-A.p/2),A.Lxg+A.Lxd,1,Screen.palette[_J])if A.C.y-A._Lyh+round(D-A.p/2)>A.C.y-A._Lyh and A.C.y-A._Lyh+round(D-A.p/2)A.C.y-A._Lyh and A.C.y+round(C+A.p/2)A.C.x-A._Lxg and A.C.x-A._Lxg+round(D-A.p/2)A.C.x-A._Lxg and A.C.x+round(C+A.p/2)A.C.y-A.Lyh and A._C.y+2A.C.x-A.Lxg:fill_rect(A._C.x+C,A.C.y-A.Lyh,1,A.Lyh+A.Lyb,Screen.palette[_H]) + if A._C.x+CA.C.x-A.Lxg and A._C.y-2>A.C.y-A.Lyh and A._C.y+2A.C.y-A.Lyh and A._C.x-2>A.C.x-A.Lxg and A._C.x+2A.C.y-A._Lyh and A.C.y+CA.C.x-A.Lxg and A._C.x+2A.C.y-A.Lyh:fill_rect(A._C.x-2,A._C.y+C,5,1,Screen.palette[_F]) + if A.text and E!=0:draw_string(str(-E),A._C.x+10,A._C.y+C-5,Screen.palette[_F],Screen.palette[_K]) + fill_rect(A._C.x,A.C.y-A.Lyh,1,A.Lyh+A.Lyb,Screen.palette[_F])if A._C.x>=A.C.x-A.Lxg and A._C.x=A.C.y-A.Lyh and A._C.y1 else B[_B];B[_C]=[A.y for A in C]if A.p-A.pas>1 else B[_C] + for B in A.liste_plot:C=expend([Point(A,B)for(A,B)in zip(B[_B],B[_C])],A.pas/A.p/100);B[_B]=[A.x for A in C]if A.p-A.pas>1 else B[_B];B[_C]=[A.y for A in C]if A.p-A.pas>1 else B[_C] + for B in A.liste_point:B[_A]=expend(B[_A],A.pas/A.p/100)if A.p-A.pas>1 else B[_A] + for B in A.liste_line:B[_A]=expend(B[_A],A.pas/A.p/100) + for B in A.liste_vector:B[_A]=expend(B[_A],A.pas/A.p/100) + for B in A.liste_droite:B[_A]=expend(B[_A],A.pas/A.p/100) + A.p-=A.pas if A.p-A.pas>1 else 0;fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes();sleep(.2) + def scroll(A): + if keydown(KEY_UP): + for B in A._liste_scatter:B[_C]=[B+A.pas/A.p for B in B[_C]] + for B in A._liste_plot:B[_C]=[B+A.pas/A.p for B in B[_C]] + for B in A._liste_point:B[_A]=[Point(B.x,B.y+A.pas/A.p)for B in B[_A]] + for B in A._liste_line:B[_A]=[Point(B.x,B.y+A.pas/A.p)for B in B[_A]] + for B in A._liste_vector:B[_A]=[Point(B.x,B.y+A.pas/A.p)for B in B[_A]] + for B in A._liste_droite:B[_A]=[Point(B.x,B.y+A.pas/A.p)for B in B[_A]] + A._C.y+=A.pas;A._Lyh+=A.pas;A._Lyb-=A.pas;fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes() + if keydown(KEY_DOWN): + for B in A._liste_scatter:B[_C]=[B-A.pas/A.p for B in B[_C]] + for B in A._liste_plot:B[_C]=[B-A.pas/A.p for B in B[_C]] + for B in A._liste_point:B[_A]=[Point(B.x,B.y-A.pas/A.p)for B in B[_A]] + for B in A._liste_line:B[_A]=[Point(B.x,B.y-A.pas/A.p)for B in B[_A]] + for B in A._liste_vector:B[_A]=[Point(B.x,B.y-A.pas/A.p)for B in B[_A]] + for B in A._liste_droite:B[_A]=[Point(B.x,B.y-A.pas/A.p)for B in B[_A]] + A._C.y-=A.pas;A._Lyh-=A.pas;A._Lyb+=A.pas;fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes() + if keydown(KEY_LEFT): + for B in A._liste_scatter:B[_B]=[B+A.pas/A.p for B in B[_B]] + for B in A._liste_plot:B[_B]=[B+A.pas/A.p for B in B[_B]] + for B in A._liste_point:B[_A]=[Point(B.x+A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_line:B[_A]=[Point(B.x+A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_vector:B[_A]=[Point(B.x+A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_droite:B[_A]=[Point(B.x+A.pas/A.p,B.y)for B in B[_A]] + A._C.x+=A.pas;A._Lxg+=A.pas;A._Lxd-=A.pas;fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes() + if keydown(KEY_RIGHT): + for B in A._liste_scatter:B[_B]=[B-A.pas/A.p for B in B[_B]] + for B in A._liste_plot:B[_B]=[B-A.pas/A.p for B in B[_B]] + for B in A._liste_point:B[_A]=[Point(B.x-A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_line:B[_A]=[Point(B.x-A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_vector:B[_A]=[Point(B.x-A.pas/A.p,B.y)for B in B[_A]] + for B in A._liste_droite:B[_A]=[Point(B.x-A.pas/A.p,B.y)for B in B[_A]] + A._C.x-=A.pas;A._Lxg-=A.pas;A._Lxd+=A.pas;fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);A.set_axes() + def main(A): + A.set_axes() + while _L: + A.zoom();A.scroll() + if keydown(KEY_BACKSPACE):sleep(.1);break + if keydown(KEY_ZERO): + for(B,C)in zip(A._liste_scatter,A.liste_scatter):B[_B]=C[_B].copy();B[_C]=C[_C].copy() + for(B,C)in zip(A._liste_plot,A.liste_plot):B[_B]=C[_B].copy();B[_C]=C[_C].copy() + for(B,C)in zip(A._liste_point,A.liste_point):B[_A]=C[_A].copy() + for(B,C)in zip(A._liste_line,A.liste_line):B[_A]=C[_A].copy() + for(B,C)in zip(A._liste_vector,A.liste_vector):B[_A]=C[_A].copy() + for(B,C)in zip(A._liste_droite,A.liste_droite):B[_A]=C[_A].copy() + A._Lxg,A._Lxd,A._Lyh,A._Lyb=A.Lxg,A.Lxd,A.Lyh,A.Lyb;A._C=Point(A.C.x,A.C.y);fill_rect(A.C.x-A.Lxg,A.C.y-A.Lyh,A.Lxg+A.Lxd,A.Lyh+A.Lyb,Screen.palette[_G]);sleep(.1);A.set_axes() +DefaultGrapher=Grapher(text=_M) +def axes(grapher=DefaultGrapher):grapher.set_axes() +def show(grapher=DefaultGrapher):grapher.main() +def clean(grapher=DefaultGrapher):grapher.clean() +def scatter(*A,grapher=DefaultGrapher,**B):grapher.scatter(*A,**B) +def plot(*A,grapher=DefaultGrapher,**B):grapher.plot(*A,**B) +def points(*A,grapher=DefaultGrapher,**B):grapher.set_points(*A,**B) +def lines(*A,grapher=DefaultGrapher,**B):grapher.set_lines(*A,**B) +def droite(*A,grapher=DefaultGrapher,**B):grapher.set_droite(*A,**B) +def vector(*A,grapher=DefaultGrapher,**B):grapher.set_vectors(*A,**B) \ No newline at end of file diff --git a/src/visual/extensions/lines/__init__.min.py b/src/visual/extensions/lines/__init__.min.py new file mode 100644 index 0000000..13d58b7 --- /dev/null +++ b/src/visual/extensions/lines/__init__.min.py @@ -0,0 +1 @@ +from.ext_lines import* \ No newline at end of file diff --git a/src/visual/extensions/lines/ext_lines.min.py b/src/visual/extensions/lines/ext_lines.min.py new file mode 100644 index 0000000..4a2d85f --- /dev/null +++ b/src/visual/extensions/lines/ext_lines.min.py @@ -0,0 +1,25 @@ +_A=True +from visual import Point,set_pixel,fill_circle,interpolate,distance +def draw_lines(line,color='0',thickness=1): + L=thickness;K=color;J=False + if isinstance(K,list): + for((A,C),(M,N))in zip(line,K): + H,I=_A if C.y>A.y else J,_A if C.x>A.x else J;D,E=C.y-A.y if H else A.y-C.y,C.x-A.x if I else A.x-C.x;F=_A if D<=E else J;G=D/E if F and(E!=0 or D!=0)else E/D;O=interpolate(M,N,round(distance(A,C))) + for B in range(E if F else D):fill_circle(Point(int(round(A.x+B)if I else round(A.x-B))if F else int(round(A.x+G*B)if I else round(A.x-G*B)),int(round(A.y+G*B)if H else round(A.y-G*B))if F else int(round(A.y+B)if H else round(A.y-B))),L,O[B]) + else: + for(A,C)in line: + H,I=_A if C.y>A.y else J,_A if C.x>A.x else J;D,E=C.y-A.y if H else A.y-C.y,C.x-A.x if I else A.x-C.x;F=_A if D<=E else J;G=D/E if F and(E!=0 or D!=0)else E/D + for B in range(E if F else D):fill_circle(Point(int(round(A.x+B)if I else round(A.x-B))if F else int(round(A.x+G*B)if I else round(A.x-G*B)),int(round(A.y+G*B)if H else round(A.y-G*B))if F else int(round(A.y+B)if H else round(A.y-B))),L,K) +def draw_lines_AA(line): + for(A,E)in line: + B,C,H,I=abs(E.x-A.x),abs(E.y-A.y),1 if A.x=-B: + if A.x==E.x:break + if D+CP1.y else _C,_D if P2.x>P1.x else _C;h,b=P2.y-P1.y if up else P1.y-P2.y,P2.x-P1.x if right else P1.x-P2.x;n=_D if h<=b else _C;set_pixel(P2.x,P2.y,color) + if b!=0 or h!=0:e=h/b if n else b/h + for i in range(b if n else h):set_pixel(int(round(P1.x+i)if right else round(P1.x-i))if n else int(round(P1.x+e*i)if right else round(P1.x-e*i)),int(round(P1.y+e*i)if up else round(P1.y-e*i))if n else int(round(P1.y+i)if up else round(P1.y-i)),color) +def draw_arrows(liste,color=_A,length=10,angle=45,fill=_C): + for(A,B)in liste:V1=Vector(findWithPoint(B,A,length),B).neg();V2,V3=V1.rotate(angle),V1.rotate(-angle);V2.round();V3.round();set_lines([(A,B)],color);set_lines([(B,V2+B),(B,V3+B)],color)if not fill else fill_triangles([(V2+B,B,V3+B)],color) +def draw_vector(P,V,color=_A):x,y=milieu(P,V+P);draw_arrows([(P,V+P)],color,fill=_C);draw_string(str(V.name),round(x-6),round(y-6),_A,'1') +def draw_droite(P1,P2,color=_A,name=_B): + if P1.x==P2.x:set_lines([(Point(P1.x,0),Point(P1.x,222))],color) + elif P1.y==P2.y:set_lines([(Point(0,P1.y),Point(320,P1.y))],color) + else:_a=a(P1,P2);_b=b(_a,P2);P0,P3=Point(round((222-_b)/_a),222)if abs(P2.x-P1.x)=0 and w2>=0 and w3>=0 or-w1>=0 and-w2>=0 and-w3>=0):set_pixel(x,y,color)if alpha==1 else alpha_pixel(x,y,color,alpha) +def draw_polygone(n,rayon,coord,color=_A):alpha=2*pi/n;set_lines(connect_points([Point(round(coord.x+rayon*cos(k*alpha)),round(coord.y+rayon*sin(k*alpha)),color)for k in range(1,n+1)],_D),color) +def fill_polygone(n,rayon,coord,color=_A,c_map=_B,alpha=1): + _alpha=2*pi/n;points=[Point(round(coord.x+rayon*cos(k*_alpha)),round(coord.y+rayon*sin(k*_alpha)))for k in range(1,n+1)] + for(p,c)in zip(connect_points(points,_D),[color for _ in range(len(points))]if not isinstance(c_map,list)else c_map):fill_triangles([[coord,p[0],p[1]]],c,alpha) +def draw_rectangle(P1,P4,color=_A):fill_rect(P1.x,P1.y,P4.x-P1.x,1,color);fill_rect(P4.x,P1.y,1,P4.y-P1.y+1,color);fill_rect(P1.x,P4.y,P4.x-P1.x,1,color);fill_rect(P1.x,P1.y,1,P4.y-P1.y,color) +def fill_rectangle(P1,P4,color=_A,alpha=1): + for x in range(P4.x-P1.x if P4.x>P1.x else P1.x-P4.x): + for y in range(P4.y-P1.y if P4.y>P1.y else P1.y-P4.y):alpha_pixel(P1.x+x,P1.y+y,color,alpha) +def draw_circle(center,rayon,color=_A): + for x in range(-abs(rayon),abs(rayon)): + l=round((abs(rayon)**2-x**2)**.5) + if abs(x)<=l:set_pixel(center.x+l,center.y+x,color);set_pixel(center.x-l,center.y-x,color);set_pixel(center.x-x,center.y-l,color);set_pixel(center.x+x,center.y+l,color) +def fill_circle(center,rayon,color=_A,alpha=1): + for x in range(-round(rayon),round(rayon)+1): + for y in range(-round(rayon),round(rayon)+1): + if round(distance(center,Point(center.x+x,center.y+y)))<=rayon:alpha_pixel(center.x+x,center.y+y,color,alpha)if alpha!=1 else set_pixel(center.x+x,center.y+y,color) +def bezier_curve(liste,color=_A,thickness=1,N=1500): + for _t in range(N): + x,y,t=0,0,_t/N + for i in range(len(liste)):x+=perm(len(liste)-1,i)/factorial(i)*t**i*(1-t)**(len(liste)-1-i)*liste[i].x;y+=perm(len(liste)-1,i)/factorial(i)*t**i*(1-t)**(len(liste)-1-i)*liste[i].y + P=Point(round(x),round(y));set_pixel(P.x,P.y,color)if thickness==1 else fill_circle(P,thickness,color,1) \ No newline at end of file diff --git a/src/visual/visual.py b/src/visual/visual.py index d5d3eb7..c09da4a 100644 --- a/src/visual/visual.py +++ b/src/visual/visual.py @@ -1,82 +1,386 @@ -from kandinsky import set_pixel,get_pixel,fill_rect,draw_string,color -from math import pi,cos,sin,radians,factorial -a,b,perm,distance,milieu,average=lambda P1,P2:(P2.y-P1.y)/(P2.x-P1.x),lambda a,P1:-(a*P1.x-P1.y),lambda n,k:factorial(n)/factorial(n-k),lambda P1,P2:((P2.x-P1.x)**2+(P2.y-P1.y)**2)**0.5,lambda P1,P2,p=2:Point((P1.x+P2.x)/p,(P1.y+P2.y)/p),lambda liste:sum(liste)/len(liste) -DrawWithStyle={'O':"fill_circle(P,3,color)",'+':"draw_croix(P,3,0,color)",'*':"draw_croix(P,4,45,color)",'.':"set_pixel(P.x,P.y,color)"} +from kandinsky import set_pixel, get_pixel, fill_rect, draw_string, color +from math import pi, cos, sin, radians, factorial + +a, b, perm, distance, milieu, average = ( + lambda P1, P2: (P2.y - P1.y) / (P2.x - P1.x), + lambda a, P1: -(a * P1.x - P1.y), + lambda n, k: factorial(n) / factorial(n - k), + lambda P1, P2: ((P2.x - P1.x) ** 2 + (P2.y - P1.y) ** 2) ** 0.5, + lambda P1, P2, p=2: Point((P1.x + P2.x) / p, (P1.y + P2.y) / p), + lambda liste: sum(liste) / len(liste), +) +DrawWithStyle = { + "O": "fill_circle(P,3,color)", + "+": "draw_croix(P,3,0,color)", + "*": "draw_croix(P,4,45,color)", + ".": "set_pixel(P.x,P.y,color)", +} + + class Point: - def __init__(self,x,y,name=''):self.x,self.y,self.name=x,y,name - def __str__(self):return str(self.name) - def __iter__(self):return iter([self.x,self.y]) - def __repr__(self):return "Point({}, {})".format(self.x,self.y) - def __eq__(self,other):return (self.x==other.x)and(self.y==other.y) if isinstance(other,Point) else False - def round(self):self.x,self.y=round(self.x),round(self.y) - def copy(self):return Point(self.x,self.y,self.name) + def __init__(self, x, y, name=""): + self.x, self.y, self.name = x, y, name + + def __str__(self): + return str(self.name) + + def __iter__(self): + return iter([self.x, self.y]) + + def __repr__(self): + return "Point({}, {})".format(self.x, self.y) + + def __eq__(self, other): + return ( + (self.x == other.x) and (self.y == other.y) + if isinstance(other, Point) + else False + ) + + def round(self): + self.x, self.y = round(self.x), round(self.y) + + def copy(self): + return Point(self.x, self.y, self.name) + + class Vector: - def __init__(self,P1=None,P2=None,x=None,y=None,name=''):cond=(P1!=None and P2!=None);self.x,self.y,self.name=P2.x-P1.x if cond else x,P2.y-P1.y if cond else y,name - def __str__(self):return str(self.name) - def __iter__(self):return iter([self.x,self.y]) - def __repr__(self):return "Vector({}, {})".format(self.x,self.y) - def __eq__(self,other):return (self.x==other.x)and(self.y==other.y) if isinstance(other,Vector) else False - def __add__(self,other):return Vector(x=self.x+other.x,y=self.y+other.y) if isinstance(other,Vector) else Point(other.x+self.x,other.y+self.y) if isinstance(other,Point) else None - def __sub__(self,other):return Vector(x=self.x-other.x,y=self.y-other.y) if isinstance(other,Vector) else Point(other.x-self.x,other.y-self.y) if isinstance(other,Point) else None - def __mul__(self,other):return Vector(x=self.x*other.x,y=self.y*other.y) if isinstance(other,Vector) else Vector(x=self.x*other,y=self.y*other) if isinstance(other,(int,float)) else None - def __truediv__(self,other):return Vector(x=self.x/other.x,y=self.y/other.y) if isinstance(other,Vector) else Vector(x=self.x/other,y=self.y/other) if isinstance(other,(int,float)) else None - def rotate(self,angle):angle=radians(angle);return Vector(x=self.x*cos(angle)-self.y*sin(angle),y=self.x*sin(angle)+self.y*cos(angle),name=self.name) - def neg(self):return Vector(x=-self.x,y=-self.y,name=self.name) - def copy(self):return Vector(x=self.x,y=self.y,name=self.name) - def round(self):self.x=round(self.x);self.y=round(self.y) -def expend(liste,d,M=None):M=Point(round(average([P.x for P in liste])),round(average([P.y for P in liste]))) if M==None else M;return [Point(round(P.x+(P.x-M.x)*d),round(P.y+(P.y-M.y)*d)) if d!=0 else P for P in liste] -def connect_points(liste,ending=False):line=[(liste[p],liste[p+1]) for p in range(len(liste)) if pP1.y else False,True if P2.x>P1.x else False;h,b=P2.y-P1.y if up else P1.y-P2.y,P2.x-P1.x if right else P1.x-P2.x;n=True if h<=b else False;set_pixel(P2.x,P2.y,color) - if b!=0 or h!=0:e=h/b if n else b/h - for i in range(b if n else h):set_pixel(int(round(P1.x+i) if right else round(P1.x-i))if n else int(round(P1.x+e*i) if right else round(P1.x-e*i)),int(round(P1.y+e*i) if up else round(P1.y-e*i))if n else int(round(P1.y+i) if up else round(P1.y-i)),color) -def draw_arrows(liste,color='0',length=10,angle=45,fill=False): - for A,B in liste:V1=Vector(findWithPoint(B,A,length),B).neg();V2,V3=V1.rotate(angle),V1.rotate(-angle);V2.round();V3.round();set_lines([(A,B)],color);set_lines([(B,V2+B),(B,V3+B)],color) if not fill else fill_triangles([(V2+B,B,V3+B)],color) -def draw_vector(P,V,color='0'):x,y=milieu(P,V+P);draw_arrows([(P,V+P)],color,fill=False);draw_string(str(V.name),round(x-6),round(y-6),'0','1') -def draw_droite(P1,P2,color='0',name=None): - if P1.x==P2.x:set_lines([(Point(P1.x,0),Point(P1.x,222))],color) - elif P1.y==P2.y:set_lines([(Point(0,P1.y),Point(320,P1.y))],color) - else: _a=a(P1,P2);_b=b(_a,P2);P0,P3=Point(round((222-_b)/_a),222) if abs(P2.x-P1.x)=0 and w2>=0 and w3>=0) or (-w1>=0 and -w2>=0 and -w3>=0)):set_pixel(x,y,color) if alpha==1 else alpha_pixel(x,y,color,alpha) -def draw_polygone(n,rayon,coord,color='0'):alpha=2*pi/n;set_lines(connect_points([Point(round(coord.x+rayon*cos(k*alpha)),round(coord.y+rayon*sin(k*alpha)),color) for k in range(1,n+1)],True),color) -def fill_polygone(n,rayon,coord,color='0',c_map=None,alpha=1): - _alpha=2*pi/n;points=[Point(round(coord.x+rayon*cos(k*_alpha)),round(coord.y+rayon*sin(k*_alpha))) for k in range(1,n+1)] - for p,c in zip(connect_points(points,True),[color for _ in range(len(points))] if not isinstance(c_map,list) else c_map):fill_triangles([([coord,p[0],p[1]])],c,alpha) -def draw_rectangle(P1,P4,color='0'):fill_rect(P1.x,P1.y,P4.x-P1.x,1,color);fill_rect(P4.x,P1.y,1,P4.y-P1.y+1,color);fill_rect(P1.x,P4.y,P4.x-P1.x,1,color);fill_rect(P1.x,P1.y,1,P4.y-P1.y,color) -def fill_rectangle(P1,P4,color='0',alpha=1): - for x in range(P4.x-P1.x if P4.x>P1.x else P1.x-P4.x): - for y in range(P4.y-P1.y if P4.y>P1.y else P1.y-P4.y): - alpha_pixel(P1.x+x,P1.y+y,color,alpha) -def draw_circle(center,rayon,color='0'): - for x in range(-abs(rayon),abs(rayon)): - l=round((abs(rayon)**2-x**2)**0.5) - if abs(x)<=l:set_pixel(center.x+l,center.y+x,color);set_pixel(center.x-l,center.y-x,color);set_pixel(center.x-x,center.y-l,color);set_pixel(center.x+x,center.y+l,color) -def fill_circle(center,rayon,color='0',alpha=1): - for x in range(-round(rayon),round(rayon)+1): - for y in range(-round(rayon),round(rayon)+1): - if round(distance(center,Point(center.x+x,center.y+y)))<=rayon:alpha_pixel(center.x+x,center.y+y,color,alpha) if alpha!=1 else set_pixel(center.x+x,center.y+y,color) -def bezier_curve(liste,color='0',thickness=1,N=1500): - for _t in range(N): - x,y,t=0,0,_t/N - for i in range(len(liste)):x+=((perm(len(liste)-1,i)/factorial(i))*(t**i)*((1-t)**(len(liste)-1-i)))*liste[i].x;y+=((perm(len(liste)-1,i)/factorial(i))*(t**i)*((1-t)**(len(liste)-1-i)))*liste[i].y - P=Point(round(x),round(y));set_pixel(P.x,P.y,color) if thickness==1 else fill_circle(P,thickness,color,1) + def __init__(self, P1=None, P2=None, x=None, y=None, name=""): + cond = P1 != None and P2 != None + self.x, self.y, self.name = ( + P2.x - P1.x if cond else x, + P2.y - P1.y if cond else y, + name, + ) + + def __str__(self): + return str(self.name) + + def __iter__(self): + return iter([self.x, self.y]) + + def __repr__(self): + return "Vector({}, {})".format(self.x, self.y) + + def __eq__(self, other): + return ( + (self.x == other.x) and (self.y == other.y) + if isinstance(other, Vector) + else False + ) + + def __add__(self, other): + return ( + Vector(x=self.x + other.x, y=self.y + other.y) + if isinstance(other, Vector) + else Point(other.x + self.x, other.y + self.y) + if isinstance(other, Point) + else None + ) + + def __sub__(self, other): + return ( + Vector(x=self.x - other.x, y=self.y - other.y) + if isinstance(other, Vector) + else Point(other.x - self.x, other.y - self.y) + if isinstance(other, Point) + else None + ) + + def __mul__(self, other): + return ( + Vector(x=self.x * other.x, y=self.y * other.y) + if isinstance(other, Vector) + else Vector(x=self.x * other, y=self.y * other) + if isinstance(other, (int, float)) + else None + ) + + def __truediv__(self, other): + return ( + Vector(x=self.x / other.x, y=self.y / other.y) + if isinstance(other, Vector) + else Vector(x=self.x / other, y=self.y / other) + if isinstance(other, (int, float)) + else None + ) + + def rotate(self, angle): + angle = radians(angle) + return Vector( + x=self.x * cos(angle) - self.y * sin(angle), + y=self.x * sin(angle) + self.y * cos(angle), + name=self.name, + ) + + def neg(self): + return Vector(x=-self.x, y=-self.y, name=self.name) + + def copy(self): + return Vector(x=self.x, y=self.y, name=self.name) + + def round(self): + self.x = round(self.x) + self.y = round(self.y) + + +def expend(liste, d, M=None): + M = ( + Point( + round(average([P.x for P in liste])), round(average([P.y for P in liste])) + ) + if M == None + else M + ) + return [ + Point(round(P.x + (P.x - M.x) * d), round(P.y + (P.y - M.y) * d)) + if d != 0 + else P + for P in liste + ] + + +def connect_points(liste, ending=False): + line = [(liste[p], liste[p + 1]) for p in range(len(liste)) if p < len(liste) - 1] + line.append((liste[-1], liste[0])) if ending else None + return line + + +def findWithPoint(P1, P2, length): + N = distance(P1, P2) + return Point( + P1.x + ((P2.x - P1.x) * length) / N, P1.y + ((P2.y - P1.y) * length) / N + ) + + +def alpha_pixel(x, y, col, alpha=1.0): + set_pixel( + x, + y, + tuple( + C1 * alpha - C2 * alpha + C2 for C1, C2 in zip(color(col), get_pixel(x, y)) + ), + ) + + +def interpolate(C1, C2, N=100): + C1, C2 = color(C1), color(C2) + interpolated_colors = [ + ( + C1[0] + (C2[0] - C1[0]) * i / (N + 1), + C1[1] + (C2[1] - C1[1]) * i / (N + 1), + C1[2] + (C2[2] - C1[2]) * i / (N + 1), + ) + for i in range(N + 2) + ] + return interpolated_colors[1:-1] + + +def scatter(X, Y, color="0", style="*", C=Point(160, 111)): + draw_points( + [Point(round(C.x + x), round(C.y - y)) for x, y in zip(X, Y)], + color, + style, + False, + ) + + +def plot(X, Y, color="0", C=Point(160, 111)): + set_lines( + connect_points([Point(round(C.x + x), round(C.y - y)) for x, y in zip(X, Y)]), + color, + ) + + +def draw_points(liste, color="0", style="*", text=True): + for P in liste: + exec( + DrawWithStyle[style], + { + "P": P, + "color": color, + "set_pixel": set_pixel, + "fill_circle": fill_circle, + "draw_croix": draw_croix, + }, + ) + draw_string(str(P.name), P.x + 6, P.y + 6, "0", "1") if text else None + + +def draw_croix(center, r, angle=90, color="0"): + R = Vector(center, Point(center.x + r, center.y)) + R = R.rotate(angle) + for _ in range(4): + R = R.rotate(90) + R.round() + set_lines([(center, R + center)], color) + + +def set_lines(line, color="0"): + for P1, P2 in line: + up, right = True if P2.y > P1.y else False, True if P2.x > P1.x else False + h, b = P2.y - P1.y if up else P1.y - P2.y, P2.x - P1.x if right else P1.x - P2.x + n = True if h <= b else False + set_pixel(P2.x, P2.y, color) + if b != 0 or h != 0: + e = h / b if n else b / h + for i in range(b if n else h): + set_pixel( + int(round(P1.x + i) if right else round(P1.x - i)) + if n + else int(round(P1.x + e * i) if right else round(P1.x - e * i)), + int(round(P1.y + e * i) if up else round(P1.y - e * i)) + if n + else int(round(P1.y + i) if up else round(P1.y - i)), + color, + ) + + +def draw_arrows(liste, color="0", length=10, angle=45, fill=False): + for A, B in liste: + V1 = Vector(findWithPoint(B, A, length), B).neg() + V2, V3 = V1.rotate(angle), V1.rotate(-angle) + V2.round() + V3.round() + set_lines([(A, B)], color) + set_lines([(B, V2 + B), (B, V3 + B)], color) if not fill else fill_triangles( + [(V2 + B, B, V3 + B)], color + ) + + +def draw_vector(P, V, color="0"): + x, y = milieu(P, V + P) + draw_arrows([(P, V + P)], color, fill=False) + draw_string(str(V.name), round(x - 6), round(y - 6), "0", "1") + + +def draw_droite(P1, P2, color="0", name=None): + if P1.x == P2.x: + set_lines([(Point(P1.x, 0), Point(P1.x, 222))], color) + elif P1.y == P2.y: + set_lines([(Point(0, P1.y), Point(320, P1.y))], color) + else: + _a = a(P1, P2) + _b = b(_a, P2) + P0, P3 = ( + Point(round((222 - _b) / _a), 222) + if abs(P2.x - P1.x) < abs(P2.y - P1.y) + else Point(0, round(_a * 0 + _b)), + Point(round((-1 - _b) / _a), -1) + if abs(P2.x - P1.x) < abs(P2.y - P1.y) + else Point(320, round(_a * 320 + _b)), + ) + set_lines([(P0, P3)], color) + if name != None: + M = milieu(P1, P2) + draw_string(str(name), round(M.x - 6), round(M.y - 6), "0", "1") + + +def fill_triangles(liste, color="0", alpha=1): + eq = lambda p, a, b: (a.x - p.x) * (b.y - p.y) - (a.y - p.y) * (b.x - p.x) + for P1, P2, P3 in liste: + xmin, xmax, ymin, ymax = ( + min(P1.x, P2.x, P3.x), + max(P1.x, P2.x, P3.x) + 1, + min(P1.y, P2.y, P3.y), + max(P1.y, P2.y, P3.y) + 1, + ) + width, height = abs(xmax + xmin), abs(ymax + ymin) + for y in range(ymin, ymax): + if 0 <= y < height: + for x in range(xmin, xmax): + pos = Point(x, y) + w1, w2, w3 = eq(pos, P3, P1), eq(pos, P1, P2), eq(pos, P2, P3) + if 0 <= x < width and ( + (w1 >= 0 and w2 >= 0 and w3 >= 0) + or (-w1 >= 0 and -w2 >= 0 and -w3 >= 0) + ): + set_pixel(x, y, color) if alpha == 1 else alpha_pixel( + x, y, color, alpha + ) + + +def draw_polygone(n, rayon, coord, color="0"): + alpha = 2 * pi / n + set_lines( + connect_points( + [ + Point( + round(coord.x + rayon * cos(k * alpha)), + round(coord.y + rayon * sin(k * alpha)), + color, + ) + for k in range(1, n + 1) + ], + True, + ), + color, + ) + + +def fill_polygone(n, rayon, coord, color="0", c_map=None, alpha=1): + _alpha = 2 * pi / n + points = [ + Point( + round(coord.x + rayon * cos(k * _alpha)), + round(coord.y + rayon * sin(k * _alpha)), + ) + for k in range(1, n + 1) + ] + for p, c in zip( + connect_points(points, True), + [color for _ in range(len(points))] if not isinstance(c_map, list) else c_map, + ): + fill_triangles([([coord, p[0], p[1]])], c, alpha) + + +def draw_rectangle(P1, P4, color="0"): + fill_rect(P1.x, P1.y, P4.x - P1.x, 1, color) + fill_rect(P4.x, P1.y, 1, P4.y - P1.y + 1, color) + fill_rect(P1.x, P4.y, P4.x - P1.x, 1, color) + fill_rect(P1.x, P1.y, 1, P4.y - P1.y, color) + + +def fill_rectangle(P1, P4, color="0", alpha=1): + for x in range(P4.x - P1.x if P4.x > P1.x else P1.x - P4.x): + for y in range(P4.y - P1.y if P4.y > P1.y else P1.y - P4.y): + alpha_pixel(P1.x + x, P1.y + y, color, alpha) + + +def draw_circle(center, rayon, color="0"): + for x in range(-abs(rayon), abs(rayon)): + l = round((abs(rayon) ** 2 - x**2) ** 0.5) + if abs(x) <= l: + set_pixel(center.x + l, center.y + x, color) + set_pixel(center.x - l, center.y - x, color) + set_pixel(center.x - x, center.y - l, color) + set_pixel(center.x + x, center.y + l, color) + + +def fill_circle(center, rayon, color="0", alpha=1): + for x in range(-round(rayon), round(rayon) + 1): + for y in range(-round(rayon), round(rayon) + 1): + if round(distance(center, Point(center.x + x, center.y + y))) <= rayon: + alpha_pixel( + center.x + x, center.y + y, color, alpha + ) if alpha != 1 else set_pixel(center.x + x, center.y + y, color) + + +def bezier_curve(liste, color="0", thickness=1, N=1500): + for _t in range(N): + x, y, t = 0, 0, _t / N + for i in range(len(liste)): + x += ( + (perm(len(liste) - 1, i) / factorial(i)) + * (t**i) + * ((1 - t) ** (len(liste) - 1 - i)) + ) * liste[i].x + y += ( + (perm(len(liste) - 1, i) / factorial(i)) + * (t**i) + * ((1 - t) ** (len(liste) - 1 - i)) + ) * liste[i].y + P = Point(round(x), round(y)) + set_pixel(P.x, P.y, color) if thickness == 1 else fill_circle( + P, thickness, color, 1 + ) From c3ffb62de243edfb32af5bcc84e58847de3fa25f Mon Sep 17 00:00:00 2001 From: Discusser <47938380+Discusser@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:30:56 +0200 Subject: [PATCH 5/5] Revert "Fix list comprehension issue with fill_rectangle" This reverts commit 95231b375e27af8994e9790cabb19d245fd7e826. --- src/visual/visual.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/visual/visual.py b/src/visual/visual.py index c09da4a..9743d4c 100644 --- a/src/visual/visual.py +++ b/src/visual/visual.py @@ -342,9 +342,12 @@ def draw_rectangle(P1, P4, color="0"): def fill_rectangle(P1, P4, color="0", alpha=1): - for x in range(P4.x - P1.x if P4.x > P1.x else P1.x - P4.x): - for y in range(P4.y - P1.y if P4.y > P1.y else P1.y - P4.y): - alpha_pixel(P1.x + x, P1.y + y, color, alpha) + for x, y in [ + (x, y) + for x in range(P4.x - P1.x if P4.x > P1.x else P1.x - P4.x) + for y in range(P4.y - P1.y if P4.y > P1.y else P1.y - P4.y) + ]: + alpha_pixel(P1.x + x, P1.y + y, color, alpha) def draw_circle(center, rayon, color="0"):