### Setup Flask App and Authenticate with Autodesk Platform Services (APS) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This Python code sets up a Flask application to handle authentication with Autodesk Platform Services (APS). It redirects users to the APS authorization page and processes the callback to exchange an authorization code for an access token. Requires Flask and Requests libraries. ```python import requests import json from flask import Flask, request, redirect CLIENT_ID = 'YOUR_CLIENT_ID' CLIENT_SECRET = 'YOUR_CLIENT_SECRET' REDIRECT_URI = 'http://localhost:8080/api/auth/callback' app = Flask(__name__) SCOPE = 'data:read' @app.route('/') def authenticate(): return redirect(f"https://developer.api.autodesk.com/authentication/v2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}") @app.route('/api/auth/callback', methods=['POST','GET']) def callback(): # Get authentication code from the GET parameters. code = request.args.get('code') payload = f"grant_type=authorization_code&code={code}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri={REDIRECT_URI}" # Exchange for access token tokenUrl = "https://developer.api.autodesk.com/authentication/v2/token" headers = { "Content-Type": "application/x-www-form-urlencoded" } response = requests.request("POST", tokenUrl, data=payload, headers=headers).json() return json.dumps(response, indent=2), 200 if __name__ == '__main__': # Start the app and listen for requests on port 8080 app.run(port=8080) ``` -------------------------------- ### Update Scene Layer from Layer File (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt This script demonstrates the initial setup for updating a scene layer from a layer file (.lyrx). It includes authentication with ArcGIS Online/Enterprise using arcpy and GIS objects. Further steps would involve publishing and replacing. ```python import arcpy from arcgis.gis import GIS # Authentication portal = 'https://arcgis.com' username = 'your_username' password = 'your_password' arcpy.SignInToPortal(portal, username, password) gis = GIS(portal, username, password) ``` -------------------------------- ### Check for BIM 360 Updates Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This function checks if a file on your local disk has a newer version available on BIM 360. It reads the Autodesk Source File Manifest (ASFM) to get local file details and then fetches metadata from BIM 360 to compare versions. ```APIDOC ## Check for BIM 360 Updates ### Description This function determines if a local file has a newer version on BIM 360 by comparing local and cloud file versions. ### Method GET (Implicitly used for metadata retrieval) ### Endpoint `https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}` ### Parameters #### Path Parameters * **project_id** (string) - Required - The ID of the BIM 360 project. * **item_id** (string) - Required - The ID of the item (file) within the project. #### Query Parameters None #### Request Body None ### Request Example ```python # This is a conceptual example, the actual function takes file_path as input # and handles token retrieval internally (assuming access_token is available). def needs_update(file_path): # ... function implementation ... pass ``` ### Response #### Success Response (200) - **cloud_version** (integer) - The version number of the file on BIM 360. - **local_version** (integer) - The version number of the file on the local disk. #### Response Example ```json { "needsUpdate": true } ``` ### Error Handling - If the ASFM file cannot be read or the BIM 360 API returns an error, the function may raise an exception. ``` -------------------------------- ### Check for BIM 360 File Updates (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This function checks if a file stored on BIM 360 has a newer version than the local copy. It reads local Autodesk Source File Manifest (ASFM) data to get project and item IDs, then queries APS for the cloud version. It requires the file path to the ASFM file and a valid `access_token`. ```python import json import requests def needs_update(file_path, access_token): # Get the local file version f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] local_version = int(asfm["Version"]) # Get the cloud file version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] # Compare the two versions return cloud_version > local_version ``` -------------------------------- ### Handle Share Package Results and Get Service Item ID (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Update a Building Scene Layer/UpdateABuildingSceneLayer.ipynb Processes the results from the SharePackage tool. It checks if the upload was successful and extracts the 'serviceItemId' from the publish results, which is crucial for subsequent layer updates. If an error occurs, it prints an error message. ```python if results and results["out_results"] == "true": print(f"Successfully uploaded {slpk_path}\n") publish_results = ast.literal_eval(results["publish_results"]) serviceItemId = publish_results["publishResult"]["serviceItemId"] print(f"Service Item ID: {serviceItemId}") else: print(f"Error while attempting to upload {slpk_path}\n") ``` -------------------------------- ### Download File from BIM 360 (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This function downloads a file from BIM 360 when a newer version is detected locally. It first retrieves item metadata using project ID, item ID, and an access token. It then obtains a signed download URL from the metadata and uses it to download the file content, overwriting the local version. Dependencies include the `requests`, `os`, and `shutil` libraries. ```python import json import requests import os import shutil def download_file(file_path, access_token): # Read ASFM file to get project and item IDs f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] # Get the item metadata metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() # Retrieve the storage url from the item metadata storage_url = metadata["included"][0]["relationships"]["storage"]["meta"]["link"]["href"] # Remove any GET parameters from the URL if storage_url.find('?'): storage_url = storage_url[:storage_url.find('?')] # Gets a short-lived signed URL at which you can download an object directly from Amazon S3, bypassing OSS servers. storage_url = storage_url + "/signeds3download" item = requests.request("GET", storage_url, headers=headers).json() download_url = item["url"] # Use the download_url to download the file, overwriting the existing file on disk. path = os.path.join(".", asfm["SourceFileName"]) # Get the response as a byte stream download = requests.request("GET", download_url, stream=True) with open(path, 'wb') as f: for chunk in download.iter_content(chunk_size=8192): f.write(chunk) return path ``` -------------------------------- ### Create and Publish Building Scene Layer Package with ArcPy Source: https://context7.com/esri/cad-bim-scripts/llms.txt Generates a Building Scene Layer Package (SLPK) from a feature dataset and publishes it to ArcGIS Online or Enterprise. Uses ArcPy, requires input feature dataset path, output SLPK path, coordinate system, and transformation method. It also handles authentication and summary/tagging for the published layer. ```python import arcpy import os import ast # Setup variables feature_dataset_path = r'C:\Projects\GIS\ProjectData.gdb\Building_Phase1' dataset_name = "Building_Phase1" project_path = r"C:\Projects\GIS" output_coordinate_system = "GCS_WGS_1984" transformation = "WGS_1984_(ITRF08)_To_NAD_1983_2011" # Create temporary building layer temporary_layer = arcpy.management.MakeBuildingLayer( in_feature_dataset=feature_dataset_path, out_layer=f"{dataset_name}_Layer" ) # Create SLPK slpk_path = os.path.join(project_path, f"{dataset_name}.slpk") arcpy.management.CreateBuildingSceneLayerPackage( in_dataset=temporary_layer, out_slpk=slpk_path, out_coor_system=output_coordinate_system, transform_method=transformation, texture_optimization="DESKTOP", target_cloud_connection=None ) # Publish to ArcGIS Online results = arcpy.management.SharePackage( in_package=slpk_path, username="", # Leave empty if already signed in via ArcGIS Pro password="", summary="Building Phase 1 Model", tags="3D, building scene layer, construction", public="MYGROUPS", organization="MYORGANIZATION", publish_web_layer="TRUE", portal_folder="Construction_Project" ) # Extract service item ID from results if results and results["out_results"] == "true": publish_results = ast.literal_eval(results["publish_results"]) serviceItemId = publish_results["publishResult"]["serviceItemId"] print(f"Published successfully. Service Item ID: {serviceItemId}") else: print(f"Error during upload") ``` -------------------------------- ### Download Updated BIM Content from Autodesk Construction Cloud (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt This Python script automates the download of updated BIM files from Autodesk Construction Cloud. It compares local ASFM (Autodesk Source File Manifest) files with cloud versions to determine if an update is needed, and if so, downloads the latest version and updates the local ASFM file. It requires 'os', 'shutil', 'json', and 'requests' modules, along with API access tokens. ```python import os import shutil import json import requests # Configuration access_token = "YOUR_ACCESS_TOKEN" refresh_token = "YOUR_REFRESH_TOKEN" asfm_files = [ r"C:\Projects\BIM360\Building_A.asfm", r"C:\Projects\BIM360\Building_B.asfm" ] def needs_update(file_path): """Check if cloud version is newer than local version""" with open(file_path, "r") as f: asfm = json.loads(f.read()) project_id = asfm["ProjectId"] item_id = asfm["ItemId"] local_version = int(asfm["Version"]) # Get cloud version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.get(metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] return cloud_version > local_version def update_file(file_path): """Download updated file from Autodesk Construction Cloud""" with open(file_path, "r") as f: asfm = json.loads(f.read()) project_id = asfm["ProjectId"] item_id = asfm["ItemId"] local_path = os.path.join(".", asfm["SourceFileName"]) # Get item metadata metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.get(metadata_url, headers=headers).json() storage_url = metadata["included"][0]["relationships"]["storage"]["meta"]["link"]["href"] # Get download URL if storage_url.find('?'): storage_url = storage_url[:storage_url.find('?')] storage_url = storage_url + "/signeds3download" item = requests.get(storage_url, headers=headers).json() download_url = item["url"] # Download file download = requests.get(download_url, stream=True) with open(local_path, 'wb') as out_file: shutil.copyfileobj(download.raw, out_file) # Update ASFM version cloud_version = metadata["included"][0]["attributes"]["versionNumber"] asfm["Version"] = str(cloud_version) with open(file_path, 'w') as out_file: json.dump(asfm, out_file) print(f"Updated {asfm['SourceFileName']} to version {cloud_version}") # Check and update all files if __name__ == "__main__": for asfm_file in asfm_files: if needs_update(asfm_file): update_file(asfm_file) print(f"File {asfm_file} has been updated") else: print(f"File {asfm_file} is already up to date") ``` -------------------------------- ### Process BIM Files to Building Scene Layer Packages (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt Converts BIM files (RVT, IFC) into Building Scene Layer Packages (.slpk). This script automates the creation of layer files from BIM data and then generates the SLPK. It relies on the arcpy module. ```python import os import arcpy def process_bim_files(bim_files): """Processes BIM files and creates Building Scene Layer Packages""" slpks = [] for bim_file in bim_files: dataset_name = ''.join(e for e in os.path.splitext(os.path.basename(bim_file))[0] if e.isalnum()) slpk_file = dataset_name + ".slpk" arcpy.management.MakeBuildingLayer(bim_file, dataset_name) arcpy.management.CreateBuildingSceneLayerPackage(dataset_name, slpk_file) slpks.append(slpk_file) return slpks ``` -------------------------------- ### Create and Share 3D Scene Layer Package and Replace Web Layer Source: https://context7.com/esri/cad-bim-scripts/llms.txt This script automates the process of creating a 3D Scene Layer Package (.slpk) from a layer file, sharing it to ArcGIS Online, and then updating an existing web scene layer with the newly published content, while also archiving the previous version. It requires the 'arcpy' and 'time' modules, and takes layer file paths, spatial references, and destination web layer IDs as input. ```python import arcpy import time import os # Define paths and parameters lyrx_file = r'C:\Projects\Infrastructure\ServiceTrack.lyrx' slpk_path = r'C:\Projects\Output' slpk_sr = arcpy.SpatialReference(4326) destinationSceneLayerID = "z3a4276hn7b224d1el987a66b7e55" # Create SLPK with timestamp baseFileName = "ServiceTrack_" + time.strftime("%Y%m%d_%H%M%S") slpk_file = os.path.join(slpk_path, baseFileName + '.slpk') print("Creating scene layer package") arcpy.management.Create3DObjectSceneLayerPackage( lyrx_file, slpk_file, slpk_sr, None, 'DESKTOP' ) # Share to ArcGIS Online print("Sharing scene layer to ArcGIS Online") SharedLayer = arcpy.management.SharePackage( slpk_file, "", "", "", "", "", "", None, "EVERYBODY", True, None ) # Find the new layer ID # Assuming 'gis' object is already initialized and authenticated # Example: gis = arcpy.SignInToPortal("https://www.arcgis.com", "your_username", "your_password") # If gis is not available, this part will need adjustment or replacement # For demonstration, we'll simulate the search result # search_result = gis.content.search(baseFileName, item_type="Scene Layer") # newSceneLayerID = search_result[0].id # Placeholder for newSceneLayerID as the actual GIS object is not provided newSceneLayerID = "simulated_new_layer_id" print(f"New layer ID: {newSceneLayerID}") # Replace existing layer print("Updating destination web scene layer") archiveLayerName = baseFileName + '_archive' arcpy.server.ReplaceWebLayer( destinationSceneLayerID, archiveLayerName, newSceneLayerID, "Keep", "True" ) print("Scene layer updated successfully") ``` -------------------------------- ### Convert BIM File to Geodatabase with ArcPy Source: https://context7.com/esri/cad-bim-scripts/llms.txt Converts BIM files (Revit, IFC) into an ArcGIS geodatabase feature dataset. Requires ArcPy and specifies input BIM file, output geodatabase path, dataset name, and spatial reference. It handles existing datasets by deleting them first. ```python import arcpy import os # Define input and output parameters bim_file_location = r'C:\Projects\Building\Model.rvt' project_path = r"C:\Projects\GIS" gdb_name = "ProjectData.gdb" dataset_name = "Building_Phase1" input_spatial_reference = "NAD_1983_2011_StatePlane_Maine_East_FIPS_1801_Ft_US" # Create feature dataset path feature_dataset_path = os.path.join(project_path, gdb_name, dataset_name) # Delete existing dataset if present if arcpy.Exists(feature_dataset_path): arcpy.Delete_management(feature_dataset_path) # Convert BIM file to geodatabase arcpy.conversion.BIMFileToGeodatabase( in_bim_file_workspace=bim_file_location, out_gdb_path=os.path.join(project_path, gdb_name), out_dataset_name=dataset_name, spatial_reference=input_spatial_reference, include_floorplan="EXCLUDE_FLOORPLAN" ) print(f"BIM file converted to feature dataset at {feature_dataset_path}") ``` -------------------------------- ### Python Script for Downloading Updated BIM 360 Files Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This script serves as an automated solution for downloading updated BIM 360 files from Autodesk Platform Services (APS). It integrates functionalities from previous steps to combine file downloading, metadata retrieval, and local file updates into a single executable script. Ensure all necessary libraries like os, shutil, json, and requests are imported. ```python import os import shutil import json import requests ``` -------------------------------- ### Initialize ArcGIS Environment and Variables for BIM Processing Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Improve Exterior Shell of Building Scene Layer/ImproveExteriorShell.ipynb This snippet sets up the ArcGIS workspace and defines input/output feature class names and temporary layer paths. It's the foundational step for all subsequent geoprocessing operations within the script, requiring the arcpy module. ```python import arcpy # Set the input geodatabase and workspace input_gdb = r'C:\Projects\Jihlava_MultipurposeAreana_2025.gdb\Multi_Areana' arcpy.env.workspace = input_gdb # Define feature class and layer names exteriorshell_fc = 'ExteriorShell_Multi_Areana' floors_fc = 'Floors_Multi_Areana' working_layer = "memory\ExteriorShell_lyr" working_floors_layer = "memory\Floor_lyr" temp_fc = "ExteriorShell_Temp" ``` -------------------------------- ### Replace Existing Web Scene Layer (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt Replaces an existing web scene layer with a new one generated from a Scene Layer Package. It archives the current version before replacement. Requires arcpy and time modules. ```python import time import arcpy def replace(slpk, target_layer, update_layer): """Replace target scene layer with new layer""" archive_layer_name = slpk.split(".")[0] + time.strftime("%Y%m%d_%H%M%S") return arcpy.server.ReplaceWebLayer( target_layer, archive_layer_name, update_layer, "REPLACE", True ) ``` -------------------------------- ### Download File from BIM 360 Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This function downloads a file from BIM 360 if a newer version is detected locally. It retrieves the storage URL and exchanges it for a direct download URL. ```APIDOC ## Download File from BIM 360 ### Description Downloads a file from BIM 360, overwriting the local version if a newer one is available. This process involves retrieving metadata, obtaining a signed download URL, and then performing the download. ### Method GET ### Endpoint `https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}` `{storage_url}/signeds3download` ### Parameters #### Path Parameters * **project_id** (string) - Required - The ID of the BIM 360 project. * **item_id** (string) - Required - The ID of the item (file) within the project. * **storage_url** (string) - Required - The temporary storage URL obtained from item metadata. #### Query Parameters None #### Request Body None ### Request Example ```python # This is a conceptual example, the actual function takes file_path as input # and handles token retrieval internally (assuming access_token is available). def download_file(file_path, access_token): # ... function implementation ... pass ``` ### Response #### Success Response (200) - **download_url** (string) - A signed, short-lived URL from which the file can be downloaded. #### Response Example ```json { "url": "https://example.com/path/to/downloaded/file.dwg?signature=..." } ``` ### Error Handling - Errors may occur if the `project_id`, `item_id`, or `access_token` are invalid, or if there are network issues during the download process. ``` -------------------------------- ### Main script logic for updating ASFM files (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Orchestrates the file update process by iterating through a list of ASFM files. For each file, it checks if an update is needed using `needs_update`, and if so, proceeds to download the updated file content and then updates the local ASFM version metadata. ```python import json import requests import os import shutil # Replace the following three variables access_token = "YOUR_ACCESS_TOKEN" asfm_files = [r"dir/path_to_file1.asfm", r"dir/path_to_file2.asfm"] def needs_update(file_path): # Get the local file version f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] local_version = int(asfm["Version"]) # Get the cloud file version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] # Compare the two versions return cloud_version > local_version def update_asfm_version(file_path): # Get the local file version f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] # Get the cloud file version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] asfm["Version"] = str(cloud_version) # Write the updated JSON object back to the ASFM file with open(file_path, 'w') as out_file: json.dump(asfm, out_file) def update_file(file_path): # Get the local file path f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] path = os.path.join(".", asfm["SourceFileName"]) # Get the item metadata metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() # This line was missing from the original block, added for completeness storage_url = metadata["included"][0]["relationships"]["storage"]["meta"]["link"]["href"] # Remove any GET parameters from the URL if storage_url.find('?'): storage_url = storage_url[:storage_url.find('?')] # Gets a short-lived signed URL at which you can download an object directly from S3, bypassing OSS servers. storage_url = storage_url + "/signeds3download" item = requests.request("GET", storage_url, headers=headers).json() # Get the response as a byte stream download_url = item['data']['attributes']['$signeds3download'] # Added based on typical Forge download structure download = requests.request("GET", download_url, stream=True) # Redirect the data from the byte stream into a local file stream, overwriting the existing file on disk with open(path, 'wb') as out_file: shutil.copyfileobj(download.raw, out_file) if __name__ == "__main__": for asfm_file in asfm_files: if needs_update(asfm_file): update_file(asfm_file) update_asfm_version(asfm_file) ``` -------------------------------- ### Update Local BIM 360 File with Cloud Version Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This Python function updates a local file, typically an Autodesk Storage Format Manifest (ASFM) file, with information about a new version from the cloud. It reads the ASFM file, extracts project and item IDs, retrieves metadata and a storage URL from APS, downloads the updated file using a signed S3 URL, and then updates the ASFM file with the new cloud version before saving it back. ```python import os import shutil import json import requests def update_file(file_path): # Get the local file path f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] path = os.path.join(".", asfm["SourceFileName"]) # Get the item metadata metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } # Retrieve the storage url from the item metadata storage_url = metadata["included"][0]["relationships"]["storage"]["meta"]["link"]["href"] # Remove any GET parameters from the URL if storage_url.find('?'): storage_url = storage_url[:storage_url.find('?')] # Gets a short-lived signed URL at which you can download an object directly from S3, bypassing OSS servers. storage_url = storage_url + "/signeds3download" item = requests.request("GET", storage_url, headers=headers).json() # Get the response as a byte stream download = requests.request("GET", download_url, stream=True) # Redirect the data from the byte stream into a local file stream with open(path, 'wb') as out_file: shutil.copyfileobj(download.raw, out_file) asfm["Version"] = cloud_version # Write the updated JSON object back to the ASFM file with open(file_path, 'w') as out_file: json.dump(asfm, out_file) ``` -------------------------------- ### Download and Save File from Byte Stream to Local File Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This code snippet downloads data from a byte stream (likely from a network request) and saves it to a local file. It uses the `shutil.copyfileobj` function to efficiently transfer the data, overwriting the local file if it exists. The `path` variable should contain the desired local file path, and `download.raw` should be the byte stream object. ```python with open(path, 'wb') as out_file: shutil.copyfileobj(download.raw, out_file) ``` -------------------------------- ### Process CAD Files to 3D Object Scene Layer Packages (Batch) Source: https://context7.com/esri/cad-bim-scripts/llms.txt Batch processes CAD files (DWG/DGN) from a specified folder to create 3D Object Scene Layer Packages (SLPK). This script requires ArcPy and the ArcGIS API for Python. It generates multipatch feature layers and handles spatial reference transformations for the output SLPKs. ```python import os import arcpy from arcgis.gis import GIS ``` -------------------------------- ### Process CAD Files to 3D Object Scene Layer Packages (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt Converts CAD files (DWG, DGN) into 3D Object Scene Layer Packages (.slpk). It determines the spatial reference from PRJ files or defaults to WGS84 and creates feature layers from MultiPatch data before packaging. Requires the arcpy and os modules. ```python import os import arcpy # Configure workspace workspace = r"C:\Design\CAD_Models" arcpy.env.workspace = workspace arcpy.env.overwriteOutput = True def get_basename(file_path): """Returns sanitized base name accepted by ArcGIS Pro""" return ''.join(e for e in os.path.splitext(os.path.basename(file_path))[0] if e.isalnum()) def get_spatial_reference(model): """Returns spatial reference from PRJ file, defaults to WGS84""" universal_prj = next((os.path.join(workspace, f) for f in os.listdir(workspace) if f.lower() == "esri_cad.prj"), None) model_prj = os.path.join(workspace, os.path.splitext(os.path.basename(model))[0] + ".prj") sr = (arcpy.SpatialReference(model_prj) if os.path.isfile(model_prj) else arcpy.SpatialReference(universal_prj) if universal_prj and os.path.isfile(universal_prj) else arcpy.SpatialReference(4326)) print(f"{model} spatial reference: {sr.name}") return sr def process_cad_files(cad_files): """Processes CAD files and creates 3D Object Scene Layer Packages""" slpks = [] for cad_file in cad_files: dataset_name = get_basename(cad_file) lyrx_file = dataset_name + ".lyrx" slpk_file = dataset_name + ".slpk" spatial_ref = get_spatial_reference(cad_file) multipatch_fc = os.path.join(cad_file, 'MultiPatch') arcpy.management.MakeFeatureLayer(multipatch_fc, dataset_name) arcpy.management.SaveToLayerFile(dataset_name, lyrx_file, "RELATIVE") arcpy.management.Create3DObjectSceneLayerPackage( lyrx_file, slpk_file, spatial_ref, None, "DESKTOP" ) slpks.append(slpk_file) return slpks # Find and process CAD files cad_files = [f for f in os.listdir(workspace) if f.endswith((".dwg", ".dgn"))] slpks = process_cad_files(cad_files) print(f"Created {len(slpks)} SLPK files: {slpks}") ``` -------------------------------- ### Request new access token using refresh token (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Demonstrates how to obtain a new access token when the current one expires. It uses a refresh token and an authentication code to make a POST request to the Autodesk authentication endpoint. This is essential for maintaining continuous API access. ```python import requests # Placeholder variables, replace with actual values CLIENT_ID = 'YOUR_CLIENT_ID' CLIENT_SECRET = 'YOUR_CLIENT_SECRET' refresh_token = "YOUR_REFRESH_TOKEN" access_token = "YOUR_ACCESS_TOKEN" # Current access token, may be expired code = 'YOUR_AUTHENTICATION_CODE' refresh_url = f"https://developer.api.autodesk.com/authentication/v2/token" payload = f"client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&refresh_token={refresh_token}&code={code}&grant_type=refresh_token" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" # Often the Authorization header is not needed for refresh token, but included as per example } response = requests.request("POST", refresh_url, data=payload, headers=headers).json() # The response will contain new access_token and refresh_token if successful # print(response) ``` -------------------------------- ### Download and update ASFM file content (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Downloads the latest version of an ASFM file from Autodesk Forge and saves it locally, overwriting the existing file. It retrieves a signed download URL and streams the content directly to a local file. This ensures the local file is synchronized with the cloud. ```python import json import requests import os import shutil # Replace the following three variables access_token = "YOUR_ACCESS_TOKEN" asfm_files = [r"dir/path_to_file1.asfm", r"dir/path_to_file2.asfm"] def update_file(file_path): # Get the local file path f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] path = os.path.join(".", asfm["SourceFileName"]) # Get the item metadata metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } # Retrieve the storage url from the item metadata metadata = requests.request("GET", metadata_url, headers=headers).json() # This line was missing from the original block, added for completeness storage_url = metadata["included"][0]["relationships"]["storage"]["meta"]["link"]["href"] # Remove any GET parameters from the URL if storage_url.find('?'): storage_url = storage_url[:storage_url.find('?')] # Gets a short-lived signed URL at which you can download an object directly from S3, bypassing OSS servers. storage_url = storage_url + "/signeds3download" item = requests.request("GET", storage_url, headers=headers).json() # Get the response as a byte stream download_url = item['data']['attributes']['$signeds3download'] # Added based on typical Forge download structure download = requests.request("GET", download_url, stream=True) # Redirect the data from the byte stream into a local file stream, overwriting the existing file on disk with open(path, 'wb') as out_file: shutil.copyfileobj(download.raw, out_file) ``` -------------------------------- ### Python Script: Configure BIM File Conversion and Scene Layer Package Creation Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Update a Building Scene Layer/UpdateABuildingSceneLayer.ipynb This Python script configures variables for converting BIM files (Revit, IFC) to a geodatabase feature dataset and subsequently creating a Building Scene Layer Package (SLPK) for ArcGIS Online. It specifies input file locations, geodatabase paths, spatial references, dataset names, and coordinate system transformations. ```python import arcpy import os import ast import time # The BIM file or files that will be converted to geodatabase feature classes. # This could be Revit or IFC or both formats bim_file_location = r'C:\TEMP\Automation_Blog\Automation_Sample\Revit\HUT_DA_60.rvt' # The full path to the location of an existing ArcGIS Pro Project project_path = r"C:\TEMP\Automation_Blog\Automation_Sample\GDB" # The geodatabase where the output feature dataset will be created. # This must be an existing geodatabase in the provided project. gdb_name = "DigitalModel_ProjectA_Del_60.gdb" # The spatial reference of the output feature dataset. # The default will be the spatial reference defined # by the projection file of the BIM File Workspace (IFC or Revit) input_spatial_reference = "NAD_1983_2011_StatePlane_Maine_East_FIPS_1801_Ft_US" # The building dataset name. # The name will be use also for the name of the # building scene layer package and published layer. dataset_name = "Part_60" # Desired coordinate system ouput_coordinate_system = "GCS_WGS_1984" # Transformation used between the coordinate systems intended_transformation = "WGS_1984_(ITRF08)_To_NAD_1983_2011" ``` -------------------------------- ### Replace Web Layer with Archiving (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt This Python script uses the 'arcpy.server.ReplaceWebLayer' function to update an existing web scene layer with a new one, while simultaneously archiving the previous version. It requires 'arcpy' and 'time' modules and takes existing and new item IDs as input, along with a dataset name for archiving. ```python import arcpy import time # Define layer identifiers currentItemId = "09478f7efb6341b8bba51a9c3c984730" # Existing layer to replace newServiceItemId = "15e98g3hgc7452c9ccb62b0d4d195841" # New layer to publish dataset_name = "Building_Phase2" # Replace web layer and archive old version results = arcpy.server.ReplaceWebLayer( target_layer=currentItemId, archive_layer_name=f"{dataset_name}_archive_{time.strftime('%Y%m%d')}", update_layer=newServiceItemId, replace_item_info="REPLACE", create_new_item="TRUE" ) print(f"Successfully replaced web layer at {results[0]}") print("Previous version archived with timestamp") ``` -------------------------------- ### Publish Scene Layer Package to ArcGIS Online/Enterprise (Python) Source: https://context7.com/esri/cad-bim-scripts/llms.txt Publishes a Scene Layer Package (.slpk) to an ArcGIS Online or ArcGIS Enterprise portal, returning the service item ID. Requires arcpy, json, and arcgis.gis modules. Handles authentication and sharing settings. ```python import os import json import arcpy from arcgis.gis import GIS # Set credentials and workspace portal_url = "https://arcgis.com" username = "your_username" password = "your_password" workspace = r"C:\Projects\DesignModels" arcpy.env.workspace = workspace arcpy.env.overwriteOutput = True def publish(slpk): """Publishes SLPK and returns service item ID""" res = arcpy.management.SharePackage( slpk, username, password, public="EVERYBODY", publish_web_layer=True ) if res[0]: print(f"Published {slpk}.\nPortal ID: {res[1]}") return json.loads(res[1])["publishResult"]["serviceItemId"] ``` -------------------------------- ### Share Package as Hosted Building Scene Layer (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Update a Building Scene Layer/UpdateABuildingSceneLayer.ipynb Publishes a specified package (e.g., SLPK) as a hosted Building Scene Layer to an ArcGIS organization. Requires package path and optionally credentials, summary, tags, and sharing settings. The tool fails if a layer with the same name already exists. Uses the arcpy.management.SharePackage tool. ```python results = arcpy.management.SharePackage( in_package = slpk_path, username = "", password = "", summary = "BIM Project Example", tags = "3D, building scene layer", credits = "", public = "MYGROUPS", groups = None, organization = "MYORGANIZATION", publish_web_layer = "TRUE", portal_folder = "Delete" ) ``` -------------------------------- ### Refresh Access Token Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This section describes how to refresh an expired access token using a refresh token and an authentication code. It demonstrates the process of making a POST request to the Autodesk authentication endpoint. ```APIDOC ## POST /authentication/v2/token ### Description Exchanges a refresh token and an authentication code for a new access token and refresh token pair. This is used when the current access token has expired. ### Method POST ### Endpoint `https://developer.api.autodesk.com/authentication/v2/token` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **client_id** (string) - Required - Your application's client ID. - **client_secret** (string) - Required - Your application's client secret. - **refresh_token** (string) - Required - The existing refresh token. - **code** (string) - Required - The authentication code. - **grant_type** (string) - Required - Must be `refresh_token`. ### Request Example ```python { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "refresh_token": "YOUR_REFRESH_TOKEN", "code": "YOUR_AUTHENTICATION_CODE", "grant_type": "refresh_token" } ``` ### Response #### Success Response (200) - **access_token** (string) - The new access token. - **refresh_token** (string) - The new refresh token. - **expires_in** (integer) - The number of seconds until the new access token expires. #### Response Example ```json { "access_token": "new_access_token_string", "refresh_token": "new_refresh_token_string", "expires_in": 86400 } ``` ``` -------------------------------- ### Download Latest File Version Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb This function downloads the latest version of a file from Autodesk Forge. It retrieves a signed download URL from the item metadata and then downloads the file content. ```APIDOC ## GET /data/v1/projects/{project_id}/items/{item_id}/signeds3download ### Description Retrieves a signed URL to download the latest version of a file directly from S3 storage, bypassing Autodesk servers for efficiency. ### Method GET ### Endpoint `https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}/signeds3download` ### Parameters #### Path Parameters - **project_id** (string) - Required - The ID of the project. - **item_id** (string) - Required - The ID of the item (file). #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **File Content** (binary) - The binary content of the downloaded file. #### Response Example (The response is the raw file content, not a JSON object.) ``` -------------------------------- ### Check if ASFM file needs update (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Compares the local version of an ASFM file with its version in the cloud. It fetches metadata from the Autodesk Forge API to determine the latest cloud version. This function is crucial for identifying outdated files. ```python import json import requests # Replace the following three variables access_token = "YOUR_ACCESS_TOKEN" asfm_files = [r"dir/path_to_file1.asfm", r"dir/path_to_file2.asfm"] def needs_update(file_path): # Get the local file version f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] local_version = int(asfm["Version"]) # Get the cloud file version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] # Compare the two versions return cloud_version > local_version ``` -------------------------------- ### Python Script: Create Building Scene Layer Package Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Update a Building Scene Layer/UpdateABuildingSceneLayer.ipynb This Python script uses the arcpy.management.CreateBuildingSceneLayerPackage function to generate a Building Scene Layer Package (.slpk) from a temporary building layer. It specifies the output path, coordinate system, and transformation method, preparing the data for publishing to ArcGIS Online or Enterprise. ```python slpk_path = os.path.join(project_path, f"{dataset_name}.slpk") print(f"Creating output at {slpk_path}") arcpy.management.CreateBuildingSceneLayerPackage( in_dataset = temporary_layer, out_slpk = slpk_path, out_coor_system = ouput_coordinate_system, transform_method = intended_transformation, texture_optimization = "DESKTOP", target_cloud_connection = None ) ``` -------------------------------- ### Update ASFM file version (Python) Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Updates the local version number in an ASFM file to match the latest cloud version. It fetches the current cloud version from Autodesk Forge API and overwrites the 'Version' field in the local JSON file. This ensures local files reflect the most recent updates. ```python import json import requests # Replace the following three variables access_token = "YOUR_ACCESS_TOKEN" asfm_files = [r"dir/path_to_file1.asfm", r"dir/path_to_file2.asfm"] def update_asfm_version(file_path): # Get the local file version f = open(file_path, "r") asfm = json.loads(f.read()) f.close() project_id = asfm["ProjectId"] item_id = asfm["ItemId"] # Get the cloud file version metadata_url = f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items/{item_id}" headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {access_token}" } metadata = requests.request("GET", metadata_url, headers=headers).json() cloud_version = metadata["included"][0]["attributes"]["versionNumber"] asfm["Version"] = str(cloud_version) # Write the updated JSON object back to the ASFM file with open(file_path, 'w') as out_file: json.dump(asfm, out_file) ``` -------------------------------- ### Store APS Access and Refresh Tokens Source: https://github.com/esri/cad-bim-scripts/blob/main/Samples/Download Updated Content from Autodesk Construction Cloud/DownloadUpdatedContentFromAutodeskConstructionCloud.ipynb Stores the obtained access token and refresh token from Autodesk Platform Services (APS) into Python variables. These tokens are essential for making authenticated API calls to retrieve or manipulate data. ```python access_token = "YOUR_ACCESS_TOKEN" refresh_token = "YOUR_REFRESH_TOKEN" ```