From f2de8ce8df38fc89dbcc3ddd4990ef4763145846 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 8 Sep 2020 22:13:41 +1000 Subject: [PATCH] Implement imperial formatting for drawing dimensions --- src/ifcblenderexport/blenderbim/bim/helper.py | 142 ++++++++++++++++++ .../blenderbim/bim/svgwriter.py | 23 ++- 2 files changed, 158 insertions(+), 7 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/helper.py b/src/ifcblenderexport/blenderbim/bim/helper.py index 38d29b5bcb..3771f1a720 100644 --- a/src/ifcblenderexport/blenderbim/bim/helper.py +++ b/src/ifcblenderexport/blenderbim/bim/helper.py @@ -1,4 +1,5 @@ import math +import bpy # TODO: Deprecate this in favour of ifcopenshell.util.unit @@ -101,3 +102,144 @@ class SIUnitHelper: value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) return value + + +# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py +# MeasureIt-ARCH is GPL-v3 +# In the future I will need to rewrite this to allow the user to have custom +# settings for each annotation object, not read from Blender. +def format_distance(value, isArea=False, hide_units=True): + s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented) + + # Get Scene Unit Settings + scaleFactor = bpy.context.scene.unit_settings.scale_length + unit_system = bpy.context.scene.unit_settings.system + unit_length = bpy.context.scene.unit_settings.length_unit + imperial_precision = 32 + # (('1', "1\"", "1 Inch"), + # ('2', "1/2\"", "1/2 Inch"), + # ('4', "1/4\"", "1/4 Inch"), + # ('8', "1/8\"", "1/8th Inch"), + # ('16', "1/16\"", "1/16th Inch"), + # ('32', "1/32\"", "1/32th Inch"), + # ('64', "1/64\"", "1/64th Inch")), + + toInches = 39.3700787401574887 + inPerFoot = 11.999 + + if isArea: + toInches = 1550 + inPerFoot = 143.999 + + value *= scaleFactor + + # Imperial Formating + if unit_system == "IMPERIAL": + base = int(imperial_precision) + decInches = value * toInches + + # Seperate ft and inches + # Unless Inches are the specified Length Unit + if unit_length != 'INCHES': + feet = math.floor(decInches/inPerFoot) + decInches -= feet*inPerFoot + else: + feet = 0 + + + #Seperate Fractional Inches + inches = math.floor(decInches) + if inches != 0: + frac = round(base*(decInches-inches)) + else: + frac = round(base*(decInches)) + + #Set proper numerator and denominator + if frac != base: + numcycles = int(math.log2(base)) + for i in range(numcycles): + if frac%2 == 0: + frac = int(frac/2) + base = int(base/2) + else: + break + else: + frac = 0 + inches += 1 + + # Check values and compose string + if inches == 12: + feet += 1 + inches = 0 + + if inches !=0: + inchesString = str(inches) + if frac != 0: inchesString += "-" + else: inchesString += "\"" + else: inchesString = "" + + if feet != 0: + feetString = str(feet) + "' " + else: feetString = "" + + if frac != 0: + fracString = str(frac) + "/" + str(base) +"\"" + else: fracString = "" + + if not isArea: + tx_dist = feetString + inchesString + fracString + else: + tx_dist = str('%1.3f' % (value*toInches/inPerFoot)) + " sq. ft." + + + # METRIC FORMATING + elif unit_system == "METRIC": + + # Meters + if unit_length == 'METERS': + fmt = '%1.3f' + if hide_units is False: + fmt += " m" + tx_dist = fmt % value + # Centimeters + elif unit_length == 'CENTIMETERS': + fmt = '%1.1f' + if hide_units is False: + fmt += " cm" + d_cm = value * (100) + tx_dist = fmt % d_cm + #Millimeters + elif unit_length == 'MILLIMETERS': + fmt = '%1.0f' + if hide_units is False: + fmt += " mm" + d_mm = value * (1000) + tx_dist = fmt % d_mm + + # Otherwise Use Adaptive Units + else: + if round(value, 2) >= 1.0: + fmt = '%1.3f' + if hide_units is False: + fmt += " m" + tx_dist = fmt % value + else: + if round(value, 2) >= 0.01: + fmt = '%1.1f' + if hide_units is False: + fmt += " cm" + d_cm = value * (100) + tx_dist = fmt % d_cm + else: + fmt = '%1.0f' + if hide_units is False: + fmt += " mm" + d_mm = value * (1000) + tx_dist = fmt % d_mm + if isArea: + tx_dist += s_code + else: + tx_dist = fmt % value + + + return tx_dist diff --git a/src/ifcblenderexport/blenderbim/bim/svgwriter.py b/src/ifcblenderexport/blenderbim/bim/svgwriter.py index c5f3bd2cba..26146a74a7 100644 --- a/src/ifcblenderexport/blenderbim/bim/svgwriter.py +++ b/src/ifcblenderexport/blenderbim/bim/svgwriter.py @@ -7,6 +7,7 @@ import xml.etree.ElementTree as ET import svgwrite import ifcopenshell from . import annotation +from . import helper from mathutils import Vector from mathutils import geometry @@ -189,14 +190,18 @@ class SvgWriter(): (x_offset + projected_points[0].x) * self.scale, ((y_offset - projected_points[0].y) * self.scale) - 2.5 )) - # TODO: unhardcode m unit + # TODO: allow metric to be configurable rl = ((matrix_world @ points[0].co).xyz + self.ifc_cutter.plan_level_obj.location).z + if bpy.context.scene.unit_settings.system == 'IMPERIAL': + rl = helper.format_distance(rl) + else: + rl = '{:.3f}m'.format(rl) if projected_points[0].x > projected_points[-1].x: text_anchor = 'end' else: text_anchor = 'start' - self.svg.add(self.svg.text('RL +{:.3f}m'.format(rl), insert=tuple(text_position), **{ + self.svg.add(self.svg.text('RL +{}'.format(rl), insert=tuple(text_position), **{ 'font-size': annotation.Annotator.get_svg_text_size(2.5), 'font-family': 'OpenGost Type B TT', 'text-anchor': text_anchor, @@ -221,9 +226,13 @@ class SvgWriter(): (x_offset + projected_points[0].x) * self.scale, ((y_offset - projected_points[0].y) * self.scale) - 3.5 )) - # TODO: unhardcode m unit + # TODO: allow metric to be configurable rl = (matrix_world @ points[0].co.xyz).z - self.svg.add(self.svg.text('RL +{:.3f}m'.format(rl), insert=tuple(text_position), **{ + if bpy.context.scene.unit_settings.system == 'IMPERIAL': + rl = helper.format_distance(rl) + else: + rl = '{:.3f}m'.format(rl) + self.svg.add(self.svg.text('RL +{}'.format(rl), insert=tuple(text_position), **{ 'font-size': annotation.Annotator.get_svg_text_size(2.5), 'font-family': 'OpenGost Type B TT', 'text-anchor': 'start', @@ -485,10 +494,10 @@ class SvgWriter(): start = Vector(((x_offset + v0.x), (y_offset - v0.y))) end = Vector(((x_offset + v1.x), (y_offset - v1.y))) mid = ((end - start) / 2) + start - # TODO: hardcoded meters to mm conversion, until I properly do units vector = end - start perpendicular = Vector((vector.y, -vector.x)).normalized() - dimension = (v1_global - v0_global).length * 1000 + dimension = (v1_global - v0_global).length + dimension = helper.format_distance(dimension) sheet_dimension = ((end*self.scale) - (start*self.scale)).length if sheet_dimension < 5: # annotation can't fit # offset text to right of marker @@ -503,7 +512,7 @@ class SvgWriter(): if text_override is not None: text = text_override else: - text = str(round(dimension)) + text = str(dimension) self.svg.add(self.svg.text(text, insert=tuple(text_position), **{ 'transform': 'rotate({} {} {})'.format( rotation,