mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 22:50:21 +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.CalculateResourceWork,
|
||||||
operator.ImportResources,
|
operator.ImportResources,
|
||||||
operator.EditProductivityData,
|
operator.EditProductivityData,
|
||||||
|
operator.ConstrainResourceWork,
|
||||||
|
operator.RemoveUsageConstraint,
|
||||||
prop.Resource,
|
prop.Resource,
|
||||||
prop.BIMResourceProperties,
|
prop.BIMResourceProperties,
|
||||||
prop.BIMResourceTreeProperties,
|
prop.BIMResourceTreeProperties,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class ResourceData:
|
|||||||
"type": resource.is_a(),
|
"type": resource.is_a(),
|
||||||
"BaseQuantity": base_quantity,
|
"BaseQuantity": base_quantity,
|
||||||
}
|
}
|
||||||
|
results[resource.id()]["Benchmarks"] = tool.Resource.get_resource_benchmarks(resource)
|
||||||
if resource.is_a() in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
|
if resource.is_a() in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
|
||||||
results[resource.id()]["Productivity"] = {}
|
results[resource.id()]["Productivity"] = {}
|
||||||
results[resource.id()]["InheritedProductivity"] = {}
|
results[resource.id()]["InheritedProductivity"] = {}
|
||||||
|
|||||||
@@ -363,3 +363,29 @@ class EditProductivityData(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.edit_productivity_pset(tool.Ifc, tool.Resource)
|
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 = self.layout.row(align=True)
|
||||||
row.label(text="Resource type cannot have productivity data", icon="ERROR")
|
row.label(text="Resource type cannot have productivity data", icon="ERROR")
|
||||||
else:
|
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"]
|
productivity = resource["Productivity"]
|
||||||
parent_productivity = resource["InheritedProductivity"]
|
parent_productivity = resource["InheritedProductivity"]
|
||||||
|
|
||||||
|
|||||||
@@ -182,3 +182,35 @@ def edit_productivity_pset(ifc, resource_tool):
|
|||||||
else:
|
else:
|
||||||
pset = ifc.run("pset.add_pset", product=resource, name="EPset_Productivity")
|
pset = ifc.run("pset.add_pset", product=resource, name="EPset_Productivity")
|
||||||
ifc.run("pset.edit_pset", pset=pset, properties=resource_tool.get_productivity_attributes())
|
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_properties(cls): pass
|
||||||
def load_resource_time_attributes(cls, resource_time): pass
|
def load_resource_time_attributes(cls, resource_time): pass
|
||||||
def load_resources(cls): 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
|
@interface
|
||||||
class Root:
|
class Root:
|
||||||
|
|||||||
@@ -381,3 +381,71 @@ class Resource(blenderbim.core.tool.Resource):
|
|||||||
pset=pset,
|
pset=pset,
|
||||||
properties=attributes,
|
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})"
|
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 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.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" to "5.00"
|
||||||
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
||||||
And I set "scene.BIMResourceProductivity.quantity_consumed[0].hours" to "5"
|
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})"
|
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 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.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" to "5.00"
|
||||||
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
And I set "scene.BIMResourceProductivity.quantity_produced_name" to "GrossSideArea"
|
||||||
And I set "scene.BIMResourceProductivity.quantity_consumed[0].hours" to "5"
|
And I set "scene.BIMResourceProductivity.quantity_consumed[0].hours" to "5"
|
||||||
|
|||||||
Reference in New Issue
Block a user