I'm trying traverse all the cells that a line goes through. I've found the Fast Voxel Traversal Algorithm that seems to fit my needs, but I'm currently finding to be inaccurate. Below is a graph with a red line and points as voxel coordinates that the algorithm gives. As you can see it is almost correct except for the (4, 7) point, as it should be (5,6). I'm not sure if i'm implementing the algorithm correctly either so I've included it in Python. So i guess my question is my implementation correct or is there a better algo to this?
Thanks
def getVoxelTraversalPts(strPt, endPt, geom):
Max_Delta = 1000000.0
#origin
x0 = geom[0]
y0 = geom[3]
(sX, sY) = (strPt[0], strPt[1])
(eX, eY) = (endPt[0], endPt[1])
dx = geom[1]
dy = geom[5]
sXIndex = ((sX - x0) / dx)
sYIndex = ((sY - y0) / dy)
eXIndex = ((eX - sXIndex) / dx) + sXIndex
eYIndex = ((eY - sYIndex) / dy) + sYIndex
deltaX = float(eXIndex - sXIndex)
deltaXSign = 1 if deltaX > 0 else -1 if deltaX < 0 else 0
stepX = deltaXSign
tDeltaX = min((deltaXSign / deltaX), Max_Delta) if deltaXSign != 0 else Max_Delta
maxX = tDeltaX * (1 - sXIndex + int(sXIndex)) if deltaXSign > 0 else tDeltaX * (sXIndex - int(sXIndex))
deltaY = float(eYIndex - sYIndex)
deltaYSign = 1 if deltaY > 0 else -1 if deltaY < 0 else 0
stepY = deltaYSign
tDeltaY = min(deltaYSign / deltaY, Max_Delta) if deltaYSign != 0 else Max_Delta
maxY = tDeltaY * (1 - sYIndex + int(sYIndex)) if deltaYSign > 0 else tDeltaY * (sYIndex - int(sYIndex))
x = sXIndex
y = sYIndex
ptsIndexes = []
pt = [round(x), round(y)]
ptsIndexes.append(pt)
prevPt = pt
while True:
if maxX < maxY:
maxX += tDeltaX
x += deltaXSign
else:
maxY += tDeltaY
y += deltaYSign
pt = [round(x), round(y)]
if pt != prevPt:
#print pt
ptsIndexes.append(pt)
prevPt = pt
if maxX > 1 and maxY > 1:
break
return (ptsIndexes)
The voxels that you are walking start at 0.0, i.e. the first voxel spans space from 0.0 to 1.0, a not from -0.5 to 0.5 as you seem to be assuming. In other words, they are the ones marked with dashed line, and not the solid one.
If you want voxels to be your way, you will have to fix initial maxX and maxY calculations.
Ain't nobody got time to read the paper you posted and figure out if you've implemented it correctly.
Here's a question, though. Is the algorithm you've used (a) actually meant to determine all the cells that a line passes through or (b) form a decent voxel approximation of a straight line between two points?
I'm more familiar with Bresenham's line algorithm which performs (b). Here's a picture of it in action:
Note that the choice of cells is "aesthetic", but omits certain cells the line passes through. Including these would make the line "uglier".
I suspect a similar thing is going on with your voxel line algorithm. However, looking at your data and the Bresenham image suggests a simple solution. Walk along the line of discovered cells, but, whenever you have to make a diagonal step, consider the two intermediate cells. You can then use a line-rectangle intersection algorithm (see here) to determine which of the candidate cells should have, but wasn't, included.
I guess just to be complete, I decided to use a different algo. the one referenced here dtb's answer on another question.
here's the implementation
def getIntersectPts(strPt, endPt, geom=[0,1,0,0,0,1]):
'''
Find intersections pts for every half cell size
** cell size has only been tested with 1
Returns cell coordinates that the line passes through
'''
x0 = geom[0]
y0 = geom[3]
(sX, sY) = (strPt[0], strPt[1])
(eX, eY) = (endPt[0], endPt[1])
xSpace = geom[1]
ySpace = geom[5]
sXIndex = ((sX - x0) / xSpace)
sYIndex = ((sY - y0) / ySpace)
eXIndex = ((eX - sXIndex) / xSpace) + sXIndex
eYIndex = ((eY - sYIndex) / ySpace) + sYIndex
dx = (eXIndex - sXIndex)
dy = (eYIndex - sYIndex)
xHeading = 1.0 if dx > 0 else -1.0 if dx < 0 else 0.0
yHeading = 1.0 if dy > 0 else -1.0 if dy < 0 else 0.0
xOffset = (1 - (math.modf(sXIndex)[0]))
yOffset = (1 - (math.modf(sYIndex)[0]))
ptsIndexes = []
x = sXIndex
y = sYIndex
pt = (x, y) #1st pt
if dx != 0:
m = (float(dy) / float(dx))
b = float(sY - sX * m )
dx = abs(int(dx))
dy = abs(int(dy))
if dx == 0:
for h in range(0, dy + 1):
pt = (x, y + (yHeading *h))
ptsIndexes.append(pt)
return ptsIndexes
#print("m {}, dx {}, dy {}, b {}, xdir {}, ydir {}".format(m, dx, dy, b, xHeading, yHeading))
#print("x {}, y {}, {} {}".format(sXIndex, sYIndex, eXIndex, eYIndex))
#snap to half a cell size so we can find intersections on cell boundaries
sXIdxSp = round(2.0 * sXIndex) / 2.0
sYIdxSp = round(2.0 * sYIndex) / 2.0
eXIdxSp = round(2.0 * eXIndex) / 2.0
eYIdxSp = round(2.0 * eYIndex) / 2.0
# ptsIndexes.append(pt)
prevPt = False
#advance half grid size
for w in range(0, dx * 4):
x = xHeading * (w / 2.0) + sXIdxSp
y = (x * m + b)
if xHeading < 0:
if x < eXIdxSp:
break
else:
if x > eXIdxSp:
break
pt = (round(x), round(y)) #snapToGrid
# print(w, x, y)
if prevPt != pt:
ptsIndexes.append(pt)
prevPt = pt
#advance half grid size
for h in range(0, dy * 4):
y = yHeading * (h / 2.0) + sYIdxSp
x = ((y - b) / m)
if yHeading < 0:
if y < eYIdxSp:
break
else:
if y > eYIdxSp:
break
pt = (round(x), round(y)) # snapToGrid
# print(h, x, y)
if prevPt != pt:
ptsIndexes.append(pt)
prevPt = pt
return set(ptsIndexes) #elminate duplicates
Related
I was working on creating a python script that could model electric field lines, but the quiver plot comes out with arrows that are way too large. I've tried changing the units and the scale, but the documentation on matplotlib makes no sense too me... This seems to only be a major issue when there is only one charge in the system, but the arrows are still slightly oversized with any number of charges. The arrows tend to be oversized in all situations, but it is most evident with only one particle.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sym
import astropy as astro
k = 9 * 10 ** 9
def get_inputs():
inputs_loop = False
while inputs_loop is False:
""""
get inputs
"""
inputs_loop = True
particles_loop = False
while particles_loop is False:
try:
particles_loop = True
"""
get n particles with n charges.
"""
num_particles = int(raw_input('How many particles are in the system? '))
parts = []
for i in range(num_particles):
parts.append([float(raw_input("What is the charge of particle %s in Coulombs? " % (str(i + 1)))),
[float(raw_input("What is the x position of particle %s? " % (str(i + 1)))),
float(raw_input('What is the y position of particle %s? ' % (str(i + 1))))]])
except ValueError:
print 'Could not convert input to proper data type. Please try again.'
particles_loop = False
return parts
def vec_addition(vectors):
x_sum = 0
y_sum = 0
for b in range(len(vectors)):
x_sum += vectors[b][0]
y_sum += vectors[b][1]
return [x_sum,y_sum]
def electric_field(particle, point):
if particle[0] > 0:
"""
Electric field exitation is outwards
If the x position of the particle is > the point, then a different calculation must be made than in not.
"""
field_vector_x = k * (
particle[0] / np.sqrt((particle[1][0] - point[0]) ** 2 + (particle[1][1] - point[1]) ** 2) ** 2) * \
(np.cos(np.arctan2((point[1] - particle[1][1]), (point[0] - particle[1][0]))))
field_vector_y = k * (
particle[0] / np.sqrt((particle[1][0] - point[0]) ** 2 + (particle[1][1] - point[1]) ** 2) ** 2) * \
(np.sin(np.arctan2((point[1] - particle[1][1]), (point[0] - particle[1][0]))))
"""
Defining the direction of the components
"""
if point[1] < particle[1][1] and field_vector_y > 0:
print field_vector_y
field_vector_y *= -1
elif point[1] > particle[1][1] and field_vector_y < 0:
print field_vector_y
field_vector_y *= -1
else:
pass
if point[0] < particle[1][0] and field_vector_x > 0:
print field_vector_x
field_vector_x *= -1
elif point[0] > particle[1][0] and field_vector_x < 0:
print field_vector_x
field_vector_x *= -1
else:
pass
"""
If the charge is negative
"""
elif particle[0] < 0:
field_vector_x = k * (
particle[0] / np.sqrt((particle[1][0] - point[0]) ** 2 + (particle[1][1] - point[1]) ** 2) ** 2) * (
np.cos(np.arctan2((point[1] - particle[1][1]), (point[0] - particle[1][0]))))
field_vector_y = k * (
particle[0] / np.sqrt((particle[1][0] - point[0]) ** 2 + (particle[1][1] - point[1]) ** 2) ** 2) * (
np.sin(np.arctan2((point[1] - particle[1][1]), (point[0] - particle[1][0]))))
"""
Defining the direction of the components
"""
if point[1] > particle[1][1] and field_vector_y > 0:
print field_vector_y
field_vector_y *= -1
elif point[1] < particle[1][1] and field_vector_y < 0:
print field_vector_y
field_vector_y *= -1
else:
pass
if point[0] > particle[1][0] and field_vector_x > 0:
print field_vector_x
field_vector_x *= -1
elif point[0] < particle[1][0] and field_vector_x < 0:
print field_vector_x
field_vector_x *= -1
else:
pass
return [field_vector_x, field_vector_y]
def main(particles):
"""
Graphs the electrical field lines.
:param particles:
:return:
"""
"""
plot particle positions
"""
particle_x = 0
particle_y = 0
for i in range(len(particles)):
if particles[i][0]<0:
particle_x = particles[i][1][0]
particle_y = particles[i][1][1]
plt.plot(particle_x,particle_y,'r+',linewidth=1.5)
else:
particle_x = particles[i][1][0]
particle_y = particles[i][1][1]
plt.plot(particle_x,particle_y,'r_',linewidth=1.5)
"""
Plotting out the quiver plot.
"""
parts_x = [particles[i][1][0] for i in range(len(particles))]
graph_x_min = min(parts_x)
graph_x_max = max(parts_x)
x,y = np.meshgrid(np.arange(graph_x_min-(graph_x_max-graph_x_min),graph_x_max+(graph_x_max-graph_x_min)),
np.arange(graph_x_min-(graph_x_max-graph_x_min),graph_x_max+(graph_x_max-graph_x_min)))
if len(particles)<2:
for x_pos in range(int(particles[0][1][0]-10),int(particles[0][1][0]+10)):
for y_pos in range(int(particles[0][1][0]-10),int(particles[0][1][0]+10)):
vecs = []
for particle_n in particles:
vecs.append(electric_field(particle_n, [x_pos, y_pos]))
final_vector = vec_addition(vecs)
distance = np.sqrt((final_vector[0] - x_pos) ** 2 + (final_vector[1] - y_pos) ** 2)
plt.quiver(x_pos, y_pos, final_vector[0], final_vector[1], distance, angles='xy', scale_units='xy',
scale=1, width=0.05)
plt.axis([particles[0][1][0]-10,particles[0][1][0]+10,
particles[0][1][0] - 10, particles[0][1][0] + 10])
else:
for x_pos in range(int(graph_x_min-(graph_x_max-graph_x_min)),int(graph_x_max+(graph_x_max-graph_x_min))):
for y_pos in range(int(graph_x_min-(graph_x_max-graph_x_min)),int(graph_x_max+(graph_x_max-graph_x_min))):
vecs = []
for particle_n in particles:
vecs.append(electric_field(particle_n,[x_pos,y_pos]))
final_vector = vec_addition(vecs)
distance = np.sqrt((final_vector[0]-x_pos)**2+(final_vector[1]-y_pos)**2)
plt.quiver(x_pos,y_pos,final_vector[0],final_vector[1],distance,angles='xy',units='xy')
plt.axis([graph_x_min-(graph_x_max-graph_x_min),graph_x_max+(graph_x_max-graph_x_min),graph_x_min-(graph_x_max-graph_x_min),graph_x_max+(graph_x_max-graph_x_min)])
plt.grid()
plt.show()
g = get_inputs()
main(g)}
You may set the scale such that it roughly corresponds to the u and v vectors.
plt.quiver(x_pos, y_pos, final_vector[0], final_vector[1], scale=1e9, units="xy")
This would result in something like this:
If I interprete it correctly, you want to draw the field vectors for point charges. Looking around at how other people have done that, one finds e.g. this blog entry by Christian Hill. He uses a streamplot instead of a quiver but we might take the code for calculating the field and replace the plot.
In any case, we do not want and do not need 100 different quiver plots, as in the code from the question, but only one single quiver plot that draws the entire field. We will of course run into a problem if we want to have the field vector's length denote the field strength, as the magnitude goes with the distance from the particles by the power of 3. A solution might be to scale the field logarithmically before plotting, such that the arrow lengths are still somehow visible, even at some distance from the particles. The quiver plot's scale parameter then can be used to adapt the lengths of the arrows such that they somehow fit to other plot parameters.
""" Original code by Christian Hill
http://scipython.com/blog/visualizing-a-vector-field-with-matplotlib/
Changes made to display the field as a quiver plot instead of streamlines
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
def E(q, r0, x, y):
"""Return the electric field vector E=(Ex,Ey) due to charge q at r0."""
den = ((x-r0[0])**2 + (y-r0[1])**2)**1.5
return q * (x - r0[0]) / den, q * (y - r0[1]) / den
# Grid of x, y points
nx, ny = 32, 32
x = np.linspace(-2, 2, nx)
y = np.linspace(-2, 2, ny)
X, Y = np.meshgrid(x, y)
charges = [[5.,[-1,0]],[-5.,[+1,0]]]
# Electric field vector, E=(Ex, Ey), as separate components
Ex, Ey = np.zeros((ny, nx)), np.zeros((ny, nx))
for charge in charges:
ex, ey = E(*charge, x=X, y=Y)
Ex += ex
Ey += ey
fig = plt.figure()
ax = fig.add_subplot(111)
f = lambda x:np.sign(x)*np.log10(1+np.abs(x))
ax.quiver(x, y, f(Ex), f(Ey), scale=33)
# Add filled circles for the charges themselves
charge_colors = {True: 'red', False: 'blue'}
for q, pos in charges:
ax.add_artist(Circle(pos, 0.05, color=charge_colors[q>0]))
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.set_aspect('equal')
plt.show()
(Note that the field here is not normalized in any way, which should no matter for visualization at all.)
A different option is to look at e.g. this code which also draws field lines from point charges.
I am new to programming, so I hope my stupid questions do not bug you.
I am now trying to calculate the poisson sphere distribution(a 3D version of the poisson disk) using python and then plug in the result to POV-RAY so that I can generate some random distributed packing rocks.
I am following these two links:
[https://github.com/CodingTrain/Rainbow-Code/blob/master/CodingChallenges/CC_33_poisson_disc/sketch.js#L13]
[https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf]
tl;dr
0.Create an n-dimensional grid array and cell size = r/sqrt(n) where r is the minimum distance between each sphere. All arrays are set to be default -1 which stands for 'without point'
1.Create an initial sample. (it should be placed randomly but I choose to put it in the middle). Put it in the grid array. Also, intialize an active array. Put the initial sample in the active array.
2.While the active list is not empty, pick a random index. Generate points near it and make sure the points are not overlapping with nearby points(only test with the nearby arrays). If no sample can be created near the 'random index', kick the 'random index' out. Loop the process.
And here is my code:
import math
from random import uniform
import numpy
import random
radius = 1 #you can change the size of each sphere
mindis = 2 * radius
maxx = 10 #you can change the size of the container
maxy = 10
maxz = 10
k = 30
cellsize = mindis / math.sqrt(3)
nrofx = math.floor(maxx / cellsize)
nrofy = math.floor(maxy / cellsize)
nrofz = math.floor(maxz / cellsize)
grid = []
active = []
default = numpy.array((-1, -1, -1))
for fillindex in range(nrofx * nrofy * nrofz):
grid.append(default)
x = uniform(0, maxx)
y = uniform(0, maxy)
z = uniform(0, maxz)
firstpos = numpy.array((x, y, z))
firsti = maxx // 2
firstj = maxy // 2
firstk = maxz // 2
grid[firsti + nrofx * (firstj + nrofy * firstk)] = firstpos
active.append(firstpos)
while (len(active) > 0) :
randindex = math.floor(uniform(0,len(active)))
pos = active[randindex]
found = False
for attempt in range(k):
offsetx = uniform(mindis, 2 * mindis)
offsety = uniform(mindis, 2 * mindis)
offsetz = uniform(mindis, 2 * mindis)
samplex = offsetx * random.choice([1,-1])
sampley = offsety * random.choice([1,-1])
samplez = offsetz * random.choice([1,-1])
sample = numpy.array((samplex, sampley, samplez))
sample = numpy.add(sample, pos)
xcoor = math.floor(sample.item(0) / cellsize)
ycoor = math.floor(sample.item(1) / cellsize)
zcoor = math.floor(sample.item(2) / cellsize)
attemptindex = xcoor + nrofx * (ycoor + nrofy * zcoor)
if attemptindex >= 0 and attemptindex < nrofx * nrofy * nrofz and numpy.all([sample, default]) == True and xcoor > 0 and ycoor > 0 and zcoor > 0 :
test = True
for testx in range(-1,2):
for testy in range(-1, 2):
for testz in range(-1, 2):
testindex = (xcoor + testx) + nrofx * ((ycoor + testy) + nrofy * (zcoor + testz))
if testindex >=0 and testindex < nrofx * nrofy * nrofz :
neighbour = grid[testindex]
if numpy.all([neighbour, sample]) == False:
if numpy.all([neighbour, default]) == False:
distance = numpy.linalg.norm(sample - neighbour)
if distance > mindis:
test = False
if test == True and len(active)<len(grid):
found = True
grid[attemptindex] = sample
active.append(sample)
if found == False:
del active[randindex]
for printout in range(len(grid)):
print("<" + str(active[printout][0]) + "," + str(active[printout][1]) + "," + str(active[printout][2]) + ">")
print(len(grid))
My code seems to run forever.
Therefore I tried to add a print(len(active)) in the last of the while loop.
Surprisingly, I think I discovered the bug as the length of the active list just keep increasing! (It is supposed to be the same length as the grid) I think the problem is caused by the active.append(), but I can't figure out where is the problem as the code is literally the 90% the same as the one made by Mr.Shiffman.
I don't want to free ride this but I have already checked again and again while correcting again and again for this code :(. Still, I don't know where the bug is. (why do the active[] keep appending!?)
Thank you for the precious time.
Right now, I am working on something (in Python) to create an ellipse and display it on the screen (in the console). I have the ellipse creation already, but rotating the ellipse gives me problems.
Ellipse Method:
def ellipse(yc, xc, b, a, rotation=0):
yc_min_b = yc - b
# divide b to account for spacing in console
b = int(round(b / 2 + 0.01)) - 1
yc = yc_min_b + b
points = []
a2 = a*a
b2 = b*b
fa2 = 4 * a2
fb2 = 4 * b2
x = 0
y = b
sigma = 2 * b2 + a2 * (1 - 2 * b)
while b2 * x <= a2 * y:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fa2 * (1 - y)
y -= 1
sigma += b2 * ((4 * x) + 6)
x += 1 # INCREMENT
x = a
y = 0
sigma = 2 * a2 + b2 * (1 - 2 * a)
while a2 * y <= b2 * x:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fb2 * (1 - x)
x -= 1
sigma += a2 * ((4 * y) + 6)
y += 1 # INCREMENT
# now rotate points
sin = math.sin(rotation)
cos = math.cos(rotation)
rotated = []
for point in points:
x = point[0]
y = point[1]
'''
px -= xc
py -= yc
xnew = px * c - py * s
ynew = px * s + py * c
px = xnew + xc
py = ynew + yc
'''
#XRot := Round(XCenter + (X - XCenter) * CAngle - (Y - YCenter) * SAngle);
#YRot := Round(YCenter + (X - XCenter) * SAngle + (Y - YCenter) * CAngle);
x = round(xc + (x + xc) * cos - (y - yc) * sin)
y = round(yc + (x - xc) * sin + (y - yc) * cos)
rotated.append((int(x), int(y)))
points = rotated
print points
ell_matr = []
# set up empty matrix
maxx = 0
maxy = 0
for point in points:
y = point[1]
x = point[0]
if y > maxy:
maxy = y
if x > maxx:
maxx = x
for i in range(maxy + 1):
ell_matr.append([])
for j in range(maxx + 1):
ell_matr[i].append(' ')
for point in points:
y = point[1]
x = point[0]
ell_matr[y][x] = fill
return ell_matr
I would ignore the matrix part, as it is translating the points into a matrix to display on screen.
Here is the output of an ellipse without rotation.
And when I add a 45 degree rotation (converted to radians)
Is there a better way to rotate the points?
It might be a very simple problem but seems I am not able to see it.
I have a list of point ordered clockwise and want to calculate the centroid of these point (a convex polygon) using the following function according to this:
and
def calculateCentroid(raLinks,raNodes, links, nodes):
orderedPointsOfLinks = orderClockwise(raLinks,raNodes, links, nodes)
arg1 = 0
arg2 = 0
Xc = 0
Yc = 0
i = 0
for point in orderedPointsOfLinks:
arg1 += point.Y*(orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].X)
arg2 += (orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].Y)*point.X
Xc += (point.X+(orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].X))*(((orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].Y)*point.X)-(point.Y*(orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].X)))
Yc += (point.Y+(orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].Y))*(((orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].Y)*point.X)-(point.Y*(orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].X)))
i+=1
area = (arg1-arg2)*0.5
print area
X = -Xc/(6*area)
Y = -Yc/(6*area)
print X , " ", Y
calculating the area and the centorid using Arcpy shows that the calculated area by the above function is correct but the centroid is wrong.
what is the problem with Xc and Yc that I cant fix it?
If I change the for loop in the following way it works:
for point in orderedPointsOfLinks:
y0 = point.Y
x0 = point.X
x1 = orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].X
y1 = orderedPointsOfLinks[i+1 if i+1<len(orderedPointsOfLinks) else 0].Y
a = x0*y1 - x1*y0
area += a
Xc += (x0+x1)*a
Yc += (y0+y1)*a
i+=1
area *= 0.5
print area
X = Xc/(6*area)
Y = Yc/(6*area)
print X , " ", Y
here is a list of nodes to examine the code:
[(371623.876, 6159668.714),(371625.994, 6159661.094), (371624.319, 6159654.634), (371619.654, 6159649.86), (371614.194, 6159647.819), (371608.401, 6159648.449), (371601.544, 6159652.652), (371598.77, 6159658.058), (371599.318, 6159665.421), (371603.025, 6159671.805), (371611.372, 6159674.882 ), (371619.417, 6159673.065)]
source
Try:
import numpy
tp = [(371623.876, 6159668.714),(371625.994, 6159661.094), (371624.319, 6159654.634), (371619.654, 6159649.86),\
(371614.194, 6159647.819), (371608.401, 6159648.449), (371601.544, 6159652.652), (371598.77, 6159658.058), \
(371599.318, 6159665.421), (371603.025, 6159671.805), (371611.372, 6159674.882 ), (371619.417, 6159673.065),(371623.876, 6159668.714)]
# cx = sigma (x[i]+x[i+1])*((x[i]*y[i+1]) - (x[i+1]*y[i] ))
# cy = sigma (y[i]+y[i+1])*((x[i]*y[i+1]) - (x[i+1]*y[i] ))
cx = 0
cy = 0
p = numpy.array(tp)
x = p[:, 0]
y = p[:, 1]
a = x[:-1] * y[1:]
b = y[:-1] * x[1:]
cx = x[:-1] + x[1:]
cy = y[:-1] + y[1:]
tp = tp[:-1] #dont need repeat
def area():
tox=0
toy=0
for i in range(len(tp)):
if i+1 == len(tp):
tox += tp[-1][0]*tp[0][1]
else:
tox += tp[i][0]*tp[i+1][1]
for i in range(len(tp)):
if i+1 == len(tp):
toy += tp[-1][1]*tp[0][0]
else:
toy += tp[i][1]*tp[i+1][0]
return abs(tox-toy)*0.5
ar = area()
Cx = abs(numpy.sum(cx * (a - b)) / (6. * ar))
Cy = abs(numpy.sum(cy * (a - b)) / (6. * ar))
print Cx,Cy
Warning !
tp[0] == tp[-1]
So: first and last coordinates are same value...
I'm looking for a short smart way to find all integer points on a line segment. The 2 points are also integers, and the line can be at an angle of 0,45,90,135 etc. degrees.
Here is my long code(so far the 90 degree cases):
def getPoints(p1,p2)
if p1[0] == p2[0]:
if p1[1] < p2[1]:
return [(p1[0],x) for x in range(p1[1],p2[1])]
else:
return [(p1[0],x) for x in range(p1[1],p2[1],-1)]
if p2[1] == p2[1]:
if p1[0] < p2[0]:
return [(x,p1[1]) for x in range(p1[0],p2[0])]
else:
return [(x,p1[1]) for x in range(p1[0],p2[0],-1)]
EDIT: I haven't mentioned it clear enough, but the slope will always be an integer -1, 0 or 1, there are 8 cases that are need to be checked.
Reduce the slope to lowest terms (p/q), then step from one endpoint of the line segment to the other in increments of p vertically and q horizontally. The same code can work for vertical line segments if your reduce-to-lowest-terms code reduces 5/0 to 1/0.
Do a little bit of maths for each pair of points calculate m & c for mx+c and compare it to the formulae for the lines you are considering. (N.B. You Will get some divide by zeros to cope with.)
i could write code that works, but the amount of repeating code is
throwing me off, that's why i turned to you guys
This could stand a lot of improvement but maybe it gets you on the track.
(sorry, don't have time to make it better just now!)
def points(p1,p2):
slope = (p2[1]-p1[1])/float(p2[0]-p1[0])
[(x,x*slope) for x in range (p1[0], p2[0]) if int(x*slope) == x*slope)]
Extending the answer of #Jon Kiparsky.
def points_on_line(p1, p2):
fx, fy = p1
sx, sy = p2
if fx == sx and fy == sy:
return []
elif fx == sx:
return [(fx, y) for y in range(fy+1, sy)]
elif fy == sy:
return [(x, fy) for x in range(fx+1, sx)]
elif fx > sx and fy > sy:
p1, p2 = p2, p1
slope = (p2[1] - p1[1]) / float(p2[0] - p1[0])
return [(x, int(x*slope)) for x in range(p1[0], p2[0]) if int(x*slope) == x*slope and (x, int(x*slope)) != p1]
def getpoints(p1, p2):
# Sort both points first.
(x1, y1), (x2, y2) = sorted([p1, p2])
a = b = 0.0
# Not interesting case.
if x1 == x2:
yield p1
# First point is in (0, y).
if x1 == 0.0:
b = y1
a = (y2 - y1) / x2
elif x2 == 0.0:
# Second point is in (0, y).
b = y2
a = (y1 - y2) / x1
else:
# Both points are valid.
b = (y2 - (y1 * x2) / x1) / (1 - (x2 / x1))
a = (y1 - b) / x1
for x in xrange(int(x1), int(x2) + 1):
y = a * float(x) + b
# Delta could be increased for lower precision.
if abs(y - round(y)) == 0:
yield (x, y)