Skip to content

Commit 09edec8

Browse files
committedJul 3, 2020
first commit
0 parents  commit 09edec8

24 files changed

+2206
-0
lines changed
 

‎batch_align.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import numpy as np
3+
from tqdm.auto import tqdm
4+
from rplan.floorplan import Floorplan
5+
from rplan.align import align_fp_gt
6+
from rplan.decorate import get_dw
7+
from rplan.utils import get_edges,savepkl,savemat
8+
from multiprocessing import Pool,Manager
9+
10+
def func(file_path):
11+
fp = Floorplan(file_path)
12+
data = fp.to_dict(dtype=np.uint8)
13+
boxes_aligned, order, room_boundaries = align_fp_gt(data['boundary'],data['boxes'],data['types'],data['edges'],dtype=np.uint8)
14+
data['boxes_aligned'] = boxes_aligned
15+
data['edges_aligned'] = np.array(get_edges(boxes_aligned),dtype=np.uint8)
16+
data['order'] = order
17+
return data
18+
19+
class Callback():
20+
def __init__(self,length):
21+
self.bar = tqdm(total=length)
22+
self.output = []
23+
24+
def update(self, ret):
25+
self.output.append(ret)
26+
self.bar.update(1)
27+
28+
def close(self):
29+
self.bar.close()
30+
31+
if __name__ == '__main__':
32+
img_dir = './data'
33+
ids = os.listdir(img_dir)
34+
ids = [f'{img_dir}/{i}' for i in ids]
35+
print(len(ids))
36+
with Manager() as manager:
37+
with Pool(32) as pool:
38+
cb = Callback(len(ids))
39+
[pool.apply_async(func,args=(i,),callback=cb.update) for i in ids]
40+
pool.close()
41+
pool.join()
42+
cb.close()
43+
savepkl('./output/data_aligned.pkl',cb.output)
44+
# for matlab
45+
# savemat('./output/data_aligned.mat',{'data':cb.output})
46+
47+

‎batch_decorate.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import os
2+
import numpy as np
3+
from tqdm.auto import tqdm
4+
from rplan.floorplan import Floorplan
5+
from rplan.align import align_fp_gt
6+
from rplan.decorate import get_dw
7+
from rplan.utils import get_edges,savepkl,savemat
8+
from multiprocessing import Pool,Manager
9+
10+
def func(file_path):
11+
fp = Floorplan(file_path)
12+
data = fp.to_dict(dtype=np.uint8)
13+
boxes_aligned, order, room_boundaries = align_fp_gt(data['boundary'],data['boxes'],data['types'],data['edges'],dtype=np.uint8)
14+
data['boxes_aligned'] = boxes_aligned
15+
data['edges_aligned'] = np.array(get_edges(boxes_aligned),dtype=np.uint8)
16+
data['order'] = order
17+
data['room_boundaries'] = room_boundaries
18+
doors,windows = get_dw(data)
19+
data['doors'] = doors
20+
data['windows'] = windows
21+
return data
22+
23+
24+
class Callback():
25+
def __init__(self,length):
26+
self.bar = tqdm(total=length)
27+
self.output = []
28+
29+
def update(self, ret):
30+
self.output.append(ret)
31+
self.bar.update(1)
32+
33+
def close(self):
34+
self.bar.close()
35+
36+
if __name__ == '__main__':
37+
img_dir = './data'
38+
ids = os.listdir(img_dir)
39+
ids = [f'{img_dir}/{i}' for i in ids]
40+
print(len(ids))
41+
with Manager() as manager:
42+
with Pool(32) as pool:
43+
cb = Callback(len(ids))
44+
[pool.apply_async(func,args=(i,),callback=cb.update) for i in ids]
45+
pool.close()
46+
pool.join()
47+
cb.close()
48+
savepkl('./output/data_decorated.pkl',cb.output)
49+
# for matlab
50+
# savemat('./output/data_decorated.mat',{'data':cb.output})
51+
52+

‎batch_save.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
import numpy as np
3+
from tqdm.auto import tqdm
4+
from rplan.floorplan import Floorplan
5+
from rplan.align import align_fp_gt
6+
from rplan.utils import get_edges,savepkl,savemat
7+
from multiprocessing import Pool,Manager
8+
9+
def func(file_path):
10+
fp = Floorplan(file_path)
11+
data = fp.to_dict(np.uint8)
12+
return data
13+
14+
class Callback():
15+
def __init__(self,length):
16+
self.bar = tqdm(total=length)
17+
self.output = []
18+
19+
def update(self, ret):
20+
self.output.append(ret)
21+
self.bar.update(1)
22+
23+
def close(self):
24+
self.bar.close()
25+
26+
if __name__ == '__main__':
27+
img_dir = './data'
28+
ids = os.listdir(img_dir)
29+
ids = [f'{img_dir}/{i}' for i in ids]
30+
print(len(ids))
31+
with Manager() as manager:
32+
with Pool() as pool:
33+
cb = Callback(len(ids))
34+
[pool.apply_async(func,args=(i,),callback=cb.update) for i in ids]
35+
pool.close()
36+
pool.join()
37+
cb.close()
38+
savepkl('./output/data.pkl',cb.output)
39+
# for matlab
40+
# savemat('./output/data.mat',{'data':cb.output})
41+
42+

‎data/0.png

1.29 KB
Loading

‎output/plot.png

12.6 KB
Loading

‎readme.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# RPLAN-ToolBox
2+
A tool box for RPLAN dataset.
3+
4+
![](./output/plot.png)
5+
6+
# Usage
7+
8+
0. Install dependency
9+
10+
- python>=3.7
11+
12+
- matlab: [Install MATLAB Engine API for Python](https://www.mathworks.com/help/matlab/matlab_external/install-matlab-engine-api-for-python-in-nondefault-locations.html)
13+
14+
- numpy, scipy, scikit-image, matplotlib
15+
16+
- shapely, descartes
17+
18+
19+
1. Load a floorplan
20+
21+
```python
22+
RPLAN_DIR = './data'
23+
file_path = f'{RPLAN_DIR}/0.png'
24+
fp = Floorplan(file_path)
25+
img = fp.image
26+
```
27+
28+
2. Get image channels
29+
30+
```python
31+
fp.boundary
32+
fp.category
33+
fp.instance
34+
fp.inside
35+
```
36+
37+
2. Get vector graphics information
38+
```
39+
data = fp.to_dict()
40+
print(data.keys())
41+
```
42+
43+
3. Align rooms with boundary, neighbors
44+
```
45+
from rplan.align import align_fp_gt
46+
boxes_aligned, order, room_boundaries = align_fp_gt(data['boundary'],data['boxes'],data['types'],data['edges'])
47+
data['boxes_aligned'] = boxes_aligned
48+
data['order'] = order
49+
data['room_boundaries'] = room_boundaries
50+
```
51+
52+
4. Add doors and windows for a vector floorplan
53+
```
54+
from rplan.decorate import get_dw
55+
doors,windows = get_dw(data)
56+
data['doors'] = doors
57+
data['windows'] = windows
58+
```
59+
60+
5. Plot floorplan
61+
```
62+
from rplan.plot import get_figure,get_axes
63+
from rplan.plot import plot_category,plot_boundary,plot_graph,plot_fp
64+
plot_category(fp.category) # raw image
65+
plot_boundary(data['boundary']) # vector boundary
66+
plot_graph(data['boundary'],data['boxes'],data['types'],data['edges']) # node graph
67+
plot_fp(data['boundary'], data['boxes_aligned'][order], data['types'][order]) # vector floorplan
68+
plot_fp(data['boundary'], data['boxes_aligned'][order], data['types'][order],data['doors'],data['windows']) # vector floorplan with doors and windows
69+
```
70+
71+
## Acknowledgement
72+
- [RPLAN](http://staff.ustc.edu.cn/~fuxm/projects/DeepLayout/index.html)
73+
- [Graph2Plan](https://github.com/jizg/Graph2plan)

‎rplan/__init__,py

Whitespace-only changes.

‎rplan/align.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import numpy as np
2+
import matlab
3+
import matlab.engine as engine
4+
import os
5+
eng = engine.start_matlab()
6+
eng.addpath(os.path.join(os.path.dirname(__file__),'matlab'),nargout=0)
7+
8+
GT_ThRESHOLD = 6
9+
PRED_ThRESHOLD = 12
10+
REFINE_ThRESHOLD = 18
11+
12+
def align_fp(boundary, boxes, types, edges, image, threshold, dtype=int):
13+
boundary = np.array(boundary,dtype=int).tolist()
14+
boxes = np.array(boxes,dtype=int).tolist()
15+
types = np.array(types,dtype=int).tolist()
16+
edges = np.array(edges,dtype=int).tolist()
17+
image = np.array(image,dtype=int).tolist()
18+
19+
boxes_aligned, order, room_boundaries = eng.align_fp(
20+
matlab.double(boundary),
21+
matlab.double(boxes),
22+
matlab.double(types),
23+
matlab.double(edges),
24+
matlab.double(image),
25+
threshold,False,nargout=3
26+
)
27+
28+
boxes_aligned = np.array(boxes_aligned,dtype=dtype)
29+
order = np.array(order,dtype=dtype).reshape(-1)-1
30+
room_boundaries = np.array([np.array(rb,dtype=float) for rb in room_boundaries]) # poly with hole has value 'nan'
31+
32+
return boxes_aligned, order, room_boundaries
33+
34+
def align_fp_gt(boundary, boxes, types, edges, dtype=int):
35+
return align_fp(boundary, boxes, types, edges, [], GT_ThRESHOLD, dtype)
36+
37+
def align_fp_gt2(eng, boundary, boxes, types, edges, dtype=int):
38+
boundary = np.array(boundary,dtype=int).tolist()
39+
boxes = np.array(boxes,dtype=int).tolist()
40+
types = np.array(types,dtype=int).tolist()
41+
edges = np.array(edges,dtype=int).tolist()
42+
image = np.array([],dtype=int).tolist()
43+
44+
boxes_aligned, order, room_boundaries = eng.align_fp(
45+
matlab.double(boundary),
46+
matlab.double(boxes),
47+
matlab.double(types),
48+
matlab.double(edges),
49+
matlab.double(image),
50+
GT_ThRESHOLD,False,nargout=3
51+
)
52+
53+
boxes_aligned = np.array(boxes_aligned,dtype=dtype)
54+
order = np.array(order,dtype=dtype).reshape(-1)-1
55+
room_boundaries = np.array([np.array(rb,dtype=dtype) for rb in room_boundaries])
56+
57+
return boxes_aligned, order, room_boundaries
58+
59+
def align_fp_coarse(boundary, boxes, types, edges, dtype=int):
60+
return align_fp(boundary, boxes, types, edges, [], PRED_ThRESHOLD, dtype)
61+
62+
def align_fp_fine(boundary, boxes, types, edges, image, dtype=int):
63+
return align_fp(boundary, boxes, types, edges, image, REFINE_ThRESHOLD, dtype)

‎rplan/decorate.py

+425
Large diffs are not rendered by default.

‎rplan/floorplan.py

+363
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
from skimage import io
2+
from skimage import morphology,feature,transform,measure
3+
from pathlib import Path
4+
from scipy import stats
5+
from scipy import ndimage
6+
from shapely import geometry
7+
import numpy as np
8+
9+
from .utils import collide2d,point_box_relation,door_room_relation
10+
11+
class Floorplan():
12+
13+
@property
14+
def boundary(self): return self.image[...,0]
15+
16+
@property
17+
def category(self): return self.image[...,1]
18+
19+
@property
20+
def instance(self): return self.image[...,2]
21+
22+
@property
23+
def inside(self): return self.image[...,3]
24+
25+
def __init__(self,file_path):
26+
self.path = file_path
27+
self.name = Path(self.path).stem
28+
self.image = io.imread(self.path)
29+
self.h,self.w,self.c = self.image.shape
30+
31+
self.front_door = None
32+
self.exterior_boundary = None
33+
self.rooms = None
34+
self.edges = None
35+
36+
self.archs = None
37+
self.graph = None
38+
39+
self._get_front_door()
40+
self._get_exterior_boundary()
41+
self._get_rooms()
42+
self._get_edges()
43+
44+
def __repr__(self):
45+
return f'{self.name},({self.h},{self.w},{self.c})'
46+
47+
def _get_front_door(self):
48+
front_door_mask = self.boundary==255
49+
# fast bbox
50+
# min_h,max_h = np.where(np.any(front_door_mask,axis=1))[0][[0,-1]]
51+
# min_w,max_w = np.where(np.any(front_door_mask,axis=0))[0][[0,-1]]
52+
# self.front_door = np.array([min_h,min_w,max_h,max_w],dtype=int)
53+
region = measure.regionprops(front_door_mask.astype(int))[0]
54+
self.front_door = np.array(region.bbox,dtype=int)
55+
56+
def _get_exterior_boundary(self):
57+
if self.front_door is None: self._get_front_door()
58+
self.exterior_boundary = []
59+
60+
min_h,max_h = np.where(np.any(self.boundary,axis=1))[0][[0,-1]]
61+
min_w,max_w = np.where(np.any(self.boundary,axis=0))[0][[0,-1]]
62+
min_h = max(min_h-10,0)
63+
min_w = max(min_w-10,0)
64+
max_h = min(max_h+10,self.h)
65+
max_w = min(max_w+10,self.w)
66+
67+
# src: http://staff.ustc.edu.cn/~fuxm/projects/DeepLayout/index.html
68+
# search direction:0(right)/1(down)/2(left)/3(up)
69+
# find the left-top point
70+
flag = False
71+
for h in range(min_h, max_h):
72+
for w in range(min_w, max_w):
73+
if self.inside[h, w] == 255:
74+
self.exterior_boundary.append((h, w, 0))
75+
flag = True
76+
break
77+
if flag:
78+
break
79+
80+
# left/top edge: inside
81+
# right/bottom edge: outside
82+
while(flag):
83+
if self.exterior_boundary[-1][2] == 0:
84+
for w in range(self.exterior_boundary[-1][1]+1, max_w):
85+
corner_sum = 0
86+
if self.inside[self.exterior_boundary[-1][0], w] == 255:
87+
corner_sum += 1
88+
if self.inside[self.exterior_boundary[-1][0]-1, w] == 255:
89+
corner_sum += 1
90+
if self.inside[self.exterior_boundary[-1][0], w-1] == 255:
91+
corner_sum += 1
92+
if self.inside[self.exterior_boundary[-1][0]-1, w-1] == 255:
93+
corner_sum += 1
94+
if corner_sum == 1:
95+
new_point = (self.exterior_boundary[-1][0], w, 1)
96+
break
97+
if corner_sum == 3:
98+
new_point = (self.exterior_boundary[-1][0], w, 3)
99+
break
100+
101+
if self.exterior_boundary[-1][2] == 1:
102+
for h in range(self.exterior_boundary[-1][0]+1, max_h):
103+
corner_sum = 0
104+
if self.inside[h, self.exterior_boundary[-1][1]] == 255:
105+
corner_sum += 1
106+
if self.inside[h-1, self.exterior_boundary[-1][1]] == 255:
107+
corner_sum += 1
108+
if self.inside[h, self.exterior_boundary[-1][1]-1] == 255:
109+
corner_sum += 1
110+
if self.inside[h-1, self.exterior_boundary[-1][1]-1] == 255:
111+
corner_sum += 1
112+
if corner_sum == 1:
113+
new_point = (h, self.exterior_boundary[-1][1], 2)
114+
break
115+
if corner_sum == 3:
116+
new_point = (h, self.exterior_boundary[-1][1], 0)
117+
break
118+
119+
if self.exterior_boundary[-1][2] == 2:
120+
for w in range(self.exterior_boundary[-1][1]-1, min_w, -1):
121+
corner_sum = 0
122+
if self.inside[self.exterior_boundary[-1][0], w] == 255:
123+
corner_sum += 1
124+
if self.inside[self.exterior_boundary[-1][0]-1, w] == 255:
125+
corner_sum += 1
126+
if self.inside[self.exterior_boundary[-1][0], w-1] == 255:
127+
corner_sum += 1
128+
if self.inside[self.exterior_boundary[-1][0]-1, w-1] == 255:
129+
corner_sum += 1
130+
if corner_sum == 1:
131+
new_point = (self.exterior_boundary[-1][0], w, 3)
132+
break
133+
if corner_sum == 3:
134+
new_point = (self.exterior_boundary[-1][0], w, 1)
135+
break
136+
137+
if self.exterior_boundary[-1][2] == 3:
138+
for h in range(self.exterior_boundary[-1][0]-1, min_h, -1):
139+
corner_sum = 0
140+
if self.inside[h, self.exterior_boundary[-1][1]] == 255:
141+
corner_sum += 1
142+
if self.inside[h-1, self.exterior_boundary[-1][1]] == 255:
143+
corner_sum += 1
144+
if self.inside[h, self.exterior_boundary[-1][1]-1] == 255:
145+
corner_sum += 1
146+
if self.inside[h-1, self.exterior_boundary[-1][1]-1] == 255:
147+
corner_sum += 1
148+
if corner_sum == 1:
149+
new_point = (h, self.exterior_boundary[-1][1], 0)
150+
break
151+
if corner_sum == 3:
152+
new_point = (h, self.exterior_boundary[-1][1], 2)
153+
break
154+
155+
if new_point != self.exterior_boundary[0]:
156+
self.exterior_boundary.append(new_point)
157+
else:
158+
flag = False
159+
self.exterior_boundary = [[r,c,d,0] for r,c,d in self.exterior_boundary]
160+
161+
door_y1,door_x1,door_y2,door_x2 = self.front_door
162+
door_h,door_w = door_y2-door_y1,door_x2-door_x1
163+
is_vertical = door_h>door_w or door_h==1 #
164+
165+
insert_index = None
166+
door_index = None
167+
new_p = []
168+
th = 3
169+
for i in range(len(self.exterior_boundary)):
170+
y1,x1,d,_ = self.exterior_boundary[i]
171+
y2,x2,_,_ = self.exterior_boundary[(i+1)%len(self.exterior_boundary)]
172+
if is_vertical!=d%2: continue
173+
if is_vertical and (x1-th<door_x1<x1+th or x1-th<door_x2<x1+th): # 1:down 3:up
174+
l1 = geometry.LineString([[y1,x1],[y2,x2]])
175+
l2 = geometry.LineString([[door_y1,x1],[door_y2,x1]])
176+
l12 = l1.intersection(l2)
177+
if l12.length>0:
178+
dy1,dy2 = l12.xy[0] # (y1>y2)==(dy1>dy2)
179+
insert_index = i
180+
door_index = i+(y1!=dy1)
181+
if y1!=dy1: new_p.append([dy1,x1,d,1])
182+
if y2!=dy2: new_p.append([dy2,x1,d,1])
183+
elif not is_vertical and (y1-th<door_y1<y1+th or y1-th<door_y2<y1+th):
184+
l1 = geometry.LineString([[y1,x1],[y2,x2]])
185+
l2 = geometry.LineString([[y1,door_x1],[y1,door_x2]])
186+
l12 = l1.intersection(l2)
187+
if l12.length>0:
188+
dx1,dx2 = l12.xy[1] # (x1>x2)==(dx1>dx2)
189+
insert_index = i
190+
door_index = i+(x1!=dx1)
191+
if x1!=dx1: new_p.append([y1,dx1,d,1])
192+
if x2!=dx2: new_p.append([y1,dx2,d,1])
193+
194+
if len(new_p)>0:
195+
self.exterior_boundary = self.exterior_boundary[:insert_index+1]+new_p+self.exterior_boundary[insert_index+1:]
196+
self.exterior_boundary = self.exterior_boundary[door_index:]+self.exterior_boundary[:door_index]
197+
198+
self.exterior_boundary = np.array(self.exterior_boundary,dtype=int)
199+
200+
def _get_rooms(self):
201+
rooms = []
202+
regions = measure.regionprops(self.instance)
203+
for region in regions:
204+
c = stats.mode(self.category[region.coords[:,0],region.coords[:,1]])[0][0]
205+
y0,x0,y1,x1 = np.array(region.bbox)
206+
rooms.append([y0,x0,y1,x1,c])
207+
self.rooms = np.array(rooms,dtype=int)
208+
209+
def _get_edges(self,th=9):
210+
if self.rooms is None: self._get_rooms()
211+
edges = []
212+
for u in range(len(self.rooms)):
213+
for v in range(u+1,len(self.rooms)):
214+
if not collide2d(self.rooms[u,:4],self.rooms[v,:4],th=th): continue
215+
uy0, ux0, uy1, ux1, c1 = self.rooms[u]
216+
vy0, vx0, vy1, vx1, c2 = self.rooms[v]
217+
uc = (uy0+uy1)/2,(ux0+ux1)/2
218+
vc = (vy0+vy1)/2,(vx0+vx1)/2
219+
if ux0 < vx0 and ux1 > vx1 and uy0 < vy0 and uy1 > vy1:
220+
relation = 5 #'surrounding'
221+
elif ux0 >= vx0 and ux1 <= vx1 and uy0 >= vy0 and uy1 <= vy1:
222+
relation = 4 #'inside'
223+
else:
224+
relation = point_box_relation(uc,self.rooms[v,:4])
225+
edges.append([u,v,relation])
226+
227+
self.edges = np.array(edges,dtype=int)
228+
229+
def _get_archs(self):
230+
'''
231+
Interior doors
232+
'''
233+
archs = []
234+
235+
# treat archs as instances
236+
# index = len(self.rooms)+1
237+
238+
# for category in range(num_category,len(room_label)):
239+
for category in [17]: # only get doors for building graphs
240+
mask = (self.category==category).astype(np.uint8)
241+
242+
# distance transform -> threshold -> corner detection -> remove corner -> watershed -> label region
243+
#distance = cv2.distanceTransform(mask,cv2.DIST_C,3)
244+
distance = ndimage.morphology.distance_transform_cdt(mask)
245+
246+
# local_maxi = feature.peak_local_max(distance, indices=False) # line with one pixel
247+
local_maxi = (distance>1).astype(np.uint8)
248+
249+
# corner_measurement = feature.corner_shi_tomasi(local_maxi) # short lines will be removed
250+
corner_measurement = feature.corner_harris(local_maxi)
251+
252+
local_maxi[corner_measurement>0] = 0
253+
254+
markers = measure.label(local_maxi)
255+
256+
labels = morphology.watershed(-distance, markers, mask=mask, connectivity=8)
257+
regions = measure.regionprops(labels)
258+
259+
for region in regions:
260+
y0,x0,y1,x1 = np.array(region.bbox)
261+
archs.append([y0,x0,y1,x1,category])
262+
263+
self.archs = np.array(archs,dtype=int)
264+
265+
def _get_graph(self,th=9):
266+
'''
267+
More detail graph
268+
'''
269+
if self.rooms is None: self._get_rooms()
270+
if self.archs is None: self._get_archs()
271+
graph = []
272+
door_pos = [[None,0] for i in range(len(self.rooms))]
273+
edge_set = set()
274+
275+
# add accessible edges
276+
doors = self.archs[self.archs[:,-1]==17]
277+
for i in range(len(doors)):
278+
bbox = doors[i,:4]
279+
280+
# left <-> right
281+
for row in range(bbox[0],bbox[2]):
282+
283+
u = self.instance[row,bbox[1]-1]-1
284+
v = self.instance[row,bbox[3]+1]-1
285+
if (u,v) in edge_set or (v,u) in edge_set:continue
286+
if u>=0 and v>=0 and (u,v):
287+
edge_set.add((u,v))
288+
graph.append([u,v,None,1,i])
289+
290+
# up <-> down
291+
for col in range(bbox[1],bbox[3]):
292+
u = self.instance[bbox[0]-1,col]-1
293+
v = self.instance[bbox[2]+1,col]-1
294+
if (u,v) in edge_set or (v,u) in edge_set:continue
295+
if u>=0 and v>=0 and (u,v):
296+
edge_set.add((u,v))
297+
graph.append([u,v,None,1,i])
298+
299+
# add adjacent edges
300+
for u in range(len(self.rooms)):
301+
for v in range(u+1,len(self.rooms)):
302+
if (u,v) in edge_set or (v,u) in edge_set: continue
303+
304+
# collision detection
305+
if collide2d(self.rooms[u,:4],self.rooms[v,:4],th=th):
306+
edge_set.add((u,v))
307+
graph.append([u,v,None,0,None])
308+
309+
# add edge relation
310+
for i in range(len(graph)):
311+
u,v,e,t,d = graph[i]
312+
uy0, ux0, uy1, ux1 = self.rooms[u,:4]
313+
vy0, vx0, vy1, vx1 = self.rooms[v,:4]
314+
uc = (uy0+uy1)/2,(ux0+ux1)/2
315+
vc = (vy0+vy1)/2,(vx0+vx1)/2
316+
317+
if ux0 < vx0 and ux1 > vx1 and uy0 < vy0 and uy1 > vy1:
318+
relation = 5 #'surrounding'
319+
elif ux0 >= vx0 and ux1 <= vx1 and uy0 >= vy0 and uy1 <= vy1:
320+
relation = 4 #'inside'
321+
else:
322+
relation = point_box_relation(uc,self.rooms[v,:4])
323+
324+
graph[i][2] = relation
325+
326+
327+
if d is not None:
328+
c_u = self.rooms[u,-1]
329+
c_v = self.rooms[v,-1]
330+
331+
if c_u > c_v and door_pos[u][0] is None:
332+
room = u
333+
else:
334+
room = v
335+
door_pos[room][0]=d
336+
337+
338+
d_center = self.archs[d,:4]
339+
d_center = (d_center[:2]+d_center[2:])/2.0
340+
341+
dpos = door_room_relation(d_center,self.rooms[room,:4])
342+
if dpos!=0: door_pos[room][1] = dpos
343+
344+
self.graph = graph
345+
self.door_pos = door_pos
346+
347+
def to_dict(self,xyxy=True,dtype=int):
348+
'''
349+
Compress data, notice:
350+
!!! int->uint8: a(uint8)+b(uint8) may overflow !!!
351+
'''
352+
return {
353+
'name' :self.name,
354+
'types' :self.rooms[:,-1].astype(dtype),
355+
'boxes' :(self.rooms[:,[1,0,3,2]]).astype(dtype)
356+
if xyxy else self.rooms[:,:4].astype(dtype),
357+
'boundary' :self.exterior_boundary[:,[1,0,2,3]].astype(dtype)
358+
if xyxy else self.exterior_boundary.astype(dtype),
359+
'edges' :self.edges.astype(dtype)
360+
}
361+
362+
if __name__ == "__main__":
363+
pass

‎rplan/matlab/align_adjacent_room.m

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
function [newBox, constraint] = align_adjacent_room(box, tempBox, updated, type, threshold)
2+
% position of box1 relative to box2
3+
% 0 left-above
4+
% 1 left-below
5+
% 2 left-of
6+
% 3 above
7+
% 4 inside
8+
% 5 surrounding
9+
% 6 below
10+
% 7 right-of
11+
% 8 right-above
12+
% 9 right-below
13+
14+
15+
newBox = box;
16+
constraint = zeros(4, 2);
17+
idx = 1;
18+
19+
if type == 0
20+
alignV(true);
21+
alignH(true);
22+
elseif type == 1
23+
alignV(true);
24+
alignH(false);
25+
elseif type == 2
26+
align([2,1], [1,3], threshold);
27+
align([2,2], [1,2], threshold/2);
28+
align([2,4], [1,4], threshold/2);
29+
elseif type == 3
30+
align([2,2], [1,4], threshold);
31+
align([2,1], [1,1], threshold/2);
32+
align([2,3], [1,3], threshold/2);
33+
elseif type == 4
34+
align([2,1], [1,1], true);
35+
align([2,2], [1,2], true);
36+
align([2,3], [1,3], true);
37+
align([2,4], [1,4], true);
38+
elseif type == 5
39+
align([1,1], [2,1], true);
40+
align([1,2], [2,2], true);
41+
align([1,3], [2,3], true);
42+
align([1,4], [2,4], true);
43+
elseif type == 6
44+
align([2,4], [1,2], threshold);
45+
align([2,1], [1,1], threshold/2);
46+
align([2,3], [1,3], threshold/2);
47+
elseif type == 7
48+
align([2,3], [1,1], threshold);
49+
align([2,2], [1,2], threshold/2);
50+
align([2,4], [1,4], threshold/2);
51+
elseif type == 8
52+
alignV(false);
53+
alignH(true);
54+
elseif type == 9
55+
alignV(false);
56+
alignH(false);
57+
end
58+
59+
constraint = constraint(1:idx-1, :);
60+
61+
function alignV(isLeft)
62+
if isLeft
63+
idx1 = 1;
64+
idx2 = 3;
65+
else
66+
idx1 = 3;
67+
idx2 = 1;
68+
end
69+
70+
if abs(tempBox(2,idx1) - tempBox(1,idx2)) <= abs(tempBox(2,idx2) - tempBox(1,idx2))
71+
align([2,idx1], [1,idx2], threshold/2)
72+
else
73+
align([2,idx2], [1,idx2], threshold/2)
74+
end
75+
end
76+
77+
function alignH(isAbove)
78+
if isAbove
79+
idx1 = 2;
80+
idx2 = 4;
81+
else
82+
idx1 = 4;
83+
idx2 = 2;
84+
end
85+
86+
if abs(tempBox(2,idx1) - tempBox(1,idx2)) <= abs(tempBox(2,idx2) - tempBox(1,idx2))
87+
align([2,idx1], [1,idx2], threshold/2)
88+
else
89+
align([2,idx2], [1,idx2], threshold/2)
90+
end
91+
end
92+
93+
function align(idx1, idx2, threshold, attach)
94+
if nargin < 4
95+
attach = false;
96+
end
97+
if abs(tempBox(idx1(1),idx1(2))- tempBox(idx2(1), idx2(2))) <= threshold
98+
if updated(idx1(1), idx1(2)) && ~updated(idx2(1), idx2(2))
99+
newBox(idx2(1), idx2(2)) = newBox(idx1(1),idx1(2));
100+
elseif updated(idx2(1), idx2(2)) && ~updated(idx1(1), idx1(2))
101+
newBox(idx1(1), idx1(2)) = newBox(idx2(1),idx2(2));
102+
elseif ~updated(idx1(1), idx1(2)) && ~updated(idx2(1), idx2(2))
103+
if attach
104+
newBox(idx2(1), idx2(2)) = newBox(idx1(1),idx1(2));
105+
else
106+
y = (newBox(idx1(1),idx1(2)) + newBox(idx2(1), idx2(2)))/2;
107+
newBox(idx1(1),idx1(2)) = y;
108+
newBox(idx2(1), idx2(2)) = y;
109+
end
110+
end
111+
112+
if idx1(1) == 1
113+
constraint(idx, :) = [idx1(2) idx2(2)];
114+
else
115+
constraint(idx, :) = [idx2(2) idx1(2)];
116+
end
117+
idx = idx + 1;
118+
end
119+
end
120+
121+
end

‎rplan/matlab/align_fp.m

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
function [newBox, order, rBoundary] = align_fp(boundary, rBox, rType, rEdge, fp, threshold, drawResult)
2+
% align the neighboring rooms first and then align with the boundary
3+
4+
if nargin < 7
5+
drawResult =false;
6+
end
7+
solid = false;
8+
9+
10+
% pre-processing:
11+
% move the edge relation w.r.t. living room to the end
12+
livingIdx = find(rType==0);
13+
idx = rEdge(:,1) == livingIdx-1 | rEdge(:,2) == livingIdx-1;
14+
% a = rEdge(~idx, :);
15+
% b = rEdge(idx, :);
16+
% rEdge = [a; b];
17+
rEdge = rEdge(~idx, :);
18+
entranceBox = get_entrance_space(boundary(1:2, 1:2), boundary(1,3), threshold);
19+
20+
if drawResult
21+
clf
22+
subplot(2,2,1)
23+
plot_fp2(boundary, rBox, rType, [], [], 3, 0, solid);
24+
title('original');
25+
end
26+
27+
%% option #1: use greedy method: align with boundary first and then neighbor
28+
% 1. align with boundary after the neighbors have been aligned
29+
[~, newBox, updated] = align_with_boundary(rBox, boundary, threshold, rType);
30+
31+
if drawResult
32+
subplot(2,2,2)
33+
plot_fp2(boundary, newBox, rType, [], [], 3, 0, solid);
34+
title('Align with boundary');
35+
end
36+
37+
38+
% 2. for each adjacent pair of room,
39+
[~, newBox, ~] = align_neighbor(newBox, rEdge, updated, threshold+6);
40+
if drawResult
41+
subplot(2,2,3)
42+
plot_fp2(boundary, newBox, rType, [], [], 3, 0, solid);
43+
title('Align with neighbors');
44+
end
45+
46+
% 3. regularize fp, include crop using boundary, gap filling
47+
[newBox, order] = regularize_fp(newBox, boundary, rType, fp);
48+
49+
% 4. generate the room polygons
50+
[newBox, rBoundary] = get_room_boundary(newBox, boundary, order);
51+
52+
if drawResult
53+
% subplot(2,2,3)
54+
% plot_fp2(boundary, newBox, rType, [], [], 3, 0, false);
55+
% title('Regularize fp');
56+
57+
subplot(2,2,4)
58+
plot_fp2(boundary, newBox, rType, [], [], 3, 0, solid);
59+
title('Regularize fp');
60+
end
61+
62+
% %% option #2: use optimization to align neighbors, and then align the boundary
63+
% % 1. get the constraint from the adjacent rooms, and optimize
64+
% %[constraint1, ~, ~] = align_with_boundary(rBox, boundary, threshold, rNode);
65+
% [constraint2, ~, ~] = align_neighbor(rBox, rEdge, [], threshold+2);
66+
% newBox = optimize_fp(rBox, [], constraint2);
67+
% if drawResult
68+
% subplot(3,4,6)
69+
% plot_fp(newBox, boundary, rNode, entranceBox);
70+
% title('Optimize the neighboring');
71+
% end
72+
%
73+
% % 2. align with boundary after the neighbors have been aligned
74+
% [constraint1, newBox2, ~] = align_with_boundary(newBox, boundary, threshold, rNode);
75+
% if drawResult
76+
% subplot(3,4,7)
77+
% plot_fp(newBox2, boundary, rNode, entranceBox);
78+
% title('Align with boundary w/o optimization');
79+
% end
80+
%
81+
% % 3. regularize fp, include crop using boundary, gap filling
82+
% [newBox2, order] = regularize_fp(newBox2, boundary, rNode);
83+
% if drawResult
84+
% subplot(3,4,8)
85+
% plot_fp(newBox2(order,:), boundary, rNode(order,:), entranceBox);
86+
% title('Regularize fp');
87+
% end
88+
%
89+
%
90+
%
91+
% newBox = optimize_fp(newBox, constraint1, constraint2);
92+
% if drawResult
93+
% subplot(3,4,11)
94+
% plot_fp(newBox, boundary, rNode, entranceBox);
95+
% title('Align with boundary with optimization');
96+
% end
97+
%
98+
% % 3. regularize fp, include crop using boundary, gap filling
99+
% [newBox, order] = regularize_fp(newBox, boundary, rNode);
100+
% if drawResult
101+
% subplot(3,4,12)
102+
% plot_fp(newBox(order,:), boundary, rNode(order,:), entranceBox);
103+
% title('Regularize fp');
104+
% if ~isempty(figName)
105+
% saveas(gcf, figName);
106+
% end
107+
% end
108+
%
109+
110+
111+
112+
%%
113+
end
114+

‎rplan/matlab/align_neighbor.m

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
function [constraint, box, updated] = align_neighbor(box, rEdge, updated, threshold)
2+
3+
if isempty(updated)
4+
updated = false(size(box));
5+
end
6+
7+
tempBox = box;
8+
constraint = zeros(size(rEdge, 1)*3, 2);
9+
iBegin = 1;
10+
checked = false(size(rEdge, 1), 1);
11+
updatedCount = get_updated_count(updated, rEdge);
12+
for i = 1:size(rEdge, 1)
13+
I = find(~checked);
14+
[~, t] = maxk(updatedCount(I), 1);
15+
checked(I(t)) = true;
16+
idx = rEdge(I(t),1:2)+1;
17+
[b, c] = align_adjacent_room(box(idx, :), tempBox(idx, :), updated(idx,:), rEdge(I(t),3), threshold);
18+
for j = 1:length(idx)
19+
20+
updated(idx(j), c(:,j)) = true;
21+
22+
c(:, j) = (c(:,j)-1)*size(box,1) + double(idx(j));
23+
24+
if b(j, 1) == b(j, 3)
25+
b(j, [1 3]) = box(idx(j), [1 3]);
26+
updated(idx(j), c(:,j)) = false;
27+
end
28+
if b(j, 2) == b(j, 4)
29+
b(j, [2 4]) = box(idx(j), [2 4]);
30+
updated(idx(j), c(:,j)) = false;
31+
end
32+
33+
end
34+
box(idx, :) = b;
35+
36+
37+
cNum = size(c, 1);
38+
39+
constraint(iBegin:iBegin+cNum-1, :) = c;
40+
iBegin = iBegin+cNum;
41+
42+
updatedCount = get_updated_count(updated, rEdge);
43+
end
44+
constraint = constraint(1:iBegin-1, :);
45+
46+
function updatedCount = get_updated_count(updated, rEdge)
47+
updatedCount = zeros(size(rEdge, 1), 1);
48+
for k = 1:size(rEdge, 1)
49+
index = rEdge(k,1:2)+1;
50+
updatedCount(k) = sum(sum(updated(index,:)));
51+
end
52+
end
53+
end

‎rplan/matlab/align_with_boundary.m

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function [constraint, box, updated] = align_with_boundary(box, boundary, threshold, rType)
2+
tempBox = box;
3+
updated = false(size(box));
4+
closedSeg = zeros(size(box));
5+
distSeg = zeros(size(box));
6+
for i = 1:length(box)
7+
[closedSeg(i,:), distSeg(i,:)] = find_close_seg(box(i,:), boundary);
8+
end
9+
10+
11+
box(distSeg <= threshold) = closedSeg(distSeg <= threshold);
12+
updated(distSeg <= threshold) = true;
13+
idx = find(distSeg <= threshold);
14+
constraint = [idx closedSeg(idx)];
15+
16+
17+
% check if any room box blocks the door
18+
entranceBox = get_entrance_space(boundary(1:2, 1:2), boundary(1,3), threshold);
19+
entrancePoly = polyshape(entranceBox([1 1 3 3]), entranceBox([2 4 4 2]));
20+
for i = 1:length(box)
21+
if rType(i) ~= 10 && rType(i) ~= 0
22+
roomPoly = polyshape(box(i, [1 1 3 3]), box(i, [2 4 4 2]));
23+
if overlaps(entrancePoly, roomPoly)
24+
box(i,:) = shrink_box(roomPoly, entrancePoly, boundary(1,3));
25+
updated(i, box(i,:)==tempBox(i,:)) = false;
26+
updated(i, box(i,:)~=tempBox(i,:)) = true;
27+
end
28+
end
29+
end

‎rplan/matlab/find_close_seg.m

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
function [closedSeg, distSeg, idx] = find_close_seg(box, boundary)
2+
3+
% need to carefully select the closed wall seg for each box
4+
% cannot introduce a hole inside the boundary
5+
6+
isNew = boundary(:,4);
7+
boundary = double(boundary(~isNew, :));
8+
9+
% get the ordered horizontal and vertical segments on the boundary
10+
bSeg = [boundary(:, 1:2), boundary([2:end 1], 1:2), boundary(:,3)];
11+
vSeg = bSeg(mod(boundary(:,3), 2)==1, :);
12+
vSeg(vSeg(:,5)==3, [2 4]) = vSeg(vSeg(:,5)==3, [4 2]);
13+
[~, I] = sort(vSeg(:,1));
14+
vSeg = vSeg(I,:);
15+
16+
hSeg = bSeg(mod(boundary(:,3), 2)==0, :);
17+
hSeg(hSeg(:,5)==2, [1 3]) = hSeg(hSeg(:,5)==2, [3 1]);
18+
[~, I] = sort(hSeg(:,2));
19+
hSeg = hSeg(I,:);
20+
21+
closedSeg = ones(1,4)*256;
22+
distSeg = ones(1,4)*256;
23+
idx = zeros(1, 4);
24+
25+
% check vertial seg
26+
for i = 1:size(vSeg,1)
27+
seg = vSeg(i, :);
28+
vdist = 0;
29+
if seg(4) <= box(2)
30+
vdist = box(2) - seg(4);
31+
elseif seg(2) >= box(4)
32+
vdist = seg(2) - box(4);
33+
end
34+
35+
hdist = box([1 3]) - seg(1);
36+
dist1 = norm(double([hdist(1), vdist]));
37+
dist3 = norm(double([hdist(2), vdist]));
38+
39+
if dist1 < distSeg(1) && dist1 <= dist3 && hdist(1) > 0
40+
distSeg(1) = dist1;
41+
idx(1) = i;
42+
closedSeg(1) = seg(1);
43+
elseif dist3 < distSeg(3) && hdist(2) < 0
44+
distSeg(3) = dist3;
45+
idx(3) = i;
46+
closedSeg(3) = seg(3);
47+
end
48+
end
49+
50+
% check horizontal seg
51+
for i = 1:size(hSeg,1)
52+
53+
seg = hSeg(i, :);
54+
hdist = 0;
55+
if seg(3) <= box(1)
56+
hdist = box(1) - seg(3);
57+
elseif seg(1) >= box(3)
58+
hdist = seg(1) - box(3);
59+
end
60+
61+
vdist = box([2 4]) - seg(2);
62+
dist2 = norm(double([vdist(1), hdist]));
63+
dist4 = norm(double([vdist(2), hdist]));
64+
65+
if dist2 <= dist4 && dist2 < distSeg(2) && vdist(1) > 0
66+
distSeg(2) = dist2;
67+
idx(2) = i;
68+
closedSeg(2) = seg(2);
69+
elseif dist4 < distSeg(4) && vdist(2) < 0
70+
distSeg(4) = dist4;
71+
idx(4) = i;
72+
closedSeg(4) = seg(4);
73+
end
74+
end

‎rplan/matlab/find_room_order.m

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function order = find_room_order(M)
2+
3+
n = size(M,1);
4+
G = digraph(M);
5+
name = cell(n,1);
6+
for i = 1:n
7+
name{i} = num2str(i);
8+
end
9+
G.Nodes.Name = name;
10+
11+
order = zeros(n, 1);
12+
i = 1;
13+
while i <= n
14+
D = indegree(G);
15+
c = find(D==0);
16+
if isempty(c)
17+
idx = find(D==1);
18+
c = setdiff(idx, order);
19+
order(i) = str2double(G.Nodes.Name{c(1)});
20+
G = rmnode(G, c(1));
21+
i = i+1;
22+
else
23+
for j = 1:length(c)
24+
order(i+j-1) = str2double(G.Nodes.Name{c(j)});
25+
end
26+
G = rmnode(G, c);
27+
i = i + length(c);
28+
end
29+
end

‎rplan/matlab/get_entrance_space.m

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
function doorBox = get_entrance_space(doorSeg, doorOri, threshold)
3+
4+
doorBox = [doorSeg(1,:) doorSeg(2,:)];
5+
if doorOri == 0
6+
doorBox(4) = doorBox(4) + threshold;
7+
elseif doorOri == 1
8+
doorBox(1) = doorBox(1) - threshold;
9+
elseif doorOri == 2
10+
doorBox(2) = doorBox(2) - threshold;
11+
elseif doorOri == 3
12+
doorBox(3) = doorBox(3) + threshold;
13+
end
14+

‎rplan/matlab/get_room_boundary.m

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
function [newBox, rBoundary] = get_room_boundary(box, boundary, order)
2+
3+
isNew = boundary(:,4);
4+
polyBoundary = polyshape(boundary(~isNew,1), boundary(~isNew,2));
5+
6+
poly = cell(size(box,1), 1);
7+
for i = 1:size(box,1)
8+
poly{i} = polyshape(box(i, [1 1 3 3]), box(i, [2 4 4 2]));
9+
end
10+
11+
newBox = box;
12+
rBoundary = cell(size(box,1), 1);
13+
for i = 1:size(box,1)
14+
idx = order(i);
15+
16+
rPoly = intersect(polyBoundary, poly{idx});
17+
for j = i+1:size(box,1)
18+
rPoly = subtract(rPoly, poly{order(j)});
19+
end
20+
rBoundary{idx} = rPoly.Vertices;
21+
[xLimit, yLimit]= boundingbox(rPoly);
22+
if ~isempty(xLimit)
23+
newBox(idx,:) = [xLimit(1) yLimit(1) xLimit(2), yLimit(2)];
24+
end
25+
end

‎rplan/matlab/refine_fp.m

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
function [newBox, order] = refine_fp(boundary, rNode, rEdge, rBox, fp, threshold, drawResult, figName)
2+
% align the neighboring rooms first and then align with the boundary
3+
4+
if nargin < 8
5+
drawResult =false;
6+
end
7+
8+
9+
% pre-processing:
10+
% move the edge relation w.r.t. living room to the end
11+
livingIdx = find(rNode(:,4)==0);
12+
idx = rEdge(:,1) == livingIdx-1 | rEdge(:,2) == livingIdx-1;
13+
% a = rEdge(~idx, :);
14+
% b = rEdge(idx, :);
15+
% rEdge = [a; b];
16+
rEdge = rEdge(~idx, :);
17+
entranceBox = get_entrance_space(boundary(1:2, 1:2), boundary(1,3), threshold);
18+
19+
if drawResult
20+
clf
21+
subplot(3,4,1)
22+
plot_fp(rBox, boundary, rNode, entranceBox);
23+
title('original');
24+
end
25+
26+
%% option #1: use greedy method: align with boundary first and then neighbor
27+
% 1. align with boundary after the neighbors have been aligned
28+
[~, newBox, updated] = align_with_boundary(rBox, boundary, threshold, rNode);
29+
30+
if drawResult
31+
subplot(3,4,2)
32+
plot_fp(newBox, boundary, rNode, entranceBox);
33+
title('Align with boundary');
34+
end
35+
36+
37+
% 2. for each adjacent pair of room,
38+
[~, newBox, ~] = align_neighbor(newBox, rEdge, updated, threshold+6);
39+
if drawResult
40+
subplot(3,4,3)
41+
plot_fp(newBox, boundary, rNode, entranceBox);
42+
title('Align with neighbors');
43+
end
44+
45+
% 3. regularize fp, include crop using boundary, gap filling
46+
[newBox, order] = regularize_fp(newBox, boundary, rNode, fp);
47+
48+
if drawResult
49+
subplot(3,4,4)
50+
plot_fp(newBox(order,:), boundary, rNode(order,:), entranceBox);
51+
title('Regularize fp');
52+
end
53+
54+
% %% option #2: use optimization to align neighbors, and then align the boundary
55+
% % 1. get the constraint from the adjacent rooms, and optimize
56+
% %[constraint1, ~, ~] = align_with_boundary(rBox, boundary, threshold, rNode);
57+
% [constraint2, ~, ~] = align_neighbor(rBox, rEdge, [], threshold+2);
58+
% newBox = optimize_fp(rBox, [], constraint2);
59+
% if drawResult
60+
% subplot(3,4,6)
61+
% plot_fp(newBox, boundary, rNode, entranceBox);
62+
% title('Optimize the neighboring');
63+
% end
64+
%
65+
% % 2. align with boundary after the neighbors have been aligned
66+
% [constraint1, newBox2, ~] = align_with_boundary(newBox, boundary, threshold, rNode);
67+
% if drawResult
68+
% subplot(3,4,7)
69+
% plot_fp(newBox2, boundary, rNode, entranceBox);
70+
% title('Align with boundary w/o optimization');
71+
% end
72+
%
73+
% % 3. regularize fp, include crop using boundary, gap filling
74+
% [newBox2, order] = regularize_fp(newBox2, boundary, rNode);
75+
% if drawResult
76+
% subplot(3,4,8)
77+
% plot_fp(newBox2(order,:), boundary, rNode(order,:), entranceBox);
78+
% title('Regularize fp');
79+
% end
80+
%
81+
%
82+
%
83+
% newBox = optimize_fp(newBox, constraint1, constraint2);
84+
% if drawResult
85+
% subplot(3,4,11)
86+
% plot_fp(newBox, boundary, rNode, entranceBox);
87+
% title('Align with boundary with optimization');
88+
% end
89+
%
90+
% % 3. regularize fp, include crop using boundary, gap filling
91+
% [newBox, order] = regularize_fp(newBox, boundary, rNode);
92+
% if drawResult
93+
% subplot(3,4,12)
94+
% plot_fp(newBox(order,:), boundary, rNode(order,:), entranceBox);
95+
% title('Regularize fp');
96+
% if ~isempty(figName)
97+
% saveas(gcf, figName);
98+
% end
99+
% end
100+
%
101+
102+
103+
104+
%%
105+
end
106+

‎rplan/matlab/regularize_fp.m

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
function [box, order] = regularize_fp(box, boundary, rType, image)
2+
3+
% 1. use the boundary to crop each room box
4+
isNew = boundary(:,4);
5+
polyBoundary = polyshape(boundary(~isNew,1), boundary(~isNew,2));
6+
for i = 1:size(box, 1)
7+
polyRoom = polyshape(box(i, [1 1 3 3]), box(i, [2 4 4 2]));
8+
[xLimit, yLimit] = boundingbox(intersect(polyBoundary,polyRoom));
9+
if isempty(xLimit)
10+
disp('One room outside the building!');
11+
else
12+
box(i,:) = [xLimit(1) yLimit(1) xLimit(2), yLimit(2)];
13+
end
14+
end
15+
16+
17+
% 2. check if there is any overlapped region to determine the layer of boxes
18+
orderM = false(size(box,1), size(box,1));
19+
for i = 1:size(box,1)
20+
polyRoom1 = polyshape(box(i, [1 1 3 3]), box(i, [2 4 4 2]));
21+
area1 = area(polyRoom1);
22+
for j = i+1:size(box,1)
23+
polyRoom2 = polyshape(box(j, [1 1 3 3]), box(j, [2 4 4 2]));
24+
area2 = area(polyRoom2);
25+
inter = intersect(polyRoom1, polyRoom2);
26+
if inter.NumRegions >= 1
27+
n1 = 0;
28+
n2 = 0;
29+
30+
if ~isempty(image)
31+
% find the overlap region in the image and determine the order
32+
% based on the vote
33+
mask = poly2mask(inter.Vertices(:, 1), inter.Vertices(:, 2), size(image,1), size(image,2));
34+
n1 = nnz(image(mask) == rType(i));
35+
n2 = nnz(image(mask) == rType(j));
36+
end
37+
38+
if n1 == n2
39+
% if there is no difference in the voting, use area
40+
if area1 <= area2
41+
orderM(i,j) = true;
42+
else
43+
orderM(j,i) = true;
44+
end
45+
elseif n1 > n2
46+
orderM(i,j) = true;
47+
elseif n1 < n2
48+
orderM(j,i) = true;
49+
end
50+
51+
end
52+
end
53+
end
54+
order = 1:size(box,1);
55+
if any(orderM(:))
56+
order = find_room_order(orderM);
57+
end
58+
order = order(end:-1:1);
59+
60+
% 3. check if there are more than one uncovered regions inside the building
61+
livingIdx = find(rType==0);
62+
for i = 1:size(box, 1)
63+
if i ~= livingIdx
64+
if box(i,1)==box(i,3) || box(i,2)==box(i,4)
65+
disp('Empty box!!!');
66+
else
67+
polyRoom = polyshape(box(i, [1 1 3 3]), box(i, [2 4 4 2]));
68+
polyBoundary = subtract(polyBoundary,polyRoom);
69+
end
70+
71+
end
72+
end
73+
livingPoly = polyshape(box(livingIdx, [1 1 3 3]), box(livingIdx, [2 4 4 2]));
74+
75+
gap = polyBoundary;
76+
if gap.NumRegions == 1
77+
[xLimit, yLimit] = boundingbox(gap);
78+
box(livingIdx,:) = [xLimit(1) yLimit(1) xLimit(2), yLimit(2)];
79+
else
80+
rIdx = find(isnan(gap.Vertices(:,1)));
81+
rIdx = [rIdx; size(gap.Vertices,1)+1];
82+
83+
% for each region, check if it intersects with the living room,
84+
% otherwise get the room label and find the room that should cover
85+
% the region
86+
87+
region = cell(length(rIdx), 1);
88+
overlapArea = zeros(length(rIdx), 1);
89+
closeRoomIdx = zeros(length(rIdx), 1);
90+
idx = 1;
91+
for k = 1:length(rIdx)
92+
regionV = gap.Vertices(idx:rIdx(k)-1, :);
93+
idx = rIdx(k) + 1;
94+
region{k} = polyshape(regionV);
95+
96+
if overlaps(region{k}, livingPoly)
97+
iter = intersect(region{k}, livingPoly);
98+
overlapArea(k) = area(iter);
99+
end
100+
101+
[x, y] = centroid(region{k});
102+
center = [x, y];
103+
104+
dist = 256;
105+
bIdx = 0;
106+
for i = 1:size(box, 1)
107+
b = box(i, :);
108+
bCenter = double([(b(:,1)+b(:,3))/2, (b(:,2)+b(:,4))/2]);
109+
d = norm(bCenter-center);
110+
if d<dist
111+
dist = d;
112+
bIdx = i;
113+
end
114+
end
115+
closeRoomIdx(k) = bIdx;
116+
end
117+
118+
[~, lIdx] = max(overlapArea);
119+
for k = 1:length(closeRoomIdx)
120+
if k == lIdx
121+
[xLimit, yLimit] = boundingbox(region{k});
122+
box(livingIdx,:) = [xLimit(1) yLimit(1) xLimit(2), yLimit(2)];
123+
else
124+
room = polyshape(box(closeRoomIdx(k), [1 1 3 3]), box(closeRoomIdx(k), [2 4 4 2]));
125+
[xLimit, yLimit] = boundingbox(union(room, region{k}));
126+
box(closeRoomIdx(k),:) = [xLimit(1) yLimit(1) xLimit(2), yLimit(2)];
127+
end
128+
end
129+
end
130+

‎rplan/matlab/shrink_box.m

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
function box = shrink_box(roomPoly, entrancePoly, doorOrient)
2+
3+
[PG, shapeId, ~] = subtract(roomPoly, entrancePoly);
4+
idx1 = find(shapeId==1);
5+
d = idx1(2:end) - idx1(1:end-1);
6+
i = find(d~=1);
7+
if ~isempty(i)
8+
idx1 = idx1([i+1:end 1:i]);
9+
end
10+
11+
idx2 = find(shapeId~=1);
12+
d = idx2(2:end) - idx2(1:end-1);
13+
i = find(d~=1);
14+
if ~isempty(i)
15+
idx2 = idx2([i+1:end 1:i]);
16+
end
17+
18+
remainPoint = length(idx1);
19+
if remainPoint == 2
20+
box = [min(PG.Vertices) max(PG.Vertices)];
21+
elseif remainPoint == 3
22+
assert(length(idx2) == 3);
23+
pointSet1 = PG.Vertices([idx1(1:2); idx2(2)], :);
24+
pointSet2 = PG.Vertices([idx1(2:3); idx2(2)], :);
25+
if mod(doorOrient, 2) == 0 % door grow vertically
26+
if pointSet1(1,1) == pointSet1(2,1)
27+
box = [min(pointSet1) max(pointSet1)];
28+
else
29+
box = [min(pointSet2) max(pointSet2)];
30+
end
31+
else
32+
if pointSet1(1,2) == pointSet1(2,2)
33+
box = [min(pointSet1) max(pointSet1)];
34+
else
35+
box = [min(pointSet2) max(pointSet2)];
36+
end
37+
end
38+
elseif remainPoint == 4
39+
% elseif remainPoint == 4 && length(idx2) == 4
40+
% pointSet = PG.Vertices([idx1(2:3); idx2(2:3)], :);
41+
% box = [min(pointSet) max(pointSet)];
42+
% elseif remainPoint == 4 % door inside the box
43+
[x1, y1] = centroid(roomPoly);
44+
[x2, y2] = centroid(entrancePoly);
45+
box = [min(roomPoly.Vertices) max(roomPoly.Vertices)];
46+
if mod(doorOrient, 2) == 0 % door grow vertically
47+
if x1 < x2
48+
box(3) = min(entrancePoly.Vertices(:,1));
49+
else
50+
box(1) = max(entrancePoly.Vertices(:,1));
51+
end
52+
else
53+
if y1 < y2
54+
box(4) = min(entrancePoly.Vertices(:,2));
55+
else
56+
box(2) = max(entrancePoly.Vertices(:,2));
57+
end
58+
end
59+
else
60+
disp(['There are other cases with point number = ', num2str(length(shapeId))]);
61+
end

‎rplan/plot.py

+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
import matplotlib.patches as patches
4+
from shapely import geometry
5+
from descartes import PolygonPatch
6+
7+
from .utils import room_label
8+
9+
def get_color_map():
10+
color = np.array([
11+
[244,242,229], # living room
12+
[253,244,171], # bedroom
13+
[234,216,214], # kitchen
14+
[205,233,252], # bathroom
15+
[208,216,135], # balcony
16+
[249,222,189], # Storage
17+
[ 79, 79, 79], # exterior wall
18+
[255,225, 25], # FrontDoor
19+
[128,128,128], # interior wall
20+
[255,255,255]
21+
],dtype=np.int64)
22+
cIdx = np.array([1,2,3,4,1,2,2,2,2,5,1,6,1,10,7,8,9,10])-1
23+
return color[cIdx]
24+
cmap = get_color_map()/255.0
25+
26+
def get_figure(size=512):
27+
if np.array(size).size==1:
28+
w,h = size,size
29+
else:
30+
w,h = size[0],size[1]
31+
fig = plt.figure()
32+
dpi = fig.get_dpi()
33+
fig.set_size_inches(w/dpi,h/dpi)
34+
fig.set_frameon(False)
35+
return fig
36+
37+
def get_axes(size=512,fig=None,rect=[0,0,1,1]):
38+
if fig is None: fig = get_figure(size)
39+
40+
ax = fig.add_axes(rect)
41+
#ax.set_frame_on(False)
42+
ax.set_aspect('equal')
43+
ax.set_xlim([0,255])
44+
ax.set_ylim([0,255])
45+
ax.invert_yaxis()
46+
ax.set_axis_off()
47+
48+
return ax
49+
50+
def plot_category(category,ax=None):
51+
if ax is None: ax = get_axes()
52+
img = np.ones((category.shape[0],category.shape[1],4))
53+
img[...,:3] = cmap[category]
54+
img[category==13,3] = 0
55+
ax.imshow(img)
56+
return ax
57+
58+
def plot_boundary(boundary, wall_thickness=6,ax=None):
59+
if ax is None: ax = get_axes()
60+
61+
is_new = boundary[:,-1]==1
62+
poly_boundary = geometry.Polygon(boundary[~is_new,:2])
63+
ax.add_patch(PolygonPatch(poly_boundary,fc='none',ec=cmap[14],lw=wall_thickness))
64+
65+
door = boundary[:2,:2]
66+
idx = np.argmin(np.sum(door,axis=-1), axis=0)
67+
if idx==1: door = door[[1,0]]
68+
69+
ori = boundary[0,2]
70+
if ori%2==0:
71+
door = door+np.array([
72+
[wall_thickness/4,0],[-wall_thickness/4,0]
73+
])
74+
else:
75+
door = door+np.array([
76+
[0,wall_thickness/4],
77+
[0,-wall_thickness/4]
78+
])
79+
ax.plot(door[:,0],door[:,1],color=cmap[15],lw=wall_thickness+1)
80+
81+
return ax
82+
83+
def plot_graph(boundary, boxes, types, edges, wall_thickness=6,with_boundary=True,ax=None):
84+
if ax is None: ax = get_axes()
85+
86+
if with_boundary: plot_boundary(boundary,wall_thickness,ax)
87+
88+
boxes = boxes.astype(float)
89+
r_node = np.zeros((len(boxes),3))
90+
for k in range(len(boxes)):
91+
r_node[k,:2] = (boxes[k,:2]+boxes[k,2:])/2
92+
r_node[k,2] = (boxes[k,2]-boxes[k,0])*(boxes[k,3]-boxes[k,1])
93+
94+
for i in range(len(edges)):
95+
idx = edges[i,:2]
96+
ax.plot(r_node[idx,0],r_node[idx,1],'-',color=[0.7,0.7,0.7],lw=wall_thickness/2)
97+
98+
is_new = boundary[:,-1]==1
99+
poly_boundary = geometry.Polygon(boundary[~is_new,:2])
100+
for i in range(len(r_node)):
101+
s = round(10*r_node[i,2])/poly_boundary.area*3+wall_thickness*3
102+
ax.plot(r_node[i,0],r_node[i,1],'o',mec=cmap[16],mfc=cmap[types[i]],ms=s)
103+
104+
return ax
105+
106+
def plot_fp(boundary, boxes, types, doors=[], windows=[], wall_thickness=6, fontsize=0, keep_box=False, alpha=1.0, ax=None):
107+
if ax is None: ax = get_axes()
108+
109+
is_new = boundary[:,-1]==1
110+
poly_boundary = geometry.Polygon(boundary[~is_new,:2])
111+
poly = dict()
112+
113+
for k in range(len(boxes)):
114+
poly_room = geometry.box(*boxes[k])
115+
poly[k] = poly_boundary.intersection(poly_room)
116+
if poly[k].area==0:
117+
print(f'ploting empty box {k}!')
118+
continue
119+
120+
if keep_box:
121+
poly[k] = geometry.box(*poly[k].bounds)
122+
x,y = poly[k].exterior.xy
123+
ax.fill(x,y,fc=cmap[types[k]],ec=cmap[16],alpha=alpha,lw=wall_thickness)
124+
else:
125+
if poly[k].geom_type!='Polygon':
126+
for p in poly[k]:
127+
if p.geom_type!='Polygon': continue
128+
ax.add_patch(PolygonPatch(p,fc=cmap[types[k]],ec=cmap[16],alpha=alpha,lw=wall_thickness))
129+
else:
130+
ax.add_patch(PolygonPatch(poly[k],fc=cmap[types[k]],ec=cmap[16],alpha=alpha,lw=wall_thickness))
131+
132+
plot_boundary(boundary,wall_thickness,ax)
133+
134+
if len(doors)>0:
135+
plot_door(doors, wall_thickness/3, ax)
136+
if len(windows)>0:
137+
plot_window(windows, wall_thickness/3, ax)
138+
139+
if fontsize!=0:
140+
for k in range(len(boxes)):
141+
if poly[k].area==0: continue
142+
cx, cy = poly[k].centroid.x,poly[k].centroid.y
143+
ax.text(cx, cy, room_label[types[k]][1], fontsize=fontsize,horizontalalignment='center',verticalalignment='center')
144+
145+
return ax
146+
147+
def plot_window(windows, thickness=2, ax=None):
148+
if ax is None: ax = get_axes()
149+
for k in range(len(windows)):
150+
window = windows[k]
151+
seg = np.zeros((2,2))
152+
seg[0] = window[1:3]
153+
seg[1] = window[1:3]+ window[3:5]
154+
155+
box = np.concatenate([seg.min(0),seg.max(0)],axis=-1)
156+
157+
if window[3] < window[4]:
158+
box = box + np.array([-1,0,1,0]) * thickness
159+
if window[4] > 0:
160+
box[1] = box[1] + thickness
161+
seg[0,1] = seg[0,1] + thickness
162+
else:
163+
box[3] = box[3] - thickness
164+
seg[0,1] = seg[0,1] - thickness
165+
else:
166+
box = box + np.array([0,-1,0,1]) * thickness
167+
if window[3] > 0:
168+
box[0] = box[0] + thickness
169+
seg[0,0] = seg[0,0] + thickness
170+
else:
171+
box[2] = box[2] - thickness
172+
seg[0,0] = seg[0,0] - thickness
173+
174+
ax.fill(box[[0,0,2,2,0]], box[[1,3,3,1,1]], 'w')
175+
176+
ax.plot(box[[0,0,2,2,0]], box[[1,3,3,1,1]], color=[0.4,0.4,0.4], lw=1)
177+
ax.plot(seg[:,0], seg[:,1], color=[0.4,0.4,0.4], lw=1)
178+
179+
return ax
180+
181+
def plot_door(doors, thickness, ax=None):
182+
if ax is None: ax = get_axes()
183+
for k in range(len(doors)):
184+
door = doors[k]
185+
seg = np.zeros((2,2))
186+
seg[0] = door[1:3]
187+
seg[1] = door[1:3]+ door[3:5]
188+
189+
box = np.concatenate([seg.min(0),seg.max(0)],axis=-1)
190+
191+
if door[3] < door[4]:
192+
box = box + np.array([-1,0,1,0]) * thickness
193+
if door[4] > 0:
194+
box[1] = box[1] + thickness
195+
else:
196+
box[3] = box[3] - thickness
197+
else:
198+
box = box + np.array([0,-1,0,1]) * thickness
199+
if door[3] > 0:
200+
box[0] = box[0] + thickness
201+
else:
202+
box[2] = box[2] - thickness
203+
204+
ax.fill(box[[0,0,2,2,0]], box[[1,3,3,1,1]], 'w', ec=cmap[16])
205+
206+
return ax
207+

‎rplan/utils.py

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import numpy as np
2+
import scipy.io as sio
3+
import pickle
4+
5+
room_label = [(0, 'LivingRoom', 1, "PublicArea"),
6+
(1, 'MasterRoom', 0, "Bedroom"),
7+
(2, 'Kitchen', 1, "FunctionArea"),
8+
(3, 'Bathroom', 0, "FunctionArea"),
9+
(4, 'DiningRoom', 1, "FunctionArea"),
10+
(5, 'ChildRoom', 0, "Bedroom"),
11+
(6, 'StudyRoom', 0, "Bedroom"),
12+
(7, 'SecondRoom', 0, "Bedroom"),
13+
(8, 'GuestRoom', 0, "Bedroom"),
14+
(9, 'Balcony', 1, "PublicArea"),
15+
(10, 'Entrance', 1, "PublicArea"),
16+
(11, 'Storage', 0, "PublicArea"),
17+
(12, 'Wall-in', 0, "PublicArea"),
18+
(13, 'External', 0, "External"),
19+
(14, 'ExteriorWall', 0, "ExteriorWall"),
20+
(15, 'FrontDoor', 0, "FrontDoor"),
21+
(16, 'InteriorWall', 0, "InteriorWall"),
22+
(17, 'InteriorDoor', 0, "InteriorDoor")]
23+
24+
def savemat(file_path,data):
25+
sio.savemat(file_path,data)
26+
27+
def loadmat(file_path):
28+
return sio.loadmat(file_path, squeeze_me=True, struct_as_record=False)
29+
30+
def savepkl(file_path,data):
31+
pickle.dump(data,open(file_path,'wb'))
32+
33+
def loadpkl(file_path):
34+
return pickle.load(open(file_path,'rb'))
35+
36+
def get_color_map():
37+
color = np.array([
38+
[244,242,229], # living room
39+
[253,244,171], # bedroom
40+
[234,216,214], # kitchen
41+
[205,233,252], # bathroom
42+
[208,216,135], # balcony
43+
[185,231,168], # balcony
44+
[249,222,189], # Storage
45+
[ 79, 79, 79], # exterior wall
46+
[255,225, 25], # FrontDoor
47+
[128,128,128], # interior wall
48+
[255,255,255]
49+
],dtype=np.int64)
50+
cIdx = np.array([1,2,3,4,1,2,2,2,2,5,1,6,1,10,7,8,9,10])-1
51+
return color[cIdx]
52+
53+
def collide2d(bbox1, bbox2, th=0):
54+
return not(
55+
(bbox1[0]-th > bbox2[2]) or
56+
(bbox1[2]+th < bbox2[0]) or
57+
(bbox1[1]-th > bbox2[3]) or
58+
(bbox1[3]+th < bbox2[1])
59+
)
60+
61+
edge_type = ['left-above',
62+
'left-below',
63+
'left-of',
64+
'above',
65+
'inside',
66+
'surrounding',
67+
'below',
68+
'right-of',
69+
'right-above',
70+
'right-below']
71+
72+
def point_box_relation(u,vbox):
73+
uy,ux = u
74+
vy0, vx0, vy1, vx1 = vbox
75+
if (ux<vx0 and uy<=vy0) or (ux==vx0 and uy==vy0):
76+
relation = 0 # 'left-above'
77+
elif (vx0<=ux<vx1 and uy<=vy0):
78+
relation = 3 # 'above'
79+
elif (vx1<=ux and uy<vy0) or (ux==vx1 and uy==vy0):
80+
relation = 8 # 'right-above'
81+
elif (vx1<=ux and vy0<=uy<vy1):
82+
relation = 7 # 'right-of'
83+
elif (vx1<ux and vy1<=uy) or (ux==vx1 and uy==vy1):
84+
relation = 9 # 'right-below'
85+
elif (vx0<ux<=vx1 and vy1<=uy):
86+
relation = 6 # 'below'
87+
elif (ux<=vx0 and vy1<uy) or (ux==vx0 and uy==vy1):
88+
relation = 1 # 'left-below'
89+
elif(ux<=vx0 and vy0<uy<=vy1):
90+
relation = 2 # 'left-of'
91+
elif(vx0<ux<vx1 and vy0<uy<vy1):
92+
relation = 4 # 'inside'
93+
94+
return relation
95+
96+
def get_edges(boxes,th=9):
97+
edges = []
98+
for u in range(len(boxes)):
99+
for v in range(u+1,len(boxes)):
100+
if not collide2d(boxes[u,:4],boxes[v,:4],th=th): continue
101+
uy0, ux0, uy1, ux1 = boxes[u,:4].astype(int)
102+
vy0, vx0, vy1, vx1 = boxes[v,:4].astype(int)
103+
uc = (uy0+uy1)/2,(ux0+ux1)/2
104+
vc = (vy0+vy1)/2,(vx0+vx1)/2
105+
if ux0 < vx0 and ux1 > vx1 and uy0 < vy0 and uy1 > vy1:
106+
relation = 5 #'surrounding'
107+
elif ux0 >= vx0 and ux1 <= vx1 and uy0 >= vy0 and uy1 <= vy1:
108+
relation = 4 #'inside'
109+
else:
110+
relation = point_box_relation(uc,boxes[v,:4])
111+
edges.append([u,v,relation])
112+
113+
edges = np.array(edges,dtype=int)
114+
return edges
115+
116+
door_pos = [
117+
'nan',
118+
'bottom',
119+
'bottom-right','right-bottom',
120+
'right',
121+
'right-top','top-right',
122+
'top',
123+
'top-left','left-top',
124+
'left',
125+
'left-bottom','bottom-left'
126+
]
127+
128+
def door_room_relation(d_center,r_box):
129+
y0,x0,y1,x1 = r_box
130+
yc,xc = (y1+y0)/2, (x0+x1)/2
131+
y,x = d_center
132+
133+
if x==xc and y<yc:return 7
134+
elif x==xc and y>yc:return 1
135+
elif y==yc and x<xc:return 10
136+
elif y==yc and x>xc:return 4
137+
elif x0<x<xc:
138+
if y<yc:return 8
139+
else:return 12
140+
elif xc<x<x1:
141+
if y<yc:return 6
142+
else:return 2
143+
elif y0<y<yc:
144+
if x<xc:return 9
145+
else:return 5
146+
elif yc<y<y1:
147+
if x<xc:return 11
148+
else:return 3
149+
else:return 0

‎test.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import matplotlib.pyplot as plt
2+
3+
from rplan.floorplan import Floorplan
4+
from rplan.align import align_fp_gt
5+
from rplan.decorate import get_dw
6+
from rplan.plot import get_figure,get_axes,plot_category,plot_boundary,plot_graph,plot_fp
7+
8+
RPLAN_DIR = './data'
9+
file_path = f'{RPLAN_DIR}/0.png'
10+
fp = Floorplan(file_path)
11+
data = fp.to_dict()
12+
13+
boxes_aligned, order, room_boundaries = align_fp_gt(data['boundary'],data['boxes'],data['types'],data['edges'])
14+
data['boxes_aligned'] = boxes_aligned
15+
data['order'] = order
16+
data['room_boundaries'] = room_boundaries
17+
18+
doors,windows = get_dw(data)
19+
data['doors'] = doors
20+
data['windows'] = windows
21+
22+
fig = get_figure([512,512])
23+
plot_boundary(data['boundary'],ax=get_axes(fig=fig,rect=[0,0.5,0.5,0.5]))
24+
ax = plot_category(fp.category,ax=get_axes(fig=fig,rect=[0.5,0.5,0.5,0.5]))
25+
plot_graph(data['boundary'],data['boxes'],data['types'],data['edges'],ax=ax)
26+
plot_fp(data['boundary'], data['boxes_aligned'][order], data['types'][order],ax=get_axes(fig=fig,rect=[0,0,0.5,0.5]))
27+
plot_fp(data['boundary'], data['boxes_aligned'][order], data['types'][order],data['doors'],data['windows'],ax=get_axes(fig=fig,rect=[0.5,0,0.5,0.5]))
28+
fig.canvas.draw()
29+
fig.canvas.print_figure('./output/plot.png')

0 commit comments

Comments
 (0)
Please sign in to comment.