Polygon decomposition in special direction - algorithm

I am searching for a library which can do the decomposition of polygons. I want define define directions or lines in which the polygon should be fragmented, as seen here:
So that I get the small polygons. Anyone know a library which supports this?
Or any ideas?

I'm not sure which language are you using. I have a library, written for my purposes, that can get a full partition by given line set and return polygons as a result. It is written on PHP and called dimension and, using it, you can solve your question like way:
Define your polygon by a set of lines LineSet_2D or a Polygon_2D
Define partition lines also through Line_2D
Use LineSet_2D method getPolygons to find all polygons
I've written an example:
//define or polygon. Note that Polygon_2D can also be used
$rPolygon = new LineSet_2D(
new Line_2D( 0, 3, 1, 1),
new Line_2D( 1, 1, 3, 0),
new Line_2D( 3, 0, 1,-1),
new Line_2D( 1,-1, 0,-3),
new Line_2D( 0,-3,-1,-1),
new Line_2D(-1,-1,-3,0),
new Line_2D(-3, 0,-1, 1),
new Line_2D(-1, 1, 0, 3)
);
//define partition line set
$rPartition = new LineSet_2D(
new Line_2D(-1, 1, 1,-1),
new Line_2D(-1,-1, 1, 1)
);
//result line set:
$rResultSet = LineSet_2D::createFromArray(array_merge(
$rPolygon->getLines(),
$rPartition->getLines()
));
//for example, dump plain result:
var_dump($rResultSet->getPolygons());
You can also find this example here But I think it is not exact solution for your question, since my LineSet_2D class will return all looped polygons (i.e. not only 'pieces').

You are looking for a "polygon chop" boolean operation. You may google it for resources available.
Some queues on doing this on your own..
For each slicing line..
Find the intersection points of the slicing line with the edges of the polygon.
For each edge that it intersects, split the edge into two.
Split the polygon corresponding to the splitted edge, into two polygons.
Do the same for all polygons.
You will have to take care of special cases, like splitting line going through vertex and so on...

Related

BufferGeometryUtils.mergeVertices - seems not to merge all identical vertices in three.js

I have a weird issues with BufferGeometryUtils.mergeVertices method
I took a simple cube from a jsfiddle and performed the mergeVertices and it seems mergeVertices does not merge all identical vertices as it should. See https://jsfiddle.net/tomfree/vpdwmycn/
E.g. the vertices given in the indexGeometry returned by mergeVertices are
Index 0 = (-1, -1, 1, )
index 1 = (1, -1, 1,)
index 2= (-1, 1, 1, )
index 3= (1, 1, 1,)
index 4= (1, -1, 1)
i.e. vertices at position 1 and 4 seem to be the same but shouldn't after mergeVertices to my understanding. I am pretty sure that I am missing sth. Can someone point me into the right direction?
Cheers
Tom
ps: Also posted as https://discourse.threejs.org/t/buffergeometryutils-mergevertices-seems-not-to-merge-all-identical-vertices/33890 in three.js forum
The merge process is functioning as expected. If you look at the count of each attribute of the original geometry you'll get 36, but if you look at the count of each attribute of the merged indexedGeo, you'll get 24:
console.log(geometry.getAttribute("position").count); // 36
console.log(indexedGeo.getAttribute("position").count); // 24
The problem you're encountering is that the merge method looks at all attributes before merging. In your case, position, normal, uv. The corners of a box have 3 vertices, each with its own normal pointing in 3 directions (one pointing up, one right, and one forward, for example). Since each vertex contains unique normal data on how to render its respective face, these vertices cannot be merged. Even though their position is the same, the other attributes are different.

3 and 4 degree curves in three.js

I am trying to reproduce the degree-3 or degree-4 3D curves typically found in parametric cad programs like Rhino or Autocad, which take any number of 3D points to create long curves. I've found that three.js has Cubic (degree-3) and Quadratic (degree-4) Bezier curves available but they take exactly three and 4 vectors, respectively. I'd like to create curves with 10 or more inputs, not just 3 or 4. I've also found that three.js has 'Path' which allows building a 2D curve of mixed degree segments using the .bezierCurveTo() or .quadraticCurveTo() methods.
So my question:
Is there currently a way to construct long chains of CubicBezierCurve3 curves that join smoothly? Ideally with a constructor that takes a simple array of vertices?
If I need to implement this myself, where is the best place to start? I'm thinking the .quadraticCurveTo() method could be extended to use a z component and added to SplineCurve3? I'm not 100% clear on how the array of curves works in the 'Path' object.
THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {
var args = Array.prototype.slice.call( arguments );
var lastargs = this.actions[ this.actions.length - 1 ].args;
var x0 = lastargs[ lastargs.length - 2 ];
var y0 = lastargs[ lastargs.length - 1 ];
var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
new THREE.Vector2( aCPx, aCPy ),
new THREE.Vector2( aX, aY ) );
this.curves.push( curve );
this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );
};
Thanks for your help!
Thanks to karatedog and fang for your in-depth answers. In searching for more information about B-spline curve, I stumbled upon this extra library for Three.js NURBS which is exactly what I needed. Upon closer inspection of the THREE.NURBSCurve() constructor in this library, it's implemented exactly as fang described: with arrays of both control points and knots. Knots are defined similarly to the method described above. I'm Marking Fang's answer as correct but I wanted to add this link to the pre-existing library as well, so any n00bs like myself could use it :)
If you are fine with using a high degree Bezier curve, then you can implement it using De Casteljau algorithm. The link in karatedog's answer provides a good source for this algorithm. If you want to stick with degree 3 polynomial curve with many control points, B-spline curve will be a good choice. B-spline curve can be implemented using Cox de Boor algorithm. You can find plenty of reference on the internet. B-spline curve definition requires degree, control points and knot vector. If you want your function to simply take an array of 3d points, you can set degree = 3 and internally define the knot vector as
[0, 0, 0, 0, 1/(N-3), 2/(N-3),....., 1, 1, 1, 1].
where N = number of control points.
For example,
N=4, knot vector=[0, 0, 0, 0, 1, 1, 1, 1],
N=5, knot vector=[0, 0, 0, 0, 1/2, 1, 1, 1, 1],
N=6, knot vector=[0, 0, 0, 0, 1/3, 2/3, 1, 1, 1, 1].
For the N=4 case, the B-spline curve is essentially the same as a cubic Bezier curve.
I suggest to implement your own calculation algorithm, it is fairly easy, the learning process is short and worth the time invested. Check this page: http://pomax.github.io/bezierinfo/
It describes a method (language agnostic) that you can calculate BeziƩr curves with any number of control points, although the a calculation that is specific to a certain number of control points (like cubic or quadratic) can be highly optimized.

Efficient algorithm to fit a linear line along the upper boundary of data only

I'm currently trying to fit a linear line through a spread of scattered data in MATLAB. Now this is easy enough using the polyfit function where I can easily obtain my y= mx + c equation. However, I need to now fit a line along the upper boundary of my data, i.e., the top few data points. I know this description is vague, so lets assume that my scattered data will be in a shape of a cone, with its apex on the y-axis, and it spreads outwards and upwards in the +x and +y direction. I need to fit a best fit line on the 'upper edge of the cone' if you will.
I've developed an algorithm but it's extremely slow. It involves first fitting a line of best fit through ALL data, deleting all data points below this line of best fit, and iterating through until only 5% of the initial data points are left. The final best fit line will then reside close to the top edge of the cone. For 250 data points, this takes about 5s and with me dealing with more than a million data points, this algorithm is simply too inefficient.
I guess my question is: is there an algorithm to more efficiently achieve what I need? Or is there a way to sharpen up my code to eliminate unnecessary complexity?
Here is my code in MATLAB:
(As an example)
a = [4, 5, 1, 8, 1.6, 3, 8, 9.2]; %To be used as x-axis points
b = [45, 53, 12, 76, 25, 67, 75, 98]; %To be used as y-axis points
while prod(size(a)) > (0.05*prod(size(a))) %Iterative line fitting occurs until there are less than 5% of the data points left
lobf = polyfit(a,b,1); %Line of Best Fit for current data points
alen = length(a);
for aindex = alen:-1:1 %For loop to delete all points below line of best fit
ValLoBF = lobf(1)*a(aindex) + lobf(2)
if ValLoBF > b(aindex) %if LoBF is above current point...
a(aindex) = []; %delete x coordinate...
b(aindex) = []; %and delete its corresponding y coordinate
end
end
end
Well first of all your example code seems to be running indefinitely ;)
Some optimizations for your code:
a = [4, 5, 1, 8, 1.6, 3, 8, 9.2]; %To be used as x-axis points
b = [45, 53, 12, 76, 25, 67, 75, 98]; %To be used as y-axis points
n_init_a = length(a);
while length(a) > 0.05*n_init_a %Iterative line fitting occurs until there are less than 5% of the data points left
lobf = polyfit(a,b,1); % Line of Best Fit for current data points
% Delete data points below line using logical indexing
% First create values of the polyfit points using element-wise vector multiplication
temp = lobf(1)*a + lobf(2); % Containing all polyfit values
% Using logical indexing to discard all points below
a(b<temp)=[]; % First destroy a
b(b<temp)=[]; % Then b, very important!
end
Also you should try profiling your code by typing in the command window
profile viewer
and check what takes most time calculating your results. I suspect it is polyfit but that can't be sped up much probably.
What you are looking for is not line fitting. You are trying to find the convex hull of the points.
You should check out the function convhull. Once you find the hull, you can remove all of the points that aren't close to it, and fit each part independently to avoid the fact that the data is noisy.
Alternatively, you could render the points onto some pixel grid, and then do some kind of morphological operation, like imclose, and finish with Hough transform. Check out also this answer.

how to efficiently store occupied/unoccupied 2D space (with insertion)

I have an X by Y space, where X and Y are determined by the sizes of the rectangles given to me. I'm inserting oriented rectangles of a certain size into the space, one at a time. Each insertion is as far left as possible, and then as far up as possible (so as close to (0,0) as I can). What's the best way to represent this? I'm implementing this in Python. The top answer to this question is helpful, but I was hoping for some Python-specific advice, as I'm pretty new to the language itself as well.
Thanks!
If you are trying to efficiently pack rectangles, there are some established algorithms. Here's a Python implementation of one particular algorithm. There's also an article on packing lightmaps here for which I have a Python version (I honestly don't remember whether I ported it myself, or got it from somewhere else).
You have two choices for working in two-dimensional space like this.
A list of lists. [ [0, 0, ..., 0], [0, 0, ..., 0], ... [0, 0, ..., 0] ] The outer list is the 'X' access, the inner list is the 'Y' access. Each point is space[x][y]. You build it with space = list( list( EMPTY for j in range(Y_size) ) for i in range(X_size) ) or something similar.
You mask off rectangles with some filler algorithm that sets values into a rectangular patch of space.
for x in range( low, high ):
for y in range ( low, high ):
space[x][y]= FILLED # or whatever object you're putting there.
A mapping. { (0,0): 0, (0,1): 0, ... (X,Y): 0 }. Each point is space[x,y]. You build it with space = dict( ( (x,y), EMPTY ) for x in range(X_size) for y in range(Y_size) ).
You mask off rectangles with almost the same filler algorithm. Just change the syntax slightly.
Quadtrees are often used for this sort of thing. It sounds like you want a region quad tree.

An algorithm to solve a simple(?) array problem

For this problem speed is pretty crucial. I've drawn a nice image to explain the problem better. The algorithm needs to calculate if edges of a rectangle continue within the confines of the canvas, will the edge intersect another rectangle?
We know:
The size of the canvas
The size of each rectangle
The position of each rectangle
The faster the solution is the better! I'm pretty stuck on this one and don't really know where to start.
alt text http://www.freeimagehosting.net/uploads/8a457f2925.gif
Cheers
Just create the set of intervals for each of the X and the Y axis. Then for each new rectangle, see if there are intersecting intervals in the X or the Y axis. See here for one way of implementing the interval sets.
In your first example, the interval set on the horizontal axis would be { [0-8], [0-8], [9-10] }, and on the vertical: { [0-3], [4-6], [0-4] }
This is only a sketch, I abstracted many details here (e.g. usually one would ask an interval set/tree "which intervals overlap this one", instead of "intersect this one", but nothing not doable).
Edit
Please watch this related MIT lecture (it's a bit long, but absolutely worths it).
Even if you find simpler solutions (than implementing an augmented red-black tree), it's good to know the ideas behind these things.
Lines that are not parallel to each other are going to intersect at some point. Calculate the slopes of each line and then determine what lines they won't intersect with.
Start with that, and then let's see how to optimize it. I'm not sure how your data is represented and I can't see your image.
Using slopes is a simple equality check which probably means you can take advantage of sorting the data. In fact, you can probably just create a set of distinct slopes. You'll have to figure out how to represent the data such that the two slopes of the same rectangle are not counted as intersecting.
EDIT: Wait.. how can two rectangles whose edges go to infinity not intersect? Rectangles are basically two lines that are perpendicular to each other. shouldn't that mean it always intersects with another if those lines are extended to infinity?
as long as you didn't mention the language you chose to solve the problem, i will use some kind of pseudo code
the idea is that if everything is ok, then a sorted collection of rectangle edges along one axis should be a sequence of non-overlapping intervals.
number all your rectangles, assigning them individual ids
create an empty binary tree collection (btc). this collection should have a method to insert an integer node with info btc::insert(key, value)
for all rectangles, do:
foreach rect in rects do
btc.insert(rect.top, rect.id)
btc.insert(rect.bottom, rect.id)
now iterate through the btc (this will give you a sorted order)
btc_item = btc.first()
do
id = btc_item.id
btc_item = btc.next()
if(id != btc_item.id)
then report_invalid_placement(id, btc_item.id)
btc_item = btc.next()
while btc_item is valid
5,7,8 - repeat steps 2,3,4 for rect.left and rect.right coordinates
I like this question. Here is my try to get on it:
If possible:
Create a polygon from each rectangle. Treat each edge as an line of maximum length that must be clipped. Use a clipping algorithm to check weather or not a line intersects with another. For example this one: Line Clipping
But keep in mind: If you find an intersection which is at the vertex position, its a valid one.
Here's an idea. Instead of creating each rectangle with (x, y, width, height), instantiate them with (x1, y1, x2, y2), or at least have it interpret these values given the width and height.
That way, you can check which rectangles have a similar x or y value and make sure the corresponding rectangle has the same secondary value.
Example:
The rectangles you have given have the following values:
Square 1: [0, 0, 8, 3]
Square 3: [0, 4, 8, 6]
Square 4: [9, 0, 10, 4]
First, we compare Square 1 to Square 3 (no collision):
Compare the x values
[0, 8] to [0, 8] These are exactly the same, so there's no crossover.
Compare the y values
[0, 4] to [3, 6] None of these numbers are similar, so they're not a factor
Next, we compare Square 3 to Square 4 (collision):
Compare the x values
[0, 8] to [9, 10] None of these numbers are similar, so they're not a factor
Compare the y values
[4, 6] to [0, 4] The rectangles have the number 4 in common, but 0 != 6, therefore, there is a collision
By know we know that a collision will occur, so the method will end, but lets evaluate Square 1 and Square 4 for some extra clarity.
Compare the x values
[0, 8] to [9, 10] None of these numbers are similar, so they're not a factor
Compare the y values
[0, 3] to [0, 4] The rectangles have the number 0 in common, but 3 != 4, therefore, there is a collision
Let me know if you need any extra details :)
Heh, taking the overlapping intervals answer to the extreme, you simply determine all distinct intervals along the x and y axis. For each cutting line, do an upper bound search along the axis it will cut based on the interval's starting value. If you don't find an interval or the interval does not intersect the line, then it's a valid line.
The slightly tricky part is to realize that valid cutting lines will not intersect a rectangle's bounds along an axis, so you can combine overlapping intervals into a single interval. You end up with a simple sorted array (which you fill in O(n) time) and a O(log n) search for each cutting line.

Resources