I want to take all the intersections of a set of lines and find all the convex quadrilaterals they create. I am not sure if there is an algorithm that works perfect for this, or if I need to loop through and create my own.
I have an array of lines, and all their intersections.
Lines and intersections:
Example Quadrilaterals 1:
Example Quadrilaterals 2
In this case, I would come out with 8 quadrilaterals.
How can I achieve this? If there isn't an algorithm I can implement for this, how can I check each intersection with other intersections to determine if they make a convex quadrilateral?
There is a simple, non-speedy, brute-force over-all algorithm to find those quadrilaterals. However, first you would need to clarify some definitions, especially that of a "quadrilateral." Do you count it as a quadrilateral if it has zero area, such as when all the vertices are collinear? Do you count it as a quadrilateral if it self-intersects or crosses? Do you count it if it is not convex? Do you count it if two adjacent sides are straight (which includes consecutive vertices identical)? What about if the polygon "doubles back" on itself so the result looks like a triangle with one side extended?
Here is a top-level algorithm: Consider all combinations of the line segments taken four at a time. If there are n line segments then there are n*(n-1)*(n-2)*(n-3)/24 combinations. For each combination, look at the intersections of pairs of these segments: there will be at most 6 intersections. Now see if you can make a quadrilateral from those intersections and segments.
This is brute-force, but at least it is polynomial in execution time, O(n^4). For your example of 8 line segments that means considering 70 combinations of segments--not too bad. This could be sped up somewhat by pre-calculating the intersection points: there are at most n*(n-1)/2 of them, 28 in your example.
Does this overall algorithm meet your needs? Is your last question "how can I check each intersection with other intersections to determine if they make a quadrilateral?" asking how to implement my statement "see if you can make a quadrilateral from those intersections and segments"? Do you still need an answer to that? You would need to clarify your definition of a quadrilateral before I could answer that question.
I'll explain the definitions of "quadrilateral" more. This diagram shows four line segments "in general position," where each segment intersects all the others and no three segments intersect in the same point.
Here are (some of) the "quadrilaterals" arising from those four line segments and six intersection points.
1 simple and convex (ABDE)
1 simple and not convex (ACDF)
1 crossing (BCEF)
4 triangles with an extra vertex on a triangle's side (ABCE, ACDE, ABDF, ABFE). Note that the first two define the same region with different vertices, and the same is true of the last two.
4 "double-backs" which looks like a triangle with one side extended (ACEF, BCDF, BDEF, CDEF)
Depending on how you define "quadrilateral" and "equal" you could get anywhere from 1 to 11 of them in that diagram. Wikipedia's definition would include only the first, second, and fourth in my list--I am not sure how that counts the "duplicates" in my fourth group. And I am not even sure that I found all the possibilities in my diagram, so there could be even more.
I see we are now defining a quadrilateral as outlined by four distinct line segments that are sub-segments of the given line segments that form a polygon that is strictly convex--the vertex angles are all less than a straight angle. This still leaves an ambiguity in a few edge cases--what if two line segments overlap more than at one point--but let's leave that aside other than defining that two such line segments have no intersection point. Then this algorithm, pseudo-code based on Python, should work.
We need a function intersection_point(seg1, seg2) that returns the intersection point of the two given line segments or None if there is none or the segments overlap. We also need a function polygon_is_strictly_convex(tuple of points) that returns True or False depending on if the tuple of points defines a strictly-convex polygon, with the addition that if any of the points is None then False is returned. Both those functions are standard in computational geometry. Note that "combination" in the following means that for each returned combination the items are in sorted order, so of (seg1, seg2) and (seg2, seg1) we will get exactly one of them. Python's itertools.combinations() does this nicely.
intersections = {} # empty dictionary/hash table
for each combination (seg1, seg2) of given line segments:
intersections[(seg1, seg2)] = intersection_point(seg1, seg2)
quadrilaterals = emptyset
for each combination (seg1, seg2, seg3, seg4) of given line segments:
for each tuple (sega, segb, segc, segc) in [
(seg1, seg2, seg3, seg4),
(seg1, seg2, seg4, seg3),
(seg1, seg3, seg2, seg4)]:
a_quadrilateral = (intersections[(sega, segb)],
intersections[(segb, segc)],
intersections[(segc, segd)],
intersections[(segd, sega)])
if polygon_is_strictly_convex(a_quadrilateral):
quadrilaterals.add(a_quadrilateral)
break # only one possible strictly convex quad per 4 segments
Here is my actual, tested, Python 3.6 code, which for your segments gives your eight polygons. First, here are the utility, geometry routines, collected into module rdgeometry.
def segments_intersection_point(segment1, segment2):
"""Return the intersection of two line segments. If none, return
None.
NOTES: 1. This version returns None if the segments are parallel,
even if they overlap or intersect only at endpoints.
2. This is optimized for assuming most segments intersect.
"""
try:
pt1seg1, pt2seg1 = segment1 # points defining the segment
pt1seg2, pt2seg2 = segment2
seg1_delta_x = pt2seg1[0] - pt1seg1[0]
seg1_delta_y = pt2seg1[1] - pt1seg1[1]
seg2_delta_x = pt2seg2[0] - pt1seg2[0]
seg2_delta_y = pt2seg2[1] - pt1seg2[1]
denom = seg2_delta_x * seg1_delta_y - seg1_delta_x * seg2_delta_y
if denom == 0.0: # lines containing segments are parallel or equal
return None
# solve for scalars t_seg1 and t_seg2 in the vector equation
# pt1seg1 + t_seg1 * (pt2seg1 - pt1seg1)
# = pt1seg2 + t_seg2(pt2seg2 - pt1seg2) and note the segments
# intersect iff 0 <= t_seg1 <= 1, 0 <= t_seg2 <= 1 .
pt1seg1pt1seg2_delta_x = pt1seg2[0] - pt1seg1[0]
pt1seg1pt1seg2_delta_y = pt1seg2[1] - pt1seg1[1]
t_seg1 = (seg2_delta_x * pt1seg1pt1seg2_delta_y
- pt1seg1pt1seg2_delta_x * seg2_delta_y) / denom
t_seg2 = (seg1_delta_x * pt1seg1pt1seg2_delta_y
- pt1seg1pt1seg2_delta_x * seg1_delta_y) / denom
if 0 <= t_seg1 <= 1 and 0 <= t_seg2 <= 1:
return (pt1seg1[0] + t_seg1 * seg1_delta_x,
pt1seg1[1] + t_seg1 * seg1_delta_y)
else:
return None
except ArithmeticError:
return None
def orientation3points(pt1, pt2, pt3):
"""Return the orientation of three 2D points in order.
Moving from Pt1 to Pt2 to Pt3 in cartesian coordinates:
1 means counterclockwise (as in standard trigonometry),
0 means straight, back, or stationary (collinear points),
-1 means counterclockwise,
"""
signed = ((pt2[0] - pt1[0]) * (pt3[1] - pt1[1])
- (pt2[1] - pt1[1]) * (pt3[0] - pt1[0]))
return 1 if signed > 0.0 else (-1 if signed < 0.0 else 0)
def is_convex_quadrilateral(pt1, pt2, pt3, pt4):
"""Return True if the quadrilateral defined by the four 2D points is
'strictly convex', not a triangle nor concave nor self-intersecting.
This version allows a 'point' to be None: if so, False is returned.
NOTES: 1. Algorithm: check that no points are None and that all
angles are clockwise or all counter-clockwise.
2. This does not generalize to polygons with > 4 sides
since it misses star polygons.
"""
if pt1 and pt2 and pt3 and pt4:
orientation = orientation3points(pt4, pt1, pt2)
if (orientation != 0 and orientation
== orientation3points(pt1, pt2, pt3)
== orientation3points(pt2, pt3, pt4)
== orientation3points(pt3, pt4, pt1)):
return True
return False
def polygon_in_canonical_order(point_seq):
"""Return a polygon, reordered so that two different
representations of the same geometric polygon get the same result.
The result is a tuple of the polygon's points. `point_seq` must be
a sequence of 'points' (which can be anything).
NOTES: 1. This is intended for the points to be distinct. If two
points are equal and minimal or adjacent to the minimal
point, which result is returned is undefined.
"""
pts = tuple(point_seq)
length = len(pts)
ndx = min(range(length), key=pts.__getitem__) # index of minimum
if pts[(ndx + 1) % length] < pts[(ndx - 1) % length]:
return (pts[ndx],) + pts[ndx+1:] + pts[:ndx] # forward
else:
return (pts[ndx],) + pts[:ndx][::-1] + pts[ndx+1:][::-1] # back
def sorted_pair(val1, val2):
"""Return a 2-tuple in sorted order from two given values."""
if val1 <= val2:
return (val1, val2)
else:
return (val2, val1)
And here is the code for my algorithm. I added a little complexity to use only a "canonical form" of a pair of line segments and for a polygon, to reduce the memory usage of the intersections and polygons containers.
from itertools import combinations
from rdgeometry import segments_intersection_point, \
is_strictly_convex_quadrilateral, \
polygon_in_canonical_order, \
sorted_pair
segments = [(( 2, 16), (22, 10)),
(( 4, 4), (14, 14)),
(( 4, 6), (12.54, 0.44)),
(( 4, 14), (20, 6)),
(( 4, 18), (14, 2)),
(( 8, 2), (22, 16))]
intersections = dict()
for seg1, seg2 in combinations(segments, 2):
intersections[sorted_pair(seg1, seg2)] = (
segments_intersection_point(seg1, seg2))
quadrilaterals = set()
for seg1, seg2, seg3, seg4 in combinations(segments, 4):
for sega, segb, segc, segd in [(seg1, seg2, seg3, seg4),
(seg1, seg2, seg4, seg3),
(seg1, seg3, seg2, seg4)]:
a_quadrilateral = (intersections[sorted_pair(sega, segb)],
intersections[sorted_pair(segb, segc)],
intersections[sorted_pair(segc, segd)],
intersections[sorted_pair(segd, sega)])
if is_strictly_convex_quadrilateral(*a_quadrilateral):
quadrilaterals.add(polygon_in_canonical_order(a_quadrilateral))
break # only one possible strictly convex quadr per 4 segments
print('\nThere are {} strictly convex quadrilaterals, namely:'
.format(len(quadrilaterals)))
for p in sorted(quadrilaterals):
print(p)
And the printout from that is:
There are 8 strictly convex quadrilaterals, namely:
((5.211347517730497, 5.211347517730497), (8.845390070921987, 2.8453900709219857), (11.692307692307693, 5.692307692307692), (9.384615384615383, 9.384615384615383))
((5.211347517730497, 5.211347517730497), (8.845390070921987, 2.8453900709219857), (14.666666666666666, 8.666666666666668), (10.666666666666666, 10.666666666666666))
((5.211347517730497, 5.211347517730497), (8.845390070921987, 2.8453900709219857), (17.384615384615387, 11.384615384615383), (12.769230769230768, 12.76923076923077))
((6.0, 14.8), (7.636363636363637, 12.181818181818182), (10.666666666666666, 10.666666666666666), (12.769230769230768, 12.76923076923077))
((6.0, 14.8), (7.636363636363637, 12.181818181818182), (14.666666666666666, 8.666666666666668), (17.384615384615387, 11.384615384615383))
((9.384615384615383, 9.384615384615383), (10.666666666666666, 10.666666666666666), (14.666666666666666, 8.666666666666668), (11.692307692307693, 5.692307692307692))
((9.384615384615383, 9.384615384615383), (11.692307692307693, 5.692307692307692), (17.384615384615387, 11.384615384615383), (12.769230769230768, 12.76923076923077))
((10.666666666666666, 10.666666666666666), (12.769230769230768, 12.76923076923077), (17.384615384615387, 11.384615384615383), (14.666666666666666, 8.666666666666668))
A O(intersection_count2) algorithm is as follows:
For each intersection:
Add the the intersection point to
a hash table with the lines as the key.
Let int be a lookup function that returns
true iff the inputted lines intersect.
RectCount = 0
For each distinct pair of intersections a,b:
Let A be the list of lines that pass
through point a but not through b.
Let B '' '' '' through b but not a.
For each pair of lines c,d in A:
For each pair of lines e,f in B:
If (int(c,e) and int(d,f) and
!int(c,f) and !int(d,e)) or
(int(c,f) and int(d,e) and
!int(c,e) and !int(d,f)):
RectCount += 1
Suppose we have a polygon with five vertices. The two coordinates of the vertices are-
>x=c(1,4,6,3,-2)
>y=c(1,1,5,9,4)
We define the centre of the polygon as the point (mean(x),mean(y)).
I am struggling to draw spokes from the centre of the polygon to the boundary of the polygon such that the spokes creates same angle in the centre (i.e., two neighbouring spokes create equal angle in the centre). I also want to have the all the points on the boundary of the polygon (red circle in the following plot) in orderly manner.
Here is a rough sample plot (convex) which I want to have:
Note: The polygon I am dealing with not necessarily convex.
Sample plot (non-convex)
The output I want: 1) The coordinates of the line (i.e., the intersection points of the line through the origin and boundary segments of the polygon).
2) For each equispaced angle (theta in fig.2) I want a to draw a spoke corresponding to each theta (as in figure 2). Note that, angle lies between 0 to 360 degree.
3) In case of my second polygon (non-convex) where the same line go through two boundary segments (creating three intersecting points), I want to have three coordinates corresponding to the same angle (theta).
Could anyone help me in doing that using R? Thanks in advance.
Here you go. You need the sp and rgeos packages:
spokey <- function(xy,n=20){
xcent = mean(xy[,1])
ycent = mean(xy[,2])
cent = sp::SpatialPoints(cbind(xcent, ycent))
pts = sp::SpatialPoints(xy)
## take the furthest distance from centre to vertex, times two!
r = 2 * max(sp::spDistsN1(pts, cent))
theta=seq(0,2*pi,length=n+1)[-(n+1)]
## construct a big wheel of spoke lines
sl = sp::SpatialLines(
lapply(1:length(theta),function(id){
t = theta[id]
sp::Lines(
list(
sp::Line(
rbind(
c(xcent, ycent),
c(xcent + r * cos(t),ycent + r * sin(t))
)
)
),ID=id)
}))
## construct the polygon as a SpatialPolygons object:
pol = sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(rbind(xy,xy[1,]))),ID=1)))
## overlay spokes on polygon as "SpatialLines" so we do line-on-line
## intersect which gets us points
spokes = rgeos::gIntersection(sl, as(pol,"SpatialLines"), byid=TRUE)
spokes
}
It takes a matrix of coordinates where the first point is not the last point:
xy1 = structure(c(4.49425847117117, 4.9161781929536, 7.95751618746858,
7.92235621065338, 9.76825499345149, 9.9616348659351, 8.04541612950659,
7.83445626861537, 6.42805719600729, 0.644241009906543, 2.40223985066665,
1.24196061576498, 2.13854002455263, 7.935927470861, 9.41043173309254,
9.33179150577352, 6.50074332228897, 7.34612576596839, 2.76533252463575,
1.07456763727692, 3.88595576393172, 1.17286792142569, 2.745672467806,
5.20317957152522, 5.81264133324759, 8.21116826647756), .Dim = c(13L,
2L))
and then:
> plot(xy1,asp=1)
> polygon(xy1)
> spokes = spokey(xy1,20) # second arg is number of spokes
> points(spokes,pch=19,col="red")
gets you:
If you don't believe it, draw the segments from the centre to the points :)
segments(mean(xy1[,1]),mean(xy1[,2]), coordinates(spokes)[,1], coordinates(spokes)[,2])
The function coordinates(spokes) will get you a two-column matrix of the spoke points - its returned as a SpatialPoints object at present.
I modified this to handle the convex case illustrated.
You will have to write code that computes the intersection of a spoke from the center to each edge line segment. Not that hard, really, but have never seen it in R. Then you will have to loop over the angles that you are interested in drawing, loop over the segments, find the ones it intersects, sort those values, and then draw the line to the intersection you are interested in.
You would then to the furthest, or some combination (maybe a dotted line between the closest and the furthest).
In pseudo-code:
for each spoke you want to draw
calculate the spoke-line from the center to some point far outside
initialize edge intersection-point list to empty
for each edge-segment
calculate the intersection-point of spoke-line and edge-segment
if the intersection-point exists
add it to the intersection list
now go through the intersections and find the furthest
draw the spoke from the center to the furthest intersection point
continue with the next spoke
This would probably take several hours to research and write, unless you write this kind of graphics code constantly.
I have three points a,b,c whose x,y,z coordinates are
a=[ -0.3519052 0 0];
b=[ 0 -0.674984 0];
c=[ 0 0 -0.6485047];
how do plot a plane(triangle) using these three points in scilab
plot3d and plo3d1 are not giving the form i am looking for.
I figured out the problem!
plot3d1 needs column vectors.
plot3d1(a',b',c')
produced the plot
how to plot triangle in scilab
Plot a triangle using its sides
Consider the fist vertex lies at origin(0,0)
Second vertex lies on X-Axis at (a,0)
From distance formula of triangle
ie.
length of side = sqrt( (x2−x1)^2+(y2−y1)^2 )
Program to Plot a Triangle when sides are given is as below in scilab :
clf()
//Length of the sides
a = 10;
b = 10
c = 10
//Vertex of third point
xc=(a^2-(b^2-c^2))/(2*a)
yc=sqrt(c^2-xc^2);
clf()
x=[0,0,xc]
y=[0,yc,0]
plot2d(0,0,-1,"010","",[0,0,0,0]);
xpoly(x,y,"lines",1)