I'm trying to develop a component that should look somewhat like this
I'm using RaphaelJS to draw this and that works just fine. I have an array of angles which I use to calculate the paths of the individual segments. I store these paths in a simple array so the inner circle is at segments[0] and so on spiralling outwards.
My problem is that I need each segment to be aware of it's adjacent segments both clockwise, anti-clockwise, inwards and outwards and I'm having difficulty figuring out how to calculate the position of these is my segment array. So for instance, in the case of the above diagram, the red segment at level 2 (where 0 is the inner-most circle) has red, bright green, kaki, light purple and dark purple neighbours.
Perhaps I need a different coordinate system. If each level had the same number and angle distribution of segments it would be a simple case of using modulus's like indexing a circular array but this isn't the case.
Any help would be much appreciated.
Many Thanks,
Anthony
I'd change how you're storing the segments from one sorted array into one sorted array per level.
Finding the neighbours of a given segment (S) is then fairly easy: the left and right neighbours are the previous and next elements of that level's array.
The neighbours in the adjacent levels are found with a couple of binary searches in those arrays: find the segments that coincide with the start and end angles of S, the neighbours are the sequence of segments between those two.
Related
I am using a Javascript library 'Tess2' to triangulate a series of contours.
https://github.com/memononen/tess2.js/blob/master/src/tess2.js
It generates a perfect 2d mesh of any shape consisting of multiple contours:
A contour consists of a series of points (in a negative winding order for solid fills, in a positive winding order for holes)
However, the resulting triangles output by the algorithm are no longer tied to a contour and its fill color.
How would I alter Tess2 (or any other javascript library that tesselates contours) to allow for the retention of color data in the resulting triangles?
I've tried looking everywhere and I cannot find a solution.
From what I've seen in the source code, the tessalation function contains a vertex indices in an returned object:
Tess2.tesselate = function(opts) {
...
return {
vertices: tess.vertices,
vertexIndices: tess.vertexIndices,
vertexCount: tess.vertexCount,
elements: tess.elements,
elementCount: tess.elementCount,
mesh: debug ? tess.mesh : undefined
};
You can create a new array with the colors for each vertex, and then use vertexIndices from the object to get a color of the vertex.
If you would like to have a color per face, you would just need to generate an array like above, which means putting the same vertex color for each vertex in a array. You would also like to wrap all of this data in some kind of convienent object or class.
[EDIT]
It turns out that the tesselation algorithm merges vertices in the same position, meaning that it reorganizes vertex array completely. There are a solution to explicitly not merge different contours with overlapping vertices:
Tess2.tesselate({ contours: yourContours, elementType: Tess2.BOUNDARY_CONTOURS });
That should preserve the original vertices, however not in an original order, use vertexIndices to get the original position of these.
After many failed attempts I finally got there.
I've been trying all this time to try and process a huge amount of contours all at once with a single tessellation pass.
I tried editing the tessellation library to make each half edge retain it original contour ID. I had several eureka moments when it finally seemed to work, only to be disappointed when I stress tested it and found it to be less than perfect.
But it turns out I've been incredibly daft...
All I had to do was group each contour with a particular fill, and then tesselate each group independently.
I didn't understand that for every interior contour fill, there would always be an opposite contour that effectively enclosed the outer contour loop.
For instance, to represent a red box with a blue box inside there would be 2 red contours and 1 blue. I thought it could be represented with only 1 blue contour and 1 red, where the blue would also represent the red contour's hole, and so processing each colour group of contours independently didn't make sense to me.
When I finally realised this, I figured it out.
I've published a solution on github but I'm not sure how much use it is to anyone:
https://github.com/hedgehog90/triangulate-contours-colour-example
I've included a pretty comprehensive exporter script for converting contours (including curves) into polygonal paths for Adobe Flash/Animate which might be useful for someone.
I will be writing an OBJ exporter on top of this shortly, so I can represent vector graphics in a 3D engine.
Does anyone know of a way to merge thousands of polygons that are contiguous? I've been using turf's union function to do this in my prototypes but the time it takes grows to be way too slow as the list of polygons increases. I'm hoping/aiming for a solution that takes sub second time.
Here is how I've been doing it.
const turfUnion = require('#turf/union').default;
const polygons = [ ... ];
const result = polygons.merge((m, f) => turfUnion(m, f));
As I mentioned this is too slow. It takes close to 5 minutes to merge 10,000 features.
I'm guessing there is a way to do this much faster given that I know which polygons share a point with which other polygons and that all the polygons are contagious. The final result can have holes so the solution has to focus on interior perimeters as well as well as the external one.
Any ideas or open source solutions would be great. Solutions in Javascript are preferred, but other low level languages would be OK.
And here is a picture of one of large sets of polygons I'm looking to merge. The data for this can be found here.
And here is the expected output.
Pairwise combine the polygons recursively The cost of computing the union of two polygons scales with the number of points in each. So you can reduce the runtime by reducing the number of operations that involve large polygons.
The approach I take is to combine polygon1 with polygon2, then polygon3 with polygon4, all the way up to polygon(N-1) with polygonN.
Then I repeat the process combining polygon1_2 (the union of polygons 1 and 2 from the previous step) with polygon3_4, all the way up to combining polygon(N-3)_(N-2) with polygon(N-1)_(N).
Keep repeating this process until you only have one polygon remaining.
Here's some sample code. It's python, not Javascript, but porting it shouldn't be difficult.
def union(geom_list):
"""Rapidly combine a list of geometries into one.
Inputs
---------
geom_list
A list of gdal/ogr geometries
Returns
-----------
A single geometry representing the union of the inputs
"""
if len(geom_list) == 1:
return geom_list[0]
if len(geom_list) == 2:
return geom_list[0].Union(geom_list[1])
size = int(np.floor(len(geom_list)/2))
geom1 = union(geom_list[:size])
geom2 = union(geom_list[size:])
return geom1.Union(geom2)
I can't claim this is the fastest possible way to do it, but it's much faster than adding one polygon at a time.
At the risk of sending you down a rabbit hole, here's what I would try if I was in your shoes...
Stage 1: O(n). Consolidate all the line segments into an array, such that you end up with an array of line segments (ie, [x0,y0,x1,y1]) representing every polygon...
[
[30.798218847530226, -26.663920391848013, 30.798209281734188, -26.66394228167575],
[30.798209281734188, -26.66394228167575, 30.798201318284743, -26.663914720621534],
[30.798201318284743, -26.663914720621534, 30.798218847530226, -26.663920391848013],
...
]
Stage 2: O(n log n). Sort this entire array by x0, such that the line segments are now ordered according to the x value of the beginning of the segment.
Stage 3: O(1). Beginning with the first element in the sorted array (segment 0), we can make the assumption that the segment with the leftmost x0 value has to be on the edge of the outer polygon. At this point we have segment 0's [x0,y0,x1,y1] as the starting outer edge segment.
Stage 4: O(log n). Now, find the corrresponding line segments that begin with the end of the previous segment. In other words, which segments connect to the current segment? This should be less than a handful, typically one or two. Searching for the matching x0 is assumed to be binary, followed by a short localized linear search for all matching [x0,y0] combinations.
Stage 5: O(1). If only one segment's [x0,y0] matched the last segment's [x1,y1], then add the segment to the list of outer edges. If more than one matching segment was found, then (assuming that we're moving in a clockwise direction) find the [x0,y0] pair that is furthest left of the current line segment, or if the outer edge is taking a right turn and none of the matching segments is to the left, then the [x0,y0] pair that is closest to the right of the current line segment. Add this new segment to the list of outer edges.
(Note that there are matrix algorithms, which avoid the more expensive trig functions, to determine whether a point is to the left or right of a segment, in addition to the perpendicular distance from a point to a line / segment.)
Stage 6: O(~n). Repeat Stage 4 until back at the starting outer edge segment.
Overall algorithm should be O(n log n)...
Note that this does not take into account interior perimeters, but believe that if you can determine a beginning segment that forms part of an interior perimeter and know whether the starting segment is moving clockwise or counterclockwise, then the same algorithm should work...
I try to arrange multiple square pictures on a canvas so that they form a circle which is completely covered with these elements like on this picture:
See original here (slide three)
How can I compute the x and y coordinates and the size of each element given n elements and a fix radius?
thanks in advance!
P.S.: probably I'll use pixi.js for this
My suggestion:
The question is related to the "Gauss circle problem", that has no simple solution.
So I would choose a too large radius, to be sure to cover at least n squares (such as the smallest integer such that π(r-1)² ≥ n). Then generate all (x, y) pairs within that radius (x²+y² ≤ r²), keeping the value of x²+y² for each.
Next, sort by increasing x²+y², and keep the n smallest. This will fill a regular circle, with extra pixels on the outer layer until the count is n.
Begin Edit
Given a set of points,
each defined by latitude and longitude,
find an ordered list of directional connections between points within three points that form a triangle such that connecting inner points of that triangle with each other and these three points produces maximum triangles, with the following constraints:
The connection of two points is directional, and the number of outgoing connections can be up to the value of some variable maxOutgoing, and the length of each outgoing connection can be up to the value of some variable maxOutgoingLength. Incoming count and length is not limited.
Connections may not cross each other.
To each point we may apply a combination of up to four modifiers:
increaseOutgoing that increases the number of outgoing by the value of some constant increaseOutgoingBy, and
increaseOutgoingLength that increases the length of the outgoing connection by the value of some constant increaseOutgoingLengthBy.
Order of connection is important:
Once a point is enclosed in a triangle, no more outgoing connections can be made.
In the original form of this question, I wanted to find a unique "path" and "notation" for each of the solution's participating points.
End Edit
Intro:
I have a recursive function that finds centers of given three points.
I start with vertices a, b, and c.
The center is labeled (abc).
The center splits triangle abc into three triangles: (abc)ab, (abc)ac, and (abc)bc, with centers: ((abc)ab), ((abc)ac), and ((abc)bc). And so on.
My function sorts the vertices' names - parentheses character codes are smaller than letters, that's why ((abc)ab) and not, for example, (ab(abc)).
I've noticed that each point has a unique count of a's, b's, and c's (as well as parentheses, which can be ignored).
Looking for:
A way to visually (I can, and do, draw the triangles: each vertex to the other two and to the center) get to a point given it's name, but it can get very long, so, perhaps, use letter-count. For example: point (((abc)ab)((abc)a((abc)ab))((abc)((abc)ab)((abc)a((abc)ab)))) has a, b, and c letter-count of 13, 11, and 7, and to get to it, assuming a is top vertex, b is below a and to the right, and c is below a and to the left (just for example. they can be in any order/direction), we (1) go to the center, (2) then right-up-right, (3) then left-up-left, (4) then down-right-down, and, finally, (5) right-up-right - all along drawn lines (green path in image below).
How to get these directions from the point's name/letter-count?!? Instead of painfully dissecting the point's name and using pencil and paper...
Ignore the grey lines in the image below.
In that case, the answer is simply (and trivially) "no". If "center" is so loosely restricted, then it is not possible to determine the direction of a center from the previous one. Consider your drawing, for example, starting from that first center. Your definition restricts the next center only to be in the triangle's interior. Thus, the directionality can be anything from RDR to UUU (with only a smidgen to the right).
Your notation is sufficient to uniquely denote any particular sub-triangle in the hierarchy. Without a definition of "center", you don't have enough information to guarantee even the cardinal direction of the center.
I'm currently trying to build a kind of pie chart / voronoi diagram hybrid (in canvas/javascript) .I don't know if it's even possible. I'm very new to this, and I haven't tried any approaches yet.
Assume I have a circle, and a set of numbers 2, 3, 5, 7, 11.
I want to subdivide the circle into sections equivalent to the numbers (much like a pie chart) but forming a lattice / honeycomb like shape.
Is this even possible? Is it ridiculously difficult, especially for someone who's only done some basic pie chart rendering?
This is my view on this after a quick look.
A general solution, assuming there are to be n polygons with k vertices/edges, will depend on the solution to n equations, where each equation has no more than 2nk, (but exactly 2k non-zero) variables. The variables in each polygon's equation are the same x_1, x_2, x_3... x_nk and y_1, y_2, y_3... y_nk variables. Exactly four of x_1, x_2, x_3... x_nk have non-zero coefficients and exactly four of y_1, y_2, y_3... y_nk have non-zero coefficients for each polygon's equation. x_i and y_i are bounded differently depending on the parent shape.. For the sake of simplicity, we'll assume the shape is a circle. The boundary condition is: (x_i)^2 + (y_i)^2 <= r^2
Note: I say no more than 2nk, because I am unsure of the lowerbound, but know that it can not be more than 2nk. This is a result of polygons, as a requirement, sharing vertices.
The equations are the collection of definite, but variable-bounded, integrals representing the area of each polygon, with the area equal for the ith polygon:
A_i = pi*r^2/S_i
where r is the radius of the parent circle and S_i is the number assigned to the polygon, as in your diagram.
The four separate pairs of (x_j,y_j), both with non-zero coefficients in a polygon's equation will yield the vertices for the polygon.
This may prove to be considerably difficult.
Is the boundary fixed from the beginning, or can you deform it a bit?
If I had to solve this, I would sort the areas from large to small. Then, starting with the largest area, I would first generate a random convex polygon (vertices along a circle) with the required size. The next area would share an edge with the first area, but would be otherwise also random and convex. Each polygon after that would choose an existing edge from already-present polygons, and would also share any 'convex' edges that start from there (where 'convex edge' is one that, if used for the new polygon, would result in the new polygon still being convex).
By evaluating different prospective polygon positions for 'total boundary approaches desired boundary', you can probably generate a cheap approximation to your initial goal. This is quite similar to what word-clouds do: place things incrementally from largest to smallest while trying to fill in a more-or-less enclosed space.
Given a set of voronio centres (i.e. a list of the coordinates of the centre for each one), we can calculate the area closest to each centre:
area[i] = areaClosestTo(i,positions)
Assume these are a bit wrong, because we haven't got the centres in the right place. So we can calculate the error in our current set by comparing the areas to the ideal areas:
var areaIndexSq = 0;
var desiredAreasMagSq = 0;
for(var i = 0; i < areas.length; ++i) {
var contrib = (areas[i] - desiredAreas[i]);
areaIndexSq += contrib*contrib;
desiredAreasMagSq += desiredAreas[i]*desiredAreas[i];
}
var areaIndex = Math.sqrt(areaIndexSq/desiredAreasMagSq);
This is the vector norm of the difference vector between the areas and the desiredAreas. Think of it like a measure of how good a least squares fit line is.
We also want some kind of honeycomb pattern, so we can call that honeycombness(positions), and get an overall measure of the quality of the thing (this is just a starter, the weighting or form of this can be whatever floats your boat):
var overallMeasure = areaIndex + honeycombnessIndex;
Then we have a mechanism to know how bad a guess is, and we can combine this with a mechanism for modifying the positions; the simplest is just to add a random amount to the x and y coords of each centre. Alternatively you can try moving each point towards neighbour areas which have an area too high, and away from those with an area too low.
This is not a straight solve, but it requires minimal maths apart from calculating the area closest to each point, and it's approachable. The difficult part may be recognising local minima and dealing with them.
Incidentally, it should be fairly easy to get the start points for the process; the centroids of the pie slices shouldn't be too far from the truth.
A definite plus is that you could use the intermediate calculations to animate a transition from pie to voronoi.