from graphics import * from math import cos,acos,sin,tan,pi n=10 # Anzahl Zacken alpha = 45 # Winkel bei A win = GraphWin("Faltsterne", 800, 800) win.setCoords(-1.2,-1.2,1.2,1.2) # Koordinatensystem setzen # Umrechnung Grad -> rad def rad(grad): return grad/180*pi # Umrechung rad -> Grad def deg(r): return r/pi*180 # Punkt auf dem Einheitskreis, evtl. mit anderem Radius und anderem Zentrum def palpha(grad, r=1.0, c=Point(0,0)): x = r*cos(rad(grad))+c.getX() y = r*sin(rad(grad))+c.getY() return Point(x,y) # Resultat zurückgeben # Summe zweier Punkte (Vektoraddition) def add(a,b): return Point(a.getX()+b.getX(), a.getY()+b.getY()) # Punkt Strecken am Ursprung mit Faktor l def mul(a,l): return Point(a.getX()*l, a.getY()*l) # Vektordifferenz def sub(a,b): return add(a,mul(b,-1)) # Lineare inerpolation zweier Punkte: a + t*(b-a) def interp(a,b,t): return add(mul(a,1.0-t), mul(b,t)) # Rechtwinkliger Vektor (Drehung um +90 Grad) def perp(a): return Point(-a.getY(), a.getX()) # Länge eines Vektors (bzw. Abstand vom Ursprung) def norm(a): return (a.getX()**2+a.getY()**2)**0.5 # Vektor zwischen zwei Punkten def vec(a,b): return sub(b,a) # Skalarprodukt def dot(a,b): return a.getX()*b.getX()+a.getY()*b.getY() # Winkel zwischen zwei Vektoren def vangle(a,b): return deg(acos(dot(a,b)/norm(a)/norm(b))) # Rotation des Punktes p um Zentrum z mit Winkel alpha def rotate(p,z,alpha): print(p,z,alpha) pp = sub(p,z) print(pp) pp = add(mul(palpha(alpha), pp.getX()), mul(palpha(alpha+90), pp.getY())) return add(pp, z) # Schnittpunkt der beiden Geraden l1, l2 (definiert als Line(p1, p2)) def intersect(l1, l2): n1 = perp(vec(l1.getP1(), l1.getP2())) d1 = -dot(n1, l1.getP1()) v2 = vec(l2.getP1(), l2.getP2()) t = (-d1-dot(l2.getP1(),n1))/dot(v2,n1) return add(l2.getP1(), mul(v2,t)) # Header einer SVG-Datei, A4-Format def svgHeader(): return """ """ # Footer der SVG-Datei def svgFooter(): return """ """ # Skalieren des Einheitskreises auf Grösse A4, zum Drucken def toa4(points): return [add(mul(p,95), Point(105,148.5)) for p in points] # Pfad in SVG def svgPath(points, style=0, closed=False): points = toa4(points) style = ['fill:none;stroke:#000000;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1',\ 'fill:none;stroke:#000000;stroke-width:0.20974073;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.20974073,0.62922219;stroke-dashoffset:0;stroke-opacity:1'][style] res = f"M {points[0].getX()} {points[0].getY()}" for p in points[1:]: res += f" L {p.getX()} {p.getY()}" if closed: res += " z" res = f'' return res # Gestrichelter Pfad (effiktive Striche, für Laserschnittvorlage) def dottedPath(points, closed=False): res = "" if closed: points = points+[points[0]] for i in range(len(points)-1): l = norm(vec(points[i], points[i+1]))*95 num = int(l/2) for j in range(num): res += svgPath([interp(points[i], points[i+1], j/num), interp(points[i], points[i+1], (j+0.5)/num)]) return res ############## # Berechnung # ############## beta = 180/n a = Point(-1,0) z = Point(0,0) # Punkt c = l*cis(gamma), (l sin(beta))/(1-l cos(beta)) = tan(alpha) l = tan(rad(alpha))/(sin(rad(beta))+tan(rad(alpha))*cos(rad(beta))) c = palpha(180-beta, l) # Umkreismittelpunkt o = (0.5, oy), ac dot (oy-(0.5(a+c)) = 0, bzw. oy = acm+t*acperp acm = interp(a,c,0.5) acperp = mul(perp(vec(a,c)),-1) t = (-0.5-acm.getX())/acperp.getX() o = add(acm, mul(acperp,t)) # Schnittpunkt mit z+t*acperp: |o - (z+t*acperp)| = orad t = 2*(o.getX()*acperp.getX()+o.getY()*acperp.getY())/(norm(acperp)**2) zz = mul(acperp,t) faltwinkel = 2*vangle(vec(a,c), vec(a,zz)) faltlinie = Line(z, palpha(180-beta)) faltdir = rotate(z,a,alpha+faltwinkel) d = intersect(faltlinie, Line(a, faltdir)) schnittlinie = Line(a, d) # Konstruktion anzeigen schnittlinie.draw(win) faltlinie.draw(win) Circle(faltdir,0.01).draw(win) Line(mul(acperp, -1.0),acperp).draw(win) Circle(o,norm(o)).draw(win) # Ortsbogen Circle(zz,0.01).draw(win) Circle(d,0.01).draw(win) Polygon([a,z,c]).draw(win) Polygon([a,zz,c]).draw(win) rcout = norm(d) # Entfernung des Punktes C' (Blattrand, wo der Einschnitt ist) rcin = norm(c) # Entfernung von C (Bis wohin eingeschnitten werden soll) svg = svgHeader() pts = [] pts2 = [] for i in range(n): pts.append(palpha(i*360/n+180)) pts.append(mul(palpha((i+0.5)*360/n+180),rcout)) #svg+=dottedPath([z,pts[-2]]) svg+=dottedPath([z,pts[-2]]) l = Line(palpha(i*360/n+180), mul(palpha((i+0.5)*360/n+180),rcout)) l.setWidth(2) l.setOutline("red") l.draw(win) l = Line(palpha((i+1)*360/n+180), mul(palpha((i+0.5)*360/n+180),rcout)) l.setWidth(2) l.setOutline("red") l.draw(win) strich = [mul(palpha((i+0.5)*360/n+180),rcin), mul(palpha((i+0.5)*360/n+180),rcout)] pts2+= [pts[-2],strich[0]] svg += svgPath(strich) svg += dottedPath([z,strich[0]]) l = Line(strich[0], strich[1]) l.setWidth(2) l.setOutline("red") l.draw(win) svg += svgPath(pts, 0, True) svg += dottedPath(pts2, True) azr = norm(vec(a,zz)) czr = norm(vec(c,zz)) pts = [] for i in range(n): pts += [mul(palpha(i*360/n+180),azr), mul(palpha((i+0.5)*360/n+180),czr)] l = Line(pts[-2], pts[-1]) l.setWidth(2) l.setOutline("green") l.draw(win) l = Line(mul(palpha((i+1)*360/n+180),azr), mul(palpha((i+0.5)*360/n+180),czr)) l.setWidth(2) l.setOutline("green") l.draw(win) svg += svgFooter() with open(f"n{n}-a{alpha}.svg", "w") as f: f.write(svg) win.getMouse() # Pause to view result win.close() # Close window when done