【问题标题】:Triangulation with holes in pythonpython中带有孔的三角剖分
【发布时间】:2014-03-25 08:01:46
【问题描述】:

我正在尝试对位图进行三角测量(为我的 2d 游戏制作关卡),但我被卡住了。我正在使用 Jonathan Shewchuk 的 Triangle 库,使用 this wrapper

我从一张图片开始,

然后我检测边缘并确定哪些顶点是孔。我选择了每四分之一进行三角测量,

然后我将这些点传递给三角测量,但我最终得到了这样的结果

我的洞消失的地方。我究竟做错了什么? 另外,为什么我得到的是凸包而不是三角多边形?

到目前为止,这是我的代码:

    #here i am loading all data, that i will use later on but i had to insert that, just in case
    mapfg = glob(path.join(pathtomapfolder, "Foreground.png"))[0] #Getting map foreground image
    mapob = glob(path.join(pathtomapfolder, "Obstacles.png"))[0] #Getting map file
    mappr = glob(path.join(pathtomapfolder, "Properties.txt"))[0] #Getting map info file
    self.mapprops = [mapob, mapfg, mappr]
    #getting ground and obstacles
    obsbitmap = Image.open(self.mapprops[0])
    lockBitmap = obsbitmap.load()
    compareClr = (0, 0, 0)
    for y in xrange(obsbitmap.size[1]):
        tmp = []
        for x in xrange(obsbitmap.size[0]):
            if lockBitmap[x, y][0] == compareClr[0] and lockBitmap[x, y][6] == compareClr[1] and lockBitmap[x, y][7] == compareClr[2]:
                tmp.append(1)
            else:
                tmp.append(0)
        self.obs.append(tmp)
    #detecting edges
    for y in xrange(len(self.obs)):      
        tmphit = []
        for x in xrange(len(self.obs[0])):
            if (self.obs[y][x] == 0 and (self.obs[MinMax.NoOver(y - 1, len(self.obs) - 1, 0)][x] == 1 or self.obs[y][MinMax.NoOver(x - 1, len(self.obs[0]) - 1, 0)] == 1 or self.obs[y][MinMax.NoOver(x + 1, len(self.obs[0]) - 1, 0)] == 1 or self.obs[MinMax.NoOver(y + 1, len(self.obs) - 1, 0)][x] == 1)) or (self.obs[y][x] == 1 and (MinMax.WillOver(y - 1, len(self.obs) - 1, 0) or MinMax.WillOver(x - 1, len(self.obs[0]) - 1, 0) or MinMax.WillOver(x + 1, len(self.obs[0]) - 1, 0) or MinMax.WillOver(y + 1, len(self.obs) - 1, 0))):
                tmphit.append(True)
            else:
                tmphit.append(False)
        self.hit.append(tmphit)
    #here it starts, first of all i search for vertice, then go CW or CCW and get all vertices from edge of one polygon, i also detect, whether it is hole or not and to which polygon is related to.
    xcirc = ycirc = 0
    coords = []
    coordvalues = []
    parentid = []
    self.allverts = [coords, coordvalues, parentid]
    polyID = 0
    for y in xrange(len(self.obs)):
        for x in xrange(len(self.obs[0])):
            if self.hit[y][x] and not (x, y) in self.allverts[0]:
                left = []
                right = []
                up = []
                down = []
                numobjects = numholes = 0
                type = ""
                parentid = -1
                for v in xrange(len(self.allverts[0])):
                    if self.allverts[0][v][8] == y and self.allverts[0][v][0] < x: left.append(self.allverts[1][v])
                    if self.allverts[0][v][9] == y and self.allverts[0][v][0] > x: right.append(self.allverts[1][v])
                    if self.allverts[0][v][0] == x and self.allverts[0][v][10] < y: up.append(self.allverts[1][v])
                    if self.allverts[0][v][0] == x and self.allverts[0][v][11] > y: down.append(self.allverts[1][v])             
                for id in xrange(polyID):
                    if ("not hole", id) in left and ("not hole", id) in right and ("not hole", id) in up and ("not hole", id) in down:
                        numobjects += 1
                        parentid = id
                    elif ("hole", id) in left and ("hole", id) in right and ("hole", id) in up and ("hole", id) in down:
                        numholes += 1
                if numobjects == 0 or numobjects == numholes: type = "not hole"
                elif numobjects > numholes: type = "hole"
                found = False
                lastangle = -90
                self.allverts[0].append((x, y))
                self.allverts[1].append((type, polyID))
                self.allverts[2].append(parentid)
                v = 1
                while not found:
                    angle = MinMax.Overflow(lastangle - 45, 180, -179)
                    lastangle = angle
                    xcirc = int(round(math.cos((math.pi / 180) * angle)))
                    ycirc = int(round(math.sin((math.pi / 180) * angle)))
                    if self.hit[MinMax.NoOver(self.allverts[0][-1][12] + ycirc, len(self.hit) - 1, 0)][MinMax.NoOver(self.allverts[0][-1][0] + xcirc, len(self.hit[0]) - 1, 0)] and (MinMax.WontOver(self.allverts[0][-1][13] + ycirc, len(self.hit) - 1, 0) and MinMax.WontOver(self.allverts[0][-1][0] + xcirc, len(self.hit[0]) - 1, 0)):                    
                        if not (self.allverts[0][-1][0] + xcirc, self.allverts[0][-1][14] + ycirc) in self.allverts[0]:
                            self.allverts[0].append((self.allverts[0][-1][0] + xcirc, self.allverts[0][-1][15] + ycirc))
                            self.allverts[1].append((type, polyID))
                            self.allverts[2].append(parentid)
                            v += 1
                        else:
                            #self.allverts.append((self.allverts[-1][0] + xcirc, self.allverts[-1][16] + ycirc))
                            found = True
                            if v < 4:
                                polyID -= 1
                                for d in xrange(v):
                                    del self.allverts[0][-1]
                                    del self.allverts[1][-1]
                                    del self.allverts[2][-1]
                        lastangle = MinMax.Overflow(lastangle + 135, 180, -179)
                polyID += 1
    # now i have to convert that data structure to something i can pass to triangulate function 
    objects = []
    objectpoints = []
    idtoindexobj = []
    holes = []
    holepoints = []
    holecoords = []
    holeleft = len(self.hit[0])
    holetop = len(self.hit)
    holeright = holebottom = 0
    idtoindexhole = []
    prevvert = (self.allverts[0][0], self.allverts[1][0], self.allverts[2][0])
    d = 0
    for u in xrange(len(self.allverts[0])):
        vert = (self.allverts[0][u], self.allverts[1][u], self.allverts[2][u])
        if vert[1][17] != prevvert[1][18]:
            d = 0
            if prevvert[1][0] == "not hole":
                objects.append(objectpoints)
                objectpoints = []
                idtoindexobj.append(prevvert[1][19])
            else:
                holes.append(holepoints)
                holepoints = []
                holecoords.append((holeleft + (MinMax.AminB(holeleft, holeright)/2), holetop + (MinMax.AminB(holetop, holebottom)/2)))
                idtoindexhole.append(prevvert[2])
                holeleft = len(self.hit[0])
                holetop = len(self.hit)
                holeright = holebottom = 0
        if vert[1][0] == "not hole":
            if d % 4 == 0:
                objectpoints.append((vert[0][0], vert[0][20]))
        else:
            if d % 4 == 0:
                holepoints.append((vert[0][0], vert[0][21]))
                if vert[0][0] < holeleft: holeleft = vert[0][0]
                if vert[0][0] > holeright: holeright = vert[0][0]
                if vert[0][22] < holetop: holetop = vert[0][23]
                if vert[0][24] > holebottom: holebottom = vert[0][25]
        d+=1
        prevvert = vert
    if prevvert[1][0] == "not hole":
        objects.append(objectpoints)
        objectpoints = []
        idtoindexobj.append(prevvert[1][26])
    else:
        holes.append(holepoints)
        holepoints = []
        holecoords.append((holeleft + (MinMax.AminB(holeleft, holeright)/2), holetop + (MinMax.AminB(holetop, holebottom)/2)))
        idtoindexhole.append(prevvert[2])
        holeleft = len(self.hit[0])
        holetop = len(self.hit)
        holeright = holebottom = 0
        objectpoints.append((vert[0][0], vert[0][27]))
    self.polygons = []
    for ind, id in enumerate(idtoindexobj):
        holecoordlist = []
        segments = []
        for k, l in enumerate(idtoindexhole):
            if l == id:
                holecoordlist.append(holecoords[k])
                prevsegpart = False
                for segpart in holes[k]:
                    if not prevsegpart:
                        prevsegpart = segpart
                        continue
                    segments.append((prevsegpart[0], prevsegpart[1], segpart[0], segpart[1]))
                    prevsegpart = segpart
                segments.append((prevsegpart[0], prevsegpart[1], holes[k][0][0], holes[k][0][1]))
        if segments:
            self.polygons.append({"vertices":objects[ind], "segments":segments, "holes":holecoordlist})
        else:
            self.polygons.append({"vertices":objects[ind]})
    indtripolylist = []
    for pol in self.polygons:
        #here i am calling that triangulate function
        indtripolylist.append(triangle.triangulate(pol, opts="q"))
    #and finally convert what has been returned to coordinates of triangles (because it returns list of vertices and touples of indexes pointing to vertices)
    self.tripolylist = []
    for po in indtripolylist:
        tmptriangles = []
        for tr in po["triangles"]:
            tmptriangles.append((po["vertices"][tr[0]], po["vertices"][tr[1]], po["vertices"][tr[2]]))
        self.tripolylist.append(tmptriangles)

感谢您的帮助。

【问题讨论】:

  • 我现在有点明白了,我需要用线段包围整个多边形,用顶点包围整个多边形,但我仍然无法让它工作
  • 这里是我做错了什么: 1. 段是两个索引指向顶点的 touples 2. 顶点中的所有点(根据图像:不仅仅是红色的) 3. 在第二个参数三角测量函数需要是字母“p”。感谢您的帮助,这是我在这里的第二个问题-第一个问题已关闭,第二个问题尚未回答,我正在寻找第三个问题,我确定您不是:D
  • 如果你解决了这个问题。很高兴知道如何。我试图以任何身份找出这个库。我提供了片段。它从未出错,但输出是相同的。此包装器的零文档。
  • 这里是一些文档,我通过运行第二个示例来解决这个问题,并将变量打印传递给三角测量。由于我大约 4 个月没有接触那个项目,而且我的英语不太好,我不知道我能否为您提供一个很好的解释。 dzhelil.info/triangle/delaunay.html如果你真的需要我试试,我会的,就写吧:)

标签: python bitmap 2d triangulation


【解决方案1】:

这让我摸不着头脑,你们的 cmets 帮我搞定了。

查看您需要传递的数据示例:

triangle.get_data('face')

要停止“填充”多边形并使其保持凹形,您可以像这样沿着线段传递

    segments = []
    for i in range(len(verts)-1):
        segments.append([int(i),int(i+1)])
    segments.append([int(i+1),int(0)])
    A = {'vertices':array(verts), 'segments':array(segments)}

要添加孔,您需要分别标记顶点和线段(警告:未经测试的代码)

    vertmarks = []
    for i in range(len(verts)):
        vertmarks.append([2])
    for i in range(len(hole)):
        vertmarks.append([4])
    segmarks = []
    for i in range(len(segments)):
        segmarks.append([2])
    for i in range(len(holesegments)):
        segmarks.append([4])
    A = {'vertices':array(verts), 'segments':array(segments),
         'segment_markers':array(segmarks), 'vertex_markers':array(vertmarks)}

'holes' 也应该作为 [x,y] 位置列表传递 - 每个孔内一个

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 2019-09-28
    • 2013-09-17
    • 2020-05-06
    • 2020-11-21
    • 2021-02-14
    • 2013-04-20
    相关资源
    最近更新 更多