So I have my circle drawn already, it has a radius of 140. Should I use r.randint(-140,140) to throw a random dot? and how do I make it seen in the circle(turtle graphic)?
You will need to verify that the point is actually inside your circle before you draw it, the point (-140,-140) isn't inside the circle for example but could be generated by (randint(-140,140), randint(-140,140)).
The common way of doing this is to loop until you get a result that fits your restrictions, in your case that its distance from (0,0) is less than the radius of the circle:
import math, random
def get_random_point(radius):
while True:
# Generate the random point
x = random.randint(-radius, radius)
y = random.randint(-radius, radius)
# Check that it is inside the circle
if math.sqrt(x ** 2 + y ** 2) < radius:
# Return it
return (x, y)
A non-looping variant:
import math, random, turtle
turtle.radians()
def draw_random_dot(radius):
# pick random direction
t = random.random() * 2 * math.pi
# ensure uniform distribution
r = 140 * math.sqrt(random.random())
# draw the dot
turtle.penup()
turtle.left(t)
turtle.forward(r)
turtle.dot()
turtle.backward(r)
turtle.right(t)
for i in xrange(1000): draw_random_dot(140)
It depends on where the beginning of the coordinate system is. If zeros start in the left upper conner of the picture, while loop is needed to make sure that dots are being placed within the circle's boundaries. If xy coordinates start in the center of the circle then the placement of the dots is limited by the circle's radius. I made a script for Cairo. It is not too too off topic. https://rockwoodguelph.wordpress.com/2015/06/12/circle/
Related
I would like to move my image by one pixel in the direction on specific point. Right now I have:
My image cords:
position.x
position.y
Coordinates of the point where I want to move:
dest.x
dest.y
And the angle at which I must move to reach the designated place:
angle
How should you calculate for each step add / subtract 1 for x and y?
If you want to move only in increments of 1 pixel in x or y at a time, it sounds like the coordinates you want correspond with the pixels on a straight line from source to destination. A common algorithm for drawing a pixellated straight line is the Bresenham algorithm:
https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
So instead of drawing pixels, you could use the coordinates to position your image.
Assuming the angle is in radians, use trigonometry:
import math
x += math.cos(angle) * amount_to_move
y += math.sin(angle) * amount_to_move
First of all, will appreciate if someone will give me a proper term for "annulus with a shifted hole", see exactly what kind of shape I mean on a picture below.
Back to main question: I want to pick a random point in the orange area, uniform distribution is not required. For a case of a usual annulus I would've picked random point in (r:R) range and a random angle, then transform those to x,y and it's done. But for this unusual shape... is there even a "simple" formula for that, or should I approach it by doing some kind of polygonal approximation of a shape?
I'm interested in a general approach but will appreciate an example in python, javascript or any coding language of your choice.
Here's a simple method that gives a uniform distribution with no resampling.
For simplicity assume that the center of the outer boundary circle (radius r_outer) is at (0, 0) and that the center of the inner circular boundary (radius r_inner) lies at (x_inner, y_inner).
Write D for the outer disk, H1 for the subset of the plane given by the off-center inner hole, and H2 for the central disk of radius r_inner, centered at (0, 0).
Now suppose that we ignore the fact that the inner circle is not central, and instead of sampling from D-H1 we sample from D-H2 (which is easy to do uniformly). Then we've made two mistakes:
there's a region A = H1 - H2 that we might sample from, even though those samples shouldn't be in the result.
there's a region B = H2 - H1 that we never sample from, even though we should
But here's the thing: the regions A and B are congruent: given any point (x, y) in the plane, (x, y) is in H2 if and only if (x_inner - x, y_inner - y) is in H1, and it follows that (x, y) is in A if and only if (x_inner - x, y_inner - y) is in B! The map (x, y) -> (x_inner - x, y_inner - y) represents a rotation by 180 degress around the point (0.5*x_inner, 0.5*y_inner). So there's a simple trick: generate from D - H2, and if we end up with something in H1 - H2, rotate to get the corresponding point of H2 - H1 instead.
Here's the code. Note the use of the square root of a uniform distribution to choose the radius: this is a standard trick. See this article, for example.
import math
import random
def sample(r_outer, r_inner, x_inner, y_inner):
"""
Sample uniformly from (x, y) satisfiying:
x**2 + y**2 <= r_outer**2
(x-x_inner)**2 + (y-y_inner)**2 > r_inner**2
Assumes that the inner circle lies inside the outer circle;
i.e., that hypot(x_inner, y_inner) <= r_outer - r_inner.
"""
# Sample from a normal annulus with radii r_inner and r_outer.
rad = math.sqrt(random.uniform(r_inner**2, r_outer**2))
angle = random.uniform(-math.pi, math.pi)
x, y = rad*math.cos(angle),rad*math.sin(angle)
# If we're inside the forbidden hole, reflect.
if math.hypot(x - x_inner, y - y_inner) < r_inner:
x, y = x_inner - x, y_inner - y
return x, y
And an example plot, generated by the following:
import matplotlib.pyplot as plt
samples = [sample(5, 2, 1.0, 2.0) for _ in range(10000)]
xs, ys = zip(*samples)
plt.scatter(xs, ys, s=0.1)
plt.axis("equal")
plt.show()
Do you really need exact sampling? Because with acceptance/rejection it should work just fine. I assume big orange circle is located at (0,0)
import math
import random
def sample_2_circles(xr, yr, r, R):
"""
R - big radius
r, xr, yr - small radius and its position
"""
x = xr
y = yr
cnd = True
while cnd:
# sample uniformly in whole orange circle
phi = 2.0 * math.pi * random.random()
rad = R * math.sqrt(random.random())
x = rad * math.cos(phi)
y = rad * math.sin(phi)
# check condition - if True we continue in the loop with sampling
cnd = ( (x-xr)**2 + (y-yr)**2 < r*r )
return (x,y)
Since you have shown no equation, algorithm, or code of your own, but just an outline of an algorithm for center-aligned circles, I'll also just give the outline of an algorithm here for the more general case.
The smaller circle is the image of the larger circle under a similarity transformation. I.e. there is a fixed point in the larger circle and a ratio (which is R/r, greater than one) such that you can take any point on the smaller circle, examine the vector from the fixed point to that point, and multiply that vector by the ratio, then the end of that vector when it starts from the fixed point is a point on the larger circle. This transformation is one-to-one.
So you can choose a random point on the smaller circle (choose the angle at random between 0 and two-pi) and choose a ratio at random between 1 and the proportionality ratio R/r between the circles. Then use that the similarity transformation with the same fixed point but using the random ratio to get the image point of the just-chosen point on the smaller circle. This is a random point in your desired region.
This method is fairly simple. In fact, the hardest mathematical part is finding the fixed point of the similarity transformation. But this is pretty easy, given the centers and radii of the two circles. Hint: the transformation takes the center of the smaller circle to the center of the larger circle.
Ask if you need more detail. My algorithm does not yield a uniform distribution: the points will be more tightly packed where the circles are closest together and less tightly packed where the circles are farthest apart.
Here is some untested Python 3.6.2 code that does the above. I'll test it and show a graphic for it when I can.
import math
import random
def rand_pt_between_circles(x_inner,
y_inner,
r_inner,
x_outer,
y_outer,
r_outer):
"""Return a random floating-point 2D point located between the
inner and the outer circles given by their center coordinates and
radii. No error checking is done on the parameters."""
# Find the fixed point of the similarity transformation from the
# inner circle to the outer circle.
x_fixed = x_inner - (x_outer - x_inner) / (r_outer - r_inner) * r_inner
y_fixed = y_inner - (y_outer - y_inner) / (r_outer - r_inner) * r_inner
# Find a a random transformation ratio between 1 and r_outer / r_inner
# and a random point on the inner circle
ratio = 1 + (r_outer - r_inner) * random.random()
theta = 2 * math.pi * random.random()
x_start = x_inner + r_inner * math.cos(theta)
y_start = y_inner + r_inner * math.sin(theta)
# Apply the similarity transformation to the random point.
x_result = x_fixed + (x_start - x_fixed) * ratio
y_result = y_fixed + (y_start - y_fixed) * ratio
return x_result, y_result
The acceptance/rejection method as described by Severin Pappadeux is probably the simplest.
For a direct approach, you can also work in polar coordinates, with the center of the hole as the pole.
The polar equation (Θ, σ) (sorry, no rho) of the external circle will be
(σ cosΘ - xc)² + (σ sinΘ - yc)² = σ² - 2(cosΘ xc + sinΘ yc)σ + xc² + yc² = R²
This is a quadratic equation in σ, that you can easily solve in terms of Θ. Then you can draw an angle in 0, 2π an draw a radius between r and σ.
This won't give you a uniform distribution, because the range of σ is a function of Θ and because of the polar bias. This might be fixed by computing a suitable transfer function, but this is a little technical and probably not tractable analytically.
I have some points that are located in the same place, with WGS84 latlngs, and I want to 'jitter' them randomly so that they don't overlap.
Right now I'm using this crude method, which jitters them within a square:
r['latitude'] = float(r['latitude']) + random.uniform(-0.0005, 0.0005)
r['longitude'] = float(r['longitude']) + random.uniform(-0.0005, 0.0005)
How could I adapt this to jitter them randomly within a circle?
I guess I want a product x*y = 0.001 where x and y are random values. But I have absolutely no idea how to generate this!
(I realise that really I should use something like this to account for the curvature of the earth's surface, but in practice a simple circle is probably fine :) )
One simple way to generate random samples within a circle is to just generate square samples as you are, and then reject the ones that fall outside the circle.
The basic idea is, you generate a vector with x = radius of circle y = 0.
You then rotate the vector by a random angle between 0 and 360, or 0 to 2 pi radians.
You then apply this displacement vector and you have your random jitter in a circle.
An example from one of my scripts:
def get_randrad(pos, radius):
radius = random() * radius
angle = random() * 2 * pi
return (int(pos[0] + radius * cos(angle)),
int(pos[1] + radius * sin(angle)))
pos beeing the target location and radius beeing the "jitter" range.
As pjs pointed out, add
radius *= math.sqrt(random())
for uniform distribution
Merely culling results that fall outside your circle will be sufficient.
If you don't want to throw out some percentage of random results, you could choose a random angle and distance, to ensure all your values fall within the radius of your circle. It's important to note, with this solution, that the precision of the methods you use to extrapolate an angle into a vector will skew your distribution to be more concentrated in the center.
If you make a vector out of your x,y values, and then do something like randomize the length of said vector to fall within your circle, your distribution will no longer be uniform, so I would steer clear of that approach, if uniformity is your biggest concern.
The culling approach is the most evenly distributed, of the three I mentioned, although the random angle/length approach is usually fine, except in cases involving very fine precision and granularity.
I have to write a program in Python that reads the value n and draws a polygon of n sides on the screen. I can use either the turtle graphics module or graphics.py module.
I know how to draw a polygon when n = the number of points you input and then click n times on the screen, but I'm having some trouble getting an idea on how to transform a number of sides into a polygon.
Here's the code I have for the polygon with n number of points:
def newPolygon(self,cmd):
p = eval(input("how many points"))
print("click",p,"times")
num = []
for i in range(p):
vertices = self.win.getMouse()
num.append(vertices)
poly = Polygon(num)
poly.setFill(self.color)
poly.draw(self.win)
self.figs.append(poly)
This isn't the whole code to the program(which is 384 lines). This is just the part of the program where the draw polygon function is where self.figs = [ ] , a list of drawn figures.
I'm assuming what you would like is a way of generating equal sided polygon coordinates which you can feed to your drawing program. I'm not sure which library you are using, so I'm going to stick to lists of pairs of values:
import math
def polygon(sides, radius=1, rotation=0, translation=None):
one_segment = math.pi * 2 / sides
points = [
(math.sin(one_segment * i + rotation) * radius,
math.cos(one_segment * i + rotation) * radius)
for i in range(sides)]
if translation:
points = [[sum(pair) for pair in zip(point, translation)]
for point in points]
return points
There's a fair bit going on in there, so I'll talk through it. The basic approach is to sweep out a circle, and put n equally spaced points on it. These will be the points of our polygon, starting at the 12 'o' clock position.
The first thing to do is work out the angle (in radians) of each wedge from the center outwards. The total number of radians in a circle is 2 pi, so our value is 2 pi / n per segment.
After that a bit of basic trig gives us our points (https://en.wikipedia.org/wiki/Trigonometry#Extending_the_definitions). At this point we scale by our desired radius, and have the opportunity to offset the rotation by a fixed amount too.
After that we translate the values by a certain amount, because you probably want your polygon in the center of the screen, not in the corner.
A few examples
print polygon(5) # A unit pentagon
# [(0.0, 1.0), (0.9510565162951535, 0.30901699437494745), (0.5877852522924732, -0.8090169943749473), (-0.587785252292473, -0.8090169943749476), (-0.9510565162951536, 0.30901699437494723)]
print polygon(4, 100) # A square, point up, 100 from the center to the points
# [(0.0, 100.0), (100.0, 6.123233995736766e-15), (1.2246467991473532e-14, -100.0), (-100.0, -1.8369701987210297e-14)]
print polygon(4, 2, math.pi / 4, [10, 10]) # A flat square centered on 10, 10
# [[11.414213562373096, 11.414213562373096], [11.414213562373096, 8.585786437626904], [8.585786437626904, 8.585786437626904], [8.585786437626904, 11.414213562373094]]
As you can see, these are all floats, so you may need to squish these to integers before you can use them.
I don't know if this will help but to define a polygon using number of sides and length then I would use my code:
import turtle as t
def polygon(n,l):
f = (n - 2) * 180/n
for i in range(n):
t.forward(l)
t.right(180 - f)
polygon()
In this case, n would be number of sides and l would be length of sides.
This took me quite a while as I am only 13 and am not advanced but this was a fun project!
I am trying to create a map editor. I intend the map to be an hexagonal grid where each hexagon is a tile of the map. A tile will be a graphical representation of that area (sea, meadow, desert, mountain, etc). The map is intended to be of any size. Let's freeze the requirements here for now :)
I want to use PyQt4 (take it as a design requirement). As I am just starting with Qt/PyQt, I am facing the problem of vastness: so big this Qt thing that I cannot grasp it all. And here I am, asking for your kind and most welcome experience.
After a bit of googling, I've decided to use the QGraphicalView/Scene approach. In fact, I was thinking about creating my own hexgrid class inheriting from QGraphicalView and creating my RegularPolygon class inheriting from QGraphicalPolygonItem.
Now they come the doubts and problems.
My main doubt is "Is my approach a correct one?" Think about the needs I have explained at the beginning of the post: hexagonal map, where each hexagon will be a tile of a given type (sea, desert, meadows, mountains, etc). I am concerned about performance once the editor works (scrolling will feel nice? and this kind of things).
And so far, the problem is about precision. I am drawing the hexgrid by creating and drawing all its hexagons (this even sounds bad to me... thinking about performance). I used some formulas to calculate the vertices of each hexagon and creating the polygon from there. I expect the sides of two consecutive hexagons to coincide exactly at the same location, but the rounding seems to be playing a bit with my desires, as sometimes the hexagon sides perfectly matches in the same location (good) and sometimes they do not match by what seems to be 1 pixel difference (bad). This gives a poor visual impression of the grid. Maybe I have not explained myself quite well... it's better if I give you the code and you run it by yourselves
So summarizing:
Do you think my approach will give future performance issues?
Why are not the hexagons placed exactly so that they share sides? How to avoid this problem?
The code:
#!/usr/bin/python
"""
Editor of the map.
"""
__meta__ = \
{
(0,0,1): (
[ "Creation" ],
[ ("Victor Garcia","vichor#xxxxxxx.xxx") ]
)
}
import sys, math
from PyQt4 import QtCore, QtGui
# ==============================================================================
class HexGrid(QtGui.QGraphicsView):
"""
Graphics view for an hex grid.
"""
# --------------------------------------------------------------------------
def __init__(self, rect=None, parent=None):
"""
Initializes an hex grid. This object will be a GraphicsView and it will
also handle its corresponding GraphicsScene.
rect -- rectangle for the graphics scene.
parent -- parent widget
"""
super(HexGrid,self).__init__(parent)
self.scene = QtGui.QGraphicsScene(self)
if rect != None:
if isinstance(rect, QtCore.QRectF): self.scene.setSceneRect(rect)
else: raise StandardError ('Parameter rect should be QtCore.QRectF')
self.setScene(self.scene)
# ==============================================================================
class QRegularPolygon(QtGui.QGraphicsPolygonItem):
"""
Regular polygon of N sides
"""
def __init__(self, sides, radius, center, angle = None, parent=None):
"""
Initializes an hexagon of the given radius.
sides -- sides of the regular polygon
radius -- radius of the external circle
center -- QPointF containing the center
angle -- offset angle in radians for the vertices
"""
super(QRegularPolygon,self).__init__(parent)
if sides < 3:
raise StandardError ('A regular polygon at least has 3 sides.')
self._sides = sides
self._radius = radius
if angle != None: self._angle = angle
else: self._angle = 0.0
self._center = center
points = list()
for s in range(self._sides):
angle = self._angle + (2*math.pi * s/self._sides)
x = center.x() + (radius * math.cos(angle))
y = center.y() + (radius * math.sin(angle))
points.append(QtCore.QPointF(x,y))
self.setPolygon( QtGui.QPolygonF(points) )
# ==============================================================================
def main():
"""
That's it: the main function
"""
app = QtGui.QApplication(sys.argv)
grid = HexGrid(QtCore.QRectF(0.0, 0.0, 500.0, 500.0))
radius = 50
sides = 6
apothem = radius * math.cos(math.pi/sides)
side = 2 * apothem * math.tan(math.pi/sides)
xinit = 50
yinit = 50
angle = math.pi/2
polygons = list()
for x in range(xinit,xinit+20):
timesx = x - xinit
xcenter = x + (2*apothem)*timesx
for y in range(yinit, yinit+20):
timesy = y - yinit
ycenter = y + ((2*radius)+side)*timesy
center1 = QtCore.QPointF(xcenter,ycenter)
center2 = QtCore.QPointF(xcenter+apothem,ycenter+radius+(side/2))
h1 = QRegularPolygon(sides, radius, center1, angle)
h2 = QRegularPolygon(sides, radius, center2, angle)
# adding polygons to a list to avoid losing them when outside the
# scope (loop?). Anyway, just in case
polygons.append(h1)
polygons.append(h2)
grid.scene.addItem(h1)
grid.scene.addItem(h2)
grid.show()
app.exec_()
# ==============================================================================
if __name__ == '__main__':
main()
and last but not least, sorry for the long post :)
Thanks
Victor
Personally, I'd define each hexagonal tile as a separate SVG image, and use QImage and QSvgRenderer classes to render them to QPixmaps (with an alpha channel) whenever the zoom level changes. I'd create a QGraphicsItem subclass for displaying each tile.
The trick is to pick the zoom level so that the width of the (upright) hexagon is a multiple of two, and the height a multiple of four, with width/height approximately sqrt(3/4). The hexagons are slightly squished in either direction, but for all hexagons at least eight pixels in diameter, the effect is inperceptible.
If the width of the hexagon is 2*w, and height 4*h, here's how to map the (upright) hexagons to Cartesian coordinates:
If each side of the hexagon is a, then h=a/2 and w=a*sqrt(3)/2, therefore w/h=sqrt(3).
For optimum display quality, pick integer w and h, so that their ratio is approximately sqrt(3) ≃ 1.732. This means your hexagons will be very slightly squished, but that's okay; it is not perceptible.
Because the coordinates are now always integers, you can safely (without display artefacts) use pre-rendered hexagon tiles, as long as they have an alpha channel, and perhaps a border to allow smoother alpha transitions. Each rectangular tile is then 2*w+2*b pixels wide and 4*h+2*b pixels tall, where b is the number of extra border (overlapping) pixels.
The extra border is needed to avoid perceptible seams (background color bleeding through) where pixels are only partially opaque in all overlapping tiles. The border allows you to better blend the tile into the neighboring tile; something the SVG renderer will do automatically if you include a small border region in your SVG tiles.
If you use typical screen coordinates where x grows right and y down, then the coordinates for hexagon X,Y relative to the 0,0 one are trivial:
y = 3*h*Y
if Y is even, then:
x = 2*w*X
else:
x = 2*w*X + w
Obviously, odd rows of hexagons are positioned half a hexagon to the right.
Subclassing QGraphicsItem and using a bounding polygon (for mouse and interaction tests) means Qt will do all the heavy work for you, when you wish to know which hexagonal tile the mouse is hovering on top of.
However, you can do the inverse mapping -- from screen coordinates back to hexagons -- yourself.
First, you calculate which rectangular grid cell (green grid lines in the image above) the coordinate pair is in:
u = int(x / w)
v = int(y / h)
Let's assume all coordinates are nonnegative. Otherwise, % must be read as "nonnegative remainder, when divided by". (That is, 0 <= a % b < b for all a, even negative a; b is always a positive integer here.)
If the origin is as shown in the above image, then two rows out of every three are trivial, except that every odd row of hexagons is shifted one grid cell right:
if v % 3 >= 1:
if v % 6 >= 4:
X = int((u - 1) / 2)
Y = int(v / 3)
else:
X = int(u / 2)
Y = int(v / 3)
Every third row contains rectangular grid cells with a diagonal boundary, but worry not: if the boundary is \ (wrt. above image), you only need to check if
(x % w) * h >= (y % h) * w
to find out if you are in the upper right triangular part. If the boundary is / wrt. above image, you only need to check if
(x % w) * h + (y % h) * w >= (w * h - (w + h) / 2)
to find out if you are in the lower right triangular part.
In each four-column and six-row section of rectangular grid cells, there are eight cases that need to be handled, using one of the above test clauses. (I'm too lazy to work the exact if clauses for you here; like I said, I'd let Qt do that for me.) This rectangular region repeats exactly for the entire hexagonal map; thus, a full coordinate conversion may need up to 9 if clauses (depending on how you write it), so it's a bit annoying to write.
If you wish to determine e.g. the mouse cursor location relative to the hexagon it is hovering over, first use the above to determine which hexagon the mouse hovers over, then substract the coordinates of that hexagon from the mouse coordinates to get the coordinates relative to the current hexagon.
Try with this main() function. I used the radius of the inscribed circle (ri) instead of the circumscribed circle that you used (radius). It looks a bit better now, but still not perfect. I think the way the oblique sides are drawn at the top and bottom of the hexagon are different.
def main():
"""
That's it: the main function
"""
app = QtGui.QApplication(sys.argv)
grid = HexGrid(QtCore.QRectF(0.0, 0.0, 500.0, 500.0))
radius = 50 # circumscribed circle radius
ri = int(radius / 2 * math.sqrt(3)) # inscribed circle radius
sides = 6
apothem = int(ri * math.cos(math.pi/sides))
side = int(2 * apothem * math.tan(math.pi/sides))
xinit = 50
yinit = 50
angle = math.pi/2
polygons = list()
for x in range(xinit,xinit+20):
timesx = x - xinit
xcenter = x + (2*apothem-1)*timesx
for y in range(yinit, yinit+20):
timesy = y - yinit
ycenter = y + ((2*ri)+side)*timesy
center1 = QtCore.QPointF(xcenter,ycenter)
center2 = QtCore.QPointF(xcenter+apothem,ycenter+ri+(side/2))
h1 = QRegularPolygon(sides, ri, center1, angle)
h2 = QRegularPolygon(sides, ri, center2, angle)
# adding polygons to a list to avoid losing them when outside the
# scope (loop?). Anyway, just in case
polygons.append(h1)
polygons.append(h2)
grid.scene.addItem(h1)
grid.scene.addItem(h2)
grid.show()
app.exec_()
There are multiple problems here. They aren't specifically related to Qt or to Python, but to general computer science.
You have floating point geometrical shapes that you want to display on a raster device, so somehow there has to be a floating point to integer conversion. It's not in your code, so it will happen at a lower level: in the graphics library, the display driver or whatever. Since you're not happy with the result, you have to handle this conversion yourself.
There's no right or wrong way to do this. For example, take your case of a hex tile that has a “radius” of 50. The hexagon is oriented so that the W vertex is at (-50,0) and the E vertex is at (50,0). Now the NE vertex of this hexagon is at approximately (25,0,43.3). The hexagon that's adjacent to this one in the N direction has its center at about y=86.6 and its top edge at 129.9. How would you like to pixellate this? If you round 43.3 down to 43, now you no longer have a mathematically exact regular hexagon. If you round 129.9 up to 130, your first hexagon is 86 pixels in total height but the one on top of it is 87. This is an issue that you must resolve based on the project's requirements.
And this is just one case (radius=50). If you allow the radius to be variable, can you come up with an algorithm to handle all cases? I couldn't. I think you need to use a fixed screen dimension for your hexagons, or at least reduce the possibilities to a small number.
Nowhere in your code do you determine the size of the display window, so I don't understand how you intend to handle scaling issues, or determine how many hexes are needed to show the full map.
As to your first question, I am certain that the performance will be poor. The constructor for QRegularPolygon is inside the loop that creates the hexes, so it gets called many times (800 in your example). It does two trig calculations for each vertex, so you perform 9600 trig calculations as you build your list of hexes. You don't need ANY of them. The calculations are the sine and cosine of 0 degrees, 60 degrees, 120 degrees and so on. Those are so easy you don't even need sin and cos.
The use of the trig functions exacerbates the floating point/integer problem, too. Look at this:
>> int(50.0*math.sin(math.pi/6))
24
We know it should be 25, but the computer figures it as int(24.999999999996) – I may have left out a few 9's.
If you calculate the vertex positions of just one hexagon, you can get all the other ones by a simple translation. See the useful Qt functions QPolygon->translate or QPolygon->translated.
It seems that you don't need a constructor that can handle any type of polygon when your design concept absolutely needs hexagons. Did you just copy it from somewhere? I think it's mostly clutter, which always opens the door to errors.
Do you really need polygons here? Later on, I suppose, the game will use raster images, so the polygons are just for display purposes.
You could just take a point cloud representing all corners of the polygon and draw lines beneath them. With this, you avoid problems of rounding / floating point arithmetics etc.