Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 71 additions & 48 deletions src/script/algorithm/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,68 +117,70 @@ def find_rects(windows, posts, maximal_length_of_side, minimal_length_of_side, m
return rectangles


def findBuildings(found_rects, posts=None, number_of_computercores=4):
if number_of_computercores > 1:
with Pool(processes=number_of_computercores) as pool:
def findBuildings(found_rects, fast=False, number_of_computercores=4):
if not fast:
if number_of_computercores > 1:
with Pool(processes=number_of_computercores) as pool:

progress = ProgressReport()
progress = ProgressReport()

buildings_to_check = []
for rect in found_rects:
buildings_to_check.append(Building(rect))
buildings_to_check = []
for rect in found_rects:
buildings_to_check.append(Building(rect))

buildings = buildings_to_check
with Manager() as manager:
found_rects1 = manager.list(found_rects)
while len(buildings_to_check) > 0:
buildings = buildings_to_check
with Manager() as manager:
found_rects_multi = manager.list(found_rects)
while len(buildings_to_check) > 0:

building_pools = dict()
for i in range(number_of_computercores):
building_pools[i] = []
for i in range(len(buildings_to_check)):
building_pools[i % number_of_computercores].append(buildings_to_check[i])
building_pools = dict()
for i in range(number_of_computercores):
building_pools[i] = []
for i in range(len(buildings_to_check)):
building_pools[i % number_of_computercores].append(buildings_to_check[i])

results = []
for pod in building_pools.values():
results.append(pool.apply_async(eeeh, (pod, found_rects, )))
results = []
for pod in building_pools.values():
results.append(pool.apply_async(eeeh, (pod, found_rects_multi, )))

new_buildings = set()
all_old = set()
for result in results:
new, old = result.get()
new_buildings |= new
all_old |= old
new_buildings = list(new_buildings)
new_buildings = set()
all_old = set()
for result in results:
new, old = result.get()
new_buildings |= new
all_old |= old
new_buildings = list(new_buildings)

buildings_to_check = manager.list(new_buildings)
buildings_to_check = manager.list(new_buildings)

buildings += all_old
buildings += all_old

progress.printProgress('(' + str(len(buildings[-1].rooms)) + ') Locking at possible buildings ' + str(len(buildings_to_check)) + ' of ' + str(len(buildings)), (len(buildings)-len(buildings_to_check)) / len(buildings))
progress.printProgress('(' + str(len(buildings[-1].rooms)) + ') Locking at possible buildings ' + str(len(buildings_to_check)) + ' of ' + str(len(buildings)), (len(buildings)-len(buildings_to_check)) / len(buildings))

real_buildings_first_pass = set()
for building in buildings:
if len(building.rooms) > 1:
real_buildings_first_pass.add(building)
real_buildings_first_pass = set()
for building in buildings:
if len(building.rooms) > 1:
real_buildings_first_pass.add(building)

progress.printProgress('Checking for duplicate buildings ' + str(len(real_buildings_first_pass)), 1)
progress.printProgress('Checking for duplicate buildings ' + str(len(real_buildings_first_pass)), 1)

real_buildings = set()
for building in real_buildings_first_pass:
if not is_contained_in_other(building, buildings): # TODO: multithreading
real_buildings.add(building)
real_buildings = set()
for building in real_buildings_first_pass:
if not is_contained_in_other(building, buildings): # TODO: multithreading
real_buildings.add(building)

buildings = list(real_buildings)
else:
building_list = []
for rect in found_rects:
building_list.append(Building(rect))

buildings = set()
for building in construct_building(building_list, found_rects):
if len(building.rooms) > 1:
buildings.add(building)
buildings = list(real_buildings)
else:
building_list = []
for rect in found_rects:
building_list.append(Building(rect))

buildings = set()
for building in construct_building(building_list, found_rects):
if len(building.rooms) > 1:
buildings.add(building)
else:
buildings = construct_buildings_fast(found_rects)

id = 0
for building in buildings:
Expand All @@ -188,6 +190,27 @@ def findBuildings(found_rects, posts=None, number_of_computercores=4):
return buildings


def construct_buildings_fast(found_rects):
buildings = list()
free_rects = list(found_rects)

while free_rects:
current_building = Building(free_rects.pop(0))
current_rect_index = 0
while current_rect_index < len(free_rects):
if (current_building.is_connected_to(free_rects[current_rect_index]) and
current_building.touches(free_rects[current_rect_index]) and
current_building.copy().addRoom(free_rects[current_rect_index]).is_valid()):
current_building.addRoom(free_rects.pop(current_rect_index))
current_rect_index = 0
else:
current_rect_index += 1
if len(current_building.rooms) > 1:
buildings.append(current_building)

return buildings


def construct_building(buildings, found_rects):
buildings = buildings
progress = ProgressReport(step=5.)
Expand Down
2 changes: 2 additions & 0 deletions src/script/algorithm/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def addRoom(self, rect):
self.hash = hash(self.identity)
self.form = unary_union([self.form, rect.polygon])

return self

def is_valid(self):
return self.form.is_valid and isinstance(self.form, Polygon) and len(list(self.form.interiors)) == 0

Expand Down
9 changes: 5 additions & 4 deletions src/script/commandline_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ def parseCommandline():
parser.add_argument('-maximal_difference_between_area_to_perfect_rectangle', '-adiff', help='Maximal diffence for area from perfect enclosing to real rectangle', type=float, default=0.05)
parser.add_argument('-number_of_computercores', '-cores', help='Number of computercores used in computations', type=int, default=4)
parser.add_argument('-construct_buildings', '-b', help='Construct buildings from found rectangles', action='store_true'),
parser.add_argument('-do_not_construct_buildings', '-no_b', dest='construct_buildings', action='store_false')
parser.add_argument('-construct_buildings_fast', '-bf', help='Construct buildings from found rectangles fast (might not find overlapping buildings)', action='store_true'),

return parser.parse_args()
args, unknown = parser.parse_known_args()
return args

if __name__ == '__main__':
try:
Expand All @@ -48,9 +49,9 @@ def parseCommandline():
print('\nFound {} rects in {:.3f}s'.format(len(found_rects), time.time()-start))

buildings = []
if arguments.construct_buildings:
if arguments.construct_buildings or arguments.construct_buildings_fast:
print('Finding buildings', end='', flush=True)
buildings = alg.findBuildings(found_rects, posts, number_of_computercores=arguments.number_of_computercores)
buildings = alg.findBuildings(found_rects, fast=arguments.construct_buildings_fast, number_of_computercores=arguments.number_of_computercores)
print('\nFound {} buildings in {:.3f}s'.format(len(buildings), time.time()-start))

print('Writing data to file', arguments.outputfile)
Expand Down
3 changes: 2 additions & 1 deletion src/script/gui/postaar.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ def run(self):
self.dlg.minimum_length_of_side.value(),
self.dlg.maximal_bounding_area_difference.value() / 100.0,

self.dlg.cBConstructBuilding.isChecked(),
self.dlg.gBConstructBuilding.isChecked(),
self.dlg.cBFindBuildingFast.isChecked(),

self.dlg.gBUseMulticore.isChecked(),
self.dlg.lEPythonDistribution.text(),
Expand Down
42 changes: 39 additions & 3 deletions src/script/gui/postaar_dialog_base.ui
Original file line number Diff line number Diff line change
Expand Up @@ -484,16 +484,52 @@ color: rgb(255, 0, 0);</string>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cBConstructBuilding">
<widget class="QGroupBox" name="gBConstructBuilding">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Connect rectangles with a common edge.</string>
</property>
<property name="text">
<property name="title">
<string>Construct buildings from found rectangles</string>
</property>
<property name="checked">
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QCheckBox" name="cBFindBuildingFast">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Faster, but less precise method to detect buildings</string>
</property>
<property name="text">
<string>Fast (Might miss overlapping buildings!)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
Expand Down
7 changes: 4 additions & 3 deletions src/script/gui/postaar_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import json

class postAARTask(QgsTask):
def __init__(self, iface, postlayer, postid, maximum_length_of_side, minimum_length_of_side, max_area_diff, construct_buildings, multicore, python_executable, number_of_cores):
def __init__(self, iface, postlayer, postid, maximum_length_of_side, minimum_length_of_side, max_area_diff, construct_buildings, construct_buildings_fast, multicore, python_executable, number_of_cores):
self.name = 'postAAR ' + postlayer.name() + ' (' + ("_".join(str(i) for i in [maximum_length_of_side, minimum_length_of_side, max_area_diff])) + ')'
super().__init__(self.name, QgsTask.AllFlags)

Expand All @@ -26,6 +26,7 @@ def __init__(self, iface, postlayer, postid, maximum_length_of_side, minimum_len
self.max_area_diff = max_area_diff

self.construct_buildings = construct_buildings
self.construct_buildings_fast = construct_buildings_fast

self.multicore = multicore
self.python_executable = python_executable
Expand Down Expand Up @@ -69,7 +70,7 @@ def runMulticore(self):
'-smin', str(self.minimum_length_of_side),
'-adiff', str(self.max_area_diff),
'-cores', str(self.number_of_cores),
'-b' if self.construct_buildings else '-no_b' # Todo: add building toggle
'-bf' if self.construct_buildings_fast else '-b' if self.construct_buildings else ''
]
)

Expand Down Expand Up @@ -119,7 +120,7 @@ def runSinglecore(self):

if self.construct_buildings:
QgsMessageLog.logMessage('Finding buildings', self.name, Qgis.Info)
self.buildings = alg.findBuildings(self.found_rects, self.list_of_posts, number_of_computercores=1)
self.buildings = alg.findBuildings(self.found_rects, self.construct_buildings_fast, number_of_computercores=1)
QgsMessageLog.logMessage('Found ' + str(len(self.buildings)) + ' buildings', self.name, Qgis.Info)
self.setProgress(90)

Expand Down