How to scatter shapes without overlapping while keeping them close together? - javascript

here's something I have been trying to figure out but couldn't because I suck at math or statistics :S
There are a lot of ways to scatter i.e. a bunch of divs or a p5 canvas element (sized slightly differently) without them overlapping - this is an example of doing it with circles. But if the total number of those elements is low, then there’s a chance that the cluster will be very far apart from each other, and the overall density can be quite inconsitent. Is there a way to scatter similarly sized rectangles without overlapping and remains a minimum distance from each other, but is never too far away?
Ideally something like this:
And not this (which is the outcome if the only criteria is "no overlapping"):

You could translate to the centre before drawing the shapes and then give them a distance from the centre using the random function where the max value for random will be calculated according to the total number of elements. While doing this, you may also check for overlapping and call the random function again if any two objects overlap.

Related

Algorithm to decompose Polygons into lineStrings (Headlands from Plots)

Consider the following polygon (an agricultural plot)
From this polygon, I would like to extract the "headlands" of the plot, being the consecutive lines (sides) of the polygon (Wikipedia) used for turning on the field. While often only the rows running perpendicular to the lay of the field are considered, I need all sides of the polygon.
Here, a consecutive line means any set of coordinates, where the angle between any two coordinates of the set is not larger than a value X (e.g 30 degrees).
For the given example, the resulting headlands should look like the following:
I wrote a small algorithm trying to accomplish this, basically checking the angle between two coordinates and either pushing the given coordinate to the existing lineString if the angle is below X degrees or creating a new lineString (headland) if not.
Check out the following Gist
However, in some cases corners of a field are rounded, therefore may consist of many coordinates within small distances of each other. The relative angles then may be less than the value X, even though the corner is too sharp to actually be cultivated without turning.
In order to overcome that issue, I added an index that increases whenever a coordinate is too close for comparison, so that the next coordinate will be checked against the initial coordinate. Check out the following Gist.
This works for simple plots like the one in the example, however I am struggling with more complex ones as the following.
Here, the bottom headland is recognised as one lineString together with the headland on the right, even though optically a sharp corner is given. Also, two coordinates in the upper right corner were found to be a separate headland even though they should be connected to the right headland. The result should therefore yield in the following:
What I would like to know is if there is an approach that efficiently decomposes any polygon into it's headlands, given a specific turning angle. I set up a repo for the code here, and an online testing page with many examples here if that helps.

Threejs draw a shape from just points

Given a list of Vector3s in no order, I would like to create an ordering of the elements such that when I draw a Shape from those points, I will be outlining the shape without ever going across its face.
How would you do this? I think the first thing is to always pick the point closest to you, but what if more than one point have exactly the same distance from a point?
Let's call the point we're on x, and a potential "neighbor" (point whose distance to x is minimal) y where there can be multiple ys.
I've thought about these two approaches:
Find the center of mass by averaging out the positions of the points, then make sure that going from x to y never goes through the center. This approach has many problems like 1. it's not guaranteed to cross the CoM or 2. imagine a fidget spinner with just two circles, and one much smaller than the other. When tracing the smaller bit, the center of mass is never crossed (or come close to), but we might still ran into problems
Randomly pick any other three points, and make sure that y is not within the triangle created. But there are cases where y is the correct choice, but still falls within the triangle (imagine a shape one of whose edge is created by two tangent circles).
Any help would be much appreciated!

Position resizable circles near each other

I am working on this browser-based experiment where i am given N specific circles (let's say they have a unique picture in them) and need to position them together, leaving as little space between them as possible. It doesn't have to be arranged in a circle, but they should be "clustered" together.
The circle sizes are customizable and a user will be able to change the sizes by dragging a javascript slider, changing some circles' sizes (for example, in 10% of the slider the circle 4 will have radius of 20px, circle 2 10px, circle 5 stays the same, etc...). As you may have already guessed, i will try to "transition" the resizing-repositioning smoothly when the slider is being moved.
The approach i have tried tried so far: instead of manually trying to position them i've tried to use a physics engine-
The idea:
place some kind of gravitational pull in the center of the screen
use a physics engine to take care of the balls collision
during the "drag the time" slider event i would just set different
ball sizes and let the engine take care of the rest
For this task i have used "box2Dweb". i placed a gravitational pull to the center of the screen, however, it took a really long time until the balls were placed in the center and they floated around. Then i put a small static piece of ball in the center so they would hit it and then stop. It looked like this:
The results were a bit better, but the circles still moved for some time before they went static. Even after playing around with variables like the ball friction and different gravitational pulls, the whole thing just floated around and felt very "wobbly", while i wanted the balls move only when i drag the time slider (when they change sizes). Plus, box2d doesn't allow to change the sizes of the objects and i would have to hack my way for a workaround.
So, the box2d approach made me realize that maybe to leave a physics engine to handle this isn't the best solution for the problem. Or maybe i have to include some other force i haven't thought of. I have found this similar question to mine on StackOverflow. However, the very important difference is that it just generates some n unspecific circles "at once" and doesn't allow for additional specific ball size and position manipulation.
I am really stuck now, does anyone have any ideas how to approach this problem?
update: it's been almost a year now and i totally forgot about this thread. what i did in the end is to stick to the physics model and reset forces/stop in almost idle conditions. the result can be seen here http://stateofwealth.net/
the triangles you see are inside those circles. the remaining lines are connected via "delaunay triangulation algorithm"
I recall seeing a d3.js demo that is very similar to what you're describing. It's written by Mike Bostock himself: http://bl.ocks.org/mbostock/1747543
It uses quadtrees for fast collision detection and uses a force based graph, which are both d3.js utilities.
In the tick function, you should be able to add a .attr("r", function(d) { return d.radius; }) which will update the radius each tick for when you change the nodes data. Just for starters you can set it to return random and the circles should jitter around like crazy.
(Not a comment because it wouldn't fit)
I'm impressed that you've brought in Box2D to help with the heavy-lifting, but it's true that unfortunately it is probably not well-suited to your requirements, as Box2D is at its best when you are after simulating rigid objects and their collision dynamics.
I think if you really consider what it is that you need, it isn't quite so much a rigid body dynamics problem at all. You actually want none of the complexity of box2d as all of your geometry consists of spheres (which I assure you are vastly simpler to model than arbitrary convex polygons, which is what IMO Box2D's complexity arises from), and like you mention, Box2D's inability to smoothly change the geometric parameters isn't helping as it will bog down the browser with unnecessary geometry allocations and deallocations and fail to apply any sort of smooth animation.
What you are probably looking for is an algorithm or method to evolve the positions of a set of coordinates (each with a radius that is also potentially changing) so that they stay separated by their radii and also minimize their distance to the center position. If this has to be smooth, you can't just apply the minimal solution every time, as you may get "warping" as the optimal configuration might shift dramatically at particular points along your slider's movement. Suffice it to say there is a lot of tweaking for you to do, but not really anything scarier than what one must contend with inside of Box2D.
How important is it that your circles do not overlap? I think you should just do a simple iterative "solver" that first tries to bring the circles toward their target (center of screen?), and then tries to separate them based on radii.
I believe if you try to come up with a simplified mathematical model for the motion that you want, it will be better than trying to get Box2D to do it. Box2D is magical, but it's only good at what it's good at.
At least for me, seems like the easiest solution is to first set up the circles in a cluster. So first set the largest circle in the center, put the second circle next to the first one. For the third one you can just put it next to the first circle, and then move it along the edge until it hits the second circle.
All the other circles can follow the same method: place it next to an arbitrary circle, and move it along the edge until it is touching, but not intersecting, another circle. Note that this won't make it the most efficient clustering, but it works. After that, when you expand, say, circle 1, you'd move all the adjacent circles outward, and shift them around to re-cluster.

expressing point position within a circle as a percentage of arbitrary segments

Ok, so... here's what I'm trying to do. In HTML/JS. With a math knowledge that would embarrass a twelve-year old.
With, say, 20 checkboxes on a page, the user picks.. five of them. A circle then appears on the page (I'd anticipate using one of the canvas libraries like Raphael) with their five answers arranged around it. So that's the first thing I don't know how to do; split a circle into x equal segments. Strange, foreign terms like "cos" and "sin" are looming on the horizon.
But then it gets even more fun: the user can click a point on the circle. And that point is translated into some sort of percentage value for each of the segments. So if the user checks Happy, Grumpy, Sneezy, Dopey and Bashful, and clicks the circle, I can tell them that they're 37% Happy, 42% Dopey and 21% Sneezy.
The best analogy is probably a colour-picker wheel, but I can't find any JS ones that I could repurpose. A pie chart is close - and there's a nice Raphael demo - but I've got a feeling that the fixed boundaries of a pie chart segment is going to take me down the wrong route for estimating percentage positions within the circle as a whole.
So, given my vague and poorly thought out request, and the noticeable absence of any "here's what I've tried so far" code - because I don't have the foggiest where to even start, apart from high school trigonometry books, can anyone suggest any code libraries or snippets that might get me at least pointing in the right direction?
Thanks :)
========================
Edit :
Wow, thanks for all the answers. I'll try to refine the question/s a bit:
I'm going to need to draw a circle with x number of points arranged equally around its circumference. The number of points will correlate to the number of checkboxes that the user checked.
That's the first bit I'm stuck on: I reckon that I can draw a circle, with dimensions and at a position on the page of my own choosing, (using Raphael or similar canvas library) but how can I calculate what the x/y pixel coordinates of those points should be on the circle circumference?
The second bit: the user then clicks anywhere in the circle. I guess what I'd do is calculate how far each of the circumference points are from that user click point - I'm not sure how to do that, apart from a vague suspicion it involves imaginary triangles - and then how much of a total distance each of those distances are. That last bit, at least, I can manage.
Actually, this is starting to make sense. I'm still not sure how the trig stuff works but it's amazing what typing your problem out so that strangers will understand it can do to help your own understanding...
You need to revise your question to explain more clearly what you are trying to do. In the meantime, I can give you the following information that may help you get started.
First of all, you'll need to know the locations of the five checkboxes that the user selects. In order to do this, the jQuery library offers some convenient functions such as $.position and $.offset.
Your question does not make clear exactly how the circle you want to draw is positioned in relation to the five checkboxes that the user clicks. As for actually drawing the circle, you may want to use something like the HTML5 canvas element. I've not yet used it myself, so I can't tell you much about it.
You might want to try asking another question on StackOverflow about how to draw a circle on your web page once you've computed the center and radius of the circle.
As for doing the math about the circle, you need to know that a circle can be parameterized on an x-y plane by the following equations:
x = x0 + r cos(theta)
y = y0 + r sin(theta)
where (x0,y0) is the center of the circle, r is the radius of the circle, and theta ranges over 0 to 2*Pi radians (0 to 360 degrees)
Let us know more about what you're doing and we can give you some more specific information.

How can I (somewhat) evenly distribute dynamically-sized SVG shapes within a canvas?

I'm looking for some high-level recommendations for how to implement a project I'm starting for a client.
This is a web page that will include an SVG canvas (sized 920px W x 450px H) containing 20-40 "circular" images (i.e., they may just be square images cropped with a circle). The size of the images will probably range from about 50px to about 200px diameter, each one set dynamically within that range based on data from an API. It's basically a dynamic data visualization, so pretty much every aspect of this needs to be configurable/dynamic.
I think the hardest problem to solve is how to distribute these images within the given canvas area, considering that they will vary in size, and should appear to be evenly/randomly distributed (i.e., they shouldn't line up to a grid, be clumped together, or be in groups of similar sizes). It's OK if they overlap slightly. Here's a quick sketch of how this should look, ideally (each gray circle represents an image):
https://skitch.com/troywarr/gwj14/adobe-fireworks-cs5
FWIW, I was planning to use Raphaël as an SVG library; I'll also have jQuery available and can probably use any other libraries as needed. This needs to be cross-browser compatible back to IE7.
Can anyone suggest a general approach to this problem, any specific libraries or algorithms to look into, or provide any other guidance or suggestions? Please let me know if this description isn't clear, or if you need any additional details.
Thanks in advance!
Here is how I would tackle it:
First decide on the percentage of the screen that will be filled in with circles and the number of circles that will be displayed. You can use that to determine the average radius of each circle using the area of a circle formula - e.g. given x circles what would the average radius of all the circles have to be to cover y% of my container. You can then decide how much you want the radius to vary, that is +/- 50%. Unless the number of circles is very small you should get a good result - statistically that is.
Then I would divide the screen in to a rectangular grid - I know that is not what you want just be patient :) The dimensions of the grid are calculable from the number of circles, e.g. 16 circles would fit nicely into a 4 X 4 grid. The number of circles can be less than the number of cells but not a lot less.
I would then select a random x,y co-ordinate inside each grid cell as my circle's center. I would also leave a padding of about 25% around the edges so that my circle is not centered too close to an edge.
You could then check for overlap - the ratio of (r1 + r2) / distance between the circle center points will equal 1 if the circles touch, be less than 1 if they don't and greater than 1 if they overlap. A ratio of 1.1 is a small overlap; careful of the limit here - exact same centers result in a distance of 0 and a division by 0 error.
One thing to worry about but should not happen unless you pick a very high initial coverage percentage or the number if circles is much smaller than the number of cells. If all the cells adjacent to a given cell have circles close to that cells edges, especially if they overlap the edge, there may not be enough room (even with circle overlap) for the current cell's circle. This can be checked for and handled by shrinking the radius or moving a circle away...
NOTE if the number of desired circle's does not exactly match your square (or rectangular) grid, just randomly leave some cells empty...
Here's a rough description of the approach I took after all. Sorry, pressed for time so this may be inexact.
I initially approached the problem similarly to #BigMac66's answer. I laid out a grid corresponding to the quantity of circles I had, drew a circle in each and then randomly shifted the circles from the center point of each grid cell.
I built in a variety of "fudge factors" - circle radius bounds, offset from center, maximum overlap with adjacent cells, etc. - but, no matter how I tweaked my settings, you could still always tell that a grid was behind the layout; the circles aligned just enough to look like a wonky polka dot pattern rather than a truly random collection of circles.
So, I changed to a more brute-force approach.
First, I set up configurable bounds for the radius of a circle, tweaking the upper bound until I found a maximum size that didn't make the canvas look crowded based on the total number of circles I had.
Then, I applied my math to size the circles as needed (in short, the largest circles represented a 100% value, and the smallest represented a 0% value; the rest were sized accordingly based on where they fell in the spectrum).
Then, I sorted the circles descending by size. I laid them out randomly on the canvas, using an algorithm roughly like so:
Place a circle at random coordinates.
Place the next circle at random coordinates.
If the latter circle overlaps the former by more than X pixels (configurable param), place it at a new set of random coordinates.
Continue step #3 for up to Y times (another configurable param) until you successfully place another circle.
If you can't place the circle in Y times, clear the canvas, drop the maximum circle radius by Z pixels (another configurable param) and start over.
This worked surprisingly well, and I tweaked the params until I could draw the entire canvas very quickly while requiring few maximum circle radius reductions.
You can actually see the finished product here:
http://www.eonline.com/news/2012_sag_awards/heatgauge
It's out of season, so click the "Overall View" tab at the top of the main box to see cumulative stats (and hence a full canvas of circles).

Categories

Resources