mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Feature to constrain a resource work or number of used resources
This commit is contained in:
@@ -50,6 +50,8 @@ classes = (
|
||||
operator.CalculateResourceWork,
|
||||
operator.ImportResources,
|
||||
operator.EditProductivityData,
|
||||
operator.ConstrainResourceWork,
|
||||
operator.RemoveUsageConstraint,
|
||||
prop.Resource,
|
||||
prop.BIMResourceProperties,
|
||||
prop.BIMResourceTreeProperties,
|
||||
|
||||
@@ -56,6 +56,7 @@ class ResourceData:
|
||||
"type": resource.is_a(),
|
||||
"BaseQuantity": base_quantity,
|
||||
}
|
||||
results[resource.id()]["Benchmarks"] = tool.Resource.get_resource_benchmarks(resource)
|
||||
if resource.is_a() in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
|
||||
results[resource.id()]["Productivity"] = {}
|
||||
results[resource.id()]["InheritedProductivity"] = {}
|
||||
|
||||
@@ -363,3 +363,29 @@ class EditProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
core.edit_productivity_pset(tool.Ifc, tool.Resource)
|
||||
|
||||
|
||||
class ConstrainResourceWork(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_usage_constraint"
|
||||
bl_label = "Constrain Resource Work"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
attribute: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.add_usage_constraint(
|
||||
tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource), reference_path=self.attribute
|
||||
)
|
||||
|
||||
|
||||
class RemoveUsageConstraint(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.remove_usage_constraint"
|
||||
bl_label = "Remove Usage Constraint"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
attribute: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.remove_usage_constraint(
|
||||
tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource), reference_path=self.attribute
|
||||
)
|
||||
|
||||
@@ -92,6 +92,49 @@ class BIM_PT_resources(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Resource type cannot have productivity data", icon="ERROR")
|
||||
else:
|
||||
is_usage_locked = False
|
||||
is_work_locked = False
|
||||
for constraint in resource["Benchmarks"] or []:
|
||||
for metric in constraint["metrics"] or []:
|
||||
if (
|
||||
metric["ConstraintGrade"] == "HARD"
|
||||
and metric["reference"]
|
||||
and metric["reference"] == "Usage.ScheduleUsage"
|
||||
):
|
||||
is_usage_locked = True
|
||||
elif (
|
||||
metric["ConstraintGrade"] == "HARD"
|
||||
and metric["reference"]
|
||||
and metric["reference"] == "Usage.ScheduleWork"
|
||||
):
|
||||
is_work_locked = True
|
||||
row = self.layout.row()
|
||||
row.label(text="Resource Work")
|
||||
schedule_usage = "Schedule Usage: {}".format(resource.get("ScheduleUsage"))
|
||||
schedule_work = "Schedule Work: {}".format(resource.get("ScheduleWork"))
|
||||
row = self.layout.row()
|
||||
row.alignment = "LEFT"
|
||||
row.label(text=schedule_usage, icon="ARMATURE_DATA")
|
||||
row2 = self.layout.row()
|
||||
row2.alignment = "LEFT"
|
||||
row2.label(text=schedule_work, icon="ARMATURE_DATA")
|
||||
if not is_usage_locked:
|
||||
op = row.operator("bim.add_usage_constraint", text="", icon="UNLOCKED")
|
||||
op.resource = ifc_definition_id
|
||||
op.attribute = "Usage.ScheduleUsage"
|
||||
else:
|
||||
op = row.operator("bim.remove_usage_constraint", text="", icon="LOCKED")
|
||||
op.resource = ifc_definition_id
|
||||
op.attribute = "Usage.ScheduleUsage"
|
||||
if not is_work_locked:
|
||||
op = row2.operator("bim.add_usage_constraint", text="", icon="UNLOCKED")
|
||||
op.resource = ifc_definition_id
|
||||
op.attribute = "Usage.ScheduleWork"
|
||||
else:
|
||||
op = row2.operator("bim.remove_usage_constraint", text="", icon="LOCKED")
|
||||
op.resource = ifc_definition_id
|
||||
op.attribute = "Usage.ScheduleWork"
|
||||
|
||||
productivity = resource["Productivity"]
|
||||
parent_productivity = resource["InheritedProductivity"]
|
||||
|
||||
|
||||
@@ -182,3 +182,35 @@ def edit_productivity_pset(ifc, resource_tool):
|
||||
else:
|
||||
pset = ifc.run("pset.add_pset", product=resource, name="EPset_Productivity")
|
||||
ifc.run("pset.edit_pset", pset=pset, properties=resource_tool.get_productivity_attributes())
|
||||
|
||||
|
||||
def add_usage_constraint(ifc, resource_tool, resource=None, reference_path=None):
|
||||
metric = resource_tool.has_usage_metric(resource)
|
||||
if metric:
|
||||
return print("Must remove existing metric first")
|
||||
|
||||
objective = ifc.run("constraint.add_objective")
|
||||
ifc.run("constraint.edit_objective", objective=objective, attributes={"ObjectiveQualifier": "PARAMETER"})
|
||||
metric = ifc.run("constraint.add_metric", objective=objective)
|
||||
ifc.run(
|
||||
"constraint.edit_metric",
|
||||
metric=metric,
|
||||
attributes={
|
||||
"ConstraintGrade": "HARD",
|
||||
"Benchmark": "EQUALTO",
|
||||
},
|
||||
)
|
||||
ifc.run("constraint.add_metric_reference", metric=metric, reference_path=reference_path)
|
||||
ifc.run("constraint.assign_constraint", product=resource, constraint=objective)
|
||||
|
||||
|
||||
def remove_usage_constraint(ifc, resource_tool, resource, reference_path):
|
||||
constraints = resource_tool.get_constraints(resource)
|
||||
for constraint in constraints:
|
||||
metrics = resource_tool.get_metrics(constraint)
|
||||
for metric in metrics:
|
||||
reference = resource_tool.get_metric_reference(metric, is_deep=True)
|
||||
if reference == reference_path:
|
||||
ifc.run("constraint.remove_metric", metric=metric)
|
||||
ifc.run("constraint.unassign_constraint", product=resource, constraint=constraint)
|
||||
ifc.run("constraint.remove_constraint", constraint=constraint)
|
||||
|
||||
@@ -617,6 +617,13 @@ class Resource:
|
||||
def load_resource_properties(cls): pass
|
||||
def load_resource_time_attributes(cls, resource_time): pass
|
||||
def load_resources(cls): pass
|
||||
def get_constraints(cls, resource): pass
|
||||
def get_metrics(cls, constraint): pass
|
||||
def get_metric_reference(cls, metric, is_deep): pass
|
||||
def get_resource_benchmarks(cls, resource): pass
|
||||
def has_metric_constraint(cls, resource, attribute): pass
|
||||
def has_usage_metric(cls, resource): pass
|
||||
|
||||
|
||||
@interface
|
||||
class Root:
|
||||
|
||||
@@ -380,4 +380,72 @@ class Resource(blenderbim.core.tool.Resource):
|
||||
"pset.edit_pset",
|
||||
pset=pset,
|
||||
properties=attributes,
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_constraints(cls, resource):
|
||||
constraints = []
|
||||
for rel in resource.HasAssociations or []:
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
constraints.append(rel.RelatingConstraint)
|
||||
return constraints
|
||||
|
||||
@classmethod
|
||||
def get_metrics(cls, constraint):
|
||||
metrics = []
|
||||
for metric in constraint.BenchmarkValues or []:
|
||||
metrics.append(metric)
|
||||
return metrics
|
||||
|
||||
@classmethod
|
||||
def get_metric_reference(cls, metric, is_deep=True):
|
||||
def get_reference_Attribute(ref, path):
|
||||
if ref:
|
||||
if is_deep:
|
||||
if not path:
|
||||
path = ref.AttributeIdentifier
|
||||
else:
|
||||
path += ".{}".format(ref.AttributeIdentifier) if ref.AttributeIdentifier else ""
|
||||
return get_reference_Attribute(ref.InnerReference, path)
|
||||
else:
|
||||
return ref.AttributeIdentifier
|
||||
return path
|
||||
|
||||
reference = metric.ReferencePath
|
||||
return get_reference_Attribute(reference, "")
|
||||
|
||||
@classmethod
|
||||
def get_resource_benchmarks(cls, resource):
|
||||
constraints = []
|
||||
for constraint in cls.get_constraints(resource) or []:
|
||||
metrics = []
|
||||
for metric in cls.get_metrics(constraint) or []:
|
||||
metrics.append(
|
||||
{
|
||||
"reference": cls.get_metric_reference(metric),
|
||||
"Benchmark": metric.Benchmark,
|
||||
"ConstraintGrade": metric.ConstraintGrade,
|
||||
}
|
||||
)
|
||||
constraints.append({"ObjectiveQualifier": constraint.ObjectiveQualifier, "metrics": metrics})
|
||||
return constraints
|
||||
|
||||
@classmethod
|
||||
def has_metric_constraint(cls, resource, attribute):
|
||||
constraints = tool.Resource.get_constraints(resource)
|
||||
metrics = []
|
||||
for constraint in constraints:
|
||||
for metric in tool.Resource.get_metrics(constraint) or []:
|
||||
is_same_reference = bool(
|
||||
tool.Resource.get_metric_reference(metric, is_deep=False) == attribute
|
||||
or tool.Resource.get_metric_reference(metric, is_deep=True) == attribute
|
||||
)
|
||||
if is_same_reference:
|
||||
metrics.append(metric)
|
||||
if metrics:
|
||||
return metrics[0]
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def has_usage_metric(cls, resource):
|
||||
return cls.has_metric_constraint(resource, "Usage")
|
||||
|
||||
@@ -249,7 +249,7 @@ Scenario: Add Productivity data
|
||||
When I press "bim.add_resource(ifc_class="IfcLaborResource", parent_resource={crew_resource})"
|
||||
And the variable "labor_resource" is "IfcStore.get_file().by_type('IfcLaborResource')[0].id()"
|
||||
And I set "scene.BIMResourceProperties.active_resource_index" to "1"
|
||||
And I set "scene.BIMResourceProperties.should_show_productivity" to "True"
|
||||
And I set "scene.BIMResourceProperties.should_show_resource_tools" to "True"
|
||||
And I set "scene.BIMResourceProductivity.quantity_produced" to "5.00"
|
||||
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
||||
And I set "scene.BIMResourceProductivity.quantity_consumed[0].hours" to "5"
|
||||
@@ -286,7 +286,7 @@ Scenario: Calculate Resource Work
|
||||
When I press "bim.add_resource(ifc_class="IfcLaborResource", parent_resource={crew_resource})"
|
||||
And the variable "labor_resource" is "IfcStore.get_file().by_type('IfcLaborResource')[0].id()"
|
||||
And I set "scene.BIMResourceProperties.active_resource_index" to "1"
|
||||
And I set "scene.BIMResourceProperties.should_show_productivity" to "True"
|
||||
And I set "scene.BIMResourceProperties.should_show_resource_tools" to "True"
|
||||
And I set "scene.BIMResourceProductivity.quantity_produced" to "5.00"
|
||||
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
||||
And I set "scene.BIMResourceProductivity.quantity_consumed[0].hours" to "5"
|
||||
|
||||
Reference in New Issue
Block a user