I am working on trying to put moving balls into appropriate bins. I like to think I'm on the right track but I've been stuck for awhile now.
I left code out that didn't seem relevant to my question but if those who answer need further details I can provide them. Basically, I have a world of 200 moving balls. They have an X and Y coordinate. I want to divide the world into square bins of width 256 and place the balls in the appropriate bin.
My approach to this was to put them into a dictionary. It looked like this:
dict_of_balls = {}
for i in range(len(balls)):
xb = int(balls[i].x/256)
yb = int(balls[i].y/256)
and I wanted to make the keys a tuple of the (xb, yb) pairs and then place the appropriate balls in that bin but I don't think you can use tuples as keys...
The code is below:
import math
import random
import time
import sys
ball_min_radius = 16.0 #world coordinates
ball_max_radius = 128.0 #world coordniates
number_balls = 200
class Ball:
"""
Implements a point/ball
"""
def __init__(self):
self.x = random.uniform(world_min_x,world_max_x)
self.y = random.uniform(world_min_y,world_max_y)
self.radius = int(random.uniform(ball_min_radius,ball_max_radius))
def __lt__(self, other):
return self.id < other.id
def main():
world_min_x = -200.0*number_balls**.5 # minimum x in world coordinates
world_max_x = +200.0*number_balls**.5 # maximum x in world coordinates
world_min_y = -200.0*number_balls**.5 # minimum y in world coordinates
world_max_y = +200.0*number_balls**.5 # maximum y in world coordinates
balls = [Ball() for i in range(number_balls)]
so does anyone have any ideas for how to divide the world into bins based on the given world coordinates? I am unsure of which data structure to use since I can't use tuples for keys. Thanks in advance for any feedback.
Why do you want a dictionary? Here's how you would do this, but keep in mind you will only get one ball per bin because you are specifically casting their key to be (int, int) and keys are unique.
If you use a collection, you can also sort (in my example I sort by the region identifiers):
I am not sure what you are doing that for, but you can do it:
import math
import random
import time
import sys
ball_min_radius = 16.0 #world coordinates
ball_max_radius = 128.0 #world coordniates
number_balls = 200
world_min_x = -200.0*number_balls**.5 # minimum x in world coordinates
world_max_x = +200.0*number_balls**.5 # maximum x in world coordinates
world_min_y = -200.0*number_balls**.5 # minimum y in world coordinates
world_max_y = +200.0*number_balls**.5 # maximum y in world coordinates
class Ball:
"""
Implements a point/ball
"""
def __init__(self):
self.x = random.uniform(world_min_x,world_max_x)
self.y = random.uniform(world_min_y,world_max_y)
self.radius = int(random.uniform(ball_min_radius,ball_max_radius))
def __lt__(self, other):
return self.id < other.id
def __str__(self):
return 'x={x} y={y} r={r}'.format(x=self.x, y=self.y, r=self.radius)
def main():
balls = [Ball() for i in range(number_balls)]
dict_of_balls = {}
ball_collection = []
for b in balls:
xb = int(b.x/256)
yb = int(b.y/256)
key = (xb, yb)
dict_of_balls[key] = b
ball_collection.append((key, b))
print 'length of dictionary:{}'.format(len(dict_of_balls.keys()))
print 'length of collection:{}'.format(len(ball_collection))
Notice that the dictionary has fewer items than the collection.
You can also print each item this way pretty trivially:
for b in ball_collection:
print 'ball region: {r} with coords: {c}'.format(r=b[0], c=b[1])
Or, sort them if you want:
print 'Collections also let you sort the collection by region(s)...'
sorted_list = sorted(ball_collection, key= lambda x: (x[0][0], x[0][1]))
for b in sorted_list:
print 'ball region: {r} with coords: {c}'.format(r=b[0], c=b[1])
You can also pretty simply get balls in a specific region too:
print '... or get only ones in a specific region'
subset = [b for b in ball_collection if b[0][0] == 1]
for b in subset:
print 'ball region: {r} with coords: {c}'.format(r=b[0], c=b[1])
main()
A collection seems to do what you are actually wanting.
You can use tuple for keys in a dictionary, since tuple is immutable. The only data type you can't use for a dictionary key is a list [] or set {}
**a = {(1,2):'example1', (2,3):'example2'}
>>> a[(1,2)]
'example1'**
So I believe this should make it much easier to solve your problem.
Related
I am currently using python to solving k-center algorithm.
When I run my codes its runtime exceeds the limit time(provided by my teacher),I don't quite know the way to improve my code so it can pass the limited runtime.
My code is below:
import math
# 1.Import group
# 2.Find the most farthest point in this group.
# 3.reassign the rest points between two center points
# 4.Find the most farthest point from its center point, and make it the newest center point
# 5.reassign points among all center points
# 6.Repeat 4 and 5 step untill the answer fits the condition
class point():
def __init__(self,x,y,num,group=[]):
self.x = x
self.y = y
self.id = num
self.group = []
def range_cus(one,two):
return math.sqrt(math.pow((one.x-two.x),2)+math.pow((one.y-two.y),2))
def reassign(all_points,all_answer):
for i in range(len(all_answer)):
all_answer[i].group = []
for i in range(len(all_points)):
if all_points[i] not in all_answer:
min_length = 0
for j in range(len(all_answer)):
current_length = range_cus(all_answer[j],all_points[i])
if min_length == 0:
min_length = current_length
current_group = all_answer[j]
elif current_length < min_length:
min_length = current_length
current_group = all_answer[j]
current_group.group.append(all_points[i])
def search(all_answer,seek_points_number):
if seek_points_number == 0:
return 0
answer_range = 0
for j in range(len(all_answer)):
for i in range(len(all_answer[j].group)):
if range_cus(all_answer[j],all_answer[j].group[i])>answer_range:
answer_range = range_cus(all_answer[j].group[i],all_answer[j])
answer_obj = all_answer[j].group[i]
seek_points_number -= 1
final_answer.append(answer_obj)
reassign(group,final_answer)
search(final_answer,seek_points_number)
info = raw_input().split(',')
info = [int(i) for i in info]
group = []
final_answer = []
for i in range(info[0]):
x = raw_input().split(',')
group.append(point(float(x[0]),float(x[1]),i+1))
final_answer.append(group[info[2]-1])
group[info[2]-1].group = [point for point in group if point not in final_answer]
search(final_answer,info[1]-1)
print ",".join([str(answer.id) for answer in final_answer])
Please help me examine where should the function be revised to save some runtime.
Example input:
10,3,10 #The first number denotes the sets of data.The second denotes the number of answer I want to return.The third denotes the first center point's id.
21.00,38.00
26.00,28.00
45.00,62.00
31.00,51.00
39.00,44.00
42.00,39.00
21.00,27.00
28.00,29.00
31.00,60.00
27.00,54.00
Example output
10,7,6
You can save at least some time by simply rewriting the range_cus function. As you call this function inside a nested loop, it should to be a good point of attack. Try replacing it with
def range_cus(one,two):
return sqrt((one.x - two.x)**2 + (one.y - two.y)**2)
and remember to do from math import sqrt at the top of your program. In this version, you get rid of a lot of lookups on the math object (math.)
I have a dictionary called "locations". A function I'm writing for the dictionary is set up in the format (d, description, current) where 'd' references the dictionary, 'description' references a string describing the location we are looking for, and 'current' references the spot we currently are in the dictionary as a pair of coordinates (x,y).
Basically, each location has multiple positions in the dictionary each with its own pair of coordinates and my goal is to find the closest position to where we currently are in the dictionary (current). The strategy is to use the distance formula to calculate this.
For example if we were looking for the nearest gas station and we were currently at (2,2), the function should return (3,1) for the nearest station if the two stations were at (3,1) and (1,4) as (3,1) is closer to (2,2) Any advice on my current code would be appreciated.
Code:
def closest(d, description, current):
current_location = (x, y)
d = {(3,1):'gas', (1,4):'gas', (2,1):'food', (5,5):'food'}
distancesFromCurrent = [distanceFormula(z, current_location) for z in places]
for z in d:
if z < minimum float:
return z
My current code has no errors but is definitely not working correctly. It is just returning 0,0 and I'm not sure how I can fix it to return the coordinates of the closest location to our current position.
After considering the comments, here is my solution.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 6 21:42:22 2016
#author: michaelcurrin
"""
import math
def findDistance(A, B):
"""
In 2D space find the distance between two co-orinates is
known as Eucliciean distance.
Args
A: tuple or list of x and y co-ordinates
e.g. (1,2) e.g. [1,2]
B: as A.
Retuns
distance: float. Decimal value for shortest between A and B
"""
x = (A[0] - B[0])
y = (A[1] - B[1])
distance = math.sqrt(x**2 + y**2) # square root
# remove comment if you want to see this outputted
# print distance
return distance
def GetClosestPlace(places, loc, feature):
"""find shortest distance between current location and each locations
but only ones which have the desired feature"""
# add distance from current location to each location
for index in range(len(places)):
# only continue if feature exists at place
if feature in places[index]['features']:
# calculate
distance = findDistance(loc,
places[index]['location'])
else:
# this is to represent n/a for now as every location needs a distance
# for this version, so that it will not be chosen
distance = 1000
# add calculated distance to existing dictionary for location
places[index]['distance'] = distance
# find shortest distance and return details for that place
allDistances = [x['distance'] for x in places]
shortestDistance = min(allDistances)
for place in places:
if place['distance'] == shortestDistance:
return place
placesList = [dict(name='foo',location=(0,3), features=['gas', 'food']),
dict(name='bar',location=(4,6), features=['food', 'hospital']),
dict(name='abc',location=(0,9), features=['gas','barber']),
dict(name='xyz',location=(2,2), features=['food','barber'])
]
currentLocation = (5,9)
desiredFeature='food'
closestPlace = GetClosestPlace(placesList, currentLocation, desiredFeature)
print 'Current location: %s' % str(currentLocation)
print 'Desired feature: %s ' % desiredFeature
print
print 'The closest place is...'
print 'Name: %s' % closestPlace['name']
print 'Location %s' % str(closestPlace['location'])
print 'Distance %f' % closestPlace['distance']
# join multiple features in the list with commas
print 'Features: %s' % ', '.join(closestPlace['features'])
"""
OUTPUT
Current location: (5, 9)
Desired feature: food
The closest place is...
Name: bar
Location (4, 6)
Distance 3.162278
Features: food, hospital
"""
I think you need to use the dictionary input to calculate results for place names against their distance from the current location as a single float (or decimal).
Something like
current_location = (x, y)
distancesFromCurrent = [distanceFormula(z, current_location) for z in places]
Where distanceFormula would be using you distance calc in function.
Once you have that for all places inputted, then you can do another loop find the minimum float value in the dictionary and return its corresponding place name and its co-ordinate location (from the original input).
I think you could change from dictionary to list input to be in this format below. (if you have anything data like this already to show us that would help too)
placesList = [dict(name='abc',location=(0,3), features=['gas station','mall', 'police dept', 'fire dept']),
dict(name='xyz',location=(4,5), features=['police dept', 'hospital']),
#etc.
]
Then your function would have find the closest the location but first filter out the locations which have the feature which matches your description.
Hope that helps.
So, my problem is: I am trying to create a program which would create a polygon that has atleast 3 points(that are composed of coordinates x and y) or angles. I would like that, if there are less than 3 points or angles submitted, the program returns an error saying there are insufficient number of points. I need to create this with classes.
I have created this so far: `
class Polygon:
number_points = 0
number_angles = 0
def __init__(self, coordinate_x, coordinate_y, angles):
s = []
self.coordinate_x = coordinate_x
self.coordinate_y = coordinate_y
self.angles = angles
self.s = s.append([coordinate_x, coordinate_y])
Polygon.number_points = Polygon.number_points + 1
Nkotnik.number_angles = Polygon.number_angles + 1
# Here i would like the program to check if there are enough points
# and angles to form a polygon and to check if all coordinates are
# numbers. If this requirement is not met, the program prints an
# error message.
def creation(self):
if not isinstance(coordinate_x, (int,float)):
#raise Exception("That is not a number")
if Polygon.number_points <= 3:
`
The idea that I had is that i store the coordinates in a list and then when the user enters enough points, a polygon can be formed.
I am not a native speaker, so if I need to clear things a bit further feel free to ask :) thank you for any possible answers :)
I see an error here:
Polygon.number_points = Polygon.number_points + 1
Nkotnik.number_angles = Polygon.number_angles + 1
Nkotnik should be Polygon. Also, to make it shorter, you could do Polygon.number_points += 1 and same for number_angles.
So now, the creation of the program:
def creation(self):
This is bad design. The function should take the number of points and the number of angles as parameters. So, do this:
def creation(self, points, angles):
But creation is basically initialization, so you should integrate it into your __init__.
Also, your __init__ is strange. number_points and number_angles should be defined in the __init__, not the object body, because those variables are different for different Polygon objects. So after modification, your code looks like this:
class Polygon:
def __init__(self, coord_list, angles):
if len(coord_list) // 2 < 3:
raise Exception("Side count must be 3 or more.")
s = []
self.number_points = 0
self.number_angles = 0
self.coordinates_x = coord_list[::2]
self.coordinates_y = coord_list[1::2]
self.angles = angles
self.s = s.append([coordinate_x, coordinate_y])
self.number_points += len(coord_list // 2)
self.number_angles += len(angles)
num_sides = int(input('Number of sides: ')) #raw_input if you're using Python 2
points = []
angles = []
for i in range(num_sides):
points.append(int(input('X value of point: ')))
points.append(int(input('Y value of point: ')))
for i in range(num_sides):
angles.append(int(input('Angle value: ')))
polygon_object = Polygon(points, angles)
And you're done!
You can do the check at creation time in the class, like this, also you need more that just a angle to define a point
import collections
PointCartesian = collections.namedtuple("PointCartesian","coordinate_x coordinate_y")
PointPolar = collections.namedtuple("PointPolar","magnitude angle")
#this is a easy way to make a class for points, that I recommend have
#a class too
class Polygon(object):
def __init__(self,*argv,**kargv):
points = list()
for elem in argv:
if isinstance(elem,(PointCartesian,PointPolar ) ):
points.append(elem)
else:
raise ValueError("Element "+str(elem)+" of wrong type")
if len(points) <3:
raise ValueError("Insufficient data")
self.points = points
and in other place you have the routine that ask the user for the data, you can check every input or leave it to the class.
to call it do something like this
Polygon(PointCartesian(1,2),PointCartesian(4,7),PointPolar(5,28.2))
Polygon(*list_of_points)
I'm trying to compare the locations of vertices on one mesh to another and generate a list of paired vertices, (the ultimate purpose is to pair up vertices on a neck geo with the top verts of a body geo.)
The way I'm 'pairing' them is to just compare the distances between all vertices in both meshes and then match up the closest ones to eachother by ordering them in separate lists, (neck_geo_verts[0] is paired with body_geo_verts[0].)
I want to use OpenMaya as I've heard it considerably faster than cmds.xform.
Here's my code so far getting the verts, although it's using cmds and not the Maya API. I am having a really tough time finding what I need from the Maya documentation.
# The user selects an edge on both the bottom of the neck and top of the body, then this code gets all the vertices in an edge border on both of those geos and populates two lists with the vertices
import maya.cmds as mc
import maya.api.OpenMaya as om
import re
mc.unloadPlugin('testingPlugin.py')
mc.loadPlugin('testingPlugin.py')
def main():
geoOneVerts = []
geoTwoVerts = []
edges = cmds.ls(selection=True, sn=True)
geoOneEdgeNum = re.search(r"\[([0-9_]+)\]", edges[0])
geoTwoEdgeNum = re.search(r"\[([0-9_]+)\]", edges[1])
cmds.polySelect(add=True, edgeBorder=int(geoOneEdgeNum.group(1)))
geoOneEdgeBorder = cmds.ls(selection=True, sn=True)
geoOneEdgeVerts = cmds.polyInfo(edgeToVertex=True)
for vertex in geoOneEdgeVerts:
vertexPairNums = re.search(r":\s*([0-9_]+)\s*([0-9_]+)", vertex)
geoOneVerts.append(vertexPairNums.group(1))
geoOneVerts.append(vertexPairNums.group(2))
cmds.polySelect(replace=True, edgeBorder=int(geoTwoEdgeNum.group(1)))
geoTwoEdgeBorder = cmds.ls(selection=True, sn=True)
geoTwoEdgeVerts = cmds.polyInfo(edgeToVertex=True)
for vertex in geoTwoEdgeVerts:
vertexPairNums = re.search(r":\s*([0-9_]+)\s*([0-9_]+)", vertex)
geoTwoVerts.append(vertexPairNums.group(1))
geoTwoVerts.append(vertexPairNums.group(2))
geoOneVerts = list(set(geoOneVerts))
geoTwoVerts = list(set(geoTwoVerts))
# How do I use OpenMaya to compare the distance from the verts in both lists?
main()
EDIT: This code gives me two lists filled with the DAG names of vertices on two meshes. I'm unsure how to get the positions of those vertices to compare the distance between the vertices in both lists and I'm also unsure if I should be using maya.cmds for this as opposed to maya.api.OpenMaya considering the amount of vertices I'm going to be operating on.
EDIT2: Thanks to Theodox and hundreds of searches for the help. I ended up making a version that worked using boundary vertices and one that assumed paired vertices on both meshes would be in identical global space. Both of which I chose to use the Maya API and forewent Maya Commands completely for performance reasons.
Vesion1 (Using Boundary Verts):
import maya.OpenMaya as om
def main():
geo1Verts = om.MFloatPointArray()
geo2Verts = om.MFloatPointArray()
selectionList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(selectionList)
geo1SeamVerts = getSeamVertsOn(selectionList, 1)
geo2SeamVerts = getSeamVertsOn(selectionList, 2)
pairedVertsDict = pairSeamVerts(geo1SeamVerts, geo2SeamVerts)
def getSeamVertsOn(objectList, objectNumber):
count = 0
indexPointDict = {}
selectedObject = om.MObject()
iter = om.MItSelectionList(objectList, om.MFn.kGeometric)
while not iter.isDone():
count += 1
connectedVerts = om.MIntArray()
if (count != objectNumber):
iter.next()
else:
iter.getDependNode(selectedObject)
vertexIter = om.MItMeshVertex(selectedObject)
while not vertexIter.isDone():
if (vertexIter.onBoundary()):
vertex = om.MPoint()
vertex = vertexIter.position()
indexPointDict[int(vertexIter.index())] = vertex
vertexIter.next()
return indexPointDict
def pairSeamVerts (dictSeamVerts1, dictSeamVerts2):
pairedVerts = {}
if (len(dictSeamVerts1) >= len(dictSeamVerts2)):
for vert1 in dictSeamVerts1:
distance = 0
closestDistance = 1000000
vertPair = 0
for vert2 in dictSeamVerts2:
distance = dictSeamVerts1[vert1].distanceTo(dictSeamVerts2[vert2])
if (distance < closestDistance):
closestDistance = distance
vertPair = vert2
pairedVerts[vert1] = vertPair
return (pairedVerts)
else:
for vert1 in dictSeamVerts2:
distance = 0
closestDistance = 1000000
vertPair = 0
for vert2 in dictSeamVerts1:
distance = dictSeamVerts2[vert1].distanceTo(dictSeamVerts1[vert2])
if (distance < closestDistance):
closestDistance = distance
vertPair = vert2
pairedVerts[vert1] = vertPair
return (pairedVerts)
main()
Version2 (Assuming Paired Vertices Would Share a Global Space):
import maya.OpenMaya as om
def main():
selectionList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(selectionList)
meshOneVerts = getVertPositions(selectionList, 1)
meshTwoVerts = getVertPositions(selectionList, 2)
meshOneHashedPoints = hashPoints(meshOneVerts)
meshTwoHashedPoints = hashPoints(meshTwoVerts)
matchingVertList = set(meshOneHashedPoints).intersection(meshTwoHashedPoints)
pairedVertList = getPairIndices(meshOneHashedPoints, meshTwoHashedPoints, matchingVertList)
def getVertPositions(objectList, objectNumber):
count = 0
pointList = []
iter = om.MItSelectionList(objectList, om.MFn.kGeometric)
while not iter.isDone():
count = count + 1
if (count != objectNumber):
iter.next()
dagPath = om.MDagPath()
iter.getDagPath(dagPath)
mesh = om.MFnMesh(dagPath)
meshPoints = om.MPointArray()
mesh.getPoints(meshPoints, om.MSpace.kWorld)
for point in range(meshPoints.length()):
pointList.append([meshPoints[point][0], meshPoints[point][1], meshPoints[point][2]])
return pointList
def hashPoints(pointList):
_clamp = lambda p: hash(int(p * 10000) / 10000.00)
hashedPointList = []
for point in pointList:
hashedPointList.append(hash(tuple(map(_clamp, point))))
return (hashedPointList)
def getPairIndices(hashListOne, hashListTwo, matchingHashList):
pairedVertIndices = []
vertOneIndexList = []
vertTwoIndexList = []
for hash in matchingHashList:
vertListOne = []
vertListTwo = []
for hashOne in range(len(hashListOne)):
if (hashListOne[hashOne] == hash):
vertListOne.append(hashOne)
for hashTwo in range(len(hashListTwo)):
if (hashListTwo[hashTwo] == hash):
vertListTwo.append(hashTwo)
pairedVertIndices.append([vertListOne, vertListTwo])
return pairedVertIndices
main()
API is significantly faster for the distance comparison method, but in this case I think the real killer is likely to be the algorithm. Comparing every vert to ever other is a lot of math.
Probably the easiest thing to do is to come up with a way to hash the vertices instead: turn each xyz point into a single value that can be compared with others without doing the distances: two verts with the same hash would necessarily be in the same position. You can tweak the hash algorithm to quantize the vert positions a bit to account for floating point error at the same time.
Here's a way to hash a point (down to 4 significant digits, which you can tweak by changing the constant in _clamp) :
def point_hash(point):
'''
hash a tuple, probably a cmds vertex pos
'''
_clamp = lambda p: hash(int(p * 10000) / 10000.00)
return hash(tuple(map(_clamp, point)))
As long as both sets of verts are hashed in the same space (presumably world space) identical hashes will mean matched verts. All you'd have to do is to loop through each mesh, creating a dictionary which keyed the vertex hash to the vertex index. Here's a way to do it in cmds:
def vert_dict(obj):
'''
returns a dictionary of hash: index pairs representing the hashed verts of <obj>
'''
results = dict()
verts = cmds.xform(obj + ".vtx[*]", q=True, t=True, ws=True)
total = len(verts)/ 3
for v in range(total):
idx = v * 3
hsh = point_hash (verts[idx: idx + 3])
results[hsh] = v
return results
You can find the intersecting verts - the ones present in both meshes -- by intersecting the keys from both dictionaries. Then convert the matching verts in both meshes back to vertex indices by looking up in the two dictionaries.
Unless the meshes are really heavy, this should be doable without the API since all the work is in the hash function which has no API analog.
The only likely issue would be making sure that the verts were in the same space. You would have to fall back on a distance based strategy if you can't get the verts into the same space for some reason.
If you want to get a more useable result from the op's version 2 script (instead of returning nested and combined lists), you could do something like the following:
indices = lambda itr, val: (i for i, v in enumerate(itr) if v==val) #Get the index of each element of a list matching the given value.
matching = set(hashA).intersection(hashB)
return [i for h in matching
for i in zip(indices(hashA, h), indices(hashB, h))]
which will return a list of two element tuples representing the matched vertex pairs:
[(119, 69), (106, 56), (82, 32), (92, 42), ...
Also, you can use om.MSpace.kObject to compare the two mesh objects in local space depending on your specific needs.
I am currently using Python/Numpy to deal with geographical/GPS data (loving it!), and I am facing the recurring task to calculate distances between geographical points defined by a coordinate pair pn = [lon, lat].
I have a function that I use like this: dist = geodistance(p1, p2) which is analog to euclidean distance in linear algebra (vector subtraction/difference), but occurs in geodesical (spherical) space instead of rectangular euclidean space.
Programmatically, euclidean distance is given by
dist = ((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)**0.5
Mathematically, this is equivalent to the "idiomatic" (for lack of a better word) sentence
dist = p1 - p1 # the "norm" of the vector difference, subtraction.
Currently, I get my distance like this:
p1 = [-51.598354,-29.953363]
p2 = [-51.598701,-29.953045]
dist = geodistance(p1, p2)
print dist
>> 44.3904032407
I would like to do this:
print p2 - p1 # these points now are from some fancy datatype
>> 44.3904032407
And the final goal:
track = numpy.array([[-51.203018 -29.996149]
[-51.203018 -29.99625 ]
[-51.20266 -29.996229]
[-51.20229 -29.996309]
[-51.201519 -29.99416 ]], dtype=fancy) # (**) or something like
print numpy.diff(track)
>> ndarray([[ 0. ]
[ 7.03531252]
[ 39.82663316]
[ 41.50958596]
[ 172.49825765]])
A similar thing is: if you take two datetime objects and subtract them, the operation returns a timedelta object. I want to subtract two coordinates and get a geodesic distance as the result.
I wonder if a class would work, but dtype (a "subtype" of float32, for example) would help a lot upon array creation from lists (** which is how I read things from xml files).
Thanks a lot!
You can define your own types by creating a class and writing a __add__ or __sub__ method.
For example:
class P(object):
def __init__(self, lon, lat):
self.lon = lon
self.lat = lat
def __sub__(self, other):
dist = ((other.lon - self.lon)**2 + (other.lat - self.lat)**2)**0.5
return dist
Given that you're currently getting the coordinates of your points using the list indexing syntax, you could also implement those:
class P(object):
def __init__(self, lon, lat):
self.lon = lon
self.lat = lat
def __sub__(self, other):
dist = ((other[0] - self[0])**2 + (other[1] - self[1])**2)**0.5
return dist
def __getitem__(self, key):
if key == 0:
return self.lon
elif key == 1:
return self.lat
else:
raise IndexError
def __setitem__(self, key, value):
if key == 0:
self.lon = value
elif key == 1:
self.lat = value
else:
raise IndexError
(I realize that the above may not be the most elegant way to do it).
That way, your new class is a drop-in replacement for the lists you're currently using.
The Python documentation contains more information about the double-underscore methods you need to write in order to create your user-defined types. (The information you're looking for starts about half-way down the page)
Python Language Reference, ยง3.4.8, "Emulating numeric types"
Specifically, __sub__().