예제 #1
0
    def test_floor_encoding_and_decoding(self):
        p2 = Polygon.from_absolute_coordinates([(12, 0), (22, 0), (22, 10), (12, 10)])
        r2 = Room(p2)
        f1 = Floor("Building cool name", "Floor cool name", [self.room1, r2])

        f_dump = json.dumps(f1.to_serializable())
        f_load = json.loads(f_dump)

        f2 = Floor.from_serializable(f_load)

        self.assertEqual(f1, f2)
예제 #2
0
   def test_floor_encoding_and_decoding(self):
      p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
      r2 = Room(p2)
      f1 = Floor("Building cool name","Floor cool name", [self.room1,r2])

      f_dump = json.dumps(f1.to_serializable())
      f_load = json.loads(f_dump)

      f2 = Floor.from_serializable(f_load)

      self.assertEqual(f1,f2)
예제 #3
0
 def test_floor_equal(self):
    p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
    r2 = Room(p2)
    floor = Floor("Building 1", "Floor1", [self.room1,r2])
    floor2 = Floor("Building 1", "Floor1",[self.room1,r2])
    self.assertEqual(floor,floor2)
    floor3 = Floor("Building 1", "Floor", [self.room1,r2])
    self.assertNotEqual(floor, floor3)
    floor3 = Floor("Building", "Floor1", [self.room1,r2])
    self.assertNotEqual(floor, floor3)
    floor3 = Floor("Building 1", "Floor1", [self.room1])
    self.assertNotEqual(floor, floor3)
예제 #4
0
   def test_calculate_scale_amount_and_trasform(self):
      polygon = Polygon.from_absolute_coordinates(
            [(0,0),(1024,0),(1024,1024),(2048,1024),(2048,2048),(0,2048)]
         )
      room = Room(polygon)
      f = Floor("Pippo", "disneyland", [room])
      self.assertEqual(f.max_output_size / 2048, f.calculate_scale_amount())

      f.normalize()
      for point in f.rooms[0].polygon.points:
         self.assertTrue(point.x <= f.max_output_size)
         self.assertTrue(point.y <= f.max_output_size)
예제 #5
0
   def test_floor_to_serializable(self):
      p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
      r2 = Room(p2)
      f  = Floor("Building cool name","Floor cool name", [self.room1, r2])

      self.assertEqual( f.to_serializable() ,
         {
            "walls"     : [],
            "windows"   : [],
            "b_id"      : f.b_id,
            "f_id"      : f.f_id,
            "rooms"     : [self.room1.to_serializable(), r2.to_serializable()]
         })
예제 #6
0
   def test_associate_text_to_rooms(self):
      p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
      r2 = Room(p2)
      t1 = Text("Text room 1", Point(5,5))
      t2 = Text("Text room 2", Point(15,8))
      t3 = Text("Text outside",Point(11,5))

      floor = Floor("Building 1", "Floor1",[self.room1, r2])
      floor.associate_room_texts([t1,t2,t3])

      self.assertEqual( len(self.room1.texts), 1 )
      self.assertTrue( len(r2.texts) == 1 )
      self.assertTrue( t1 in self.room1.texts )
      self.assertTrue( t2 in r2.texts )
예제 #7
0
    def test_floor_to_serializable(self):
        p2 = Polygon.from_absolute_coordinates([(12, 0), (22, 0), (22, 10), (12, 10)])
        r2 = Room(p2)
        f = Floor("Building cool name", "Floor cool name", [self.room1, r2])

        self.assertEqual(
            f.to_serializable(),
            {
                "walls": [],
                "windows": [],
                "b_id": f.b_id,
                "f_id": f.f_id,
                "rooms": [self.room1.to_serializable(), r2.to_serializable()],
            },
        )
예제 #8
0
    def __init__(self, filename):
        """
      Try reading a dxf file pointed by filename and save the floor in the
      respective attribute.

      Arguments:
      - filename: string rapresents the filename with path of the dxf file.

      Raise:
      - FileUpdateException in case of impossibility to identify building, floor
      or rooms.

      Initialise a DxfReader, try to read a dxf file and associate the texts
      found to the respective room. Call the FloorInference class to find a
      standard floor id, and save the results of the operations in the floor
      attribute as a Floor object.
      """

        self._filename = filename
        self._basename = os.path.basename(filename)
        self.floor = None

        self._read_dxf(self._filename)
        self._extract_entities()

        b_id = self._get_b_id(self._basename)

        if not b_id:
            raise FileUpdateException(
                "It was not possible to identify the building associated to the DXF file"
            )

        f_id = FloorInference.get_identifier(self._basename, self._grabber)

        if not f_id:
            raise FileUpdateException(
                "It was not possible to identify the floor associated to the DXF file"
            )

        self.floor = Floor(b_id, f_id, self._rooms, self._wall_lines,
                           self._window_lines)
        if self.floor.n_rooms == 0:
            raise FileUpdateException("The floor read has no rooms: " +
                                      self._filename)
        self.floor.associate_room_texts(self._texts)
        self.floor.normalize()
        self.floor.discard_tiny_lines()
예제 #9
0
   def test_associate_text_to_rooms2(self):
      p2 = Polygon.from_absolute_coordinates([(6,0),(12,0),(12,10),(11,10),(11,4),(6,4)])
      r2 = Room(p2)
      t1_1     = Text("Text room 1",Point(2,2))
      t1_2     = Text("Text room 1",Point(8,8))
      t2_1     = Text("Text room 2",Point(7,2))
      t2_2     = Text("Text room 2",Point(11,8))
      t_none   = Text("Text none",Point(5,12))

      floor = Floor("Building 1", "Floor1",[ self.room1,r2])
      floor.associate_room_texts([t1_1,t1_2,t2_1,t2_2,t_none])

      self.assertTrue( len(self.room1.texts) == 2 )
      self.assertTrue( len(r2.texts) == 2 )
      self.assertTrue( t1_1 in self.room1.texts )
      self.assertTrue( t1_2 in self.room1.texts )
      self.assertTrue( t2_1 in r2.texts )
      self.assertTrue( t2_2 in r2.texts )
      self.assertTrue( t1_1 in self.room1.texts )
      self.assertTrue( t_none not in self.room1.texts )
예제 #10
0
   def __init__(self, filename):
      """
      Try reading a dxf file pointed by filename and save the floor in the
      respective attribute.

      Arguments:
      - filename: string rapresents the filename with path of the dxf file.

      Raise:
      - FileUpdateException in case of impossibility to identify building, floor
      or rooms.

      Initialise a DxfReader, try to read a dxf file and associate the texts
      found to the respective room. Call the FloorInference class to find a
      standard floor id, and save the results of the operations in the floor
      attribute as a Floor object.
      """

      self._filename = filename;
      self._basename = os.path.basename(filename)
      self.floor     = None

      self._read_dxf(self._filename)
      self._extract_entities()


      b_id = self._get_b_id(self._basename)

      if not b_id:
         raise FileUpdateException("It was not possible to identify the building associated to the DXF file")

      f_id = FloorInference.get_identifier(
                     self._basename,
                     self._grabber
                  )

      if not f_id:
         raise FileUpdateException("It was not possible to identify the floor associated to the DXF file")

      self.floor = Floor(b_id, f_id, self._rooms, self._wall_lines, self._window_lines)
      if self.floor.n_rooms == 0:
         raise FileUpdateException("The floor read has no rooms: " + self._filename)
      self.floor.associate_room_texts(self._texts)
      self.floor.normalize()
      self.floor.discard_tiny_lines()
예제 #11
0
class DxfReader():
   """
      Class to read the dxf file with the dxfgrabber.
   """

   # Todo: extract to external config file
   valid_poly_layers = ["RM$"]
   valid_text_layers = ["NLOCALI", "RM$TXT"]
   valid_wall_layers = ["MURI", "GROS$"]

   def __init__(self, filename):
      """
      Try reading a dxf file pointed by filename and save the floor in the
      respective attribute.

      Arguments:
      - filename: string rapresents the filename with path of the dxf file.

      Raise:
      - FileUpdateException in case of impossibility to identify building, floor
      or rooms.

      Initialise a DxfReader, try to read a dxf file and associate the texts
      found to the respective room. Call the FloorInference class to find a
      standard floor id, and save the results of the operations in the floor
      attribute as a Floor object.
      """

      self._filename = filename;
      self._basename = os.path.basename(filename)
      self.floor     = None

      self._read_dxf(self._filename)
      self._extract_entities()


      b_id = self._get_b_id(self._basename)

      if not b_id:
         raise FileUpdateException("It was not possible to identify the building associated to the DXF file")

      f_id = FloorInference.get_identifier(
                     self._basename,
                     self._grabber
                  )

      if not f_id:
         raise FileUpdateException("It was not possible to identify the floor associated to the DXF file")

      self.floor = Floor(b_id, f_id, self._rooms, self._wall_lines, self._window_lines)
      if self.floor.n_rooms == 0:
         raise FileUpdateException("The floor read has no rooms: " + self._filename)
      self.floor.associate_room_texts(self._texts)
      self.floor.normalize()
      self.floor.discard_tiny_lines()

   def _extract_entities(self):
      self._rooms          = []
      self._texts          = []
      self._wall_lines     = []
      self._window_lines   = []

      for ent in self._grabber.entities:
         if self._is_valid_room(ent):
            points = [(p[0], -p[1]) for p in ent.points]

            polygon = Polygon.from_absolute_coordinates(points)
            polygon.ensure_is_closed(tollerance = 0.8)
            polygon.simplify_close_points(tollerance = 0.8)

            if polygon.is_self_crossing():
               Logger.warning("Self crossing room is not valid: "+str(polygon))
               continue

            self._rooms.append(
               Room(
                  polygon
               )
            )
         elif self._is_valid_text(ent):
            self._texts.append(
               Text(
                  ent.plain_text().strip(), Point(ent.insert[0], -ent.insert[1])
               )
            )
         elif self._is_valid_wall_line(ent):
            start = Point(ent.start[0], -ent.start[1])
            end   = Point(ent.end[0], -ent.end[1])
            line  = Segment(start, end)
            self._wall_lines.append( line )

         elif self._is_valid_wall_polyline(ent):
            points = [(p[0], -p[1]) for p in ent.points]
            polygon = Polygon.from_relative_coordinates((0,0), points)
            polygon.ensure_is_closed(tollerance = 1)
            polygon.simplify_close_points(tollerance = 1)

            self._wall_lines.extend( polygon.as_segment_list() )

         elif self._is_valid_window_line(ent):
            start = Point(ent.start[0], -ent.start[1])
            end   = Point(ent.end[0], -ent.end[1])
            line  = Segment(start, end)
            self._window_lines.append( line )


   def _is_valid_room(self, ent):
      """
      Method to validate a room entity.

      Arguments:
      - ent: an entity read from the dxf file.

      Returns: True or False.

      If ent is a valid polyline in the polylines layer returns True else
      returns False.
      """

      return type(ent) in [LWPolyline, Polyline] and ent.layer in self.valid_poly_layers

   def _is_valid_text(self, ent):
      """
      Method to validate a text entity.

      Arguments:
      - ent: an entity read from the dxf file.

      Returns: True or False.

      If ent is a text in the text layers returns True else return False.
      """

      if type(ent) not in [MText, dxfgrabber.entities.Text]:
         return False

      if ent.layer not in self.valid_text_layers:
         return False

      txt = ent.plain_text().strip()
      m1  = re.match("^[a-zA-Z\d]*\d+[a-zA-Z\d]*$", txt)
      m2  = re.match("^([a-zA-Z]{2,}\s*)+$", txt)

      if not(m1 or m2):
         return False

      return True

   def _is_valid_wall_line(self, ent):
      return ent.layer.upper() in self.valid_wall_layers and type(ent) is dxfgrabber.entities.Line

   def _is_valid_wall_polyline(self, ent):
      return ent.layer.upper() in self.valid_wall_layers and type(ent) in [LWPolyline, Polyline]

   def _is_valid_window_line(self, ent):
      return ent.layer.upper() == "FINESTRE" and type(ent) is dxfgrabber.entities.Line

   def _get_b_id(self, basename):
      """
      Method to extract the building id from the filename.

      Arguments:
      - basename: a string representing the name of the dxf file.

      Returns: a string.
      """

      b_id  = None
      rm    = re.match("(\d+)_(-?[a-zA-Z0-9]+(\.\d+)?).*\.dxf", basename, re.I)

      if rm:
         b_id = rm.group(1)
      else:
         rm = re.match("(\d+)\.dxf", basename, re.I)
         if rm:
            b_id = rm.group(1)

      return b_id

   def _read_dxf(self, filename):
      """
         Read the dxf file with the dxf grabber.

         Arguments:
         - filename: representing the path and the name  of the dxf file.

         Returns: None.

         Raise: PermissionError, IsADirectoryError, FileNotFoundError or generic
         Exception in case of reading failure.

         Try to read the dxf file with the grabber.
      """

      try:
         self._grabber = dxfgrabber.readfile(filename)
      except PermissionError:
         Logger.error("Permission error: cannot read file " + filename)
         raise
      except IsADirectoryError:
         Logger.error("File is a directory error: cannot read file " + filename)
         raise
      except FileNotFoundError:
         Logger.error("File not found error: cannot read file " + filename)
         raise
      except Exception as e:
         Logger.error("Unknown exception on DXF file reading: " + str(e))
         raise
예제 #12
0
 def setUp(self):
    self.f = Floor("Pippo", "disneyland")
    self.polygon1 = Polygon.from_absolute_coordinates([(0,0),(5,0),(5,5),(10,5),(10,10),(0,10)])
    self.room1 = Room(self.polygon1)
예제 #13
0
class FloorTest(unittest.TestCase):

   def setUp(self):
      self.f = Floor("Pippo", "disneyland")
      self.polygon1 = Polygon.from_absolute_coordinates([(0,0),(5,0),(5,5),(10,5),(10,10),(0,10)])
      self.room1 = Room(self.polygon1)

   def test_floor_creation(self):
      self.assertEqual(self.f.b_id, "Pippo")
      self.assertEqual(self.f.f_id, "disneyland")
      self.assertEqual(self.f.rooms, [])

   def test_floor_room_addition(self):
      self.f.add_room(self.room1)

      self.assertEqual(self.f.rooms[0], self.room1)

      p2 = Polygon.from_absolute_coordinates( [(4, 4), (22, 14), (53, 53)] )
      r2 = Room(p2)
      self.f.add_room(r2)

      self.assertEqual(len(self.f.rooms), 2)
      self.assertTrue( r2 in self.f.rooms )

   def test_associate_text_to_rooms(self):
      p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
      r2 = Room(p2)
      t1 = Text("Text room 1", Point(5,5))
      t2 = Text("Text room 2", Point(15,8))
      t3 = Text("Text outside",Point(11,5))

      floor = Floor("Building 1", "Floor1",[self.room1, r2])
      floor.associate_room_texts([t1,t2,t3])

      self.assertEqual( len(self.room1.texts), 1 )
      self.assertTrue( len(r2.texts) == 1 )
      self.assertTrue( t1 in self.room1.texts )
      self.assertTrue( t2 in r2.texts )

   def test_associate_text_to_rooms2(self):
      p2 = Polygon.from_absolute_coordinates([(6,0),(12,0),(12,10),(11,10),(11,4),(6,4)])
      r2 = Room(p2)
      t1_1     = Text("Text room 1",Point(2,2))
      t1_2     = Text("Text room 1",Point(8,8))
      t2_1     = Text("Text room 2",Point(7,2))
      t2_2     = Text("Text room 2",Point(11,8))
      t_none   = Text("Text none",Point(5,12))

      floor = Floor("Building 1", "Floor1",[ self.room1,r2])
      floor.associate_room_texts([t1_1,t1_2,t2_1,t2_2,t_none])

      self.assertTrue( len(self.room1.texts) == 2 )
      self.assertTrue( len(r2.texts) == 2 )
      self.assertTrue( t1_1 in self.room1.texts )
      self.assertTrue( t1_2 in self.room1.texts )
      self.assertTrue( t2_1 in r2.texts )
      self.assertTrue( t2_2 in r2.texts )
      self.assertTrue( t1_1 in self.room1.texts )
      self.assertTrue( t_none not in self.room1.texts )

   def test_floor_equal(self):
      p2 = Polygon.from_absolute_coordinates([(12,0),(22,0),(22,10),(12,10)])
      r2 = Room(p2)
      floor = Floor("Building 1", "Floor1", [self.room1,r2])
      floor2 = Floor("Building 1", "Floor1",[self.room1,r2])
      self.assertEqual(floor,floor2)
      floor3 = Floor("Building 1", "Floor", [self.room1,r2])
      self.assertNotEqual(floor, floor3)
      floor3 = Floor("Building", "Floor1", [self.room1,r2])
      self.assertNotEqual(floor, floor3)
      floor3 = Floor("Building 1", "Floor1", [self.room1])
      self.assertNotEqual(floor, floor3)

   def test_floor_trasform(self):
      self.room1.traslate = MagicMock()
      self.room1.scale = MagicMock()
      self.f.add_room(self.room1)
      self.f.transform()
      self.room1.traslate.assert_called_once_with(0, 0)
      self.room1.scale.assert_called_once_with(1)

      for count in range(1, 10):
         self.f.add_room(self.room1)

      self.f.transform()
      self.assertEqual(self.room1.traslate.call_count, 11)
      self.assertEqual(self.room1.scale.call_count, 11)

   def test_floor_normalize(self):
      self.f.transform = MagicMock()
      sa = self.f.calculate_scale_amount()
      self.f.normalize()
      self.f.transform.assert_called_once_with(
         scale_amount = sa,
         traslate_x   = -self.f.min_x,
         traslate_y   = -self.f.min_y
         )

   def test_calculate_scale_amount_and_trasform(self):
      polygon = Polygon.from_absolute_coordinates(
            [(0,0),(1024,0),(1024,1024),(2048,1024),(2048,2048),(0,2048)]
         )
      room = Room(polygon)
      f = Floor("Pippo", "disneyland", [room])
      self.assertEqual(f.max_output_size / 2048, f.calculate_scale_amount())

      f.normalize()
      for point in f.rooms[0].polygon.points:
         self.assertTrue(point.x <= f.max_output_size)
         self.assertTrue(point.y <= f.max_output_size)
예제 #14
0
class DxfReader():
    """
      Class to read the dxf file with the dxfgrabber.
   """

    # Todo: extract to external config file
    valid_poly_layers = ["RM$"]
    valid_text_layers = ["NLOCALI", "RM$TXT"]
    valid_wall_layers = ["MURI", "GROS$"]

    def __init__(self, filename):
        """
      Try reading a dxf file pointed by filename and save the floor in the
      respective attribute.

      Arguments:
      - filename: string rapresents the filename with path of the dxf file.

      Raise:
      - FileUpdateException in case of impossibility to identify building, floor
      or rooms.

      Initialise a DxfReader, try to read a dxf file and associate the texts
      found to the respective room. Call the FloorInference class to find a
      standard floor id, and save the results of the operations in the floor
      attribute as a Floor object.
      """

        self._filename = filename
        self._basename = os.path.basename(filename)
        self.floor = None

        self._read_dxf(self._filename)
        self._extract_entities()

        b_id = self._get_b_id(self._basename)

        if not b_id:
            raise FileUpdateException(
                "It was not possible to identify the building associated to the DXF file"
            )

        f_id = FloorInference.get_identifier(self._basename, self._grabber)

        if not f_id:
            raise FileUpdateException(
                "It was not possible to identify the floor associated to the DXF file"
            )

        self.floor = Floor(b_id, f_id, self._rooms, self._wall_lines,
                           self._window_lines)
        if self.floor.n_rooms == 0:
            raise FileUpdateException("The floor read has no rooms: " +
                                      self._filename)
        self.floor.associate_room_texts(self._texts)
        self.floor.normalize()
        self.floor.discard_tiny_lines()

    def _extract_entities(self):
        self._rooms = []
        self._texts = []
        self._wall_lines = []
        self._window_lines = []

        for ent in self._grabber.entities:
            if self._is_valid_room(ent):
                points = [(p[0], -p[1]) for p in ent.points]

                polygon = Polygon.from_absolute_coordinates(points)
                polygon.ensure_is_closed(tollerance=0.8)
                polygon.simplify_close_points(tollerance=0.8)

                if polygon.is_self_crossing():
                    Logger.warning("Self crossing room is not valid: " +
                                   str(polygon))
                    continue

                self._rooms.append(Room(polygon))
            elif self._is_valid_text(ent):
                self._texts.append(
                    Text(ent.plain_text().strip(),
                         Point(ent.insert[0], -ent.insert[1])))
            elif self._is_valid_wall_line(ent):
                start = Point(ent.start[0], -ent.start[1])
                end = Point(ent.end[0], -ent.end[1])
                line = Segment(start, end)
                self._wall_lines.append(line)

            elif self._is_valid_wall_polyline(ent):
                points = [(p[0], -p[1]) for p in ent.points]
                polygon = Polygon.from_relative_coordinates((0, 0), points)
                polygon.ensure_is_closed(tollerance=1)
                polygon.simplify_close_points(tollerance=1)

                self._wall_lines.extend(polygon.as_segment_list())

            elif self._is_valid_window_line(ent):
                start = Point(ent.start[0], -ent.start[1])
                end = Point(ent.end[0], -ent.end[1])
                line = Segment(start, end)
                self._window_lines.append(line)

    def _is_valid_room(self, ent):
        """
      Method to validate a room entity.

      Arguments:
      - ent: an entity read from the dxf file.

      Returns: True or False.

      If ent is a valid polyline in the polylines layer returns True else
      returns False.
      """

        return type(ent) in [LWPolyline, Polyline
                             ] and ent.layer in self.valid_poly_layers

    def _is_valid_text(self, ent):
        """
      Method to validate a text entity.

      Arguments:
      - ent: an entity read from the dxf file.

      Returns: True or False.

      If ent is a text in the text layers returns True else return False.
      """

        if type(ent) not in [MText, dxfgrabber.entities.Text]:
            return False

        if ent.layer not in self.valid_text_layers:
            return False

        txt = ent.plain_text().strip()
        m1 = re.match("^[a-zA-Z\d]*\d+[a-zA-Z\d]*$", txt)
        m2 = re.match("^([a-zA-Z]{2,}\s*)+$", txt)

        if not (m1 or m2):
            return False

        return True

    def _is_valid_wall_line(self, ent):
        return ent.layer.upper(
        ) in self.valid_wall_layers and type(ent) is dxfgrabber.entities.Line

    def _is_valid_wall_polyline(self, ent):
        return ent.layer.upper() in self.valid_wall_layers and type(ent) in [
            LWPolyline, Polyline
        ]

    def _is_valid_window_line(self, ent):
        return ent.layer.upper(
        ) == "FINESTRE" and type(ent) is dxfgrabber.entities.Line

    def _get_b_id(self, basename):
        """
      Method to extract the building id from the filename.

      Arguments:
      - basename: a string representing the name of the dxf file.

      Returns: a string.
      """

        b_id = None
        rm = re.match("(\d+)_(-?[a-zA-Z0-9]+(\.\d+)?).*\.dxf", basename, re.I)

        if rm:
            b_id = rm.group(1)
        else:
            rm = re.match("(\d+)\.dxf", basename, re.I)
            if rm:
                b_id = rm.group(1)

        return b_id

    def _read_dxf(self, filename):
        """
         Read the dxf file with the dxf grabber.

         Arguments:
         - filename: representing the path and the name  of the dxf file.

         Returns: None.

         Raise: PermissionError, IsADirectoryError, FileNotFoundError or generic
         Exception in case of reading failure.

         Try to read the dxf file with the grabber.
      """

        try:
            self._grabber = dxfgrabber.readfile(filename)
        except PermissionError:
            Logger.error("Permission error: cannot read file " + filename)
            raise
        except IsADirectoryError:
            Logger.error("File is a directory error: cannot read file " +
                         filename)
            raise
        except FileNotFoundError:
            Logger.error("File not found error: cannot read file " + filename)
            raise
        except Exception as e:
            Logger.error("Unknown exception on DXF file reading: " + str(e))
            raise