Calculate circle coordinates in a sequential fashion
I need to have all point coordinates for a given circle one after another, so I can make an object go in circles by hopping from one point to the next. I tried the Midpoint circle algorithm, but the version I found is meant to draw and the coordinates are not sequential. They are produced simultaneously for 8 quadrants and in opposing directions on top of that. If at least they were in the same direction, I could make a separate array for every quadrant and append them to one another at the end. This is the JavaScript adapted code I have now:
function calcCircle(centerCoordinates, radius) {
var coordinatesArray = new Array();
// Translate coordinates
var x0 = centerCoordinates.left;
var y0 = centerCoordinates.top;
// Define variables
var f = 1 - radius;
var ddFx = 1;
var ddFy = -radius << 1;
var x = 0;
var y = radius;
coordinatesArray.push(new Coordinates(x0, y0 + radius));
coordinatesArray.push(new Coordinates(x0, y0 - radius));
coordinatesArray.push(new Coordinates(x0 + radius, y0));
coordinatesArray.push(new Coordinates(x0 - radius, y0));
// Main loop
while (x < y) {
if (f >= 0) {
y--;
ddFy += 2;
f += ddFy;
}
x++;
ddFx += 2;
f += ddFx;
coordinatesArray.push(new Coordinates(x0 + x, y0 + y));
coordinatesArray.push(new Coordinates(x0 - x, y0 + y));
coordinatesArray.push(new Coordinates(x0 + x, y0 - y));
coordinatesArray.push(new Coordinates(x0 - x, y0 - y));
coordinatesArray.push(new Coordinates(x0 + y, y0 + x));
coordinatesArray.push(new Coordinates(x0 - y, y0 + x));
coordinatesArray.push(new Coordinates(x0 + y, y0 - x));
coordinatesArray.push(new Coordinates(x0 - y, y0 - x));
}
// Return the result
return coordinatesArray;
}
I prefer some fast algorithm without trigonometry, but any help is appreciated!
EDIT
This is the final solution. Thanks everybody!
function calcCircle(centerCoordinates, radius) {
var coordinatesArray = new Array();
var octantArrays =
{oct1: new Array(), oct2: new Array(), oct3: new Array(), oct4: new Array(),
oct5: new Array(), oct6: new Array(), oct7: new Array(), oct8: new Array()};
// Translate coordinates
var xp = centerCoordinates.left;
var yp = centerCoordinates.top;
// Define add coordinates to array
var setCrd =
function (targetArray, xC, yC) {
targetArray.push(new Coordinates(yC, xC));
};
// Define variables
var xoff = 0;
var yoff = radius;
var balance = -radius;
// Main loop
while (xoff <= yoff) {
// Quadrant 7 - Reverse
setCrd(octantArrays.oct7, xp + xoff, yp + yoff);
// Quadrant 6 - Straight
setCrd(octantArrays.oct6, xp - xoff, yp + yoff);
// Quadrant 3 - Reverse
setCrd(octantArrays.oct3, xp - xoff, yp - yoff);
// Quadrant 2 - Straight
setCrd(octantArrays.oct2, xp + xoff, yp - yoff);
// Avoid duplicates
if (xoff != yoff) {
// Quadrant 8 - Straight
setCrd(octantArrays.oct8, xp + yoff, yp + xoff);
// Quadrant 5 - Reverse
setCrd(octantArrays.oct5, xp - yoff, yp + xoff);
// Quadrant 4 - Straight
setCrd(octantArrays.oct4, xp - yoff, yp - xoff);
// Quadrant 1 - Reverse
setCrd(octantArrays.oct1, xp + yoff, yp - xoff);
}
// Some weird stuff
balance += xoff++ + xoff;
if (balance >= 0) {
balance -= --yoff + yoff;
}
}
// Reverse counter clockwise octant arrays
octantArrays.oct7.re开发者_如何学JAVAverse();
octantArrays.oct3.reverse();
octantArrays.oct5.reverse();
octantArrays.oct1.reverse();
// Remove counter clockwise octant arrays last element (avoid duplicates)
octantArrays.oct7.pop();
octantArrays.oct3.pop();
octantArrays.oct5.pop();
octantArrays.oct1.pop();
// Append all arrays together
coordinatesArray =
octantArrays.oct4.concat(octantArrays.oct3).concat(octantArrays.oct2).concat(octantArrays.oct1).
concat(octantArrays.oct8).concat(octantArrays.oct7).concat(octantArrays.oct6).concat(octantArrays.oct5);
// Return the result
return coordinatesArray;
}
Use can try the following approach: use the algorithm you gave but push your coordinates to eight different coordinateArrays. Afterwards you have to reverse half of them (those with (x0+x,y0-y), (x0-x,y0+y), (x0+y,y0+x), (x0-y,y0-x)) and afterwards append all arrays in the correct order. Take care that you add the first four points to the correct arrays.
As far as I know, you cannot do it without trigonometry, but it works pretty fast for me. Sorry I'm not familiar with Java, so I write the code in VB:
Dim PointList As New List(Of PointF)
For angle = 0 To Math.PI * 2 Step 0.01
'the smaller the step, the more points you get
PointList.Add(New PointF(Math.Cos(angle) * r + x0, Math.Sin(angle) * r + y0))
Next
x0 and y0 are the center coordinates of the circle, r is the radius.
Hope I answered your question.
Here is a javascript implementation based on Dave's answer. A bit over-engineered, I wanted to avoid calling sin and cos more than necessary. Ironically making use of Dave's first answer without the radius :)
function calculateCircle(x,y,radius) {
var basicPoints = getBasicCircle();
var i = basicPoints.length;
var points = []; // don't change basicPoints: that would spoil the cache.
while (i--) {
points[i] = {
x: x + (radius * basicPoints[i].x),
y: y + (radius * basicPoints[i].y)
};
}
return points;
}
function getBasicCircle() {
if (!arguments.callee.points) {
var points = arguments.callee.points = [];
var end = Math.PI * 2;
for (var angle=0; angle < end; angle += 0.1) {
points.push({x: Math.sin(angle),
y: Math.cos(angle)
});
}
}
return arguments.callee.points
}
精彩评论