There are two points in 2D
point1 = (x1, y1)
point2 = (x2, y2)
There is stretch between those two points:
stretch = math.hypot(x2 - x1, y2 - y1)
How to find point (x3, y3) anywhere in that strech?
What you call "stretch" is a line segment, and you compute its norm (or length, if you will) with math.hypot
For any t between 0 and 1, the point (x1 + t*(x2-x1), y1 + t*(y2-y1)) is part of the line segment. In particular, with t = 0 your point will be the (x1,y1) and with t = 1 your point will be the (x2,y2).
If you use a t value outside of the interval [0,1] then you will have a point on the same line but outside of the segment.
If you want to get some point lying on P1P2 segment, you can use equations of linear interpolation:
x3 = x1 + t * (x2 - x1)
y3 = y1 + t * (y2 - y1)
where t is in range 0..1
Related
I'm using a python caller in fme to create polygons from points with aixm 4.5 data
Somes of the polygons contains arcs, and theirs direction clockwise (CWA) or anti-clock wise (CCA) matters, I don't know how to handle this.
here's the code I have so far:
import fme
import fmeobjects
from math import hypot
def replaceWithArc(feature):
coords = feature.getAllCoordinates()
x0, y0 = coords[0][0], coords[0][1] # coordinates of start of arc
xc, yc = coords[1][0], coords[1][1] # coordinates of cetner of arc
x2, y2 = coords[2][0], coords[2][1] # coordinates of end of arc
vx0, vy0 = (x0 - xc), (y0 - yc) # vector: center -> start
vx2, vy2 = (x2 - xc), (y2 - yc) # vector: center -> end
vx1, vy1 = (vx0 + vx2), (vy0 + vy2) # vector: center -> middle
len = hypot(vx1, vy1) # length of the vector
radius = (hypot(vx0, vy0) + hypot(vx2, vy2)) * 0.5
x1, y1 = xc + vx1 / len * radius, yc + vy1 / len * radius # coordinates of middle point on arc
threePoints = (
fmeobjects.FMEPoint(x0, y0),
fmeobjects.FMEPoint(x1, y1),
fmeobjects.FMEPoint(x2, y2)
)
feature.setGeometry(fmeobjects.FMEArc(threePoints))
This looks to me like there is something wrong with the three points.
Could you please paste the values?
From the image above it looks slightly asymmetric, but I could be wrong.
Another thing that you could try is to use a different function to initialize FMEArc, e.g.
init(twoPoints, bulge)
init(centerPoint, rotation, primaryRadius, secondaryRadius, startAngle, sweepAngle, startPoint, endPoint)
As above: I'm trying to draw a bounding box. Given the x and y coordinates of the two opposite points that form a box, I'm trying to implement a function that multiplies the diagonal of that box by an arbitrary multiplier, then compute the new x and y coordinates. x and y can be positive or negative floats.
def return_box(x1, x2, y1, y2, multiplier = n):
do_magic()
return new_x, new_y
Assuming you want to keep (x1, y1) in the same place, scale the diagonal and return the new (x2, y2):
def return_box(x1, x2, y1, y2, multiplier = n):
return (
x1 + multiplier * (x2 - x1),
y1 + multiplier * (y2 - y1)
)
If you instead want to keep the center of the rectangle in the same place and return the two new corners:
def return_box(x1, x2, y1, y2, multiplier = n):
xmid = (x1 + x2) / 2
ymid = (y1 + y2) / 2
return (
xmid + multiplier * (x1 - xmid),
ymid + multiplier * (y1 - ymid),
), (
xmid + multiplier * (x2 - xmid),
ymid + multiplier * (y2 - ymid)
)
I want to calculate all geo coordinates between two geo points(lat/long) on earth. I would like to have a python solution for this problem.
Note: I don't want the distance I need coordinates between two points to simulate a person on the map to move him from one point to another on the map that's why I need all coordinates to show a smooth lifelike movement.
This is more of a geometry problem than a python problem.
The following formula gives you all the points (x,y) between points (x1,y1) and (x2,y2):
y = (y1-y2)/(x1-x2) * (x - x1) + y1 for x in [x1, x2]
so if you want a simple python code (not the smoothest increment possible):
# your geo points
x1, y1 = 0, 0
x2, y2 = 1, 1
# the increment step (higher = faster)
STEP = 0.004
if x1 > x2: # x2 must be the bigger one here
x1, x2 = x2, x1
y1, y2 = y2, y1
for i in range(int((x2-x1)/STEP) + 1):
x = x1 + i*STEP
y = (y1-y2)/(x1-x2) * (x - x1) + y1
do_something(x, y)
Is this the correct way to calculate the area of a triangle given the 3 triangle points/vertices? The vertices will never be negative values.
def triangle_area(tri):
x1, y1, x2, y2, x3, y3 = tri[0][0], tri[0][1], tri[1][0], tri[1][1], tri[2][0], tri[2][1]
return 0.5 * (((x2-x1)*(y3-y1))-((x3-x1)*(y2-y1)))
It is necessary to add abs to this formula to avoid negative area value (sign depends on orientation, not on positive/negative coordinates)
Yes, this formula is correct and it implements the best approach if you have vertices coordinates. It is based on cross product properties.
def triangle_area(tri):
x1, y1, x2, y2, x3, y3 = tri[0][0], tri[0][1], tri[1][0], tri[1][1], tri[2][0], tri[2][1]
return abs(0.5 * (((x2-x1)*(y3-y1))-((x3-x1)*(y2-y1))))
Almost, but you need to take the absolute value at the end.
You're formula can be derived from the Shoelace formula which applies to any simple (no crossing edges, no holes) polygon.
If you want to calculate a triangles area, you can calculate the surrounding rectangles area and substract the 3 triangles which have 90° angles around it:
def triangle_area(tri):
x_min = min([point[0] for point in tri])
x_max = max([point[0] for point in tri])
y_min = min([point[1] for point in tri])
y_max = max([point[1] for point in tri])
area_rectangle = (y_max - y_min) * (x_max - x_min)
t1 = 0.5 * abs((tri[0][0] - tri[1][0]) * (tri[0][1] - tri[1][1]))
t2 = 0.5 * abs((tri[0][0] - tri[2][0]) * (tri[0][1] - tri[2][1]))
t3 = 0.5 * abs((tri[1][0] - tri[2][0]) * (tri[1][1] - tri[2][1]))
return area_rectangle - t1 - t2 - t3
Alternatively, you can use Herons Formula
If I have a definite line segment and then am given two random different points, how would i be able to determine if they are on the same side of the line segment?
I am wanting to use a function def same_side (line, p1, p2). I know based on geometry that cross products can be used but am unsure how to do so with python.
If you can get the equation of the line in slope-intercept form, you should be able to set up an inequality.
Say we have points (x1, y1), (x2, y2), and the line y = mx+b
You should be able to plug in the x and y values for both points, and if both make the equation y < mx + b or both make it y > mx + b, they are on the same side.
If either point satisfies the equation (y = mx + b), that point is on the line.
if (y1 > m * x1 + b and y2 > m * x2 + b) or (y1 < m * x1 + b and y2 < m *x2 + b):
return True #both on same side
Based on the tutorial here:
def same_side (line, p1, p2):
return ((line['y1']−line['y2'])*(p1['x']−line['x1'])+(line['x2']−line['x1'])*(p1['y']−line['y1']))*((line['y1']−line['y2'])*(p2['x']−line['x1'])+(line['x2']−line['x1'])*(p2['y']−line['y1']))>0
Example:
# Same side
line = {'x1':0,'y1':0,'x2':1,'y2':1}
p1 = {'x':0,'y':1}
print same_side (line, p1, p1)
# Same side
line = {'x1':0,'y1':0,'x2':1,'y2':1}
p1 = {'x':0,'y':1}
p2 = {'x':0,'y':2}
print same_side (line, p1, p2)
# Different side
line = {'x1':0,'y1':0,'x2':1,'y2':1}
p1 = {'x':0,'y':1}
p2 = {'x':0,'y':-2}
print same_side (line, p1, p2)
Assuming you have the line segment's endpoints (x1, y1) and (x2, y2), the equation for the line passing through them is y = y1 + (x - x1)/(x2 - x1) * (y2 - y1). Points above the line will have larger y values and points below will have smaller y values. So you simply have to plug each query point's x value into this formula, which gives you the y-coordinate of the line at that x, and compare it to the query point's x. If both points are on the same side, their x's will both be larger or both be smaller.
The one exception to this is when the line is perfectly vertical (x1 == x2). Here the formula breaks down, so you'll need a special case to check for this. In this case, compare the x-coordinates of the query points to the x-coordinate of the line (x1 or x2, doesn't matter which).
If you have numpy available, this is as simple as:
import numpy as np
def same_side(line, point1, point2):
v1 = np.array([line.start.x - line.end.x, line.start.y - line.end.y])
v2 = np.array([line.start.x - point1.x, line.start.y - point1.y])
v3 = np.array([line.start.x - point2.x, line.start.y - point1.y])
return (np.dot(np.cross(v1, v2), np.cross(v1, v3)) >= 0)