Compare commits

..

35 Commits

Author SHA1 Message Date
Gergő Jedlicska 13421a23a0 build for osx 13 for arm 2022-12-13 16:48:23 +01:00
Gergő Jedlicska 4328c5b8cb only parameter 2022-12-13 13:12:49 +01:00
Gergő Jedlicska 4d44a49988 no CD 2022-12-13 13:11:36 +01:00
Gergő Jedlicska c174101176 pipe the zip 2022-12-13 13:11:18 +01:00
Gergő Jedlicska 62566b1bab top level cp operation 2022-12-13 12:59:27 +01:00
Gergő Jedlicska 88ec39caa4 mkdir 101 2022-12-13 12:52:37 +01:00
Gergő Jedlicska d65920a774 copy 101 2022-12-13 12:42:26 +01:00
Gergő Jedlicska c133689fea force copy 2022-12-13 12:37:52 +01:00
Gergő Jedlicska 6aaf4a5a99 mkdir -p 2022-12-13 12:33:42 +01:00
Gergő Jedlicska 66ec9d5af1 mkdir for the zip folder 2022-12-13 12:31:29 +01:00
Gergő Jedlicska 3cabadf552 fix zipping dir 2022-12-13 12:28:01 +01:00
Gergő Jedlicska c15bb7f045 ci(circleci): fix persist to workspace pathing 2022-12-13 12:21:26 +01:00
Gergő Jedlicska b0aa9cb48f ci(circleci): wtf is microsoft doing with env vars in net6 containers? 2022-12-13 12:05:58 +01:00
Gergő Jedlicska 7bbc286ae2 ci(circleci): fix missing semver in files 2022-12-13 11:48:56 +01:00
Gergő Jedlicska 99b130290f ci(circleci): fix env var restore in deploy 2022-12-13 11:38:51 +01:00
Gergő Jedlicska a0f782af5f make sure semver is set 2022-12-13 11:26:49 +01:00
Gergő Jedlicska f48a5c9582 ci(cirleci): fix mac build triggers 2022-12-13 11:21:12 +01:00
Gergő Jedlicska a9875ffbaa ci(circleci): fix filters 2022-12-13 11:18:13 +01:00
Gergő Jedlicska cee9d83e1d ci(circleci): update details in deploy 2022-12-13 11:09:56 +01:00
Gergő Jedlicska f76b6cf59b publish only usefull stuff 2022-12-12 18:10:52 +01:00
Gergő Jedlicska 8cd9d03806 only zip the published isntaller 2022-12-12 18:08:23 +01:00
Gergő Jedlicska 28ace1f591 add zip again 2022-12-12 18:04:26 +01:00
Gergő Jedlicska beebe10dff add python to dotnet installer 2022-12-12 17:58:33 +01:00
Gergő Jedlicska 1f964bf939 properly saving packaged zip 2022-12-12 17:52:40 +01:00
Gergő Jedlicska 997b94dab9 fix installer patch pathing 2022-12-12 17:46:48 +01:00
Gergő Jedlicska ea962952e5 force remove new lines from installer tags 2022-12-12 17:45:33 +01:00
Gergő Jedlicska 5aff85b586 get proper ci tools 2022-12-12 17:37:28 +01:00
Gergő Jedlicska e1553ed389 getting the specific installer branch 2022-12-12 17:36:20 +01:00
Gergő Jedlicska 88235402f1 ci(circleci): update dependency graph 2022-12-12 17:28:14 +01:00
Gergő Jedlicska a1eea0a6fc ci(circleci): update semver location 2022-12-12 17:26:34 +01:00
Gergő Jedlicska 80496be394 ci(circleci): update filters 2022-12-12 17:21:01 +01:00
Gergő Jedlicska ac63cbe17d ci(circleci): fix naming 2022-12-12 17:18:15 +01:00
Gergő Jedlicska de0c97cdbd ci(circleci): updates 2022-12-12 17:16:51 +01:00
Gergő Jedlicska 14e8445cf2 fix(installer): ensure pip call was commented outy 2022-12-12 16:09:45 +01:00
Gergő Jedlicska ddf908b3f9 ci(circleci): rewrite full ci WIP 2022-12-09 13:58:48 +01:00
14 changed files with 847 additions and 1038 deletions
+22 -89
View File
@@ -1,7 +1,7 @@
version: 2.1
orbs:
win: circleci/windows@5.0.0
win: circleci/windows@2.4.0
jobs:
package-connector:
@@ -49,20 +49,11 @@ jobs:
docker:
- image: cimg/base:2021.01
steps:
- add_ssh_keys:
fingerprints:
- "77:64:03:93:c5:f3:1d:a6:fd:bd:fb:d1:05:56:ca:e9"
- run:
name: I know Github as a host
command: |
mkdir ~/.ssh
touch ~/.ssh/known_hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts
- run:
- run: # Could not get ssh to work, so using a personal token
name: Clone
command: git clone git@github.com:specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
command: git clone https://$GITHUB_TOKEN@github.com/specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
- run:
command: cd speckle-sharp-ci-tools
command: cd speckle-sharp-ci-tools && git checkout blender/installer-changes
- persist_to_workspace:
root: ./
paths:
@@ -79,12 +70,6 @@ jobs:
name: Patch installer
shell: powershell.exe
command: python patch_installer.py (Get-Content -Raw SEMVER)
- run:
name: Create Innosetup signing cert
shell: powershell.exe
command: |
echo $env:PFX_B64 > "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt"
certutil -decode "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt" "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.pfx"
- run:
name: Installer
shell: cmd.exe #does not work in powershell
@@ -94,9 +79,9 @@ jobs:
paths:
- speckle-sharp-ci-tools/Installers/blender/blender-*.exe
build-installer-mac:
macos:
xcode: 12.5.1
build-dotnet-installer:
docker:
- image: mcr.microsoft.com/dotnet/sdk:6.0
parameters:
runtime:
type: string
@@ -106,26 +91,23 @@ jobs:
type: string
default: speckle-sharp-ci-tools/Mac/SpeckleBlenderInstall
steps:
- checkout
- attach_workspace:
at: ./
- run:
name: Install mono
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install mono
# Compress build files
- run:
name: Install dotnet
command: curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin
- run: *restore_semver
- run:
name: ensure zip
command: apt update && apt install -y zip
- run:
name: Copy connector files to installer
command: |
mkdir -p <<parameters.installer_path >>/.installationFiles/
mkdir -p << parameters.installer_path >>/.installationFiles
cp bpy_speckle.zip << parameters.installer_path >>/.installationFiles
- run:
name: Build Mac installer
command: ~/.dotnet/dotnet publish << parameters.installer_path >>/SpeckleBlenderInstall.sln -r << parameters.runtime >> -c Release
name: Build installer
command: dotnet publish <<parameters.installer_path>>/SpeckleBlenderInstall.sln -r << parameters.runtime >> -c Release
# cd <<parameters.installer_path>>/bin/Release/net6.0/<< parameters.runtime >>/publish/
# zip -r << parameters.slug >>-${SEMVER}.zip <<parameters.installer_path>>/bin/Release/net6.0/<< parameters.runtime >>/publish/.
# cd ${CIRCLE_WORKING_DIRECTORY}
- run:
name: Zip installer
command: |
@@ -140,28 +122,6 @@ jobs:
paths:
- speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>*.zip
build-installer-manual:
docker:
- image: cimg/base:2021.01
parameters:
slug:
type: string
default: bpy_speckle
steps:
- attach_workspace:
at: ./
- run: *restore_semver
- run:
name: Copy zip with semver
command: |
SEMVER=$(cat ./SEMVER)
mkdir -p speckle-sharp-ci-tools/Installers/blender
cp bpy_speckle.zip speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>-${SEMVER}.zip
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>*.zip
deploy-connector:
docker:
- image: mcr.microsoft.com/dotnet/sdk:6.0
@@ -203,18 +163,18 @@ workflows:
- package-connector:
filters: &build_filters
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
- build-connector-zip:
requires:
- package-connector
filters: *build_filters
- get-ci-tools:
filters: *build_filters
- build-installer-win:
context: innosetup
name: Windows Installer Build
requires:
- package-connector
@@ -222,14 +182,12 @@ workflows:
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-windows
file_slug: blender
os: WIN
arch: Any
extension: exe
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
@@ -237,32 +195,30 @@ workflows:
branches:
ignore: /.*/
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
- build-installer-mac:
- build-dotnet-installer:
name: Mac ARM Build
slug: blender-mac-arm
runtime: osx-arm64
runtime: osx.13-arm64
requires:
- get-ci-tools
- build-connector-zip
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-mac-arm
file_slug: blender-mac-arm
os: OSX
arch: Arm
extension: zip
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
- build-installer-mac:
- build-dotnet-installer:
name: Mac Intel Build
slug: blender-mac-intel
runtime: osx-x64
@@ -272,36 +228,13 @@ workflows:
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-mac-intel
file_slug: blender-mac-intel
os: OSX
arch: Intel
extension: zip
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
- build-installer-manual:
name: Manual Installer Build
requires:
- get-ci-tools
- build-connector-zip
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-manual
file_slug: bpy_speckle
os: Any
arch: Any
extension: zip
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
+70 -4
View File
@@ -6,7 +6,73 @@ on:
jobs:
update_issue:
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo "$PROJECT_ID"
echo "$STATUS_FIELD_ID"
echo 'DONE_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .settings | fromjson | .options[] | select(.name== "Done") | .id' project_data.json) >> $GITHUB_ENV
echo "$DONE_ID"
- name: Add Issue to project #it's already in the project, but we do this to get its node id!
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Update Status
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $status:ID!, $id:ID!, $value:String!) {
set_status: updateProjectNextItemField(
input: {
projectId: $project
itemId: $id
fieldId: $status
value: $value
}
) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f status=$STATUS_FIELD_ID -f id=$ITEM_ID -f value=${{ env.DONE_ID }}
+42 -4
View File
@@ -6,7 +6,45 @@ on:
jobs:
track_issue:
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
- name: Add Issue to project
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
+1 -2
View File
@@ -36,8 +36,7 @@ loading a Blender file
@persistent
def load_handler(dummy):
pass
#bpy.ops.speckle.users_load() #this is an expensive operation, one that forces the user to wait every time blender loads. Until we can do this non-blocking, we will make the user hit the refresh button each time.
bpy.ops.speckle.users_load()
"""
+101 -175
View File
@@ -1,6 +1,5 @@
import math
from typing import Iterable, Union, Collection
from bpy_speckle.convert.to_speckle import transform_to_speckle
from typing import Union
from bpy_speckle.functions import get_scale_length, _report
import mathutils
import bpy, bmesh, bpy_types
@@ -8,8 +7,7 @@ from specklepy.objects.other import *
from specklepy.objects.geometry import *
from bpy.types import Object
from .util import (
get_render_material,
render_material_to_native,
add_blender_material,
add_custom_properties,
add_vertices,
add_faces,
@@ -21,8 +19,9 @@ SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve)
CAN_CONVERT_TO_NATIVE = (
Mesh,
Brep,
*SUPPORTED_CURVES,
transform_to_speckle,
Transform,
BlockDefinition,
BlockInstance,
)
@@ -31,50 +30,88 @@ CAN_CONVERT_TO_NATIVE = (
def can_convert_to_native(speckle_object: Base) -> bool:
if type(speckle_object) in CAN_CONVERT_TO_NATIVE:
return True
for alias in DISPLAY_VALUE_PROPERTY_ALIASES:
if getattr(speckle_object, alias, None):
return True
if getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
):
return True
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return False
def convert_to_native(speckle_object: Base) -> list[Object]:
def convert_to_native(speckle_object: Base, name: Optional[str] = None) -> Optional[Union[list, Object]]:
speckle_type = type(speckle_object)
speckle_name = generate_object_name(speckle_object)
speckle_name = (
name
or getattr(speckle_object, "name", None)
or f"{speckle_object.speckle_type} -- {speckle_object.id}"
)
# convert unsupported types with display values
if speckle_type not in CAN_CONVERT_TO_NATIVE:
elements = getattr(speckle_object, "elements", []) or []
display = getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
)
if not elements and not display:
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return None
if isinstance(display, list):
elements.extend(display)
else:
elements.append(display)
# TODO: depreciate the parent type
# add parent type here so we can use it as a blender custom prop
# not making it hidden, so it will get added on send as i think it might be helpful? can reconsider
converted = []
for item in elements:
if not isinstance(item, Base):
continue
item.parent_speckle_type = speckle_object.speckle_type
blender_object = convert_to_native(item)
if isinstance(blender_object, list):
converted.extend(blender_object)
else:
add_custom_properties(speckle_object, blender_object)
converted.append(blender_object)
return converted
try:
scale = get_scale_factor(speckle_object)
# convert breps
if speckle_type is Brep:
meshes = getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", iter([]))
)
if material := getattr(speckle_object, "renderMaterial", getattr(speckle_object, "@renderMaterial", None),):
for mesh in meshes:
mesh["renderMaterial"] = material
obj_data: Optional[Union[bpy.types.ID, bpy.types.Object, mathutils.Matrix]] = None
converted: list[Object] = []
# convert elements/breps
if speckle_type not in CAN_CONVERT_TO_NATIVE:
(obj_data, converted) = display_value_to_native(speckle_object, speckle_name, scale)
return [convert_to_native(mesh) for mesh in meshes]
scale = 1.0
if units := getattr(speckle_object, "units", None):
scale = get_scale_length(units) / bpy.context.scene.unit_settings.scale_length
# convert supported geometry
elif isinstance(speckle_object, Mesh):
obj_data = mesh_to_native(speckle_object, speckle_name, scale)
if isinstance(speckle_object, Mesh):
obj_data = mesh_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type in SUPPORTED_CURVES:
obj_data = icurve_to_native(speckle_object, speckle_name, scale)
obj_data = icurve_to_native(speckle_object, name=speckle_name, scale=scale)
elif isinstance(speckle_object, Transform):
obj_data = transform_to_native(speckle_object, scale)
obj_data = transform_to_native(speckle_object, scale=scale)
elif isinstance(speckle_object, BlockDefinition):
obj_data = block_def_to_native(speckle_object)
elif isinstance(speckle_object, BlockInstance):
obj_data = block_instance_to_native(speckle_object, scale)
obj_data = block_def_to_native(speckle_object, scale=scale)
elif isinstance(speckle_object, BlockInstance): # speckle_type is BlockInstance:
obj_data = block_instance_to_native(speckle_object, scale=scale)
else:
_report(f"Unsupported type {speckle_type}")
return []
return None
except Exception as ex: # conversion error
_report(f"Error converting {speckle_object} \n{ex}")
return []
return None
if speckle_name in bpy.data.objects.keys():
blender_object = bpy.data.objects[speckle_name]
blender_object.data = (
obj_data.data if isinstance(obj_data, Object) else obj_data
obj_data.data if isinstance(obj_data, bpy_types.Object) else obj_data
)
blender_object.matrix_world = (
blender_object.matrix_world
@@ -86,143 +123,39 @@ def convert_to_native(speckle_object: Base) -> list[Object]:
else:
blender_object = (
obj_data
if isinstance(obj_data, Object)
if isinstance(obj_data, bpy_types.Object)
else bpy.data.objects.new(speckle_name, obj_data)
)
blender_object.speckle.object_id = str(speckle_object.id)
blender_object.speckle.enabled = True
add_custom_properties(speckle_object, blender_object)
add_blender_material(speckle_object, blender_object)
for child in converted:
child.parent = blender_object
converted.append(blender_object)
return converted
return blender_object
def mesh_to_native(speckle_mesh: Mesh, name: str, scale=1.0) -> bpy.types.Mesh:
def generate_object_name(speckle_object: Base) -> str:
prefix = (getattr(speckle_object, "name", None)
or getattr(speckle_object, "Name", None)
or speckle_object.speckle_type.rsplit(':')[-1])
return f"{prefix} -- {speckle_object.id}"
def get_scale_factor(speckle_object: Base, fallback: float = 1.0) -> float:
scale = fallback
if units := getattr(speckle_object, "units", None):
scale = get_scale_length(units) / bpy.context.scene.unit_settings.scale_length
return scale
DISPLAY_VALUE_PROPERTY_ALIASES = ["displayValue", "@displayValue", "displayMesh", "@displayMesh", "elements", "@elements"]
def display_value_to_native(speckle_object: Base, name: str, scale: float) -> tuple[Optional[bpy.types.Mesh], list[bpy.types.Object]]:
"""
Converts mesh displayValues as one mesh
Converts non-mesh displayValues as child Objects
"""
meshes: list[Mesh] = []
elements: list[Base] = []
#NOTE: raw Mesh elements will be treated like displayValues, which is not ideal, but no connector sends raw Mesh elements so its fine
for alias in DISPLAY_VALUE_PROPERTY_ALIASES:
display = getattr(speckle_object, alias, None)
count = 0
max_depth = 255
def seperate(value: Any) -> None:
nonlocal meshes, elements, count, max_depth
if isinstance(value, Mesh):
meshes.append(value)
elif isinstance(value, Base):
elements.append(value)
elif isinstance(value, list):
count += 1
if(count > max_depth):
return
for x in value:
seperate(x)
seperate(display)
converted: list[Object] = []
mesh = None
if meshes:
mesh = meshes_to_native(speckle_object, meshes, name, scale)
# add parent type here so we can use it as a blender custom prop
# not making it hidden, so it will get added on send as i think it might be helpful? can reconsider
for item in elements:
item.parent_speckle_type = speckle_object.speckle_type
blender_object = convert_to_native(item)
if isinstance(blender_object, list):
converted.extend(blender_object)
else:
add_custom_properties(speckle_object, blender_object)
converted.append(blender_object)
if not elements and not meshes:
_report(f"Unsupported type {speckle_object.speckle_type}")
return (mesh, converted)
def mesh_to_native(speckle_mesh: Mesh, name: str, scale: float) -> bpy.types.Mesh:
return meshes_to_native(speckle_mesh, [speckle_mesh], name, scale)
def meshes_to_native(element: Base, meshes: Collection[Mesh], name: str, scale: float) -> bpy.types.Mesh:
if name in bpy.data.meshes.keys():
blender_mesh = bpy.data.meshes[name]
else:
blender_mesh = bpy.data.meshes.new(name=name)
fallback_material = get_render_material(element)
bm = bmesh.new()
# First pass, add vertex data
for mesh in meshes:
scale = get_scale_factor(mesh, scale)
add_vertices(mesh, bm, scale)
bm.verts.ensure_lookup_table()
# Second pass, add face data
offset = 0
for i, mesh in enumerate(meshes):
add_faces(mesh, bm, offset, i)
render_material = get_render_material(mesh) or fallback_material
if render_material is not None:
native_material = render_material_to_native(render_material)
blender_mesh.materials.append(native_material)
offset += len(mesh.vertices) // 3
bm.faces.ensure_lookup_table()
bm.verts.index_update()
# Third pass, add vertex instance data
for mesh in meshes:
add_colors(mesh, bm)
add_uv_coords(mesh, bm)
add_vertices(speckle_mesh, bm, scale)
add_faces(speckle_mesh, bm)
add_colors(speckle_mesh, bm)
add_uv_coords(speckle_mesh, bm)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(blender_mesh)
bm.free()
bm.free()
return blender_mesh
def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
line = blender_curve.splines.new("POLY")
line.points.add(1)
@@ -242,10 +175,10 @@ def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: f
1,
)
return [line]
return []
return line
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
if value := scurve.value:
N = len(value) // 3
@@ -266,14 +199,13 @@ def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float)
1,
)
return [polyline]
return []
return polyline
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
if points := scurve.points:
N = len(points) // 3
nurbs = bcurve.splines.new("NURBS")
if hasattr(scurve, "closed"):
@@ -296,8 +228,7 @@ def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> lis
# nurbs.use_endpoint_u = True
nurbs.order_u = scurve.degree + 1
return [nurbs]
return []
return nurbs
def arc_to_native(rcurve: Arc, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
@@ -362,7 +293,7 @@ def arc_to_native(rcurve: Arc, bcurve: bpy.types.Curve, scale: float) -> Optiona
return arc
def polycurve_to_native(scurve: Polycurve, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
def polycurve_to_native(scurve: Polycurve, bcurve: bpy.types.Curve, scale: float):
"""
Convert Polycurve object
"""
@@ -374,38 +305,33 @@ def polycurve_to_native(scurve: Polycurve, bcurve: bpy.types.Curve, scale: float
speckle_type = type(seg)
if speckle_type in SUPPORTED_CURVES:
curves.append(icurve_to_native_spline(seg, bcurve, scale))
curves.append(icurve_to_native_spline(seg, bcurve, scale=scale))
else:
_report(f"Unsupported curve type: {speckle_type}")
return curves
def icurve_to_native_spline(speckle_curve: Base, blender_curve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
# polycurves
if isinstance(speckle_curve, Polycurve):
def icurve_to_native_spline(speckle_curve: Base, blender_curve: bpy.types.Curve, scale=1.0):
curve_type = type(speckle_curve)
if curve_type is Line:
return line_to_native(speckle_curve, blender_curve, scale)
if curve_type is Polyline:
return polyline_to_native(speckle_curve, blender_curve, scale)
if curve_type is Curve:
return nurbs_to_native(speckle_curve, blender_curve, scale)
if curve_type is Polycurve:
return polycurve_to_native(speckle_curve, blender_curve, scale)
# single curves
if isinstance(speckle_curve, Line):
spline = line_to_native(speckle_curve, blender_curve, scale)
elif isinstance(speckle_curve, Curve):
spline = nurbs_to_native(speckle_curve, blender_curve, scale)
elif isinstance(speckle_curve,Polyline):
spline = polyline_to_native(speckle_curve, blender_curve, scale)
elif isinstance(speckle_curve, Arc):
spline = arc_to_native(speckle_curve, blender_curve, scale)
else:
raise TypeError(f"{speckle_curve} is not a supported curve type. Supported types: {SUPPORTED_CURVES}")
return [spline] if spline is not None else []
if curve_type is Arc:
return arc_to_native(speckle_curve, blender_curve, scale)
def icurve_to_native(speckle_curve: Base, name: str, scale: float) -> Optional[bpy.types.Curve]:
def icurve_to_native(speckle_curve: Base, name=None, scale=1.0) -> Optional[Curve]:
curve_type = type(speckle_curve)
if curve_type not in SUPPORTED_CURVES:
_report(f"Unsupported curve type: {curve_type}")
return None
name = name or f"{curve_type} -- {speckle_curve.id}"
blender_curve = (
bpy.data.curves[name]
if name in bpy.data.curves.keys()
@@ -419,7 +345,7 @@ def icurve_to_native(speckle_curve: Base, name: str, scale: float) -> Optional[b
return blender_curve
def transform_to_native(transform: Transform, scale: float) -> mathutils.Matrix:
def transform_to_native(transform: Transform, scale=1.0) -> mathutils.Matrix:
mat = mathutils.Matrix(
[
transform.value[:4],
@@ -434,7 +360,7 @@ def transform_to_native(transform: Transform, scale: float) -> mathutils.Matrix:
return mat
def block_def_to_native(definition: BlockDefinition) -> bpy.types.Collection:
def block_def_to_native(definition: BlockDefinition, scale=1.0) -> bpy.types.Collection:
native_def = bpy.data.collections.get(definition.name)
if native_def:
return native_def
@@ -452,12 +378,12 @@ def block_def_to_native(definition: BlockDefinition) -> bpy.types.Collection:
return native_def
def block_instance_to_native(instance: BlockInstance, scale: float) -> bpy.types.Object:
def block_instance_to_native(instance: BlockInstance, scale=1.0) -> bpy.types.Object:
"""
Convert BlockInstance to native
"""
name = f"{getattr(instance, 'name', None) or instance.blockDefinition.name} -- {instance.id}"
native_def = block_def_to_native(instance.blockDefinition)
native_def = block_def_to_native(instance.blockDefinition, scale)
native_instance = bpy.data.objects.new(name, None)
add_custom_properties(instance, native_instance)
+54 -71
View File
@@ -1,6 +1,6 @@
from typing import Dict, Iterable, Optional, Tuple
from typing import Optional
import bpy
from bpy.types import Depsgraph, Material, MeshPolygon, Object
from bpy.types import Depsgraph, MeshVertColor, MeshVertex, Object
from specklepy.objects.geometry import Mesh, Curve, Interval, Box, Point, Polyline
from specklepy.objects.other import *
from bpy_speckle.functions import _report
@@ -23,7 +23,7 @@ def convert_to_speckle(blender_object: Object, scale: float, units: str, desgrap
return None
speckle_objects = []
# speckle_material = material_to_speckle_old(blender_object) #TODO: What about curves with materials...
speckle_material = material_to_speckle(blender_object)
if desgraph:
blender_object = blender_object.evaluated_get(desgraph)
converted = None
@@ -40,11 +40,12 @@ def convert_to_speckle(blender_object: Object, scale: float, units: str, desgrap
speckle_objects.extend([c for c in converted if c != None])
else:
speckle_objects.append(converted)
for so in speckle_objects:
so.properties = get_blender_custom_properties(blender_object)
so.applicationId = so.properties.pop("applicationId", None)
if speckle_material:
so["renderMaterial"] = speckle_material
# Set object transform
if blender_type != "EMPTY":
@@ -54,67 +55,53 @@ def convert_to_speckle(blender_object: Object, scale: float, units: str, desgrap
return speckle_objects
def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float = 1.0) -> List[Mesh]:
#if data.loop_triangles is None or len(data.loop_triangles) < 1:
# data.calc_loop_triangles()
# Categorise polygons by material index
submesh_data: Dict[int, List[MeshPolygon]] = {}
def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale=1.0) -> List[Mesh]:
if data.loop_triangles is None or len(data.loop_triangles) < 1:
data.calc_loop_triangles()
for p in data.polygons:
if p.material_index not in submesh_data:
submesh_data[p.material_index] = []
submesh_data[p.material_index].append(p)
transform = blender_object.matrix_world
scaled_vertices = [tuple(transform @ x.co * scale) for x in data.vertices]
mat = blender_object.matrix_world
# Create Speckle meshes for each material
submeshes = []
index_counter = 0
for i in submesh_data:
index_mapping: Dict[int, int] = {}
verts = [tuple(mat @ x.co * scale) for x in data.vertices]
#Loop through each polygon, and map indicies to their new index in m_verts
m_verts: List[float] = []
m_faces: List[int] = []
m_texcoords: List[float] = []
for face in submesh_data[i]:
u_indices = face.vertices
m_faces.append(len(u_indices))
for u_index in u_indices:
if u_index not in index_mapping:
# Create mapping between index in blender mesh, and new index in speckle submesh
index_mapping[u_index] = len(m_verts) // 3
vert = scaled_vertices[u_index]
m_verts.append(vert[0])
m_verts.append(vert[1])
m_verts.append(vert[2])
if data.uv_layers.active:
vt = data.uv_layers.active.data[index_counter]
m_texcoords.extend([vt.uv.x, vt.uv.y])
flattend_verts = []
for row in verts: flattend_verts.extend(row)
m_faces.append(index_mapping[u_index])
index_counter += 1
faces = [p.vertices for p in data.polygons]
unit_system = bpy.context.scene.unit_settings.system
speckle_mesh = Mesh(
vertices=m_verts,
faces=m_faces,
colors=[],
textureCoordinates=m_texcoords,
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
if i < len(data.materials):
material = data.materials[i]
if material is not None:
speckle_mesh["renderMaterial"] = material_to_speckle(material)
submeshes.append(speckle_mesh)
sm = Mesh(
name=blender_object.name,
vertices=flattend_verts,
faces=[],
colors=[],
textureCoordinates=[],
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
return submeshes
if data.uv_layers.active:
for vt in data.uv_layers.active.data:
sm.textureCoordinates.extend([vt.uv.x, vt.uv.y])
for f in faces:
n = len(f)
if n == 3:
sm.faces.append(0)
elif n == 4:
sm.faces.append(1)
else:
sm.faces.append(n)
sm.faces.extend(f)
# TODO: figure out how to align vertex colors and vertices consistantly in receiving applications
# we are seeing the same issue as with texture coordinate alignment
#if data.color_attributes.active_color:
# sm.colors = [to_argb_int(x.color) for x in data.color_attributes.active_color.data]
return [sm]
def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
@@ -279,7 +266,15 @@ def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, sca
return polylines
def material_to_speckle(blender_mat: bpy.types.Material) -> RenderMaterial:
def material_to_speckle(blender_object: Object) -> Optional[RenderMaterial]:
"""Create and return a render material from a blender object"""
if not getattr(blender_object.data, "materials", None):
return None
blender_mat: bpy.types.Material = blender_object.data.materials[0]
if not blender_mat:
return None
speckle_mat = RenderMaterial()
speckle_mat.name = blender_mat.name
@@ -301,19 +296,7 @@ def material_to_speckle(blender_mat: bpy.types.Material) -> RenderMaterial:
return speckle_mat
def material_to_speckle_old(blender_object: Object) -> Optional[RenderMaterial]:
"""Create and return a render material from a blender object"""
if not getattr(blender_object.data, "materials", None):
return None
blender_mat: bpy.types.Material = blender_object.data.materials[0]
if not blender_mat:
return None
return material_to_speckle(blender_mat)
def transform_to_speckle(blender_transform: Iterable[Iterable[float]], scale=1.0) -> Transform:
def transform_to_speckle(blender_transform: List[float], scale=1.0) -> Transform:
value = [y for x in blender_transform for y in x]
# scale the translation
for i in (3, 7, 11):
+42 -51
View File
@@ -1,13 +1,13 @@
import math
from typing import Any, Optional, Tuple
from typing import Tuple
from bmesh.types import BMesh
import bpy, struct, idprop
from specklepy.objects.base import Base
from specklepy.objects.geometry import Mesh
from specklepy.objects.other import RenderMaterial
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
from bpy_speckle.functions import _report
from bpy.types import Material, Object
from bpy.types import Object
IGNORED_PROPERTY_KEYS = {
"id",
@@ -25,7 +25,7 @@ IGNORED_PROPERTY_KEYS = {
}
def to_rgba(argb_int: int) -> Tuple[float, float, float, float]:
def to_rgba(argb_int: int) -> Tuple[float]:
"""Converts the int representation of a colour into a percent RGBA tuple"""
alpha = ((argb_int >> 24) & 255) / 255
red = ((argb_int >> 16) & 255) / 255
@@ -35,27 +35,18 @@ def to_rgba(argb_int: int) -> Tuple[float, float, float, float]:
return (red, green, blue, alpha)
def to_argb_int(rgba_color: list[float]) -> int:
def to_argb_int(diffuse_colour) -> int:
"""Converts an RGBA array to an ARGB integer"""
argb_color = rgba_color[-1:] + rgba_color[:3]
int_color = [int(val * 255) for val in argb_color]
diffuse_colour = diffuse_colour[-1:] + diffuse_colour[:3]
diffuse_colour = [int(val * 255) for val in diffuse_colour]
return int.from_bytes(int_color, byteorder="big", signed=True)
def set_custom_property(key: str, value: Any, blender_object: Object) -> None:
try:
#Expected c types: float, int, string, float[], int[]
blender_object[key] = value
except (OverflowError, TypeError) as ex:
print(f"Skipping setting property ({key}={value}) on {blender_object.name_full}, Reason: {ex}")
except Exception as ex:
#TODO: Log this as it's unexpected!!!
print(f"Skipping setting property ({key}={value}) on {blender_object.name_full}, Reason: {ex}")
return int.from_bytes(diffuse_colour, byteorder="big", signed=True)
def add_custom_properties(speckle_object: Base, blender_object: Object):
if blender_object is None:
return
serializer = BaseObjectSerializer()
blender_object["_speckle_type"] = type(speckle_object).__name__
app_id = getattr(speckle_object, "applicationId", None)
@@ -68,28 +59,39 @@ def add_custom_properties(speckle_object: Base, blender_object: Object):
continue
if isinstance(val, (int, str, float)):
set_custom_property(key, val, blender_object)
blender_object[key] = val
elif key == "properties" and isinstance(val, Base):
val["applicationId"] = None
add_custom_properties(val, blender_object)
elif isinstance(val, list):
items = [item for item in val if not isinstance(item, Base)]
if items:
set_custom_property(key, items, blender_object)
blender_object[key] = items
elif isinstance(val,dict):
for (k,v) in val.items():
if not isinstance(v, Base):
set_custom_property(k, v, blender_object)
blender_object[k] = v
def render_material_to_native(speckle_mat: RenderMaterial) -> Material:
mat_name = speckle_mat.name
def add_blender_material(speckle_object: Base, blender_object: Object) -> None:
"""Add material to a blender object if the corresponding speckle object has a render material"""
if blender_object.data is None:
return
speckle_mat = getattr(
speckle_object,
"renderMaterial",
getattr(speckle_object, "@renderMaterial", None),
)
if not speckle_mat:
return
mat_name = getattr(speckle_mat, "name", None) or speckle_mat.__dict__.get("@name")
if not mat_name:
mat_name = speckle_mat.applicationId or speckle_mat.id or speckle_mat.get_id()
blender_mat = bpy.data.materials.get(mat_name)
if blender_mat is None:
if not blender_mat:
blender_mat = bpy.data.materials.new(mat_name)
# for now, we're not updating these materials. as per tom's suggestion, we should have a toggle
@@ -103,24 +105,10 @@ def render_material_to_native(speckle_mat: RenderMaterial) -> Material:
inputs["Metallic"].default_value = speckle_mat.metalness
inputs["Alpha"].default_value = speckle_mat.opacity
if speckle_mat.opacity < 1.0:
if speckle_mat.opacity < 1:
blender_mat.blend_method = "BLEND"
return blender_mat
def get_render_material(speckle_object: Base) -> Optional[RenderMaterial]:
"""Trys to get a RenderMaterial on given speckle_object and convert it to a blender material"""
speckle_mat = getattr(
speckle_object,
"renderMaterial",
getattr(speckle_object, "@renderMaterial", None),
)
if not isinstance(speckle_mat, RenderMaterial):
return None
return speckle_mat
blender_object.data.materials.append(blender_mat)
def add_vertices(speckle_mesh: Mesh, blender_mesh: BMesh, scale=1.0):
@@ -136,11 +124,12 @@ def add_vertices(speckle_mesh: Mesh, blender_mesh: BMesh, scale=1.0):
)
)
blender_mesh.verts.ensure_lookup_table()
def add_faces(speckle_mesh: Mesh, blender_mesh: BMesh, indexOffset: int, materialIndex: int = 0, smooth:bool = False):
def add_faces(speckle_mesh: Mesh, blender_mesh: BMesh, smooth=False):
sfaces = speckle_mesh.faces
if sfaces and len(sfaces) > 0:
i = 0
while i < len(sfaces):
@@ -151,14 +140,16 @@ def add_faces(speckle_mesh: Mesh, blender_mesh: BMesh, indexOffset: int, materia
i += 1
try:
f = blender_mesh.faces.new(
[blender_mesh.verts[x + indexOffset] for x in sfaces[i : i + n]]
[blender_mesh.verts[int(x)] for x in sfaces[i : i + n]]
)
f.material_index = materialIndex
f.smooth = smooth
except Exception as e:
_report(f"Failed to create face for mesh {speckle_mesh.id} \n{e}")
i += n
blender_mesh.faces.ensure_lookup_table()
blender_mesh.verts.index_update()
def add_colors(speckle_mesh: Mesh, blender_mesh: BMesh):
@@ -205,7 +196,7 @@ def add_uv_coords(speckle_mesh: Mesh, blender_mesh: BMesh):
)
else:
_report(
f"Failed to match UV coordinates to vert data. Blender mesh verts: {len(blender_mesh.verts)}, Speckle UVs: {len(s_uvs) // 2}"
f"Failed to match UV coordinates to vert data. Blender mesh verts: {len(blender_mesh.verts)}, Speckle UVs * 2: {len(s_uvs) * 2}"
)
return
@@ -259,15 +250,15 @@ from: https://blender.stackexchange.com/a/34276
"""
def macro_knotsu(nu: bpy.types.Spline) -> int:
def macro_knotsu(nu):
return nu.order_u + nu.point_count_u + (nu.order_u - 1 if nu.use_cyclic_u else 0)
def macro_segmentsu(nu: bpy.types.Spline) -> int:
def macro_segmentsu(nu):
return nu.point_count_u if nu.use_cyclic_u else nu.point_count_u - 1
def make_knots(nu: bpy.types.Spline) -> list[float]:
def make_knots(nu):
knots = [0.0] * (4 + macro_knotsu(nu))
flag = nu.use_endpoint_u + (nu.use_bezier_u << 1)
if nu.use_cyclic_u:
@@ -278,7 +269,7 @@ def make_knots(nu: bpy.types.Spline) -> list[float]:
return knots
def calc_knots(knots: list[float], point_count: int, order: int, flag: int) -> None:
def calc_knots(knots, point_count, order, flag):
pts_order = point_count + order
if flag == 1:
k = 0.0
@@ -303,7 +294,7 @@ def calc_knots(knots: list[float], point_count: int, order: int, flag: int) -> N
knots[a] = a
def makecyclicknots(knots: list[float], point_count: int, order: int) -> None:
def makecyclicknots(knots, point_count, order):
order2 = order - 1
if order > 2:
+5 -8
View File
@@ -1,5 +1,5 @@
from pathlib import Path
from importlib import import_module, invalidate_caches
from importlib import import_module
import bpy
import sys
@@ -17,7 +17,7 @@ def modules_path() -> Path:
# set user modules path at beginning of paths for earlier hit
if sys.path[1] != modules_path:
sys.path.insert(1, str(modules_path))
sys.path.insert(1, modules_path)
return modules_path
@@ -113,15 +113,12 @@ def _import_dependencies() -> None:
def ensure_dependencies() -> None:
try:
install_dependencies()
invalidate_caches()
_import_dependencies()
print("Found all dependencies, proceed with loading")
except ImportError:
raise Exception(
"Cannot automatically ensure Speckle dependencies. Please restart Blender!"
)
print("Failed to load all dependencies, trying to install them...")
install_dependencies()
raise Exception("Please restart Blender.")
if __name__ == "__main__":
+21 -37
View File
@@ -3,14 +3,13 @@ Stream operators
"""
from itertools import chain
from math import radians
from typing import Callable, Dict, Iterable, Optional
from typing import Callable, Dict, Iterable
import bpy
from specklepy.api.models import Commit
import webbrowser
from bpy.props import (
StringProperty,
BoolProperty,
EnumProperty,
)
from bpy.types import Context, Object
from bpy_speckle.convert.to_native import can_convert_to_native, convert_to_native
@@ -22,6 +21,7 @@ from bpy_speckle.functions import (
get_scale_length,
_report,
)
from bpy_speckle.convert import get_speckle_subobjects
from bpy_speckle.clients import speckle_clients
from bpy_speckle.operators.users import add_user_stream
@@ -52,8 +52,6 @@ def get_objects_collections(base: Base) -> Dict[str, list]:
def get_objects_nested_lists(items: list, parent_col: Optional[bpy.types.Collection] = None) -> List:
"""For handling the weird nested lists that come from Grasshopper"""
objects = []
if not items:
return objects
if isinstance(items[0], list):
items = list(chain.from_iterable(items))
@@ -79,6 +77,8 @@ def get_objects_collections_recursive(base: Base, parent_col: Optional[bpy.types
for name in base.get_dynamic_member_names():
value = base[name]
if name == "parameters" and "Revit" in base.speckle_type:
continue
if isinstance(value, list):
objects.extend(item for item in value if isinstance(item, Base))
if isinstance(value, Base):
@@ -125,7 +125,7 @@ def get_receive_funcs(context: Context, created_objects: Dict[str, Object]) -> t
nonlocal created_objects
nonlocal objectCallback
progress += 1 #NOTE:XXX Progress bar never reaches 100 because func is only called for convertible objects
progress += 1 #TODO: Progress bar never reaches 100 because func is only called for convertible objects
context.window_manager.progress_update(progress)
created_objects[obj.name] = obj
@@ -146,7 +146,7 @@ def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], sc
for obj in objects:
if isinstance(obj, dict):
bases_to_native(context, obj, scale, stream_id, func)
elif isinstance(obj, list): #FIXME: wtf are these nested if statement, can this not be a recursive call?
elif isinstance(obj, list):
for item in obj:
if isinstance(item, dict):
bases_to_native(context, item, scale, stream_id, func)
@@ -159,7 +159,7 @@ def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], sc
else:
_report(
f"Something went wrong when receiving collection: {col_name}" #FIXME: undescript report message
f"Something went wrong when receiving collection: {col_name}"
)
bpy.context.view_layer.update()
@@ -177,16 +177,16 @@ def base_to_native(context: bpy.types.Context,
existing: Dict[str, Object],
func: ObjectCallback = None
):
new_objects = convert_to_native(base)
if not isinstance(new_objects, list):
new_objects = [new_objects]
#NOTE: this code is ancient, and in testing does nothing, so we are removing it.
# if hasattr(base, "properties") and base.properties is not None:
# new_objects.extend(get_speckle_subobjects(base.properties, scale, base.id))
# elif isinstance(base, dict) and "properties" in base.keys():
# new_objects.extend(
# get_speckle_subobjects(base["properties"], scale, base["id"])
# )
if hasattr(base, "properties") and base.properties is not None:
new_objects.extend(get_speckle_subobjects(base.properties, scale, base.id))
elif isinstance(base, dict) and "properties" in base.keys():
new_objects.extend(
get_speckle_subobjects(base["properties"], scale, base["id"])
)
"""
Set object Speckle settings
@@ -199,11 +199,11 @@ def base_to_native(context: bpy.types.Context,
Run injected function
"""
if func:
new_object = func(context, new_object, base) #this base object isn't always the right one for hosted elements! #TODO: may be it now, need to double check!
new_object = func(context, new_object, base) #this base object isn't the right one for hosted elements!
if (
new_object is None
): # If the injected function returned None, then we should ignore this object.
): # Make sure that the injected function returned an object
_report(f"Script '{func.__module__}' returned None.")
continue
@@ -244,7 +244,7 @@ def get_existing_collection_objs(col: bpy.types.Collection) -> Dict[str, bpy.typ
}
def get_collection_parents(collection: bpy.types.Collection, names: list[str]) -> None:
def get_collection_parents(collection, names):
for parent in bpy.data.collections:
if collection.name in parent.children.keys():
# TODO: this should be rethought to make it clear when this is an IFC delim so we know to replace it
@@ -253,7 +253,7 @@ def get_collection_parents(collection: bpy.types.Collection, names: list[str]) -
get_collection_parents(parent, names)
def get_collection_hierarchy(collection: Optional[bpy.types.Collection]) -> list[str]:
def get_collection_hierarchy(collection):
if not collection:
return []
names = [collection.name.replace("/", "::").replace(".", "::")]
@@ -262,7 +262,7 @@ def get_collection_hierarchy(collection: Optional[bpy.types.Collection]) -> list
return names
def create_nested_hierarchy(base: Base, hierarchy: List[str], objects: Any):
def create_nested_hierarchy(base, hierarchy, objects):
child = base
while hierarchy:
@@ -279,12 +279,6 @@ def create_nested_hierarchy(base: Base, hierarchy: List[str], objects: Any):
return base
#RECEIVE_MODES = [#TODO: modes
# ("create", "Create", "Add new geometry, without removing any existing objects"),
# ("replace", "Replace", "Replace objects from previous receive operations from the same stream"),
# #("update","Update") #TODO: update mode!
#]
class ReceiveStreamObjects(bpy.types.Operator):
"""
Receive stream objects
@@ -298,14 +292,10 @@ class ReceiveStreamObjects(bpy.types.Operator):
clean_meshes: BoolProperty(name="Clean Meshes", default=False)
#receive_mode: EnumProperty(items=RECEIVE_MODES, name="Receive Type", default="replace", description="The behaviour of the recieve operation")
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(self, "clean_meshes")
#col.prop(self, "receive_mode")
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
@@ -395,12 +385,7 @@ class ReceiveStreamObjects(bpy.types.Operator):
if not collections:
return {"CANCELLED"}
# name = ""
# if self.receive_mode == "create":
name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id) # Matches Rhino "Create" naming
# else:
# name = stream.name # Doesn't quite match rhino's Update layer naming, but is close enough no?
name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id)
col = create_collection(name)
col.speckle.stream_id = stream.id
col.speckle.units = stream_data.units or "m"
@@ -431,7 +416,6 @@ class ReceiveStreamObjects(bpy.types.Operator):
"""
Iterate through retrieved resources
"""
bases_to_native(context, collections, scale, stream.id, func)
context.window_manager.progress_end()
+7 -9
View File
@@ -4,7 +4,6 @@ User account operators
import bpy
from bpy_speckle.functions import _report
from bpy_speckle.clients import speckle_clients
from bpy_speckle.properties.scene import SpeckleSceneSettings
from specklepy.api.client import SpeckleClient
from specklepy.api.models import Stream, User
from specklepy.api.credentials import get_local_accounts
@@ -24,14 +23,12 @@ class LoadUsers(bpy.types.Operator):
_report("Loading users...")
speckle : SpeckleSceneSettings = context.scene.speckle
users = speckle.users
users = context.scene.speckle.users
speckle.users.clear()
context.scene.speckle.users.clear()
speckle_clients.clear()
profiles = get_local_accounts()
active_user_index = 0
for profile in profiles:
user = users.add()
@@ -40,21 +37,22 @@ class LoadUsers(bpy.types.Operator):
user.name = profile.userInfo.name
user.email = profile.userInfo.email
user.company = profile.userInfo.company or ""
user.authToken = profile.token
try:
client = SpeckleClient(
host=profile.serverInfo.url,
use_ssl="https" in profile.serverInfo.url,
)
client.authenticate_with_account(profile)
client.authenticate(user.authToken)
speckle_clients.append(client)
except Exception as ex:
_report(ex)
users.remove(len(users) - 1)
if profile.isDefault:
active_user_index = len(users) - 1
context.scene.speckle.active_user = str(len(users) - 1)
speckle.active_user_index = int(speckle.active_user)
speckle.active_user = str(active_user_index)
context.scene.speckle.active_user_index = int(context.scene.speckle.active_user)
bpy.ops.speckle.load_user_streams()
bpy.context.view_layer.update()
if context.area:
+1
View File
@@ -73,6 +73,7 @@ class SpeckleUserObject(bpy.types.PropertyGroup):
name: StringProperty(default="Speckle User")
email: StringProperty(default="user@speckle.xyz")
company: StringProperty(default="SpeckleSystems")
authToken: StringProperty(default="")
streams: CollectionProperty(type=SpeckleStreamObject)
active_stream: IntProperty(default=0)
+2 -3
View File
@@ -115,14 +115,13 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
col = layout.column()
if len(speckle.users) < 1:
col.label(text="Refresh to initialise")
col.label(text="No users found.")
else:
col.prop(speckle, "active_user", text="")
user = speckle.users[int(speckle.active_user)]
col.label(text="{} ({})".format(user.server_name, user.server_url))
col.label(text="{} ({})".format(user.name, user.email))
col.operator("speckle.users_load", text="", icon="FILE_REFRESH")
class VIEW3D_PT_SpeckleStreams(bpy.types.Panel):
"""
Generated
+478 -584
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@ license = "Apache-2.0"
[tool.poetry.dependencies]
python = ">=3.8, <4.0.0"
specklepy = "^2.12.0"
specklepy = "^2.9.1"
# [tool.poetry.group.local_specklepy.dependencies]
# specklepy = {path = "../specklepy", develop = true}