- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试创建地图编辑器。我希望地图是一个六边形网格,其中每个六边形都是地图的图块。图块将是该区域(海洋,草地,沙漠,山脉等)的图形表示。该地图的大小不限。让我们暂时冻结需求:)
我想使用PyQt4(将其作为设计要求)。当我刚开始使用Qt / PyQt时,我面临着一个巨大的问题:这个Qt太大了,我无法全部掌握。我在这里,要求您的亲切和最欢迎的经历。
经过一番谷歌搜索后,我决定使用QGraphicalView / Scene方法。实际上,我在考虑创建自己的继承自QGraphicalView的hexgrid类,以及创建继承自QGraphicalPolygonItem的RegularPolygon类。
现在他们来了疑问和问题。
我的主要疑问是“我的方法正确吗?”考虑一下我在文章开头所解释的需求:六边形地图,其中每个六边形将是给定类型的瓷砖(海洋,沙漠,草地,山脉等)。编辑器工作后,我会担心性能(滚动会感觉不错吗?这类事情)。
到目前为止,问题在于精度。我通过创建和绘制所有六边形来绘制六边形网格(这甚至听起来对我来说很糟糕……考虑性能)。我使用了一些公式来计算每个六边形的顶点并从中创建多边形。我希望两个连续的六边形的边恰好在同一位置重合,但是四舍五入似乎有点符合我的要求,因为有时六边形的边在同一位置完全匹配(良好),有时它们不匹配。似乎有1个像素的差异(不好)。这给网格的视觉印象很差。也许我对自己的解释不是很好...最好给我代码,然后由您自己运行
总结一下:
您认为我的方法会给将来的性能带来问题吗?
为什么六边形不能正确放置,以使它们共享边?如何避免这个问题?
代码:
#!/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()
最佳答案
就个人而言,我将每个六边形图块定义为单独的SVG图像,并在缩放级别更改时使用QImage和QSvgRenderer类将它们呈现为QPixmaps(具有alpha通道)。我将创建一个QGraphicsItem子类来显示每个图块。
技巧是选择缩放级别,以使(垂直)六边形的宽度是2的倍数,而高度是4的倍数,其宽度/高度大约为sqrt(3/4)。六边形在任一方向上都被轻微挤压,但是对于所有六边形,直径至少为八个像素,效果是不可察觉的。
如果六边形的宽度为2*w
,高度为4*h
,这是将(直立)六边形映射到笛卡尔坐标的方法:
如果六角形的每一边都是a
,则h=a/2
和w=a*sqrt(3)/2
,因此是w/h=sqrt(3)
。
为了获得最佳显示质量,请选择整数w
和h
,以使它们的比率大约为sqrt(3) ≃ 1.732
。这意味着您的六角形将被轻微挤压,但这没关系;这是不可感知的。
由于坐标现在始终是整数,因此只要它们具有alpha通道,甚至可以使用边框以允许更平滑的alpha过渡,就可以安全地(不带显示假象)使用预渲染的六边形图块。每个矩形图块的宽度为2*w+2*b
像素,高度为4*h+2*b
像素,其中b
是额外边框(重叠)像素的数量。
需要额外的边框以避免在所有重叠的图块中像素仅部分不透明的可见接缝(背景色渗入)。边框使您可以将图块更好地融合到相邻图块中;如果在SVG磁贴中包含较小的边框区域,SVG渲染器将自动执行某些操作。
如果您使用典型的屏幕坐标,其中x
向右增长,而y
向下,那么六角形X,Y
相对于0,0
的坐标就微不足道了:
y = 3*h*Y
if Y is even, then:
x = 2*w*X
else:
x = 2*w*X + w
u = int(x / w)
v = int(y / h)
%
必须读作“除以负数”。 (也就是说,对于所有
0 <= a % b < b
,甚至是负
a
,都为
a
;在这里,
b
始终是正整数。)
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)
\
(位于图片上方),则只需检查是否
(x % w) * h >= (y % h) * w
/
wrt。上图,您只需要检查
(x % w) * h + (y % h) * w >= (w * h - (w + h) / 2)
关于python - 使用PyQt4的十六进制网格图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18463854/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!