honeybee-core 1.61.33__py2.py3-none-any.whl → 1.61.34__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
honeybee/aperture.py CHANGED
@@ -2,16 +2,18 @@
2
2
  """Honeybee Aperture."""
3
3
  from __future__ import division
4
4
  import math
5
+ import re
5
6
 
6
- from ladybug_geometry.geometry2d.pointvector import Vector2D
7
- from ladybug_geometry.geometry3d.pointvector import Point3D
8
- from ladybug_geometry.geometry3d.face import Face3D
7
+ from ladybug_geometry.geometry2d import Vector2D
8
+ from ladybug_geometry.geometry3d import Point3D, Face3D
9
9
  from ladybug.color import Color
10
10
 
11
11
  from ._basewithshade import _BaseWithShade
12
12
  from .typing import clean_string
13
+ from .search import get_attr_nested
13
14
  from .properties import ApertureProperties
14
15
  from .boundarycondition import boundary_conditions, Outdoors, Surface
16
+ from .facetype import RoofCeiling
15
17
  from .shade import Shade
16
18
  import honeybee.writer.aperture as writer
17
19
 
@@ -276,6 +278,23 @@ class Aperture(_BaseWithShade):
276
278
  """
277
279
  return isinstance(self.boundary_condition, Outdoors)
278
280
 
281
+ @property
282
+ def gbxml_type(self):
283
+ """Get text for the type of object this is in gbXML schema.
284
+
285
+ This will always be one of the following.
286
+
287
+ * FixedWindow
288
+ * OperableWindow
289
+ * FixedSkylight
290
+ * OperableSkylight
291
+ """
292
+ base_type = 'Window'
293
+ if self.has_parent and isinstance(self.parent.type, RoofCeiling):
294
+ base_type = 'Skylight'
295
+ win_type = 'Fixed' if not self.is_operable else 'Operable'
296
+ return win_type + base_type
297
+
279
298
  @property
280
299
  def type_color(self):
281
300
  """Get a Color to be used in visualizations by type."""
@@ -298,16 +317,23 @@ class Aperture(_BaseWithShade):
298
317
  return math.degrees(
299
318
  north_vector.angle_clockwise(Vector2D(self.normal.x, self.normal.y)))
300
319
 
301
- def cardinal_direction(self, north_vector=Vector2D(0, 1)):
320
+ def cardinal_direction(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
302
321
  """Get text description for the cardinal direction that the aperture is pointing.
303
322
 
304
323
  Will be one of the following: ('North', 'NorthEast', 'East', 'SouthEast',
305
- 'South', 'SouthWest', 'West', 'NorthWest').
324
+ 'South', 'SouthWest', 'West', 'NorthWest', 'Up', 'Down').
306
325
 
307
326
  Args:
308
327
  north_vector: A ladybug_geometry Vector2D for the north direction.
309
328
  Default is the Y-axis (0, 1).
310
- """
329
+ angle_tolerance: The angle tolerance in degrees used to determine if
330
+ the geometry is perfectly Up or Down. (Default: 1).
331
+ """
332
+ tilt = self.tilt
333
+ if tilt < angle_tolerance:
334
+ return 'Up'
335
+ elif tilt > 180 - angle_tolerance:
336
+ return 'Down'
311
337
  orient = self.horizontal_orientation(north_vector)
312
338
  orient_text = ('North', 'NorthEast', 'East', 'SouthEast', 'South',
313
339
  'SouthWest', 'West', 'NorthWest')
@@ -317,6 +343,31 @@ class Aperture(_BaseWithShade):
317
343
  return orient_text[i]
318
344
  return orient_text[0]
319
345
 
346
+ def cardinal_abbrev(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
347
+ """Get text abbreviation for the cardinal direction that the aperture is pointing.
348
+
349
+ Will be one of the following: ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW',
350
+ 'Up', 'Down').
351
+
352
+ Args:
353
+ north_vector: A ladybug_geometry Vector2D for the north direction.
354
+ Default is the Y-axis (0, 1).
355
+ angle_tolerance: The angle tolerance in degrees used to determine if
356
+ the aperture is perfectly Up or Down. (Default: 1).
357
+ """
358
+ tilt = self.tilt
359
+ if tilt < angle_tolerance:
360
+ return 'Up'
361
+ elif tilt > 180 - angle_tolerance:
362
+ return 'Down'
363
+ orient = self.horizontal_orientation(north_vector)
364
+ orient_text = ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW')
365
+ angles = (22.5, 67.5, 112.5, 157.5, 202.5, 247.5, 292.5, 337.5)
366
+ for i, ang in enumerate(angles):
367
+ if orient < ang:
368
+ return orient_text[i]
369
+ return orient_text[0]
370
+
320
371
  def add_prefix(self, prefix):
321
372
  """Change the identifier of this object and child objects by inserting a prefix.
322
373
 
@@ -340,6 +391,28 @@ class Aperture(_BaseWithShade):
340
391
  in self._boundary_condition._boundary_condition_objects)
341
392
  self._boundary_condition = Surface(new_bc_objs, True)
342
393
 
394
+ def rename_by_attribute(
395
+ self,
396
+ format_str='{parent.parent.display_name} - {gbxml_type} - {cardinal_direction}'
397
+ ):
398
+ """Set the display name of this Aperture using a format string with attributes.
399
+
400
+ Args:
401
+ format_str: Text string for the pattern with which the Aperture will be
402
+ renamed. Any property on this class may be used (eg. gbxml_str)
403
+ and each property should be put in curly brackets. Nested
404
+ properties can be specified by using "." to denote nesting levels
405
+ (eg. properties.energy.construction.display_name). Functions that
406
+ return string outputs can also be passed here as long as these
407
+ functions defaults specified for all arguments.
408
+ """
409
+ matches = re.findall(r'{([^}]*)}', format_str)
410
+ attributes = [get_attr_nested(self, m, decimal_count=2) for m in matches]
411
+ for attr_name, attr_val in zip(matches, attributes):
412
+ format_str = format_str.replace('{{{}}}'.format(attr_name), attr_val)
413
+ self.display_name = format_str
414
+ return format_str
415
+
343
416
  def set_adjacency(self, other_aperture):
344
417
  """Set this aperture to be adjacent to another.
345
418
 
honeybee/door.py CHANGED
@@ -2,14 +2,15 @@
2
2
  """Honeybee Door."""
3
3
  from __future__ import division
4
4
  import math
5
+ import re
5
6
 
6
- from ladybug_geometry.geometry2d.pointvector import Vector2D
7
- from ladybug_geometry.geometry3d.pointvector import Point3D
8
- from ladybug_geometry.geometry3d.face import Face3D
7
+ from ladybug_geometry.geometry2d import Vector2D
8
+ from ladybug_geometry.geometry3d import Point3D, Face3D
9
9
  from ladybug.color import Color
10
10
 
11
11
  from ._basewithshade import _BaseWithShade
12
12
  from .typing import clean_string
13
+ from .search import get_attr_nested
13
14
  from .properties import DoorProperties
14
15
  from .boundarycondition import boundary_conditions, Outdoors, Surface
15
16
  from .shade import Shade
@@ -278,6 +279,16 @@ class Door(_BaseWithShade):
278
279
  """
279
280
  return isinstance(self.boundary_condition, Outdoors)
280
281
 
282
+ @property
283
+ def gbxml_type(self):
284
+ """Get text for the type of object this is in gbXML schema."""
285
+ return 'NonSlidingDoor'
286
+
287
+ @property
288
+ def energyplus_type(self):
289
+ """Get text for the type of object this is in IDF schema."""
290
+ return 'GlassDoor' if self.is_glass else 'Door'
291
+
281
292
  @property
282
293
  def type_color(self):
283
294
  """Get a Color to be used in visualizations by type."""
@@ -300,16 +311,23 @@ class Door(_BaseWithShade):
300
311
  return math.degrees(
301
312
  north_vector.angle_clockwise(Vector2D(self.normal.x, self.normal.y)))
302
313
 
303
- def cardinal_direction(self, north_vector=Vector2D(0, 1)):
314
+ def cardinal_direction(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
304
315
  """Get text description for the cardinal direction that the door is pointing.
305
316
 
306
317
  Will be one of the following: ('North', 'NorthEast', 'East', 'SouthEast',
307
- 'South', 'SouthWest', 'West', 'NorthWest').
318
+ 'South', 'SouthWest', 'West', 'NorthWest', 'Up', 'Down').
308
319
 
309
320
  Args:
310
321
  north_vector: A ladybug_geometry Vector2D for the north direction.
311
322
  Default is the Y-axis (0, 1).
323
+ angle_tolerance: The angle tolerance in degrees used to determine if
324
+ the geometry is perfectly Up or Down. (Default: 1).
312
325
  """
326
+ tilt = self.tilt
327
+ if tilt < angle_tolerance:
328
+ return 'Up'
329
+ elif tilt > 180 - angle_tolerance:
330
+ return 'Down'
313
331
  orient = self.horizontal_orientation(north_vector)
314
332
  orient_text = ('North', 'NorthEast', 'East', 'SouthEast', 'South',
315
333
  'SouthWest', 'West', 'NorthWest')
@@ -319,6 +337,31 @@ class Door(_BaseWithShade):
319
337
  return orient_text[i]
320
338
  return orient_text[0]
321
339
 
340
+ def cardinal_abbrev(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
341
+ """Get text abbreviation for the cardinal direction that the door is pointing.
342
+
343
+ Will be one of the following: ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW',
344
+ 'Up', 'Down').
345
+
346
+ Args:
347
+ north_vector: A ladybug_geometry Vector2D for the north direction.
348
+ Default is the Y-axis (0, 1).
349
+ angle_tolerance: The angle tolerance in degrees used to determine if
350
+ the door is perfectly Up or Down. (Default: 1).
351
+ """
352
+ tilt = self.tilt
353
+ if tilt < angle_tolerance:
354
+ return 'Up'
355
+ elif tilt > 180 - angle_tolerance:
356
+ return 'Down'
357
+ orient = self.horizontal_orientation(north_vector)
358
+ orient_text = ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW')
359
+ angles = (22.5, 67.5, 112.5, 157.5, 202.5, 247.5, 292.5, 337.5)
360
+ for i, ang in enumerate(angles):
361
+ if orient < ang:
362
+ return orient_text[i]
363
+ return orient_text[0]
364
+
322
365
  def add_prefix(self, prefix):
323
366
  """Change the identifier of this object and child objects by inserting a prefix.
324
367
 
@@ -342,6 +385,28 @@ class Door(_BaseWithShade):
342
385
  in self._boundary_condition._boundary_condition_objects)
343
386
  self._boundary_condition = Surface(new_bc_objs, True)
344
387
 
388
+ def rename_by_attribute(
389
+ self,
390
+ format_str='{parent.parent.display_name} - {energyplus_type} - {cardinal_direction}'
391
+ ):
392
+ """Set the display name of this Door using a format string with attributes.
393
+
394
+ Args:
395
+ format_str: Text string for the pattern with which the Door will be
396
+ renamed. Any property on this class may be used (eg. energyplus_type)
397
+ and each property should be put in curly brackets. Nested
398
+ properties can be specified by using "." to denote nesting levels
399
+ (eg. properties.energy.construction.display_name). Functions that
400
+ return string outputs can also be passed here as long as these
401
+ functions defaults specified for all arguments.
402
+ """
403
+ matches = re.findall(r'{([^}]*)}', format_str)
404
+ attributes = [get_attr_nested(self, m, decimal_count=2) for m in matches]
405
+ for attr_name, attr_val in zip(matches, attributes):
406
+ format_str = format_str.replace('{{{}}}'.format(attr_name), attr_val)
407
+ self.display_name = format_str
408
+ return format_str
409
+
345
410
  def set_adjacency(self, other_door):
346
411
  """Set this door to be adjacent to another (and vice versa).
347
412
 
honeybee/face.py CHANGED
@@ -2,6 +2,7 @@
2
2
  """Honeybee Face."""
3
3
  from __future__ import division
4
4
  import math
5
+ import re
5
6
 
6
7
  from ladybug_geometry.geometry2d import Vector2D, Point2D, Polygon2D, Mesh2D
7
8
  from ladybug_geometry.geometry3d import Vector3D, Point3D, Plane, Face3D
@@ -9,8 +10,10 @@ from ladybug.color import Color
9
10
 
10
11
  from ._basewithshade import _BaseWithShade
11
12
  from .typing import clean_string, invalid_dict_error
13
+ from .search import get_attr_nested
12
14
  from .properties import FaceProperties
13
- from .facetype import face_types, get_type_from_normal, AirBoundary, Floor, RoofCeiling
15
+ from .facetype import face_types, get_type_from_normal, AirBoundary, Wall, \
16
+ Floor, RoofCeiling
14
17
  from .boundarycondition import boundary_conditions, get_bc_from_position, \
15
18
  _BoundaryCondition, Outdoors, Surface, Ground
16
19
  from .shade import Shade
@@ -398,6 +401,52 @@ class Face(_BaseWithShade):
398
401
  """
399
402
  return isinstance(self.boundary_condition, Outdoors)
400
403
 
404
+ @property
405
+ def gbxml_type(self):
406
+ """Get text for the type of object this is in gbXML schema.
407
+
408
+ This will always be one of the following.
409
+
410
+ * InteriorWall
411
+ * ExteriorWall
412
+ * UndergroundWall
413
+ * Roof
414
+ * Ceiling
415
+ * UndergroundCeiling
416
+ * InteriorFloor
417
+ * ExposedFloor
418
+ * UndergroundSlab
419
+ * SlabOnGrade
420
+ * Air
421
+ """
422
+ if isinstance(self.type, AirBoundary):
423
+ return 'Air'
424
+ elif isinstance(self.type, Wall):
425
+ bc_type = 'Interior'
426
+ if isinstance(self.boundary_condition, Outdoors):
427
+ bc_type = 'Exterior'
428
+ elif isinstance(self.boundary_condition, Ground):
429
+ bc_type = 'Underground'
430
+ return bc_type + 'Wall'
431
+ elif isinstance(self.type, Floor):
432
+ if isinstance(self.boundary_condition, Ground):
433
+ if self.has_parent:
434
+ for f in self.parent.faces:
435
+ if isinstance(f.type, Wall) and \
436
+ isinstance(f.boundary_condition, Outdoors):
437
+ return 'SlabOnGrade'
438
+ return 'UndergroundSlab'
439
+ elif isinstance(self.boundary_condition, Outdoors):
440
+ return 'ExposedFloor'
441
+ else:
442
+ return 'InteriorFloor'
443
+ else:
444
+ if isinstance(self.boundary_condition, Outdoors):
445
+ return 'Roof'
446
+ elif isinstance(self.boundary_condition, Ground):
447
+ return 'UndergroundCeiling'
448
+ return 'Ceiling'
449
+
401
450
  @property
402
451
  def type_color(self):
403
452
  """Get a Color to be used in visualizations by type."""
@@ -425,16 +474,23 @@ class Face(_BaseWithShade):
425
474
  return math.degrees(
426
475
  north_vector.angle_clockwise(Vector2D(self.normal.x, self.normal.y)))
427
476
 
428
- def cardinal_direction(self, north_vector=Vector2D(0, 1)):
477
+ def cardinal_direction(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
429
478
  """Get text description for the cardinal direction that the face is pointing.
430
479
 
431
480
  Will be one of the following: ('North', 'NorthEast', 'East', 'SouthEast',
432
- 'South', 'SouthWest', 'West', 'NorthWest').
481
+ 'South', 'SouthWest', 'West', 'NorthWest', 'Up', 'Down').
433
482
 
434
483
  Args:
435
484
  north_vector: A ladybug_geometry Vector2D for the north direction.
436
485
  Default is the Y-axis (0, 1).
486
+ angle_tolerance: The angle tolerance in degrees used to determine if
487
+ the Face is perfectly Up or Down. (Default: 1).
437
488
  """
489
+ tilt = self.tilt
490
+ if tilt < angle_tolerance:
491
+ return 'Up'
492
+ elif tilt > 180 - angle_tolerance:
493
+ return 'Down'
438
494
  orient = self.horizontal_orientation(north_vector)
439
495
  orient_text = ('North', 'NorthEast', 'East', 'SouthEast', 'South',
440
496
  'SouthWest', 'West', 'NorthWest')
@@ -444,6 +500,31 @@ class Face(_BaseWithShade):
444
500
  return orient_text[i]
445
501
  return orient_text[0]
446
502
 
503
+ def cardinal_abbrev(self, north_vector=Vector2D(0, 1), angle_tolerance=1):
504
+ """Get text abbreviation for the cardinal direction that the face is pointing.
505
+
506
+ Will be one of the following: ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW',
507
+ 'Up', 'Down').
508
+
509
+ Args:
510
+ north_vector: A ladybug_geometry Vector2D for the north direction.
511
+ Default is the Y-axis (0, 1).
512
+ angle_tolerance: The angle tolerance in degrees used to determine if
513
+ the Face is perfectly Up or Down. (Default: 1).
514
+ """
515
+ tilt = self.tilt
516
+ if tilt < angle_tolerance:
517
+ return 'Up'
518
+ elif tilt > 180 - angle_tolerance:
519
+ return 'Down'
520
+ orient = self.horizontal_orientation(north_vector)
521
+ orient_text = ('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW')
522
+ angles = (22.5, 67.5, 112.5, 157.5, 202.5, 247.5, 292.5, 337.5)
523
+ for i, ang in enumerate(angles):
524
+ if orient < ang:
525
+ return orient_text[i]
526
+ return orient_text[0]
527
+
447
528
  def add_prefix(self, prefix):
448
529
  """Change the identifier of this object and child objects by inserting a prefix.
449
530
 
@@ -471,6 +552,28 @@ class Face(_BaseWithShade):
471
552
  in self._boundary_condition._boundary_condition_objects)
472
553
  self._boundary_condition = Surface(new_bc_objs, False)
473
554
 
555
+ def rename_by_attribute(
556
+ self,
557
+ format_str='{parent.display_name} - {gbxml_type} - {cardinal_direction}'
558
+ ):
559
+ """Set the display name of this Face using a format string with Face attributes.
560
+
561
+ Args:
562
+ format_str: Text string for the pattern with which the Face will be
563
+ renamed. Any property on this class may be used (eg. gbxml_str)
564
+ and each property should be put in curly brackets. Nested
565
+ properties can be specified by using "." to denote nesting levels
566
+ (eg. properties.energy.construction.display_name). Functions that
567
+ return string outputs can also be passed here as long as these
568
+ functions defaults specified for all arguments.
569
+ """
570
+ matches = re.findall(r'{([^}]*)}', format_str)
571
+ attributes = [get_attr_nested(self, m, decimal_count=2) for m in matches]
572
+ for attr_name, attr_val in zip(matches, attributes):
573
+ format_str = format_str.replace('{{{}}}'.format(attr_name), attr_val)
574
+ self.display_name = format_str
575
+ return format_str
576
+
474
577
  def remove_sub_faces(self):
475
578
  """Remove all apertures and doors from the face."""
476
579
  self.remove_apertures()
honeybee/room.py CHANGED
@@ -2,6 +2,7 @@
2
2
  """Honeybee Room."""
3
3
  from __future__ import division
4
4
  import math
5
+ import re
5
6
  import uuid
6
7
 
7
8
  from ladybug_geometry.geometry2d import Point2D, Vector2D, Polygon2D
@@ -11,8 +12,7 @@ from ladybug_geometry_polyskel.polysplit import perimeter_core_subpolygons
11
12
 
12
13
  import honeybee.writer.room as writer
13
14
  from ._basewithshade import _BaseWithShade
14
- from .typing import float_in_range, int_in_range, clean_string, \
15
- invalid_dict_error
15
+ from .typing import float_in_range, int_in_range, clean_string, invalid_dict_error
16
16
  from .properties import RoomProperties
17
17
  from .face import Face
18
18
  from .aperture import Aperture
@@ -605,6 +605,81 @@ class Room(_BaseWithShade):
605
605
  face.add_prefix(prefix)
606
606
  self._add_prefix_shades(prefix)
607
607
 
608
+ def rename_by_attribute(
609
+ self, format_str='{story} - {display_name}'
610
+ ):
611
+ """Set the display name of this Room using a format string with Room attributes.
612
+
613
+ Args:
614
+ format_str: Text string for the pattern with which the Room will be
615
+ renamed. Any property on this class may be used (eg. story)
616
+ and each property should be put in curly brackets. Nested
617
+ properties can be specified by using "." to denote nesting levels
618
+ (eg. properties.energy.program_type.display_name). Functions that
619
+ return string outputs can also be passed here as long as these
620
+ functions defaults specified for all arguments.
621
+ """
622
+ matches = re.findall(r'{([^}]*)}', format_str)
623
+ attributes = [get_attr_nested(self, m) for m in matches]
624
+ for attr_name, attr_val in zip(matches, attributes):
625
+ format_str = format_str.replace('{{{}}}'.format(attr_name), attr_val)
626
+ self.display_name = format_str
627
+ return format_str
628
+
629
+ def rename_faces_by_attribute(
630
+ self,
631
+ format_str='{parent.display_name} - {gbxml_type} - {cardinal_direction}'
632
+ ):
633
+ """Set the display name for all of this Room's faces using a format string.
634
+
635
+ Args:
636
+ format_str: Text string for the pattern with which the faces will be
637
+ renamed. Any property of the Face class may be used (eg. gbxml_str)
638
+ and each property should be put in curly brackets. Nested
639
+ properties can be specified by using "." to denote nesting levels
640
+ (eg. properties.energy.construction.display_name). Functions that
641
+ return string outputs can also be passed here as long as these
642
+ functions defaults specified for all arguments.
643
+ """
644
+ for face in self.faces:
645
+ face.rename_by_attribute(format_str)
646
+
647
+ def rename_apertures_by_attribute(
648
+ self,
649
+ format_str='{parent.parent.display_name} - {gbxml_type} - {cardinal_direction}'
650
+ ):
651
+ """Set the display name for all of this Room's apertures using a format string.
652
+
653
+ Args:
654
+ format_str: Text string for the pattern with which the apertures will be
655
+ renamed. Any property on the Aperture class may be used (eg. gbxml_str)
656
+ and each property should be put in curly brackets. Nested
657
+ properties can be specified by using "." to denote nesting levels
658
+ (eg. properties.energy.construction.display_name). Functions that
659
+ return string outputs can also be passed here as long as these
660
+ functions defaults specified for all arguments.
661
+ """
662
+ for ap in self.apertures:
663
+ ap.rename_by_attribute(format_str)
664
+
665
+ def rename_doors_by_attribute(
666
+ self,
667
+ format_str='{parent.parent.display_name} - {energyplus_type} - {cardinal_direction}'
668
+ ):
669
+ """Set the display name for all of this Room's doors using a format string.
670
+
671
+ Args:
672
+ format_str: Text string for the pattern with which the doors will be
673
+ renamed. Any property on the Door class may be used (eg. gbxml_str)
674
+ and each property should be put in curly brackets. Nested
675
+ properties can be specified by using "." to denote nesting levels
676
+ (eg. properties.energy.construction.display_name). Functions that
677
+ return string outputs can also be passed here as long as these
678
+ functions defaults specified for all arguments.
679
+ """
680
+ for dr in self.doors:
681
+ dr.rename_by_attribute(format_str)
682
+
608
683
  def horizontal_boundary(self, match_walls=False, tolerance=0.01):
609
684
  """Get a Face3D representing the horizontal boundary around the Room.
610
685
 
honeybee/search.py CHANGED
@@ -82,7 +82,10 @@ def get_attr_nested(obj_instance, attr_name, decimal_count=None, cast_to_str=Tru
82
82
  else:
83
83
  current_obj = getattr(current_obj, attribute)
84
84
  if isinstance(current_obj, float) and decimal_count:
85
- return round(current_obj, decimal_count)
85
+ val = round(current_obj, decimal_count)
86
+ return str(val) if cast_to_str else val
87
+ elif callable(current_obj):
88
+ return str(current_obj()) if cast_to_str else current_obj()
86
89
  else:
87
90
  return str(current_obj) if cast_to_str else current_obj
88
91
  except AttributeError as e:
@@ -94,7 +97,10 @@ def get_attr_nested(obj_instance, attr_name, decimal_count=None, cast_to_str=Tru
94
97
  try:
95
98
  current_obj = getattr(obj_instance, attr_name)
96
99
  if isinstance(current_obj, float) and decimal_count:
97
- return round(current_obj, decimal_count)
100
+ val = round(current_obj, decimal_count)
101
+ return str(val) if cast_to_str else val
102
+ elif callable(current_obj):
103
+ return str(current_obj()) if cast_to_str else current_obj()
98
104
  else:
99
105
  return str(current_obj) if cast_to_str else current_obj
100
106
  except AttributeError:
honeybee/shade.py CHANGED
@@ -2,6 +2,7 @@
2
2
  """Honeybee Shade."""
3
3
  from __future__ import division
4
4
  import math
5
+ import re
5
6
 
6
7
  from ladybug_geometry.geometry3d.pointvector import Point3D
7
8
  from ladybug_geometry.geometry3d.face import Face3D
@@ -9,6 +10,7 @@ from ladybug.color import Color
9
10
 
10
11
  from ._base import _Base
11
12
  from .typing import clean_string
13
+ from .search import get_attr_nested
12
14
  from .properties import ShadeProperties
13
15
  import honeybee.writer.shade as writer
14
16
 
@@ -253,6 +255,11 @@ class Shade(_Base):
253
255
  """
254
256
  return math.degrees(self._geometry.azimuth)
255
257
 
258
+ @property
259
+ def gbxml_type(self):
260
+ """Get text for the type of object this is in gbXML schema."""
261
+ return 'Shade'
262
+
256
263
  @property
257
264
  def type_color(self):
258
265
  """Get a Color to be used in visualizations by type."""
@@ -280,6 +287,27 @@ class Shade(_Base):
280
287
  self.display_name = '{}_{}'.format(prefix, self.display_name)
281
288
  self.properties.add_prefix(prefix)
282
289
 
290
+ def rename_by_attribute(
291
+ self, format_str='{display_name} - {gbxml_type}'
292
+ ):
293
+ """Set the display name of this Shade using a format string with attributes.
294
+
295
+ Args:
296
+ format_str: Text string for the pattern with which the Shade will be
297
+ renamed. Any property on this class may be used (eg. energyplus_type)
298
+ and each property should be put in curly brackets. Nested
299
+ properties can be specified by using "." to denote nesting levels
300
+ (eg. properties.energy.construction.display_name). Functions that
301
+ return string outputs can also be passed here as long as these
302
+ functions defaults specified for all arguments.
303
+ """
304
+ matches = re.findall(r'{([^}]*)}', format_str)
305
+ attributes = [get_attr_nested(self, m, decimal_count=2) for m in matches]
306
+ for attr_name, attr_val in zip(matches, attributes):
307
+ format_str = format_str.replace('{{{}}}'.format(attr_name), attr_val)
308
+ self.display_name = format_str
309
+ return format_str
310
+
283
311
  def move(self, moving_vec):
284
312
  """Move this Shade along a vector.
285
313
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-core
3
- Version: 1.61.33
3
+ Version: 1.61.34
4
4
  Summary: A library to create 3D building geometry for various types of environmental simulation.
5
5
  Home-page: https://github.com/ladybug-tools/honeybee-core
6
6
  Author: Ladybug Tools
@@ -4,24 +4,24 @@ honeybee/_base.py,sha256=11TweR_0YJFv5ma1ttN2bs6FW_RlC3hNTjhhjvqXDB0,13181
4
4
  honeybee/_basewithshade.py,sha256=SXCWZ-4do6_Z-bZpVFidUINbylVyjwpkY2TIJE28Vuw,12943
5
5
  honeybee/_lockable.py,sha256=jmTVsXEWmYyEHpL3WsQZ_ItGOVVlJht1z3NFn07DIp0,3707
6
6
  honeybee/altnumber.py,sha256=nVXIvji9YDpy_I37oG41-rkPDx5QLplW9B2RYRCNeoA,1002
7
- honeybee/aperture.py,sha256=IHWU_-y1S2CEnIJnvBWU3WzwUqM3isn2JU_-3cXYPQQ,42425
7
+ honeybee/aperture.py,sha256=Kegu9rPZtRhezwsJwqVz74jxepoTmGnzzLJ3D1xUfmc,45512
8
8
  honeybee/boundarycondition.py,sha256=ys3kgMqgeJDBMLpXwSgwNBwvKMRz-LbCtLiL9tiOXS0,13777
9
9
  honeybee/checkdup.py,sha256=8q5p4tD3S4dl69jcURQhppeajJ_pYXRBlA48zTOoAGI,8221
10
10
  honeybee/colorobj.py,sha256=jhJmTBcLayFKSniW5ASo2-XMKFsW-RBUJilc9v-33ik,13349
11
11
  honeybee/config.json,sha256=GAFduJOXTlNcPM4M0fMkSXom5Cb7XZAMYQis2WsNaq0,167
12
12
  honeybee/config.py,sha256=auH_ooOyqMKAeBZxUc2NGUehUcYg8SHya98b5hfNlvM,13836
13
13
  honeybee/dictutil.py,sha256=cOqkhgJSQ3MviIkqOPv8MRb-N-BeDv07cVcNg7w7nLY,1992
14
- honeybee/door.py,sha256=xbdefvnPPhwWzU66SpNL1C1A1YW5CNC8sLRabFZUf4E,28571
14
+ honeybee/door.py,sha256=HiMBdT07_KjaGdasT2MvUdDl6XjOM7lhr-DxEy_0oZE,31406
15
15
  honeybee/extensionutil.py,sha256=DDQYhM7tFD3avRSCOjwTzLqX9ldUxl5GzY79V3_sATE,9644
16
- honeybee/face.py,sha256=RTd5NGqV-RXHqLEpKpANXp9Wi2HcDRp2AtEbPy2pqmc,108049
16
+ honeybee/face.py,sha256=j8ud3d-8Z8RvDomeiyYTqalu5czgiCMb08Xue_tFRGo,112287
17
17
  honeybee/facetype.py,sha256=vCtWZKHp21RH-Yzs8zsHJHuFhJvczNh0yFl8wDe_RWY,4489
18
18
  honeybee/logutil.py,sha256=2gn-6RcWqFLvwdFzBHPqUwFqTj_R3iwHKALrl-2eL7M,2564
19
19
  honeybee/model.py,sha256=oGuhSSBimZ-MEJKyidh6_poi7twUgeEJKUzbr_j7qcQ,175868
20
20
  honeybee/orientation.py,sha256=GogGblASW9OU-fobfDaQ7w5yRbEAFdJJuHwg2fadhKI,5046
21
21
  honeybee/properties.py,sha256=fnlT71in22HpFQGD8ta5kXNnSZVXwXq5cNgvD-hrMRg,33462
22
- honeybee/room.py,sha256=eVmfUv_9R0Tfkgcc2sKlJG60hEYZbpR6ZH20O7xK52k,152735
23
- honeybee/search.py,sha256=OiXibGGVb1ff4gTn_768i-sehB-zAYG12c0o3B0RjKE,4718
24
- honeybee/shade.py,sha256=GSlceN2kpo8NOc_QkvvxEhKozRytOS8InZ1Ge0fPuko,19746
22
+ honeybee/room.py,sha256=WrQuXHoomD_vbxF6Io8SIlUCpkXqh6j59N4yIR26mhM,156468
23
+ honeybee/search.py,sha256=KOIeQjYdj0yhRWPmF5kiFiH8Ei0WbzuiU-capnwYVeM,5060
24
+ honeybee/shade.py,sha256=HwLkOqvPpluLMXzicWXmKl4fMVJHmkqqehntT69e00Q,21026
25
25
  honeybee/shademesh.py,sha256=oldugnwhu-ibX9f0hfxpO-DvgM8U7S-dYwUjBSVzo4g,13273
26
26
  honeybee/typing.py,sha256=E8-HrCB9cSoqhFR6zcFXhrAlQRAFw_sxHGdobB8Lre8,20051
27
27
  honeybee/units.py,sha256=_qG_G5b9hdqjpyVOpGdIYCB6k8VKYjcxSJn1St-7Xjc,3204
@@ -40,9 +40,9 @@ honeybee/writer/model.py,sha256=N7F_jksf-5TrdVecuxTaFWxnPVFLmQs7k8g27TsdB7Q,177
40
40
  honeybee/writer/room.py,sha256=kFghgStTU1SEJSLigXB0VjOWhZtgs4uXuAqdwd4yRQo,174
41
41
  honeybee/writer/shade.py,sha256=EpgX-vMc-s21TnMvNWvWTKyT8iAnxu1nFVXzjY1oyF8,177
42
42
  honeybee/writer/shademesh.py,sha256=Y41bLogJ7dwpvMe5cAWVRDRVqJEwo9e5hFJQjlt6UX8,189
43
- honeybee_core-1.61.33.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
44
- honeybee_core-1.61.33.dist-info/METADATA,sha256=AvK29igv9UAsKHY_yNvrQ7pU-yIO2UI-DNsRbslkwxw,3317
45
- honeybee_core-1.61.33.dist-info/WHEEL,sha256=AHX6tWk3qWuce7vKLrj7lnulVHEdWoltgauo8bgCXgU,109
46
- honeybee_core-1.61.33.dist-info/entry_points.txt,sha256=r3YqOm40goBroH3ccUhpwQjvTwu10JWLd0HIRHI1J8E,47
47
- honeybee_core-1.61.33.dist-info/top_level.txt,sha256=8ve7puCRLUA9XDEGc1Mcs-UX9sFjpPV8MeTaIMwQ_Tg,9
48
- honeybee_core-1.61.33.dist-info/RECORD,,
43
+ honeybee_core-1.61.34.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
44
+ honeybee_core-1.61.34.dist-info/METADATA,sha256=1n2sQVCaIqbaL5-S2niJsI8mo9QC3W6TimxVwIF5mJ8,3317
45
+ honeybee_core-1.61.34.dist-info/WHEEL,sha256=AHX6tWk3qWuce7vKLrj7lnulVHEdWoltgauo8bgCXgU,109
46
+ honeybee_core-1.61.34.dist-info/entry_points.txt,sha256=r3YqOm40goBroH3ccUhpwQjvTwu10JWLd0HIRHI1J8E,47
47
+ honeybee_core-1.61.34.dist-info/top_level.txt,sha256=8ve7puCRLUA9XDEGc1Mcs-UX9sFjpPV8MeTaIMwQ_Tg,9
48
+ honeybee_core-1.61.34.dist-info/RECORD,,