demo enhanced
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled

This commit is contained in:
Jonathon Broughton
2023-11-13 21:59:38 +00:00
parent 5ad615eb5b
commit b221d2168e
3 changed files with 31 additions and 35 deletions
+17 -23
View File
@@ -1,3 +1,4 @@
from collections import defaultdict
from concurrent.futures import ProcessPoolExecutor, as_completed from concurrent.futures import ProcessPoolExecutor, as_completed
from typing import List, Tuple, Any, Optional from typing import List, Tuple, Any, Optional
@@ -63,7 +64,7 @@ def detect_clashes_old(
def check_for_clash( def check_for_clash(
ref_element: Element, latest_element: Element ref_element: Element, latest_element: Element
) -> Optional[tuple[Any, Any, Any]]: ) -> Optional[tuple[Any, Any]]:
""" """
Check for a clash between two elements and calculate the severity of the clash. Check for a clash between two elements and calculate the severity of the clash.
@@ -86,16 +87,14 @@ def check_for_clash(
intersection = pymesh.boolean(latest_pymesh, ref_pymesh, operation="intersection") intersection = pymesh.boolean(latest_pymesh, ref_pymesh, operation="intersection")
if intersection and intersection.volume > 0: if intersection and intersection.volume > 0:
severity = intersection.volume / min(
ref_pymesh.volume, latest_pymesh.volume return ref_element.id, latest_element.id
)
return ref_element.id, latest_element.id, severity
return None return None
def detect_clashes( def detect_clashes(
reference_elements: List[Element], latest_elements: List[Element], _tolerance: float reference_elements: List[Element], latest_elements: List[Element], _tolerance: float
) -> List[Tuple[str, str, float]]: ) -> List[Tuple[str, str]]:
""" """
Detect clashes between two sets of mesh elements using parallel processing. Detect clashes between two sets of mesh elements using parallel processing.
@@ -127,30 +126,25 @@ def detect_and_report_clashes(
latest_elements: list[Element], latest_elements: list[Element],
tolerance: float, tolerance: float,
automate_context: AutomationContext, automate_context: AutomationContext,
) -> list[tuple[str, str, float]]: ) -> list[tuple[str, str]]:
print(f"{len(reference_elements[0].meshes)} reference meshes")
print(f"{len(latest_elements[0].meshes)} latest meshes")
clashes = detect_clashes(reference_elements, latest_elements, tolerance) clashes = detect_clashes(reference_elements, latest_elements, tolerance)
total_clashes = len(clashes) grouped_clashes = defaultdict(list)
padding_length = len(str(total_clashes))
for i, (ref_id, latest_id, severity) in enumerate(clashes, start=1): for ref, latest in clashes:
clash_number = str(i).zfill(padding_length) if not latest:
combined_message = f"Clash {clash_number}: between {ref_id} and {latest_id} with severity {severity:.2f}" continue
object_ids = [ref_id, latest_id] grouped_clashes[ref].append(latest)
# Assuming severity levels: Low (<0.25), Medium (0.25-0.75), High (>0.75) TODO: Determine severity levels for group_number, clashing_objects in enumerate(grouped_clashes.items(), start=1):
if severity > 0.75:
category = "High" ref_id, latest_elements = clashing_objects
elif severity > 0.25:
category = "Medium" all_clashing_objects = [ref_id] + [element_id for element_id in latest_elements]
else:
category = "Low"
automate_context.attach_error_to_objects( automate_context.attach_error_to_objects(
category=category, object_ids=object_ids, message=combined_message category="Clash", object_ids=all_clashing_objects, message=str(group_number)
) )
return clashes return clashes
+10 -8
View File
@@ -2,6 +2,7 @@
use the automation_context module to wrap your function in an Automate context helper use the automation_context module to wrap your function in an Automate context helper
""" """
from collections import defaultdict
from typing import Optional from typing import Optional
from pydantic import Field from pydantic import Field
@@ -132,17 +133,23 @@ def automate_function(
tolerance = function_inputs.tolerance tolerance = function_inputs.tolerance
if len(reference_mesh_elements) == 0 or len(latest_mesh_elements) == 0:
automate_context.mark_run_failed(
status_message="Clash detection failed. No objects to compare."
)
return
clashes = detect_and_report_clashes( clashes = detect_and_report_clashes(
reference_mesh_elements, latest_mesh_elements, tolerance, automate_context reference_mesh_elements, latest_mesh_elements, tolerance, automate_context
) )
percentage_reference_objects_clashing = ( percentage_reference_objects_clashing = (
len(set([ref_id for ref_id, latest_id, severity in clashes])) len(set([ref_id for ref_id, latest_id in clashes]))
/ len(reference_mesh_elements) / len(reference_mesh_elements)
* 100 * 100
) )
percentage_latest_objects_clashing = ( percentage_latest_objects_clashing = (
len(set([latest_id for ref_id, latest_id, severity in clashes])) len(set([latest_id for ref_id, latest_id in clashes]))
/ len(latest_mesh_elements) / len(latest_mesh_elements)
* 100 * 100
) )
@@ -151,11 +158,6 @@ def automate_function(
all_objects_count = len(reference_mesh_elements) + len(latest_mesh_elements) all_objects_count = len(reference_mesh_elements) + len(latest_mesh_elements)
all_clashes_count = len(clashes) all_clashes_count = len(clashes)
print(f"Clash detection report: {all_clashes_count} clashes found between {all_objects_count} objects.")
print(f"Reference objects: {len([x for x in reference_objects])}.")
print(f"Latest objects: {len([x for x in latest_objects])}.")
clash_report_message = ( clash_report_message = (
f"Clash detection report: {all_clashes_count} clashes found " f"Clash detection report: {all_clashes_count} clashes found "
f"between {all_objects_count} objects. " f"between {all_objects_count} objects. "
+4 -4
View File
@@ -97,8 +97,8 @@ def test_object() -> Base:
# fixture to mock the AutomationRunData that would be generated by a full Automation Run # fixture to mock the AutomationRunData that would be generated by a full Automation Run
def fake_automation_run_data(request, test_client: SpeckleClient) -> AutomationRunData: def fake_automation_run_data(request, test_client: SpeckleClient) -> AutomationRunData:
server_url = request.config.SPECKLE_SERVER_URL server_url = request.config.SPECKLE_SERVER_URL
project_id = "4f064f09e6" project_id = "7d8e96669a"
model_id = "5a16cf52af" model_id = "efeb71387b"
function_name = "Clash Test" function_name = "Clash Test"
@@ -119,7 +119,7 @@ def fake_automation_run_data(request, test_client: SpeckleClient) -> AutomationR
project_id=project_id, project_id=project_id,
model_id=model_id, model_id=model_id,
branch_name="main", branch_name="main",
version_id="861bbab860", version_id="2eb06c1034",
speckle_server_url=server_url, speckle_server_url=server_url,
# These ids would be available with a valid registered Automation definition. # These ids would be available with a valid registered Automation definition.
automation_id=automation_id, automation_id=automation_id,
@@ -142,7 +142,7 @@ def test_function_run(fake_automation_run_data: AutomationRunData, speckle_token
context, context,
automate_function, automate_function,
FunctionInputs( FunctionInputs(
tolerance=0.1, tolerance_unit="mm", static_model_name="structures from revit" tolerance=0.1, tolerance_unit="mm", static_model_name="simple beams"
), ),
) )