This is the python example in wiki.python.org
https://wiki.python.org/moin/PointsAndRectangles
Don't worry, python is one of the many language doing this class. It is an actual use case for learning classes.
200 lines of code and you do nothing. Not even fun
Except in python complex is a base type, and I learned the use of complex numbers when I was in public high school in my sweet banlieue. (a place said to be full of delinquents and uneducated kids)
Then I thought : with just simple math how hard would it be to just draw two polygons one of which rotated with the python base types?
How hard is programming when you keep it simple?
Here is my answer in less than 10% of the initial number of lines of code and a drawing to illustrate how hard it is :
from PIL import Image, ImageDraw
# short constant names a la fortran
from cmath import pi as PI, e as E I = complex("j")
to_x_y = lambda cpl: (cpl.real, cpl.imag) im = Image.new("RGB", (512, 512), "white") draw = ImageDraw.Draw(im) rotation = E**(I*PI/3) homothetia = min(im.size[0], im.size[1]) trans = homothetia/2 homothetia /= 2.5 polygone = (complex(0,0), complex(0,1), complex(1,1), complex(1,0), complex(0,0)) bigger = map(lambda x: x * homothetia + trans, polygone) bigger_rotated = map(lambda x: x * rotation, bigger) draw.line(map(to_x_y, bigger), "blue") draw.line(map(to_x_y, bigger_rotated), "green") im.save("this.png", "PNG")
I don't say classes are useless, I use them. But, I still have a hard time thinking of a simple pedagogic example of their use. However, I see a lot of overuse of Object Oriented Programming to try to make people able to use concepts that are not accessible without basic knowledge. OOP is no shortcut for avoiding to learn math, or anything else. If you don't understand geometry and math, you will probably be whatever the quality of the class given unable to do any proper geometrical operations.
We need OOP. But the basic complex type far outweigh in usefulness any 2D geometry classes I see so far without requiring any dependencies. And I never saw in 5 years complex types used even for doing 2D geometry, however it seems the alternative buzzword to OOP -including numpy- is so making you look data scientist and pro!
So what is the excuse again for not using something that works and is included in base types with no requirements for doing geometry when we say that games could be a nice way to bring teenagers to coding? Are we also gonna tell them learning is useless and that reinventing the square wheel is a good idea? Are we gonna tell them to not learn because we have libraries for everything?
For the fun I did an OOP facade to complex as point/rectangle but seriously, it is just pedantic and useless. But still 50% less lines and more useful than the initial example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# version 2 here https://gist.github.com/jul/200d3a5895a437e20df6 | |
from cmath import polar, rect, pi as PI, e as E, phase | |
rad_to_deg = lambda r : r/2/PI*360.0 | |
deg_to_rad = lambda r : r*2*PI/360.0 | |
identity = lambda r: r | |
class Point(complex): | |
def __repr__(self): | |
return "<Point x:%.3f y:%.3f>" % self.as_euclidian() | |
def as_euclidian(self): | |
return (self.real, self.imag) | |
def as_polar(self,measure="rad" ): | |
conv = measure == "rad" and identity or rad_to_deg | |
return (abs(self), conv(phase(self))) | |
class Vector(Point): | |
def __repr__(self): | |
return "<Vector x:%.3f y:%.3f>" % self.as_euclidian() | |
class Rotation(Point): | |
def __repr__(self): | |
return "<Rotation r:%.3f theta:%.3f deg>" % self.as_polar("deg") | |
def __init__(self,*a,**kw): | |
if(abs(abs(self)-1.0) > .0001): | |
raise ValueError("norm must be 1") | |
I = complex("j") | |
point = center = Point(-1,-1) | |
vector = shape = Vector(2,2) | |
rotation = r = Rotation(E**(I*PI/3)) | |
print("translating a point is as easy as") | |
print("%r + %r = %r" % (point, vector, Point(point+vector))) | |
print("rotating a point is as easy as") | |
print("%r * %r = %r" % (point, rotation, Point(point*rotation))) | |
class Rectangle(object): | |
def __init__(self, center,shape,rotation): | |
self.center=center | |
self.shape=shape | |
self.rotation=rotation | |
def __repr__(self): | |
return "<Rectangle: Center %r, shape %r, rotation %r>" % ( | |
self.center,self.shape, self.rotation.as_polar('deg')) | |
def area(self): | |
return self.shape.imag*self.shape.real | |
def as_points(self): | |
return list(map(lambda p:Point((p/2+self.center)*self.rotation), | |
[ -self.shape, Vector(-self.shape.real, self.shape.imag), | |
self.shape, Vector(self.shape.real, -self.shape.imag) ])) | |
### Quite trivial, pretty useless method | |
def translation(self,vector): | |
self.center += Vector(vector) | |
def homothetia(self, factor): | |
self.shape*=float(factor) | |
def rotate(self, rotation): | |
self.rotation*=Rotation(rotation) | |
def rotate_from_origin(self, rotation): | |
self.center*=Rotation(rotation) | |
self.rotation*=Rotation(rotation) | |
#### just for convenience, but really useless | |
def as_polars(self, measure="rad"): | |
return list(map(lambda p:p.as_polar(measure), self.as_points())) | |
def as_euclidians(self): | |
return list(map(lambda p:p.as_euclidian(), self.as_points())) | |
def rotate_from_point(self, point, rotation): | |
self.center-= Point(point) | |
self.rotate_from_origin(Rotation(rotation)) | |
self.center+= Point(point) | |
rec=Rectangle(center,shape,r) | |
print("let's see our rectangle true data %r" % rec) | |
print("list on euclidian coord %r" % rec.as_euclidians()) | |
print("let's list all the point in polar %r" % rec.as_polars()) | |
print("rectangle area is %f" % rec.area()) | |
print("center is %r" % rec.center) | |
print("apply a rotation of -60 degrees") | |
rec.rotate(rect(1,-PI/3)) | |
print("rotation becomes %r" % rec.rotation) | |
print("points are now %r" % rec.as_points()) | |
print("distance from origin of all points of the rectangle %s" % ( | |
",".join( map(lambda p:"%.2f" % abs(p), rec.as_points())))) | |
print("angle in degrees from origin from all points of the rectangle %s" %( | |
",".join(map(lambda r: "%.2f" % rad_to_deg(phase(r)), rec.as_points())) | |
)) | |
print("let's center back the square to see") | |
rec.translation(-rec.center) | |
print("finally %r" % rec.as_points()) | |
try: | |
r=Rotation(1,1) | |
except ValueError: | |
print("Rotation is a complex with a norm of 1") |
No comments:
Post a Comment