Dieser Artikel beschreibt, wie man ein Python-Skript erstellt, das einen CIPM-Bericht, der aus dem Progress-Monitoring-Tool extrahiert wurde, transformiert in:
- BCF-Dateien zur Verwendung mit einem Revit-Modell oder einem anderen Tool
- formatiert Annotationen innerhalb eines Cintoo-Projekts, verbunden mit problematischen Modellelementen basierend auf dem Parameter Coverage .
Berechtigungen: Benutzer mit Rollen, die die Verwalten von Anmerkungen-Berechtigung einschließen, können mit diesem Skript Anmerkungen erstellen.
Ein Beispiel für ein Skript befindet sich im Anhang. Alle zusätzlichen Skripte sind ebenfalls angehängt.
INHALTSVERZEICHNIS
- Voraussetzungen
- Eingabeinformationen
- Genehmigung
- Einschränkungen
- Ergebnisse
- CreateBCF.py-Skript erklärt
- CreateAnnotation.py-Skript erklärt
Voraussetzungen
Installieren Sie Python anhand der Anweisungen eines AI-Chatbots Ihrer Wahl. Fragen Sie nach einer Anleitung, um Python-Skripte über die Eingabeaufforderung auszuführen, wenn keine dedizierte Umgebung installiert ist.
In diesem Python-Skript werden die folgenden Bibliotheken verwendet, um den Workflow auszuführen.
Installieren Sie sie, bevor Sie das Skript verwenden:
- png - führen Sie den folgenden Befehl aus, um die Bibliothek zu verbinden
pip install pypng
- requests - führen Sie den folgenden Befehl aus, um die Bibliothek zu verbinden
pip install requests
Eingabeinformationen
Führen Sie das Skript createBCF.py in der Eingabeaufforderung aus. Alle anderen Skripte sind ergänzender Natur.
python createBCF.py
Nach der Ausführung wird das Skript den Benutzer auffordern, die folgenden Informationen bereitzustellen:
- Geben Sie den Pfad zum CIPM .csv-Bericht ein - vollständiger Pfad zum CIPM-Bericht im CSV-Format mit Erweiterung
Beispiel: C:\Projects\ProgressMonitoring\Walls_0.0500(Meters).csv - Geben Sie den Pfad ein, in dem BCF-Dateien erstellt werden sollen - vollständiger Pfad zum Erstellen und Speichern von BCF-Dateien lokal
Beispiel: C:\Projects\ProgressMonitoring\BCF - Geben Sie die minimale Abdeckung ein - vom Benutzer definierter Grenzwert, um alle Abdeckung -Werte, die strikt darunter liegen, in Prozent zu erfassen.
Beispiel: Um BCF/Annotations für Modellelemente mit weniger als 25% Scan-Abdeckung zu erstellen, Wert 25 eingeben - Geben Sie den Pfad zur Arbeitszone ein, in der Anmerkungen erstellt werden sollen - vollständige URL-Adresse zur Arbeitszone in einem Cintoo-Projekt.
Hinweis: Es wird dringend empfohlen, eine dedizierte Arbeitszone für Anmerkungen zu erstellen, die mit diesem Skript erstellt wurden, da dies mehr Kontrolle über das Ergebnis bieten und eine einfachere Bereinigung bei Bedarf ermöglichen würde.
Beispiel: https://aec.cintoo.com/accounts/0a000a00-000a-000a-a0000aa0a00000a0/
projects/a0a0000a-aaa0000a-000a-aaaa00aaa000/workzones/aaaaaaaaaa0aaaaaaaa/data
Kopieren Sie diese URL direkt aus dem Browser.
Genehmigung
Sobald alle Parameter eingegeben sind, wird der Benutzer aufgefordert, die Nutzung eines Cintoo-Kontos auf einer angezeigten Browser-Seite zu autorisieren. Klicken Sie auf Zulassen , um fortzufahren.
Nach der Autorisierung erscheint die folgende Nachricht, die eine erfolgreiche Authentifizierung signalisiert. Diese Browser-Registerkarte kann sicher geschlossen werden.
Cintoo-tokens.json - Authentifizierungs-JSON, das vom Skript erstellt wurde, um die Verbindung herzustellen. Es wird empfohlen, bei jedem Abschluss eines Jobs vom Benutzer gelöscht zu werden.
Hinweis: Die Zeit, die für die Generierung von BCF und Anmerkungen aufgewendet wird, basiert auf dem Wert der Abdeckungsebene und der Menge der Modellelemente.
Einschränkungen
Warnung: Bitte beachten Sie, dass maximal 3000 Anmerkungen mit dem Skript unter Verwendung von APIs erstellt werden können.
Ergebnisse
- BCF-Dateien am benutzerdefinierten Pfad lokal gespeichert, die in Revit verwendet werden können, um problematische Modellelemente zu erkennen und zu korrigieren.
- Cintoo Annotations im Projekt, das visuell mit Modellelementen verbunden ist, mit allen notwendigen Daten in der Beschreibung (bearbeitbar).
CreateBCF.py-Skript erklärt
Im Folgenden finden Sie das Skript mit Kommentaren zu jedem Teil.
Warnung: Wenn Anpassungen am Code vorgenommen werden müssen, ist dies möglich, aber Cintoo übernimmt keine Verantwortung für die Funktionalität dieses Codes, sobald er geändert wurde.
import csv import os import zipfile import png from createAnnotation import createAnnotation import login from cintooUtils import parse_cintoo_workzone_context_url import datetime import uuid def create_png(path): width = 255 height = 255 img = [] for y in range(height): row = () for x in range(width): row = row + (x, max(0, 255 - x - y), y) img.append(row) with open(path, 'wb') as f: w = png.Writer(width, height, greyscale=False) w.write(f, img)
Importieren aller notwendigen Bibliotheken und ergänzenden Skripte zur Unterstützung des Hauptskripts. Erstellen einer Vorlage png, die erforderlich ist, um eine BCF-Datei zu erstellen.
def create_bcfzip(input_csv, output_dir, min_coverage, tenant=None, account_id=None, project_id=None, workzone_id=None, camera_state=None, headers=None): if not os.path.exists(output_dir): os.makedirs(output_dir) report_name = input_csv.split("\\")[-1] with open(input_csv, 'r', encoding='utf-8') as file: reader = csv.DictReader(file) elements_to_be_created = [row for row in reader if float(row['Coverage by Scan Data (%)']) < min_coverage] if len(elements_to_be_created) > 1000: print("More than 1000 elements have a lower score than the minimum coverage score. Nur die obersten 1000 werden erstellt.") elements_to_be_created = sorted( elements_to_be_created, key=lambda x: float(x['Coverage by Scan Data (%)']), reverse=True )[0:999] for row in elements_to_be_created: if (row.get('IfcGUID') or row.get('GlobalId')) and row.get('Coverage by Scan Data (%)'): print(row) try: coverage = float(row['Coverage by Scan Data (%)']) print(coverage) except ValueError: continue guid = row.get('IfcGUID') or row.get('GlobalId') element_name = row.get('Model Element Name', 'Unknown') element_id = list(row.values())[0] print(element_id) create_bcf_file(guid, element_name, output_dir, coverage, report_name) if all([tenant, account_id, project_id, workzone_id, camera_state]): createAnnotation(tenant, account_id, project_id, workzone_id, f'Low Coverage Issue: {element_name}', f"The element {element_name} has a coverage score of {coverage}, according to the report {report_name}", {"x": 0, "y": 0, "z": 0}, camera_state, headers, modelElementId=element_id)
Funktion, die BCF-Dateien erstellt, die mit jedem Element basierend auf dem vom Benutzer definierten Coverage -Parameter verknüpft sind.
Es analysiert alle notwendigen Daten aus vom Benutzer bereitgestellten Parametern wie Ausgabeverzeichnis, minimale Abdeckung, Mandant etc. und vorhandene GUIDs in den Zeilen des CIPM-Berichts, um sie basierend auf Abdeckungsvergleichen zu extrahieren.
Warnung: Es wird nicht empfohlen, die create_bcfzip-Funktion zu ändern, es sei denn, es besteht die Notwendigkeit, die Bedingung zu ändern, wie die Daten ausgewählt werden (z. B. Abdeckung<min_coverage). Bei Änderungen des Anmerkungstextes, der Beschreibung oder der Beschriftung - bitte die create_issue_xml-Funktion beachten.
def create_bcf_file(guid, element_name, output_dir, coverage, report_name):
bcf_dir = os.path.join(output_dir, guid)
os.makedirs(bcf_dir, exist_ok=True)
viewpoint_guid = str(uuid.uuid4())
comment_guid = str(uuid.uuid4())
topic_guid = str(uuid.uuid4())
project_guid = str(uuid.uuid4())
viewpoint_filename = os.path.join(bcf_dir, 'viewpoint.bcfv')
viewpoint_xml = create_viewpoint_xml(guid, viewpoint_guid)
with open(viewpoint_filename, 'w', encoding='utf-8') as f:
f.write(viewpoint_xml)
issue_filename = os.path.join(bcf_dir, 'markup.bcf')
issue_xml = create_issue_xml(element_name, coverage, report_name, viewpoint_guid, comment_guid, topic_guid)
with open(issue_filename, 'w', encoding='utf-8') as f:
f.write(issue_xml)
project_filename = os.path.join(output_dir, 'project.bcfp')
project_xml = create_project_xml(project_guid)
with open(project_filename, 'w', encoding='utf-8') as f:
f.write(project_xml)
version_filename = os.path.join(output_dir, 'bcf.version')
with open(version_filename, 'w', encoding='utf-8') as f:
f.write(create_bcf_version())
snapshot_filename = os.path.join(output_dir, 'snapshot.png')
create_png(snapshot_filename)
zip_filename = os.path.join(output_dir, f'{guid}.bcf')
with zipfile.ZipFile(zip_filename, 'w') as zf:
zf.write(viewpoint_filename, os.path.join(topic_guid, 'viewpoint.bcfv'))
zf.write(issue_filename, os.path.join(topic_guid, 'markup.bcf'))
zf.write(snapshot_filename, os.path.join(topic_guid, 'snapshot.png'))
zf.write(project_filename, os.path.join('project.bcfp'))
zf.write(version_filename, os.path.join('bcf.version'))
# Cleanup
os.remove(viewpoint_filename)
os.remove(issue_filename)
os.remove(project_filename)
os.remove(version_filename)
os.remove(snapshot_filename)
os.rmdir(bcf_dir)
Erstellen individueller BCF-Dateien.
def create_viewpoint_xml(guid, viewpoint_guid): return f"""<?xml version="1.0" encoding="UTF-8"?> <VisualizationInfo Guid="{viewpoint_guid}"> <Components> <ViewSetupHints SpacesVisible="false" SpaceBoundariesVisible="false" OpeningsVisible="false" /> <Selection> <Component IfcGuid="{guid}" /> </Selection> <Visibility DefaultVisibility="true" /> </Components> <OrthogonalCamera> <CameraViewPoint> <X>129.93820633961636</X> <Y>-124.61204504554462</Y> <Z>104.47418360973809</Z> </CameraViewPoint> <CameraDirection> <X>-0.58963662529065941</X> <Y>0.5647967039409042</Y> <Z>-0.57735026918962584</Z> </CameraDirection> <CameraUpVector> <X>-0.41693605617897656</X> <Y>0.39937157934842415</Y> <Z>0.81649658092772603</Z> </CameraUpVector> <ViewToWorldScale>44.256083397559856</ViewToWorldScale> </OrthogonalCamera> </VisualizationInfo>"""
Einrichten der Standardkamera-Position.
def create_issue_xml(element_name, coverage, report_name, viewpoint_guid, comment_guid, topic_guid): return f"""<?xml version="1.0" encoding="UTF-8"?> <Markup> <Topic Guid="{topic_guid}" TopicType="Issue" TopicStatus="Active"> <Title>Geringes Abdeckungsproblem: {element_name}</Title> <Priority>Normal</Priority> <Index>1</Index> <CreationDate>2025-03-05T09:22:02+00:00</CreationDate> <CreationAuthor>youremail@domain.com</CreationAuthor> <ModifiedDate>2025-03-05T09:22:03+00:00</ModifiedDate> <ModifiedAuthor>youremail@domain.com</ModifiedAuthor> <DueDate>2025-03-05T09:00:00+00:00</DueDate> <AssignedTo>youremail@domain.com</AssignedTo> <Description>Das Element {element_name} hat einen Abdeckungswert von {coverage}, gemäß dem Bericht {report_name}</Description> </Topic> <Comment Guid="{comment_guid}"> <Date>2025-03-04T09:53:03+00:00</Date> <Author>youremail@domain.com</Author> <Comment>Das Element {element_name} hat einen Abdeckungswert von {coverage}, gemäß dem Bericht {report_name}</Comment> <Viewpoint Guid="{viewpoint_guid}" /> <ModifiedDate>2025-03-04T09:53:03+00:00</ModifiedDate> <ModifiedAuthor>youremail@domain.com</ModifiedAuthor> </Comment> <Viewpoints Guid="{viewpoint_guid}"> <Viewpoint>viewpoint.bcfv</Viewpoint> <Snapshot>snapshot.png</Snapshot> </Viewpoints> </Markup> """
Erstellen von XMLs für Metadaten zu Problemen.
Benötigte Informationen über den Autor in den Feldern eingeben:
- CreationAuthor - Zeile 154
- ModifiedAuthor - Zeile 156
- AssignedTo - Zeile 158
- Author - Zeile 163
- ModifiedAuthor - Zeile 167
def create_project_xml(projectGuid): return f"""<?xml version="1.0" encoding="UTF-8"?> <ProjectExtension> <Project ProjectId="{projectGuid}" /> <ExtensionSchema></ExtensionSchema> </ProjectExtension>"""
Erstellen einer Datei, die auf ein Projekt verweist.
def create_extensions_xsd(): return """<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <schema> <redefine schemaLocation="markup.xsd"> <simpleType name="Priority"> <restriction base="Priority"> <enumeration value="Aucune"/> <enumeration value="Faible"/> <enumeration value="Moyenne"/> <enumeration value="Haute"/> <enumeration value="Critique"/> </restriction> </simpleType> <simpleType name="TopicStatus"> <restriction base="TopicStatus"> <enumeration value="Assignée"/> <enumeration value="En cours"/> <enumeration value="Terminée"/> <enumeration value="Bloquée"/> <enumeration value="Validée"/> <enumeration value="Archivée"/> </restriction> </simpleType> <simpleType name="TopicLabel"> <restriction base="TopicLabel"/> </simpleType> </redefine> </schema> """
Beschreibung der BCF-Struktur (Kategorien).
def create_bcf_version(): return """<?xml version="1.0" encoding="UTF-8"?> <Version VersionId="2.1" xsi:noNamespaceSchemaLocation="version.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DetailedVersion>2.1 KUBUS BV</DetailedVersion> </Version>"""
Definition der BCF-Version (2.1).
def main():
input_csv = input("Insert the path to the CIPM .csv report :")
output_dir = input("Insert the path where BCF files should be created :")
min_coverage = float(input("Insert the minimum coverage"))
context_url = input("Insert the path to the workzone where to create annotations (e.g: "
"https://aec.cintoo.com/accounts/0a000a00-000a-000a-a000-0aa0a00000a0/projects/a0a0000a-aaa0"
"-000a-000a-aaaa00aaa000/workzones/aaaaaaaaaa0aaaaaaaa/data ")
context_details = parse_cintoo_workzone_context_url(context_url)
tenant, account_id, project_id, workzone_id = context_details['tenant'], context_details['accountId'], \
context_details['projectId'], context_details['workzoneId']
# Authenticate and get access token
login.load_tokens()
token = login.get_token(tenant)
headers = {"Authorization": f"Bearer {token}"}
camera_state = {"type": "legacy",
"camerastate": {
"position": [0, 0, 1],
"rotationQuaternion": [0, 0, 0, 1],
"fov": 1.5708,
"ortho": False,
"overviewScale": 10,
"camType": "scan"},
}
create_bcfzip(input_csv,
output_dir,
min_coverage,
tenant,
account_id,
project_id,
workzone_id,
camera_state,
headers)
main()
Definition des Hauptteils des Skripts, das dem Benutzer Eingabefragen stellt, Zugriffstoken abruft und sich gemäß Cintoo API Authentifizierung bei einem Cintoo-Konto authentifiziert, Standard-Kameraposition, die nach dem Import in Cintoo geändert wird, Ausgabe-BCFzip-Dateien erstellt und die Hauptfunktion ausführt.
CreateAnnotation.py-Skript erklärt
Nachfolgend finden Sie das Skript mit Kommentaren zu jedem Teil.
Warnung: Wenn Anpassungen am Code vorgenommen werden müssen, ist dies möglich, aber Cintoo übernimmt keine Verantwortung für die Funktionalität dieses Codes nach der Änderung.
import login
import requests
from cintooUtils import parse_cintoo_workzone_context_url
TIMEOUT = 10
Importieren aller notwendigen Bibliotheken und Daten aus ergänzenden Skripten zur Unterstützung des Hauptskripts. Festlegen eines Timeout-Parameters.
def getWorkzoneGuid(tenant, account_id, project_id, workzone_idv1, headers):
url = f"{tenant}/api/2/accounts/{account_id}/projects/{project_id}/workzones"
response = requests.get(url, headers=headers, timeout=TIMEOUT)
response.raise_for_status()
return [wz for wz in response.json() if wz["api1Id"] == workzone_idv1]
Extrahieren der Arbeitszonen-ID aus Benutzereingabe.
def createAnnotation(tenant,
account_id,
project_id,
workzone_id,
title,
description,
position,
saved_view,
headers,
modelElementId=None,):
"""Erstellt ein Projekt im angegebenen Konto."""
workzone_guid = getWorkzoneGuid(tenant, account_id, project_id, workzone_id, headers)[0]['id'].split(':')[-1]
url = f"{tenant}/api/2/accounts/{account_id}/projects/{project_id}/annotations"
print(f"modelElementId : {modelElementId}")
if modelElementId:
body = {
'workzoneId': workzone_guid,
'annotationType': "Note",
'title': title,
'description': description,
'position': position,
'normal': {"x": 0, "y": 0, "z": 1},
'savedView': {**saved_view, 'modelElementId': modelElementId},
}
else:
body = {
'workzoneId': workzone_guid,
'annotationType': "Note",
'title': title,
'description': description,
'position': position,
'normal': {"x": 0, "y": 0, "z": 1},
'savedView': saved_view,
'elementId': "Toto"
}
print(url)
print(body)
response = requests.post(url, headers=headers, json=body, timeout=TIMEOUT)
print(response.text)
response.raise_for_status()
return response.json()
Parsing von Cintoo-Standortinformationen aus Benutzereingaben, um jede Annotation einem entsprechenden Modellelement zuzuordnen.
def main(context_url):
context_details = parse_cintoo_workzone_context_url(context_url)
tenant, account_id, project_id, workzone_id = context_details['tenant'], context_details['accountId'], \
context_details['projectId'], context_details['workzoneId']
# Authenticate and get access token
login.load_tokens()
token = login.get_token(tenant)
headers = {"Authorization": f"Bearer {token}"}
camera_state = {"type": "legacy",
"camerastate": {
"position": [0, 0, 1],
"rotationQuaternion": [0, 0, 0, 1],
"fov": 1.5708,
"ortho": False,
"overviewScale": 10,
"camType": "scan"}}
print(workzone_id)
createAnnotation(tenant, account_id, project_id, workzone_id, "Test API", "Created with API",
{"x": 0, "y": 0, "z": 0}, camera_state, headers)
Hauptfunktion mit Authentifizierungsprozess, Kameraeinstellung und Erstellen von Anmerkungen im Cintoo-Projekt.
War dieser Artikel hilfreich?
Das ist großartig!
Vielen Dank für das Feedback
Leider konnten wir nicht helfen
Vielen Dank für das Feedback
Feedback gesendet
Wir wissen Ihre Bemühungen zu schätzen und werden versuchen, den Artikel zu korrigieren