2014-02-23 84 views
3

我想三角化一個位圖(爲我的2D遊戲生成關卡),並且卡住了。我正在使用由Jonathan Shewchuk使用this wrapper的Triangle庫。python中的孔三角網

我開始與圖像,

starting 2d bitmap

然後我檢測邊緣,並確定哪些頂點是孔。我拿起每四個三角高程測量,

enter image description here

然後我通過這些點到三角,但我最終是這樣的

enter image description here

在我的洞已經消失了。我究竟做錯了什麼? 另外,爲什麼我有點凸包而不是三角形多邊形?

這是到目前爲止我的代碼:

#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) 

謝謝您的幫助。

+0

我現在有點兒需要,我需要圍繞整個多邊形的部分和頂點的洞,但我仍然無法得到它的工作 –

+1

這是我做錯了: 1.段是指向頂點的兩個索引的超鏈接 2.在頂點中是所有點(根據圖像:不僅僅是紅色) 3.在三角函數的第二個參數中需要字母「p」。 感謝您的幫助,這是我的第二個問題 - 第一個是關閉的,第二個只是沒有意見,我在尋找第三個,我相信你不是:D –

+0

如果你解決了這個問題。知道如何將是一件好事。我試圖以任何身份找出這個圖書館。我提供了細分。它從來沒有錯,但輸出是一樣的。零封裝文件。 – Kaliber64

回答

1

這讓我撓了腦袋一陣子,你的評論幫我搞定了。

看到的數據的一個例子,你需要傳遞:

triangle.get_data( '臉')

停止多邊形的存在「填充「,並保持它的凹面,你可以通過這樣的片段

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)} 

添加一個孔,則需要seperatly標記綠黨和段(警告:未經測試的代碼)

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)} 

「洞」應該還可以作爲列表傳遞[X,Y]上的位置 - 一個每個洞內