I have 2D polygons, with their vertices positioned in local polygon-space. I'm trying to calculate new vertices that would form a uniform length edge around the inside of the polygon.
Currently to calculate the edge, I'm basically shrinking the original vertices. For each polygon vertex I calculate the negated unit vector and multiply this by a constant edge length factor. Then I add this to the original polygon vertex.
Pseudocode:
const float edgeLength = 0.5;
for each vertex v
vec2 n = -v.unit();
vec2 edgeVertex = v + n * edgeLength;
The result works fine on regular polygons:
screenshot 1
However, on other polygons, such as rectangles, the edge lengths are not uniform:
screenshot 2
I've tried many different attempts, but nothing seems to work so far, any help would be greatly appreciated, thanks!
(Please ignore that the polygons are rendered in 3D, the actual polygon data is 2D).
Move each edge a fixed distance, in a direction perpendicular to the edge (all to the left, if the edges run counterclockwise). Then calculate the intersections of the new edges-- these are the new vertices.
Related
So I'm attempting to make a wall system like the Sims. While it is 3D, it can be simplified to 2D (think a bird's eye view). A wall is defined by two points: a starting point an an ending point and the walls themselves have directions and can be simplified to unit vectors. Walls are also made with rectangular prisms, each of these prisms start at one point and end at another. So, bearing this in mind, sometimes walls have to be extended, otherwise there will be a small gap in the convex corner of the wall
if one of the points is shared between the walls. Any number of walls can be placed in a single position, so all of this in mind, a grid point's data could contain something like this (using Lua), each table represents a vector2, using a table for ease of visualization, this code won't actually work:
local gridPoint = {
{x = 1, y = 0},
{x = 0.7071, y = 0.7071},
{x = 0, y = 1},
{x = 0.7071, y = -0.7071},
}
Here's a visual of what the points might look like, where the intersection is the grid point and the walls are the vectors extending from the intersection, assuming each of the vectors have a length of 1 (excuse my terrible drawing skills). Since dot products flip when greater than 180 degrees, the largest angle would always be <=180.
So now, to get the angle between any two of points, we can just do math.deg(math.acos(v1:dot(v2))) to get the angle between these two points in degrees, where v1 is vector 1, v2 is vector 2, and dot is a function that returns the dot product of v1 and v2.
So up to this point, everything is fine. The issue is that I have to create two loops which goes through every single combination of possible dot products which I'm not sure is the best method of finding the largest angle, this is #gridPoint^2 possible combinations which is fine at lower numbers, but this number of possible combination increases exponentially with each new wall.
Is there an easier way of doing this?
This problem is equivalent to finding of the farthest pair of points, where all the points lie at unit circle.
Sort points - it is simpler to separate points with positive y (angles 0..Pi) into the first list, and points with negative y into the second list,sort them by X-coordinate, then join the first list and reversed second one. This stage takes O(nlogn) time
Then perform searching of the farthest points - fix the first point index (A[i]), walk through the list until squared distance A[i]-A[j+1] becomes less than squared distance A[i]-A[j]. So we find the farthest point A[j] for A[i]. Now increment i and search the farthest point for it - starting from j.
Repeat until j exceeds n.
This stage is linear because we move i and j only in forward direction. Essentially this is a method of rotating calipers, so you can get some implementation elsewhere.
I am asking if there is any particular order that i need to input my set of coordinates for the drawing of polygon using Graphics2D class in Java.
For example, do values of my coordinates(X,Y) need to be arranged in descending/ascending order for both X and Y arrays of coordinates?
Or another example is if i wish to draw a polygon and i have 4 sets of points, topleft, topright, bottomright and bottomleft and i simply input them in this order to drawPolygon method in Java to get a drawn polygon with corners corresponding to all this 4 points.
Or i can just arrange my coordinates in any random order?
Thanks in advance.
To understand polygon filling in general you have to understand edge direction, winding order and the selected polygon fill rule.
Edge direction is determined by the order that vertices have been declared. For example ...
Polygon poly= new Polygon();
poly.addPoint(10, 10);
poly.addPoint(100, 10);
poly.addPoint(100, 100);
poly.addPoint(10, 100);
Polygons are drawn by joining adjacent vertices (from an ordered list of vertices) to form edges. The last vertex in the list is also joining the first (as if the list were circular). The first edge in the polygon above is constructed from the first two vertices - Point(10,10) and Point(100,10).
Whenever polygons self-intersect or overlap, to understand how the polygons will be drawn, you need a knowledge of both winding order and the applied polygon filling rule. When polygons overlap, polygon sub-regions are created - discrete regions that are enclosed by edges. The winding order of these sub-regions and the applied polygon filling rule determine whether these sub-regions are filled or not.
(source: angusj.com)
The winding number for any given polygon sub-region can be derived by:
set the winding count to zero
from a point (P1) that's within a given sub-region, draw an imaginary horizontal line to another point that's outside the polygon or polygons (P2)
while traversing this line from P1 to P2, for each polygon edge that crosses this imaginary line - if it's heading up then increment the winding count, otherwise decrement the winding count.
According to the Java Graphics2D documentation, fillPolygon only uses the even-odd fill rule where only odd numbered sub-regions are filled.
(source: angusj.com)
The polygon is drawn from each point to the following point.
So the two points of an edge have to be neighbors in the list of points you submit to DrawPolygon.
If you want to draw a polygon between the points A, B, C and D, you will need to submit these points in the order
A,B,C,D or
D,A,B,C or
C,D,A,B or
B,C,D,A or
D,C,B,A or
A,D,C,B or
B,A,D,C or
C,B,A,D or
All other combinations of A,B,C and D will produce a polygon with the same points but different edges
This is the polygon you get if you use one of the above orders
A------B
| |
| |
| |
D------C
This is the polygon you get if you use for example A,B,D,C
A------B
\ /
\ /
*
/ \
/ \
D-----C
I have 2 circles that collide in a certain collision point and under a certain collision angle which I calculate using this formula :
C1(x1,y1) C2(x2,y2)
and the angle between the line uniting their centre and the x axis is
X = arctg (|y2 - y1| / |x2 - x1|)
and what I want is to translate the circle on top under the same angle that collided with the other circle. I mean with the angle X and I don't know what translation coordinates should I give for a proper and a straight translation!
For what I think you mean, here's how to do it cleanly.
Think in vectors.
Suppose the centre of the bottom circle has coordinates (x1,y1), and the centre of the top circle has coordinates (x2,y2). Then define two vectors
support = (x1,y1)
direction = (x2,y2) - (x1,y1)
now, the line between the two centres is fully described by the parametric representation
line = support + k*direction
with k any value in (-inf,+inf). At the initial time, substituting k=1 in the equation above indeed give the coordinates of the top circle. On some later time t, the value of k will have increased, and substituting that new value of k in the equation will give the new coordinates of the centre of the top circle.
How much k increases at value t is equal to the speed of the circle, and I leave that entirely up to you :)
Doing it this way, you never need to mess around with any angles and/or coordinate transformations etc. It even works in 3D (provided you add in z-coordinates everywhere).
I'm using CML to manage the 3D math in an OpenGL-based interface project I'm making for work. I need to know the width of the viewing frustum at a given distance from the eye point, which is kept as a part of a 4x4 matrix that represents the camera. My goal is to position gui objects along the apparent edge of the viewport, but at some distance into the screen from the near clipping plane.
CML has a function to extract the planes of the frustum, giving them back in Ax + By + Cz + D = 0 form. This frustum is perpendicular to the camera, which isn't necessarily aligned with the z axis of the perspective projection.
I'd like to extract x and z coordinates so as to pin graphical elements to the sides of the screen at different distances from the camera. What is the best way to go about doing it?
Thanks!
This seems to be a duplicate of Finding side length of a cross-section of a pyramid frustum/truncated pyramid, if you already have a cross-section of known width a known distance from the apex. If you don't have that and you want to derive the answer yourself you can follow these steps.
Take two adjacent planes and find
their line of intersection L1. You
can use the steps here. Really
what you need is the direction
vector of the line.
Take two more planes, one the same
as in the previous step, and find
their line of intersection L2.
Note that all planes of the form Ax + By + Cz + D = 0 go through the origin, so you know that L1 and L2
intersect.
Draw yourself a picture of the
direction vectors for L1 and L2,
tails at the origin. These form an
angle; call it theta. Find theta
using the formula for the angle
between two vectors, e.g. here.
Draw a bisector of that angle. Draw
a perpendicular to the bisector at
the distance d you want from the
origin (this creates an isosceles
triangle, bisected into two
congruent right triangles). The
length of the perpendicular is your
desired frustum width w. Note that w is
twice the length of one of the bases
of the right triangles.
Let r be the length of the
hypotenuses of the right triangles.
Then rcos(theta/2)=d and
rsin(theta/2)=w/2, so
tan(theta/2)=(w/2)/d which implies
w=2d*tan(theta/2). Since you know d
and theta, you are done.
Note that we have found the length of one side of a cross-section of a frustrum. This will work with any perpendicular cross-section of any frustum. This can be extended to adapt it to a non-perpendicular cross-section.
Given a list of vertices (v), and a list of edges connecting the vertices (e), and a list of surfaces that connect the edges (s), how to calculate the volume of the Polyhedron?
Take the polygons and break them into triangles.
Consider the tetrahedron formed by each triangle and an arbitrary point (the origin).
Sum the signed volumes of these tetrahedra.
Notes:
This will only work if you can keep a consistent CW or CCW order to the triangles as viewed from the outside.
The signed volume of the tetrahedron is equal to 1/6 the determinant of the following matrix:
[ x1 x2 x3 x4 ]
[ y1 y2 y3 y4 ]
[ z1 z2 z3 z4 ]
[ 1 1 1 1 ]
where the columns are the homogeneous coordinates of the verticies (x,y,z,1).
It works even if the shape does not enclose the origin by subracting off that volume as well as adding it in, but that depends on having a consistent ordering.
If you can't preserve the order you can still find some way to break it into tetrahedrons and sum 1/6 absolute value of the determinant of each one.
Edit:
I'd like to add that for triangle mesh where one vertex (say V4) of the tetrahedron is (0,0,0) the determinante of the 4x4 matrix can be simplified to the upper left 3x3 (expansion along the 0,0,0,1 column) and that can be simplified to Vol = V1xV2.V3 where "x" is cross product and "." is dot product. So compute that expression for every triangle, sum those volumes and divide by 6.
Similarly with a polygon where we can split it into triangles and sum the areas,
you could split a polyhedron into pyramids and sum their volumes. But I'm not sure how hard is to implement an algorithm for that.
(I believe there is a mathematical way/formula, like using vectors and matrices.
I suggest to post your question also on http://mathoverflow.net)
I have done this before, but the surface mesh I used always had triangular facets. If your mesh has non triangular facets, you can easily break them up into triangular facets first. Then I fed it to TetGen to obtain a tetrahedralization of the interior. Finally, I added up all the volumes of the tetrahedra. TetGen is reasonably easy to use, and is the only library other than CGAL I know of that can handle complicated meshes. CGAL is pretty easy to use if you don't mind installing a gigantic library and use templates like crazy.
First, break every face into triangles by drawing in new edges.
Now look at one triangle, and suppose it's on the "upper" surface (some of these details will turn out to be unimportant later). Look at the volume below the triangle, down to some horizontal plane below the polyhedron. If {h1, h2, h3} are the heights of the three points, and A is the area of the base, then the volume of the solid will be A(h1+h2+h3)/3. Now we have to add up the volumes of these solids for the upper faces, and subtract them for the lower faces to get the volume of the polyhedron.
Play with the algebra and you'll see that the height of the polyhedron above the horizontal plane doesn't matter. The plane can be above the polyhedron, or pass through it, and the result will still be correct.
So what we need is (1) a way to calculate the area of the base, and (2) a way to tell an "upper" face from a "lower" one. The first is easy if you have the Cartesian coordinates of the points, the second is easy if the points are ordered, and you can combine them and kill two birds with one stone. Suppose for each face you have a list of its corners, in counter-clockwise order. Then the projection of those points on the x-y plane will be counterclockwise for an upper face and clockwise for a lower one. If you use this method to calculate the area of the base, it will come up positive for an upper face and negative for a lower one, so you can add them all together and have the answer.
So how do you get the ordered lists of corners? Start with one triangle, pick an ordering, and for each edge the neighbor that shares that edge should list those two points in the opposite order. Move from neighbor to neighbor until you have a list for every triangle. If the volume of the polyhedron comes up negative, just multiply by -1 (it means you chose the wrong ordering for that first triangle, and the polyhedron was inside-out).
EDIT:
I forgot the best part! If you check the algebra for adding up these volumes, you'll see that a lot of terms cancel out, especially when combining triangles back into the original faces. I haven't worked this out in detail, but it looks as if the final result could be a surprisingly simple function.
Here's a potential implementation for that in Python.
Can anyone please check if it's correct?
I believe that I am missing permutations of the points because my second test (cube) gives 0.666 and not 1. Ideas anyone?
Cheers
EL
class Simplex(object):
'''
Simplex
'''
def __init__(self,coordinates):
'''
Constructor
'''
if not len(coordinates) == 4:
raise RuntimeError('You must provide only 4 coordinates!')
self.coordinates = coordinates
def volume(self):
'''
volume: Return volume of simplex. Formula from http://de.wikipedia.org/wiki/Tetraeder
'''
import numpy
vA = numpy.array(self.coordinates[1]) - numpy.array(self.coordinates[0])
vB = numpy.array(self.coordinates[2]) - numpy.array(self.coordinates[0])
vC = numpy.array(self.coordinates[3]) - numpy.array(self.coordinates[0])
return numpy.abs(numpy.dot(numpy.cross(vA,vB),vC)) / 6.0
class Polyeder(object):
def __init__(self,coordinates):
'''
Constructor
'''
if len(coordinates) < 4:
raise RuntimeError('You must provide at least 4 coordinates!')
self.coordinates = coordinates
def volume(self):
pivotCoordinate = self.coordinates[0]
volumeSum = 0
for i in xrange(1,len(self.coordinates)-3):
newCoordinates = [pivotCoordinate]
for j in xrange(i,i+3):
newCoordinates.append(self.coordinates[j])
simplex = Simplex(newCoordinates)
volumeSum += simplex.volume()
return volumeSum
coords = []
coords.append([0,0,0])
coords.append([1,0,0])
coords.append([0,1,0])
coords.append([0,0,1])
s = Simplex(coords)
print s.volume()
coords.append([0,1,1])
coords.append([1,0,1])
coords.append([1,1,0])
coords.append([1,1,1])
p = Polyeder(coords)
print p.volume()