Feature to constrain a resource work or number of used resources

This commit is contained in:
Sigma Dimensions (Yass)
2023-08-22 20:01:19 +01:00
parent eae6983ca5
commit 0b2007011e
8 changed files with 182 additions and 3 deletions
@@ -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)
+7
View File
@@ -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:
+69 -1
View File
@@ -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"