I recently wanted to program ray marching in python using ursina engine. to do that i need a special class called float2.
in unity engine you can program float2 normally and give it into your paramater arguments, but in python there is no such class as float2, i tried doing some easy ways to make it but i have problem when i want to store variables.
basically i have a float2 class:
class float2:
def __init__(self, x, y):
self.x = x,
self.y = y
it just stores x and y.
then i have some functions where i use the class:
def length(v: float2):
return float(sqrt(v.x*v.x + v.y*v.y))
def signedDstToCircle(p: float2, centre: float2, radius: float):
return length(centre-p) - radius
this works great but i hit a roadblock.
i need to asign one variable a from a function:
def signedDstToBox(p: float2, centre: float2, size: float2):
offset = float2(abs(p-centre) - size)
# dst from point outside the box to edge (0 if inside the box)
unsignedDst = length(max(offset, 0))
# -dst from point inside the box to edge (0 if outside the box)
dstInsideBox = max(min(offset, 0))
return unsignedDst + dstInsideBox
if i try to run the program now with all it gives me an error:
offset = float2(abs(p-centre) - size)
TypeError: unsupported operand type(s) for -: 'float2' and 'float2'
i think it gives me error because it not a number, so it cant do math operations and also i think when i will fix this issue there will be another problem with storing the variable.
if anyone know how to make this possible so i can math operations and also being able to store variable by just doing offset = float2(abs(p-centre)-size) so it will be stored and i can acces it by doing offset.x and offset.y
thanks in advance, galfar(SpringPeace)
Related
I've been trying to write a Python program to calculate a point location, based on distance from 4 anchors. I decided to calculate it as intersection points of 4 circles.
I have a question regarding not the algorithm but rather the use of classes in such program. I don't really have much experience with OOP. Is it really necessary to use classes here or does it at least improve a program in any way?
Here's my code:
import math
class Program():
def __init__(self, anchor_1, anchor_2, anchor_3, anchor_4, data):
self.anchor_1 = anchor_1
self.anchor_2 = anchor_2
self.anchor_3 = anchor_3
self.anchor_4 = anchor_4
def intersection(self, P1, P2, dist1, dist2):
PX = abs(P1[0]-P2[0])
PY = abs(P1[1]-P2[1])
d = math.sqrt(PX*PX+PY*PY)
if d < dist1+ dist2 and d > (abs(dist1-dist2)):
ex = (P2[0]-P1[0])/d
ey = (P2[1]-P1[1])/d
x = (dist1*dist1 - dist2*dist2 + d*d) / (2*d)
y = math.sqrt(dist1*dist1 - x*x)
P3 = ((P1[0] + x * ex - y * ey),(P1[1] + x*ey + y*ex))
P4 = ((P1[0] + x * ex + y * ey),(P1[1] + x*ey - y*ex))
return (P3,P4)
elif d == dist1 + dist2:
ex = (P2[0]-P1[0])/d
ey = (P2[1]-P1[1])/d
x = (dist1*dist1 - dist2*dist2 + d*d) / (2*d)
y = math.sqrt(dist1*dist1 - x*x)
P3 = ((P1[0] + x * ex + y * ey),(P1[1] + x*ey + y*ex))
return(P3, None)
else:
return (None, None)
def calc_point(self, my_list):
if len(my_list) != 5:
print("Wrong data")
else:
tag_id = my_list[0];
self.dist_1 = my_list[1];
self.dist_2 = my_list[2];
self.dist_3 = my_list[3];
self.dist_4 = my_list[4];
(self.X1, self.X2) = self.intersection(self.anchor_1, self.anchor_2, self.dist_1, self.dist_2)
(self.X3, self.X4) = self.intersection(self.anchor_1, self.anchor_3, self.dist_1, self.dist_3)
(self.X5, self.X6) = self.intersection(self.anchor_1, self.anchor_4, self.dist_1, self.dist_4)
with open('distances.txt') as f:
dist_to_anchor = f.readlines()
dist_to_anchor = [x.strip() for x in dist_to_anchor]
dist_to_anchor = [x.split() for x in dist_to_anchor]
for row in dist_to_anchor:
for k in range(0,5):
row[k] = float(row[k])
anchor_1= (1,1)
anchor_2 = (-1,1)
anchor_3 = (-1, -1)
anchor_4 = (1, -1)
My_program = Program (anchor_1, anchor_2, anchor_3, anchor_4, dist_to_anchor)
My_program.calc_point(dist_to_anchor[0])
print(My_program.X1)
print(My_program.X2)
print(My_program.X3)
print(My_program.X4)
print(My_program.X5)
print(My_program.X6)
Also, I don't quite understand where should I use self keyword and where it is needless.
Is it really necessary to use classes here or does it at least improve a program in any way?
Classes are never necessary, but they are often very useful for organizing code.
In your case, you've taken procedural code and just wrapped it in a class. It's still basically a bunch of function calls. You'd be better off either writing it as procedures or writing proper classes.
Let's look at how you'd do some geometry in a procedural style vs an object oriented style.
Procedural programming is all about writing functions (procedures) which take some data, process it, and return some data.
def area_circle(radius):
return math.pi * radius * radius
print(area_circle(5))
You have the radius of a circle and you get the area.
Object oriented programming is about asking data to do things.
class Circle():
def __init__(self, radius=0):
self.radius = radius
def area(self):
return math.pi * self.radius * self.radius
circle = Circle(radius=5)
print(circle.area())
You have a circle and you ask it for its area.
That seems a lot of extra code for a very subtle distinction. Why bother?
What happens if you need to calculate other shapes? Here's a Square in OO.
class Square():
def __init__(self, side=0):
self.side = side
def area(self):
return self.side * self.side
square = Square(side=5)
print(square.area())
And now procedural.
def area_square(side):
return side * side
print(area_square(5));
So what? What happens when you want to calculate the area of a shape? Procedurally, everywhere that wants to deal with shapes has to know what sort of shape it's dealing with and what procedure to call on it and where to get that procedure from. This logic might be scattered all over the code. To avoid this you could write a wrapper function and make sure its imported as needed.
from circle import 'area_circle'
from square import 'area_square'
def area(type, shape_data):
if type == 'circle':
return area_circle(shape_data)
elif type == 'square':
return area_square(shape_data)
else:
raise Exception("Unrecognized type")
print(area('circle', 5))
print(area('square', 5))
In OO you get that for free.
print(shape.area())
Whether shape is a Circle or a Square, shape.area() will work. You, the person using the shape, don't need to know anything about how it works. If you want to do more with your shapes, perhaps calculate the perimeter, add a perimeter method to your shape classes and now it's available wherever you have a shape.
As more shapes get added the procedural code gets more and more complex everywhere it needs to use shapes. The OO code remains exactly the same, instead you write more classes.
And that's the point of OO: hiding the details of how the work is done behind an interface. It doesn't matter to your code how it works so long as the result is the same.
Classes and OOP are IMHO always a good choice, by using them, you will be able to better organize and reuse your code, you can create new classes that derive from an existing class to extend its functionality (inheritance) or to change its behavior if you need it to (polymorphism) as well as to encapsulate the internals of your code so it becomes safer (no real encapsulation in Python, though).
In your specific case, for example, you are building a calculator, that uses a technique to calculate an intersection, if somebody else using your class wants to modify that behavior they could override the function (this is Polymorphism in action):
class PointCalculator:
def intersection(self, P1, P2, dist1, dist2):
# Your initial implementation
class FasterPointCalculator(PointCalculator):
def __init__(self):
super().__init__()
def intersection(self, P1, P2, dist1, dist2):
# New implementation
Or, you might extend the class in the future:
class BetterPointCalculator(PointCalculator):
def __init__(self):
super().__init__()
def distance(self, P1, P2):
# New function
You may need to initialize your class with some required data and you may not want users to be able to modify it, you could indicate encapsulation by naming your variables with an underscore:
class PointCalculator:
def __init__(self, p1, p2):
self._p1 = p1
self._p2 = p2
def do_something(self):
# Do something with your data
self._p1 + self._p2
As you have probably noticed, self is passed automatically when calling a function, it contains a reference to the current object (the instance of the class) so you can access anything declared in it like the variables _p1 and _p2 in the example above.
You can also create class methods (static methods) and then you don't have access to self, you should do this for methods that perform general calculations or any operation that doesn't need a specific instance, your intersection method could be a good candidate e.g.
class PointCalculator:
#staticmethod
def intersection(P1, P2, dist1, dist2):
# Return the result
Now you don't need an instance of PointCalculator, you can simply call PointCalculator.intersection(1, 2, 3, 4)
Another advantage of using classes could be memory optimization, Python will delete objects from memory when they go out of scope, so if you have a long script with a lot of data, they will not be released from memory until the script terminates.
Having said that, for small utility scripts that perform very specific tasks, for example, install an application, configure some service, run some OS administration task, etc... a simple script is totally fine and it is one of the reasons Python is so popular.
I have the following RayCastCallback function in python Box2D.
Class RayCastCallback(Box2D.b2.rayCastCallback):
def ReportFixture(self, fixture, point, normal, fraction):
if (fixture.filterData.categoryBits & 1) == 0:
return 1
self.p2 = point
self.fraction = fraction
return 0
I use it by instantiating one for each angle and then saying
ray_cast_callback.p1 = position
ray_cast_callback.fraction = 1.0
ray_cast_callback.p2 = (position[0] + math.cos(radians)*range, position[1] + math.sin(radians)*range)
world.RayCast(ray_cast_callback, ray_cast_callback.p1, ray_cast_callback.p2)
This works well, but my problem is that in the world I've set up, there are multiple different types of static and dynamic objects and I want it to exclude instances of a particular static object so that the RayCast just goes right through them.
How do I do this?
Usually in raycasting the following values are used as a return type
-1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue
You can check the object type and if it is static return -1 to have this object ignored.
My book requires me to Make another program using functions, the catch is that I need to make it a little bit more complex this time, so instead of going for a simple addition I try to solve a very simple physics problem with values given to me by the user, using two functions (velocity and acceleration).
Heres the aim of the program (sampledoc)
Create a program that reads and prints this txt document
Introduces the Program and the name of the script
Uses a function to solve a problem, make the function more complex
User gives distance (x) and time (t)
Program calculates velocity and acceleration
Creates a new txt document and writtes the results in it
Prints the results of the problem directly from the new document.
And heres the code:
from sys import argv
script, textf = argv; sampledoc = open(textf)
def velocity (x, t):
vel = (float(x)) / (float(t))
return float(vel)
def acceleration (v, t):
accel = (float(v)) / (float(t))
return float(accel)
print "Hello my name is TAR or as my creator called me %s" % script; print sampledoc.read(); sampledoc.close()
print "Results will be printed on a new text document, thanks for your preference"
x = float(raw_input("Please introduce the Distance")); t = float(raw_input("Please introduce the time:... "))
vel = velocity(x, t)
accel = acceleration (velocity, t)
results = 'ResultsP.txt'
new_file = open(results, 'w')
new_file.write(str(vel)); new_file.write(str(accel))
new_file.close()
new_file.open(results, 'r')
print new_file.read()
new_file.close()
I know there's something wrong here, somewhere, but my brain isn't working right now, I suppose it has something to do with either the way I am trying to solve this or the ''floats'' I used in the function since I am getting this error:
File "ex21Study.py", line 20, in <module>
accel = acceleration (velocity, t)
File "ex21Study.py", line 10, in acceleration
accel = (float(v)) / (float(t))
TypeError: float() argument must be a string or a number
I googled this and found some answers on other similar issues that said something about converting my results to float or str, however, I tried both and with no fruitful results.
You are passing in a function here:
accel = acceleration (velocity, t)
velocity is not a floating point value; it is a function object. You probably meant to use vel instead here, which you calculated on the preceding line:
vel = velocity(x, t)
accel = acceleration(vel, t)
The following code is the initialization method of a basic Angle object with float as its parent class.
class Angle(float):
def __init__(self, value, vertex2 = None, vertex3 = None, atype = 'convex'):
#type-checking for the input args
try:
#checks for value arg
angle = value
if not (0 < value < 360):
angle %= 360
except TypeError:
#checks for three-vertice args
try:
angle = three_point_angle(value, vertex2, vertex3)
#three_point_angle is a function to calculate the
#convex angle between three vertices (i.e. at vertex2)
if atype == 'concave':
angle = 360 - angle
self._vdict = {}
for pos, vert in enumerate([value, vertex2, vertex3]):
self._vdict[pos] = vert
except:
raise TypeError(\
"You may only specify either an angle value, or three vertices from which \
to calculate the angle. You input a %s, %s and %s value." % (\
type(value), type(vertex2), type(vertex3)))
self.angle = angle
The idea behind this class is that you can either input a value for the angle, or specify three vertices (and an optional angle type parameter) to automatically calculate the angle. In the end, self.angle is always initialized, and this is where all the arithmetic takes place (so __add__(self, other) would affect self.angle).
The reason it inherits from float is to inherit its magic methods for reflective and augmented assignment, which are all performed on self.angle.
The problem arises when one tries to input three values for the vertices. Since it inherits from float, it can't take more than one argument, and as such raises an error. How would I work around this? My guess is that I would have to create a __new__ method for Angle, such that it would be invoked instead of the superclass', but I have no clue where I'd even start with that or even if it's the right/best way to go about this.
You don't need to inherit from float. You're incorrect in thinking that magic methods are performed on self.angle; they're just performed on self. Try the following code:
class Angle(float):
def __init__(self, x):
self.angle = x
def double(self):
self.angle *= 2
a = Angle(1)
a.double()
print a # prints 1.0
print a.angle # prints 2
a *= 5
print a # prints 5.0
print a.angle # throws AttributeError
a.angle isn't affected by magic methods, nor is float(a) affected by operations on a.angle. floats are immutable, so a *= 5 created a new float, with different attributes.
So, if you change Angle to inherit from Object instead of float, you can control initialization, without losing any convenience.
See this related question:
How to overload `float()` for a custom class in Python?
then change
class Angle(float):
to
class Angle(object):
I'm writing some Python code and have a class as follows
class GO:
##irrelevant code
def getCenter(self):
xList = []
yList = []
# Put all the x and y coordinates from every GE
# into separate lists
for ge in self.GEList:
for point in ge.pointList:
xList.append(point[0])
yList.append(point[1])
# Return the point whose x and y values are halfway between
# the left- and right-most points, and the top- and
# bottom-most points.
centerX = min(xList) + (max(xList) - min(xList)) / 2
centerY = min(yList) + (max(yList) - min(yList)) / 2
return (centerX, centerY)
###more irrelevant code
def scale(self, factor):
matrix = [[factor,0,0],[0,factor,0],[0,0,1]]
for ge in self.GEList:
fpt = []
(Cx, Cy) = ge.getCenter()
for pt in ge.pointList:
newpt = [pt[0]-C[0],pt[1]-C[0],1]###OR USE TRANSLATE
spt = matrixPointMultiply(matrix, newpt)
finalpt = [spt[0]+C[0],spt[1]+C[0],1]
fpt.append(finalpt)
ge.pointList=fpt
return
Whenever I run it it says: AttributeError: circle instance has no attribute 'getCenter'.
How do I get the object to correctly the call the function upon itself?
This is kind of a noobish question and I am learning, so detailed advice would be helpful.
Have you checked your indenting to make sure it's all consistent? That's a classic Python beginner problem. You need to use consistent whitespace (either tabs or spaces, most people prefer spaces) and the right amount of whitespace.
For example, this may look OK, but it won't do what you expect:
class Dummy(object):
def foo(self):
print "foo!"
def bar(self):
print "bar!"
d = Dummy()
d.bar()
This will return:
AttributeError: 'Dummy' object has no attribute 'bar'
If that's not it, try to pare your code down to the minimum, and post that and how you're calling it. As it stands, the general form looks OK to me, unless I'm missing something.