demo enhanced
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
This commit is contained in:
+17
-23
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user