mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Fix #3209. Handle loading of custom scales, fix incomplete NTS implementation, and use Lark for more reliable imperial scale parsing.
This commit is contained in:
@@ -9,6 +9,7 @@ DATA;
|
|||||||
#2=IFCSIMPLEPROPERTYTEMPLATE('23JavTMk98ZxXhrUEnjAcf',$,'TargetView','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
#2=IFCSIMPLEPROPERTYTEMPLATE('23JavTMk98ZxXhrUEnjAcf',$,'TargetView','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||||
#3=IFCSIMPLEPROPERTYTEMPLATE('1yVWUt5H9DAOuu0OaMMLpe',$,'Scale','The scale of this drawing represented as a numerator and denominator, such as 1/100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
#3=IFCSIMPLEPROPERTYTEMPLATE('1yVWUt5H9DAOuu0OaMMLpe',$,'Scale','The scale of this drawing represented as a numerator and denominator, such as 1/100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||||
#4=IFCSIMPLEPROPERTYTEMPLATE('3gsuPBtU93b8f0gg1pjkq6',$,'HumanScale','The scale of this drawing in human readable format, such as 1:100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
#4=IFCSIMPLEPROPERTYTEMPLATE('3gsuPBtU93b8f0gg1pjkq6',$,'HumanScale','The scale of this drawing in human readable format, such as 1:100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||||
|
#4=IFCSIMPLEPROPERTYTEMPLATE('2T$a4OFsv2LeD5JeBKEV4f',$,'IsNTS','Whether or not the scale is intended to be significant',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||||
#5=IFCSIMPLEPROPERTYTEMPLATE('0AK5C2UpL4$eaac2LszAx$',$,'HasUnderlay','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
#5=IFCSIMPLEPROPERTYTEMPLATE('0AK5C2UpL4$eaac2LszAx$',$,'HasUnderlay','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||||
#6=IFCSIMPLEPROPERTYTEMPLATE('2j2ZEZR8X5tONm7kli5hM6',$,'HasLinework','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
#6=IFCSIMPLEPROPERTYTEMPLATE('2j2ZEZR8X5tONm7kli5hM6',$,'HasLinework','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||||
#7=IFCSIMPLEPROPERTYTEMPLATE('1ttChRysH9UuEX2FeMj5Hu',$,'HasAnnotation','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
#7=IFCSIMPLEPROPERTYTEMPLATE('1ttChRysH9UuEX2FeMj5Hu',$,'HasAnnotation','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||||
|
|||||||
@@ -63,12 +63,7 @@ class Annotator:
|
|||||||
font_size = 1.6 / 1000
|
font_size = 1.6 / 1000
|
||||||
font_size *= float(text_obj.data.BIMTextProperties.font_size)
|
font_size *= float(text_obj.data.BIMTextProperties.font_size)
|
||||||
|
|
||||||
if camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
|
font_size /= tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"])
|
||||||
human_scale, fraction = camera.data.BIMCameraProperties.custom_diagram_scale.split("|")
|
|
||||||
else:
|
|
||||||
human_scale, fraction = camera.data.BIMCameraProperties.diagram_scale.split("|")
|
|
||||||
numerator, denominator = fraction.split("/")
|
|
||||||
font_size /= float(numerator) / float(denominator)
|
|
||||||
|
|
||||||
text_obj.data.size = font_size
|
text_obj.data.size = font_size
|
||||||
|
|
||||||
|
|||||||
@@ -171,14 +171,6 @@ class BaseDecorator:
|
|||||||
def is_landscape(render):
|
def is_landscape(render):
|
||||||
return render.resolution_x > render.resolution_y
|
return render.resolution_x > render.resolution_y
|
||||||
|
|
||||||
def get_scale(camera):
|
|
||||||
if camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
|
|
||||||
human_scale, fraction = camera.data.BIMCameraProperties.custom_diagram_scale.split("|")
|
|
||||||
else:
|
|
||||||
human_scale, fraction = camera.data.BIMCameraProperties.diagram_scale.split("|")
|
|
||||||
numerator, denominator = fraction.split("/")
|
|
||||||
return float(numerator) / float(denominator)
|
|
||||||
|
|
||||||
camera = bpy.context.scene.camera
|
camera = bpy.context.scene.camera
|
||||||
render = bpy.context.scene.render
|
render = bpy.context.scene.render
|
||||||
if is_landscape(render):
|
if is_landscape(render):
|
||||||
@@ -186,7 +178,8 @@ class BaseDecorator:
|
|||||||
else:
|
else:
|
||||||
camera_width_model = camera.data.ortho_scale / render.resolution_y * render.resolution_x
|
camera_width_model = camera.data.ortho_scale / render.resolution_y * render.resolution_x
|
||||||
|
|
||||||
camera_width_mm = get_scale(camera) * camera_width_model
|
scale = tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"])
|
||||||
|
camera_width_mm = scale * camera_width_model
|
||||||
return camera_width_mm
|
return camera_width_mm
|
||||||
|
|
||||||
def camera_zoom_to_factor(self, zoom):
|
def camera_zoom_to_factor(self, zoom):
|
||||||
|
|||||||
@@ -947,53 +947,13 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
return svg_path
|
return svg_path
|
||||||
|
|
||||||
def get_scale(self, context):
|
def get_scale(self, context):
|
||||||
camera_props = self.camera.data.BIMCameraProperties
|
diagram_scale = tool.Drawing.get_diagram_scale(self.camera)
|
||||||
if camera_props.diagram_scale == "CUSTOM":
|
self.human_scale = diagram_scale["HumanScale"]
|
||||||
if context.scene.unit_settings.system == "IMPERIAL":
|
self.scale = tool.Drawing.get_scale_ratio(diagram_scale["Scale"])
|
||||||
if (
|
|
||||||
camera_props.custom_diagram_scale_input1[-1] == "'"
|
|
||||||
or camera_props.custom_diagram_scale_input1[-1] == '"'
|
|
||||||
):
|
|
||||||
camera_props.custom_diagram_scale_input1 = camera_props.custom_diagram_scale_input1[:-1]
|
|
||||||
if camera_props.custom_diagram_scale_input2[-1] == "'":
|
|
||||||
camera_props.custom_diagram_scale_input2 = camera_props.custom_diagram_scale_input2[:-1]
|
|
||||||
if (
|
|
||||||
camera_props.custom_diagram_scale_input2[1:] == "'-0\""
|
|
||||||
or camera_props.custom_diagram_scale_input2[1:] == "' 0\""
|
|
||||||
):
|
|
||||||
camera_props.custom_diagram_scale_input2 = camera_props.custom_diagram_scale_input2[0]
|
|
||||||
if "/" in camera_props.custom_diagram_scale_input1:
|
|
||||||
if " " in camera_props.custom_diagram_scale_input1:
|
|
||||||
n1, n2 = camera_props.custom_diagram_scale_input1.split(" ")
|
|
||||||
n2_1, n2_2 = n2.split("/")
|
|
||||||
numerator = int(n1) + (int(n2_1) / int(n2_2))
|
|
||||||
elif "-" in camera_props.custom_diagram_scale_input1:
|
|
||||||
n1, n2 = camera_props.custom_diagram_scale_input1.split("-")
|
|
||||||
n2_1, n2_2 = n2.split("/")
|
|
||||||
numerator = int(n1) + (int(n2_1) / int(n2_2))
|
|
||||||
else:
|
|
||||||
n1, n2 = camera_props.custom_diagram_scale_input1.split("/")
|
|
||||||
numerator = int(n1) / int(n2)
|
|
||||||
else:
|
|
||||||
numerator = 1
|
|
||||||
denominator = (int(camera_props.custom_diagram_scale_input2) / numerator) * 12
|
|
||||||
scale = "1" + "/" + str(denominator)
|
|
||||||
human_scale = camera_props.custom_diagram_scale_input1 + "=" + camera_props.custom_diagram_scale_input2
|
|
||||||
else:
|
|
||||||
scale = camera_props.custom_diagram_scale_input1 + "/" + camera_props.custom_diagram_scale_input2
|
|
||||||
human_scale = camera_props.custom_diagram_scale_input1 + ":" + camera_props.custom_diagram_scale_input2
|
|
||||||
|
|
||||||
camera_props.custom_diagram_scale = human_scale + "|" + scale
|
if ifcopenshell.util.element.get_pset(self.camera_element, "EPset_Drawing", "IsNTS"):
|
||||||
self.human_scale, fraction = camera_props.custom_diagram_scale.split("|")
|
|
||||||
else:
|
|
||||||
self.human_scale, fraction = camera_props.diagram_scale.split("|")
|
|
||||||
|
|
||||||
if camera_props.is_nts:
|
|
||||||
self.human_scale = "NTS"
|
self.human_scale = "NTS"
|
||||||
|
|
||||||
numerator, denominator = fraction.split("/")
|
|
||||||
self.scale = float(numerator) / float(denominator)
|
|
||||||
|
|
||||||
def is_landscape(self, render):
|
def is_landscape(self, render):
|
||||||
return render.resolution_x > render.resolution_y
|
return render.resolution_x > render.resolution_y
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,27 @@ def get_location_hint(self, context):
|
|||||||
|
|
||||||
|
|
||||||
def update_diagram_scale(self, context):
|
def update_diagram_scale(self, context):
|
||||||
scale = self.diagram_scale
|
try:
|
||||||
if scale == "CUSTOM":
|
element = (
|
||||||
scale = self.custom_diagram_scale
|
tool.Ifc.get()
|
||||||
if "|" not in scale:
|
.by_id(self.id_data.BIMMeshProperties.ifc_definition_id)
|
||||||
|
.OfProductRepresentation[0]
|
||||||
|
.ShapeOfProduct[0]
|
||||||
|
)
|
||||||
|
except:
|
||||||
return
|
return
|
||||||
human_scale, scale = scale.split("|")
|
diagram_scale = tool.Drawing.get_diagram_scale(tool.Ifc.get_object(element))
|
||||||
|
if not diagram_scale:
|
||||||
|
return
|
||||||
|
pset = ifcopenshell.util.element.get_pset(element, "EPset_Drawing")
|
||||||
|
if pset:
|
||||||
|
pset = tool.Ifc.get().by_id(pset["id"])
|
||||||
|
else:
|
||||||
|
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Drawing")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=diagram_scale)
|
||||||
|
|
||||||
|
|
||||||
|
def update_is_nts(self, context):
|
||||||
try:
|
try:
|
||||||
element = (
|
element = (
|
||||||
tool.Ifc.get()
|
tool.Ifc.get()
|
||||||
@@ -85,9 +100,7 @@ def update_diagram_scale(self, context):
|
|||||||
pset = tool.Ifc.get().by_id(pset["id"])
|
pset = tool.Ifc.get().by_id(pset["id"])
|
||||||
else:
|
else:
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Drawing")
|
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Drawing")
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"IsNTS": self.is_nts})
|
||||||
"pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Scale": scale, "HumanScale": human_scale}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_diagram_scales(self, context):
|
def get_diagram_scales(self, context):
|
||||||
@@ -351,12 +364,11 @@ class BIMCameraProperties(PropertyGroup):
|
|||||||
representation: StringProperty(name="Representation")
|
representation: StringProperty(name="Representation")
|
||||||
view_name: StringProperty(name="View Name")
|
view_name: StringProperty(name="View Name")
|
||||||
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale", update=update_diagram_scale)
|
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale", update=update_diagram_scale)
|
||||||
custom_diagram_scale: StringProperty(name="Custom Scale", update=update_diagram_scale)
|
custom_scale_numerator: bpy.props.StringProperty(default="1", update=update_diagram_scale)
|
||||||
custom_diagram_scale_input1: StringProperty(name="Custom Scale Input 1", update=update_diagram_scale)
|
custom_scale_denominator: bpy.props.StringProperty(default="100", update=update_diagram_scale)
|
||||||
custom_diagram_scale_input2: StringProperty(name="Custom Scale Input 2", update=update_diagram_scale)
|
|
||||||
raster_x: IntProperty(name="Raster X", default=1000)
|
raster_x: IntProperty(name="Raster X", default=1000)
|
||||||
raster_y: IntProperty(name="Raster Y", default=1000)
|
raster_y: IntProperty(name="Raster Y", default=1000)
|
||||||
is_nts: BoolProperty(name="Is NTS")
|
is_nts: BoolProperty(name="Is NTS", update=update_is_nts)
|
||||||
active_drawing_style_index: IntProperty(name="Active Drawing Style Index")
|
active_drawing_style_index: IntProperty(name="Active Drawing Style Index")
|
||||||
|
|
||||||
# For now, this JSON dump are all the parameters that determine a camera's "Block representation"
|
# For now, this JSON dump are all the parameters that determine a camera's "Block representation"
|
||||||
|
|||||||
@@ -71,28 +71,19 @@ class BIM_PT_camera(Panel):
|
|||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(dprops, "should_extract")
|
row.prop(dprops, "should_extract")
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(props, "is_nts")
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.operator("bim.resize_text")
|
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props, "raster_x")
|
row.prop(props, "raster_x")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props, "raster_y")
|
row.prop(props, "raster_y")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row(align=True)
|
||||||
row.prop(props, "diagram_scale")
|
row.prop(props, "diagram_scale")
|
||||||
|
row.prop(props, "is_nts", text="", icon="MOD_EDGESPLIT")
|
||||||
|
|
||||||
if props.diagram_scale == "CUSTOM":
|
if props.diagram_scale == "CUSTOM":
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.prop(props, "custom_diagram_scale_input1", text="Custom Scale")
|
row.prop(props, "custom_scale_numerator", text="Custom Scale")
|
||||||
if context.scene.unit_settings.system == "IMPERIAL":
|
row.prop(props, "custom_scale_denominator", text="")
|
||||||
separator = " ="
|
|
||||||
else:
|
|
||||||
separator = " :"
|
|
||||||
row.label(text=separator)
|
|
||||||
row.prop(props, "custom_diagram_scale_input2", text="")
|
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.operator("bim.create_drawing", text="Create Drawing", icon="OUTPUT")
|
row.operator("bim.create_drawing", text="Create Drawing", icon="OUTPUT")
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
import math
|
||||||
|
import lark
|
||||||
import bmesh
|
import bmesh
|
||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
@@ -35,11 +36,10 @@ import blenderbim.bim.module.drawing.sheeter as sheeter
|
|||||||
import blenderbim.bim.module.drawing.scheduler as scheduler
|
import blenderbim.bim.module.drawing.scheduler as scheduler
|
||||||
import blenderbim.bim.module.drawing.annotation as annotation
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
import blenderbim.bim.module.drawing.helper as helper
|
import blenderbim.bim.module.drawing.helper as helper
|
||||||
|
|
||||||
from blenderbim.bim.module.drawing.data import FONT_SIZES, DecoratorData
|
from blenderbim.bim.module.drawing.data import FONT_SIZES, DecoratorData
|
||||||
from blenderbim.bim.module.drawing.prop import get_diagram_scales, BOX_ALIGNMENT_POSITIONS, ANNOTATION_TYPES_DATA
|
from blenderbim.bim.module.drawing.prop import get_diagram_scales, BOX_ALIGNMENT_POSITIONS, ANNOTATION_TYPES_DATA
|
||||||
|
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
from fractions import Fraction
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
|
||||||
@@ -580,13 +580,20 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
camera.BIMCameraProperties.diagram_scale = valid_scales[0]
|
camera.BIMCameraProperties.diagram_scale = valid_scales[0]
|
||||||
else:
|
else:
|
||||||
camera.BIMCameraProperties.diagram_scale = "CUSTOM"
|
camera.BIMCameraProperties.diagram_scale = "CUSTOM"
|
||||||
camera.BIMCameraProperties.custom_diagram_scale = pset["HumanScale"] + "|" + pset["Scale"]
|
if ":" in pset["HumanScale"]:
|
||||||
|
numerator, denominator = pset["HumanScale"].split(":")
|
||||||
|
else:
|
||||||
|
numerator, denominator = pset["HumanScale"].split("=")
|
||||||
|
camera.BIMCameraProperties.custom_scale_numerator = numerator
|
||||||
|
camera.BIMCameraProperties.custom_scale_denominator = denominator
|
||||||
if "HasUnderlay" in pset:
|
if "HasUnderlay" in pset:
|
||||||
camera.BIMCameraProperties.has_underlay = pset["HasUnderlay"]
|
camera.BIMCameraProperties.has_underlay = pset["HasUnderlay"]
|
||||||
if "HasLinework" in pset:
|
if "HasLinework" in pset:
|
||||||
camera.BIMCameraProperties.has_linework = pset["HasLinework"]
|
camera.BIMCameraProperties.has_linework = pset["HasLinework"]
|
||||||
if "HasAnnotation" in pset:
|
if "HasAnnotation" in pset:
|
||||||
camera.BIMCameraProperties.has_annotation = pset["HasAnnotation"]
|
camera.BIMCameraProperties.has_annotation = pset["HasAnnotation"]
|
||||||
|
if "IsNTS" in pset:
|
||||||
|
camera.BIMCameraProperties.is_nts = pset["IsNTS"]
|
||||||
|
|
||||||
tool.Loader.link_mesh(shape, camera)
|
tool.Loader.link_mesh(shape, camera)
|
||||||
|
|
||||||
@@ -1330,7 +1337,8 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_drawing_human_scale(cls, drawing):
|
def get_drawing_human_scale(cls, drawing):
|
||||||
return ifcopenshell.util.element.get_psets(drawing)["EPset_Drawing"].get("HumanScale", "NTS")
|
pset = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing") or {}
|
||||||
|
return "NTS" if pset.get("IsNTS", False) else pset.get("HumanScale", "NTS")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_drawing_metadata(cls, drawing):
|
def get_drawing_metadata(cls, drawing):
|
||||||
@@ -1610,3 +1618,65 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
bm.free()
|
bm.free()
|
||||||
|
|
||||||
return verts, edges
|
return verts, edges
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_scale_ratio(cls, scale):
|
||||||
|
numerator, denominator = scale.split("/")
|
||||||
|
return float(numerator) / float(denominator)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_diagram_scale(cls, obj):
|
||||||
|
props = obj.data.BIMCameraProperties
|
||||||
|
scale = props.diagram_scale
|
||||||
|
if scale != "CUSTOM":
|
||||||
|
human_scale, scale = scale.split("|")
|
||||||
|
return {"HumanScale": human_scale, "Scale": scale}
|
||||||
|
numerator_string = props.custom_scale_numerator
|
||||||
|
denominator_string = props.custom_scale_denominator
|
||||||
|
numerator = tool.Drawing.convert_scale_string(numerator_string)
|
||||||
|
denominator = tool.Drawing.convert_scale_string(denominator_string)
|
||||||
|
if not numerator or not denominator:
|
||||||
|
return
|
||||||
|
scale = str(Fraction(numerator / denominator).limit_denominator(1000)) # Any ratio >1000 is stupid.
|
||||||
|
if "'" in scale or '"' in scale:
|
||||||
|
human_separator = "=" # Imperial scales use "=", like 1" = 1' - 0"
|
||||||
|
# If for some crazy reason we mix metric and imperial, assume metric is SI units, like 1m = 1'
|
||||||
|
if "'" not in numerator_string and '"' not in numerator_string:
|
||||||
|
numerator_string += "m"
|
||||||
|
if "'" not in denominator_string and '"' not in denominator_string:
|
||||||
|
denominator_string += "m"
|
||||||
|
else:
|
||||||
|
human_separator = ":" # Metric scales use ":", like 1:100
|
||||||
|
human_scale = f"{numerator_string}{human_separator}{denominator_string}"
|
||||||
|
return {"HumanScale": human_scale, "Scale": scale}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def convert_scale_string(cls, value):
|
||||||
|
try:
|
||||||
|
return float(value)
|
||||||
|
except:
|
||||||
|
pass # Perhaps it's imperial?
|
||||||
|
l = lark.Lark(
|
||||||
|
"""start: feet? "-"? inches?
|
||||||
|
feet: NUMBER? "-"? fraction? "'"
|
||||||
|
inches: NUMBER? "-"? fraction? "\\""
|
||||||
|
fraction: NUMBER "/" NUMBER
|
||||||
|
%import common.NUMBER
|
||||||
|
%import common.WS
|
||||||
|
%ignore WS // Disregard spaces in text
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
start = l.parse(value)
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
result = 0
|
||||||
|
for dimension in start.children:
|
||||||
|
factor = 12 if dimension.data == "feet" else 1
|
||||||
|
for child in dimension.children:
|
||||||
|
if getattr(child, "data", None) == "fraction":
|
||||||
|
result += (float(child.children[0]) / float(child.children[1])) * factor
|
||||||
|
else:
|
||||||
|
result += float(child) * factor
|
||||||
|
return result * 0.0254
|
||||||
|
|||||||
Reference in New Issue
Block a user