Compare commits

...

42 Commits

Author SHA1 Message Date
Jedd Morgan 235b49d8c6 Merge pull request #150 from specklesystems/hotfix-authtoken
fix(auth): hotfix for serializing authTokens in blender file
2023-02-15 18:00:53 +00:00
Jedd Morgan a1fcdad0e3 fix(auth): hotfix for serializing authTokens in blender file 2023-02-15 15:41:36 +00:00
Gergő Jedlicska 584e543964 makes sure to insert a path string into the sys path not a path object (#149) 2023-02-08 12:45:29 +01:00
Jedd Morgan ef20c5240c Merge pull request #148 from specklesystems/jrm/converter/fix
Custom Properties overflow fix
2023-02-05 17:20:17 +00:00
Jedd Morgan 9fe12a018a fix(ToNative): fixed issue with attaching custom properties that exceed int32 max value 2023-02-05 15:30:55 +00:00
JR-Morgan 8411c01f1b Merge branch 'main' of https://github.com/specklesystems/speckle-blender 2023-02-02 15:06:25 +00:00
JR-Morgan 63b82a30cb bumped specklepy 2.12.0 2023-02-02 15:05:59 +00:00
Jedd Morgan 0b6e39cf38 Merge pull request #147 from specklesystems/jrm/converter/multi-mesh
Fixed misalgined uv error message
2023-02-02 13:56:21 +00:00
JR-Morgan b7efcec517 uv experimentation 2023-02-02 13:45:57 +00:00
Jedd Morgan 0ab0096aac Merge pull request #142 from specklesystems/jrm/converter/multi-mesh
Jrm/converter/multi mesh
2023-02-01 14:00:11 +00:00
JR-Morgan cbd8fc99bb Merge remote-tracking branch 'origin' into jrm/converter/multi-mesh 2023-02-01 14:00:00 +00:00
JR-Morgan 2a9287e762 final polish 2023-02-01 13:52:20 +00:00
Jedd Morgan 98c70f237c Merge pull request #146 from specklesystems/gergo/alwaysInstall
fix(installer): make sure to always install specklepy dependencies
2023-02-01 13:10:22 +00:00
Gergő Jedlicska 048047cf05 fix(installer): make sure to always install specklepy dependencies
Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
2023-01-31 10:57:05 +02:00
Jedd Morgan 6118215cae Experimentation with receive modes 2023-01-26 14:58:53 +00:00
Jedd Morgan 8e06432fe6 relock poetry 2023-01-23 23:50:42 +00:00
Jedd Morgan cb8620ff8a Merge branch 'main' into jrm/converter/multi-mesh
Signed-off-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
2023-01-23 23:49:12 +00:00
Jedd Morgan e0eddea8ab Fixed regression of null elements 2023-01-23 19:59:49 +00:00
Jedd Morgan 8497d0c195 Merge pull request #144 from specklesystems/jrm/ifc/fix
fixed IFC commits with empty lists
2023-01-20 17:00:04 +00:00
Jedd Morgan 1ce394c08f fixed issue with IFC commits with empty lists 2023-01-20 15:31:44 +00:00
Jedd Morgan aabbf87dda fix(ci): signing cert for iss 2023-01-16 17:12:39 +00:00
Jedd Morgan 7e31787d37 Updated config.yml 2023-01-16 16:29:13 +00:00
Jedd Morgan f1259587fd Bumped speckle py to 2.11.4 2023-01-16 15:00:10 +00:00
Jedd Morgan 7f913e3af0 Merge pull request #141 from specklesystems/gergo/ciContextUpdate
clone ci tools with ssh, use circleci context for env vars
2023-01-16 13:42:24 +00:00
Jedd Morgan 5433c34a4d Merge pull request #140 from specklesystems/jrm/manual-installer
Manual Installer
2023-01-16 13:39:50 +00:00
Alan Rynne 2c52e93660 ci: Updated github actions to use new actions repo 2023-01-09 20:41:22 +01:00
Gergő Jedlicska 3c3b24cf98 use innosetup context in the windows build 2023-01-06 14:01:56 +01:00
Gergő Jedlicska 3012b0ebcb clone ci tools with ssh, use circleci context for env vars 2023-01-06 12:17:19 +01:00
Jedd Morgan 35b96eaa4e feat(converter): meshes with multiple materials ToSpeckle 2022-12-19 13:42:35 +00:00
Jedd Morgan c229bb2414 materials 2022-12-15 18:04:31 +00:00
Jedd Morgan 318bd086c0 feat(converter): convert displayValues ToNative as a single mesh 2022-12-15 16:00:44 +00:00
Jedd Morgan e3eb29daa4 fiX(ci): fixed mistake in manual installer ci 2022-12-15 14:17:29 +00:00
Jedd Morgan 3359c8f275 feat(ci): Added manual instaler deploy 2022-12-14 17:01:45 +00:00
Gergő Jedlicska cfc5007d00 update tag fiter for numbered alpha and beta 2022-12-14 11:20:00 +01:00
Jedd Morgan 977994e141 feat(converter): initial refactor of mesh traversal 2022-12-13 19:02:43 +00:00
Jedd Morgan d9cbc80ee7 Zero restart installation 2022-12-09 15:00:44 +00:00
Jedd Morgan 45038fad79 feat(connector): Added reload operation to user account selection 2022-12-09 03:26:21 +00:00
Gergő Jedlicska cda621d735 chore(deps): relock again 2022-12-07 14:46:09 +01:00
Gergő Jedlicska 2d052d1379 chore(deps): remove local specklepy dep 2022-12-07 14:44:20 +01:00
Gergő Jedlicska 46ce2bc0df ci(circleci): install dependencies before packaging 2022-12-07 14:38:06 +01:00
Gergő Jedlicska 80e2216aa0 ci(circleci): add new package connector step 2022-12-07 14:32:48 +01:00
Gergő Jedlicska 10d69aa44b add new installer mechanism 2022-12-07 13:52:22 +01:00
14 changed files with 1009 additions and 828 deletions
+70 -6
View File
@@ -1,7 +1,7 @@
version: 2.1
orbs:
win: circleci/windows@2.4.0
win: circleci/windows@5.0.0
jobs:
package-connector:
@@ -49,9 +49,18 @@ jobs:
docker:
- image: cimg/base:2021.01
steps:
- run: # Could not get ssh to work, so using a personal token
- 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:
name: Clone
command: git clone https://$GITHUB_TOKEN@github.com/specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
command: git clone git@github.com:specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
- run:
command: cd speckle-sharp-ci-tools
- persist_to_workspace:
@@ -70,6 +79,12 @@ 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
@@ -125,6 +140,28 @@ 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
@@ -166,18 +203,18 @@ workflows:
- package-connector:
filters: &build_filters
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?/
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
- 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
@@ -185,12 +222,14 @@ 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
@@ -198,7 +237,7 @@ workflows:
branches:
ignore: /.*/
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?/
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
- build-installer-mac:
name: Mac ARM Build
@@ -210,12 +249,14 @@ workflows:
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
@@ -231,13 +272,36 @@ 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
+4 -70
View File
@@ -6,73 +6,7 @@ on:
jobs:
update_issue:
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 }}
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+4 -42
View File
@@ -6,45 +6,7 @@ on:
jobs:
track_issue:
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
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+2 -1
View File
@@ -36,7 +36,8 @@ loading a Blender file
@persistent
def load_handler(dummy):
bpy.ops.speckle.users_load()
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.
"""
+175 -101
View File
@@ -1,5 +1,6 @@
import math
from typing import Union
from typing import Iterable, Union, Collection
from bpy_speckle.convert.to_speckle import transform_to_speckle
from bpy_speckle.functions import get_scale_length, _report
import mathutils
import bpy, bmesh, bpy_types
@@ -7,7 +8,8 @@ from specklepy.objects.other import *
from specklepy.objects.geometry import *
from bpy.types import Object
from .util import (
add_blender_material,
get_render_material,
render_material_to_native,
add_custom_properties,
add_vertices,
add_faces,
@@ -19,9 +21,8 @@ SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve)
CAN_CONVERT_TO_NATIVE = (
Mesh,
Brep,
*SUPPORTED_CURVES,
Transform,
transform_to_speckle,
BlockDefinition,
BlockInstance,
)
@@ -30,88 +31,50 @@ CAN_CONVERT_TO_NATIVE = (
def can_convert_to_native(speckle_object: Base) -> bool:
if type(speckle_object) in CAN_CONVERT_TO_NATIVE:
return True
if getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
):
return True
for alias in DISPLAY_VALUE_PROPERTY_ALIASES:
if getattr(speckle_object, alias, None):
return True
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return False
def convert_to_native(speckle_object: Base, name: Optional[str] = None) -> Optional[Union[list, Object]]:
def convert_to_native(speckle_object: Base) -> list[Object]:
speckle_type = type(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
speckle_name = generate_object_name(speckle_object)
try:
# 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
scale = get_scale_factor(speckle_object)
return [convert_to_native(mesh) for mesh in meshes]
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)
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
if isinstance(speckle_object, Mesh):
obj_data = mesh_to_native(speckle_object, name=speckle_name, scale=scale)
elif isinstance(speckle_object, Mesh):
obj_data = mesh_to_native(speckle_object, speckle_name, scale)
elif speckle_type in SUPPORTED_CURVES:
obj_data = icurve_to_native(speckle_object, name=speckle_name, scale=scale)
obj_data = icurve_to_native(speckle_object, speckle_name, scale)
elif isinstance(speckle_object, Transform):
obj_data = transform_to_native(speckle_object, scale=scale)
obj_data = transform_to_native(speckle_object, scale)
elif isinstance(speckle_object, BlockDefinition):
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)
obj_data = block_def_to_native(speckle_object)
elif isinstance(speckle_object, BlockInstance):
obj_data = block_instance_to_native(speckle_object, scale)
else:
_report(f"Unsupported type {speckle_type}")
return None
return []
except Exception as ex: # conversion error
_report(f"Error converting {speckle_object} \n{ex}")
return None
return []
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, bpy_types.Object) else obj_data
obj_data.data if isinstance(obj_data, Object) else obj_data
)
blender_object.matrix_world = (
blender_object.matrix_world
@@ -123,39 +86,143 @@ def convert_to_native(speckle_object: Base, name: Optional[str] = None) -> Optio
else:
blender_object = (
obj_data
if isinstance(obj_data, bpy_types.Object)
if isinstance(obj_data, 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)
return blender_object
for child in converted:
child.parent = blender_object
converted.append(blender_object)
return converted
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()
add_vertices(speckle_mesh, bm, scale)
add_faces(speckle_mesh, bm)
add_colors(speckle_mesh, bm)
add_uv_coords(speckle_mesh, bm)
# 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)
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) -> Optional[bpy.types.Spline]:
def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
line = blender_curve.splines.new("POLY")
line.points.add(1)
@@ -175,10 +242,10 @@ def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: f
1,
)
return line
return [line]
return []
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
if value := scurve.value:
N = len(value) // 3
@@ -199,13 +266,14 @@ def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float)
1,
)
return polyline
return [polyline]
return []
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
if points := scurve.points:
N = len(points) // 3
nurbs = bcurve.splines.new("NURBS")
if hasattr(scurve, "closed"):
@@ -228,7 +296,8 @@ def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> Opt
# nurbs.use_endpoint_u = True
nurbs.order_u = scurve.degree + 1
return nurbs
return [nurbs]
return []
def arc_to_native(rcurve: Arc, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
@@ -293,7 +362,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):
def polycurve_to_native(scurve: Polycurve, bcurve: bpy.types.Curve, scale: float) -> list[bpy.types.Spline]:
"""
Convert Polycurve object
"""
@@ -305,33 +374,38 @@ 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=scale))
curves.append(icurve_to_native_spline(seg, bcurve, 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=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:
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):
return polycurve_to_native(speckle_curve, blender_curve, scale)
if curve_type is Arc:
return arc_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 []
def icurve_to_native(speckle_curve: Base, name=None, scale=1.0) -> Optional[Curve]:
def icurve_to_native(speckle_curve: Base, name: str, scale: float) -> Optional[bpy.types.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()
@@ -345,7 +419,7 @@ def icurve_to_native(speckle_curve: Base, name=None, scale=1.0) -> Optional[Curv
return blender_curve
def transform_to_native(transform: Transform, scale=1.0) -> mathutils.Matrix:
def transform_to_native(transform: Transform, scale: float) -> mathutils.Matrix:
mat = mathutils.Matrix(
[
transform.value[:4],
@@ -360,7 +434,7 @@ def transform_to_native(transform: Transform, scale=1.0) -> mathutils.Matrix:
return mat
def block_def_to_native(definition: BlockDefinition, scale=1.0) -> bpy.types.Collection:
def block_def_to_native(definition: BlockDefinition) -> bpy.types.Collection:
native_def = bpy.data.collections.get(definition.name)
if native_def:
return native_def
@@ -378,12 +452,12 @@ def block_def_to_native(definition: BlockDefinition, scale=1.0) -> bpy.types.Col
return native_def
def block_instance_to_native(instance: BlockInstance, scale=1.0) -> bpy.types.Object:
def block_instance_to_native(instance: BlockInstance, scale: float) -> 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, scale)
native_def = block_def_to_native(instance.blockDefinition)
native_instance = bpy.data.objects.new(name, None)
add_custom_properties(instance, native_instance)
+71 -54
View File
@@ -1,6 +1,6 @@
from typing import Optional
from typing import Dict, Iterable, Optional, Tuple
import bpy
from bpy.types import Depsgraph, MeshVertColor, MeshVertex, Object
from bpy.types import Depsgraph, Material, MeshPolygon, 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(blender_object)
# speckle_material = material_to_speckle_old(blender_object) #TODO: What about curves with materials...
if desgraph:
blender_object = blender_object.evaluated_get(desgraph)
converted = None
@@ -40,12 +40,11 @@ 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":
@@ -55,53 +54,67 @@ 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()
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()
# Categorise polygons by material index
submesh_data: Dict[int, List[MeshPolygon]] = {}
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)
mat = blender_object.matrix_world
transform = blender_object.matrix_world
scaled_vertices = [tuple(transform @ x.co * scale) for x in data.vertices]
verts = [tuple(mat @ x.co * scale) for x in data.vertices]
# Create Speckle meshes for each material
submeshes = []
index_counter = 0
for i in submesh_data:
index_mapping: Dict[int, int] = {}
flattend_verts = []
for row in verts: flattend_verts.extend(row)
#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])
faces = [p.vertices for p in data.polygons]
unit_system = bpy.context.scene.unit_settings.system
m_faces.append(index_mapping[u_index])
index_counter += 1
sm = Mesh(
name=blender_object.name,
vertices=flattend_verts,
faces=[],
colors=[],
textureCoordinates=[],
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
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)
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]
return submeshes
def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
@@ -266,15 +279,7 @@ def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, sca
return polylines
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
def material_to_speckle(blender_mat: bpy.types.Material) -> RenderMaterial:
speckle_mat = RenderMaterial()
speckle_mat.name = blender_mat.name
@@ -296,7 +301,19 @@ def material_to_speckle(blender_object: Object) -> Optional[RenderMaterial]:
return speckle_mat
def transform_to_speckle(blender_transform: List[float], scale=1.0) -> Transform:
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:
value = [y for x in blender_transform for y in x]
# scale the translation
for i in (3, 7, 11):
+51 -42
View File
@@ -1,13 +1,13 @@
import math
from typing import Tuple
from typing import Any, Optional, Tuple
from bmesh.types import BMesh
import bpy, struct, idprop
from specklepy.objects.base import Base
from specklepy.objects.geometry import Mesh
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
from specklepy.objects.other import RenderMaterial
from bpy_speckle.functions import _report
from bpy.types import Object
from bpy.types import Material, Object
IGNORED_PROPERTY_KEYS = {
"id",
@@ -25,7 +25,7 @@ IGNORED_PROPERTY_KEYS = {
}
def to_rgba(argb_int: int) -> Tuple[float]:
def to_rgba(argb_int: int) -> Tuple[float, float, float, 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,18 +35,27 @@ def to_rgba(argb_int: int) -> Tuple[float]:
return (red, green, blue, alpha)
def to_argb_int(diffuse_colour) -> int:
def to_argb_int(rgba_color: list[float]) -> int:
"""Converts an RGBA array to an ARGB integer"""
diffuse_colour = diffuse_colour[-1:] + diffuse_colour[:3]
diffuse_colour = [int(val * 255) for val in diffuse_colour]
argb_color = rgba_color[-1:] + rgba_color[:3]
int_color = [int(val * 255) for val in argb_color]
return int.from_bytes(diffuse_colour, byteorder="big", signed=True)
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}")
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)
@@ -59,39 +68,28 @@ def add_custom_properties(speckle_object: Base, blender_object: Object):
continue
if isinstance(val, (int, str, float)):
blender_object[key] = val
set_custom_property(key, val, blender_object)
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:
blender_object[key] = items
set_custom_property(key, items, blender_object)
elif isinstance(val,dict):
for (k,v) in val.items():
if not isinstance(v, Base):
blender_object[k] = v
set_custom_property(k, v, blender_object)
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")
def render_material_to_native(speckle_mat: RenderMaterial) -> Material:
mat_name = speckle_mat.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 not blender_mat:
if blender_mat is None:
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
@@ -105,10 +103,24 @@ def add_blender_material(speckle_object: Base, blender_object: Object) -> None:
inputs["Metallic"].default_value = speckle_mat.metalness
inputs["Alpha"].default_value = speckle_mat.opacity
if speckle_mat.opacity < 1:
if speckle_mat.opacity < 1.0:
blender_mat.blend_method = "BLEND"
blender_object.data.materials.append(blender_mat)
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
def add_vertices(speckle_mesh: Mesh, blender_mesh: BMesh, scale=1.0):
@@ -124,12 +136,11 @@ 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, smooth=False):
def add_faces(speckle_mesh: Mesh, blender_mesh: BMesh, indexOffset: int, materialIndex: int = 0, smooth:bool = False):
sfaces = speckle_mesh.faces
if sfaces and len(sfaces) > 0:
i = 0
while i < len(sfaces):
@@ -140,16 +151,14 @@ def add_faces(speckle_mesh: Mesh, blender_mesh: BMesh, smooth=False):
i += 1
try:
f = blender_mesh.faces.new(
[blender_mesh.verts[int(x)] for x in sfaces[i : i + n]]
[blender_mesh.verts[x + indexOffset] 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):
@@ -196,7 +205,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 * 2: {len(s_uvs) * 2}"
f"Failed to match UV coordinates to vert data. Blender mesh verts: {len(blender_mesh.verts)}, Speckle UVs: {len(s_uvs) // 2}"
)
return
@@ -250,15 +259,15 @@ from: https://blender.stackexchange.com/a/34276
"""
def macro_knotsu(nu):
def macro_knotsu(nu: bpy.types.Spline) -> int:
return nu.order_u + nu.point_count_u + (nu.order_u - 1 if nu.use_cyclic_u else 0)
def macro_segmentsu(nu):
def macro_segmentsu(nu: bpy.types.Spline) -> int:
return nu.point_count_u if nu.use_cyclic_u else nu.point_count_u - 1
def make_knots(nu):
def make_knots(nu: bpy.types.Spline) -> list[float]:
knots = [0.0] * (4 + macro_knotsu(nu))
flag = nu.use_endpoint_u + (nu.use_bezier_u << 1)
if nu.use_cyclic_u:
@@ -269,7 +278,7 @@ def make_knots(nu):
return knots
def calc_knots(knots, point_count, order, flag):
def calc_knots(knots: list[float], point_count: int, order: int, flag: int) -> None:
pts_order = point_count + order
if flag == 1:
k = 0.0
@@ -294,7 +303,7 @@ def calc_knots(knots, point_count, order, flag):
knots[a] = a
def makecyclicknots(knots, point_count, order):
def makecyclicknots(knots: list[float], point_count: int, order: int) -> None:
order2 = order - 1
if order > 2:
+6 -6
View File
@@ -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, modules_path)
sys.path.insert(1, str(modules_path))
return modules_path
@@ -113,14 +113,14 @@ def _import_dependencies() -> None:
def ensure_dependencies() -> None:
try:
install_dependencies()
invalidate_caches()
_import_dependencies()
print("Found all dependencies, proceed with loading")
except ImportError:
print("Failed to load all dependencies, trying to install them...")
install_dependencies()
invalidate_caches()
_import_dependencies()
raise Exception(
"Cannot automatically ensure Speckle dependencies. Please restart Blender!"
)
+38 -22
View File
@@ -3,13 +3,14 @@ Stream operators
"""
from itertools import chain
from math import radians
from typing import Callable, Dict, Iterable
from typing import Callable, Dict, Iterable, Optional
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
@@ -21,7 +22,6 @@ 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,6 +52,8 @@ 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))
@@ -77,8 +79,6 @@ 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 #TODO: Progress bar never reaches 100 because func is only called for convertible objects
progress += 1 #NOTE:XXX 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):
elif isinstance(obj, list): #FIXME: wtf are these nested if statement, can this not be a recursive call?
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}"
f"Something went wrong when receiving collection: {col_name}" #FIXME: undescript report message
)
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]
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"])
)
new_objects = convert_to_native(base)
#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"])
# )
"""
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 the right one for hosted elements!
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!
if (
new_object is None
): # Make sure that the injected function returned an object
): # If the injected function returned None, then we should ignore this 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, names):
def get_collection_parents(collection: bpy.types.Collection, names: list[str]) -> None:
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, names):
get_collection_parents(parent, names)
def get_collection_hierarchy(collection):
def get_collection_hierarchy(collection: Optional[bpy.types.Collection]) -> list[str]:
if not collection:
return []
names = [collection.name.replace("/", "::").replace(".", "::")]
@@ -262,7 +262,7 @@ def get_collection_hierarchy(collection):
return names
def create_nested_hierarchy(base, hierarchy, objects):
def create_nested_hierarchy(base: Base, hierarchy: List[str], objects: Any):
child = base
while hierarchy:
@@ -279,6 +279,12 @@ def create_nested_hierarchy(base, hierarchy, objects):
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
@@ -292,10 +298,14 @@ 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)
@@ -385,7 +395,12 @@ class ReceiveStreamObjects(bpy.types.Operator):
if not collections:
return {"CANCELLED"}
name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id)
# 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?
col = create_collection(name)
col.speckle.stream_id = stream.id
col.speckle.units = stream_data.units or "m"
@@ -416,6 +431,7 @@ class ReceiveStreamObjects(bpy.types.Operator):
"""
Iterate through retrieved resources
"""
bases_to_native(context, collections, scale, stream.id, func)
context.window_manager.progress_end()
+2 -3
View File
@@ -40,13 +40,12 @@ 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(user.authToken)
client.authenticate_with_account(profile)
speckle_clients.append(client)
except Exception as ex:
_report(ex)
@@ -54,7 +53,7 @@ class LoadUsers(bpy.types.Operator):
if profile.isDefault:
active_user_index = len(users) - 1
speckle.active_user_index = int(speckle.active_user) #TODO: what is this?
speckle.active_user_index = int(speckle.active_user)
speckle.active_user = str(active_user_index)
bpy.context.view_layer.update()
-1
View File
@@ -73,7 +73,6 @@ class SpeckleUserObject(bpy.types.PropertyGroup):
name: StringProperty(default="Speckle User")
email: StringProperty(default="user@speckle.xyz")
company: StringProperty(default="SpeckleSystems")
authToken: StringProperty(default="", subtype='PASSWORD')
streams: CollectionProperty(type=SpeckleStreamObject)
active_stream: IntProperty(default=0)
+1 -1
View File
@@ -115,7 +115,7 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
col = layout.column()
if len(speckle.users) < 1:
col.label(text="No users found.")
col.label(text="Refresh to initialise")
else:
col.prop(speckle, "active_user", text="")
user = speckle.users[int(speckle.active_user)]
Generated
+584 -478
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.9.1"
specklepy = "^2.12.0"
# [tool.poetry.group.local_specklepy.dependencies]
# specklepy = {path = "../specklepy", develop = true}