Compare commits

...

10 Commits

Author SHA1 Message Date
izzy lyseggen ba931e8205 fix(installer/metrics): updates and cleanup (#92)
* ci: use semver tag instead of full circle tag

* chore: update deps

* chore: update specklepy

* feat(metrics): add blender version
2022-04-22 11:58:47 +01:00
izzy lyseggen 572925cfbb feat(convert): temps custom props patch (#89)
* chore: bump specklepy and fix deps

* feat(convert): wip attached props

* feat(convert): wip custom props
2022-04-04 12:10:57 +01:00
izzy lyseggen 03f94d6371 fix(convert): breps and dates (#87) 2022-03-28 15:03:27 +01:00
izzy lyseggen c220337aec chore: upgrade specklepy and add Blender v3.1 to ci (#86)
* chore(specklepy): upgrade to 2.6.3

* ci: add py 3.10 for blender 3.1
2022-03-28 11:47:56 +01:00
izzy lyseggen 1b67304cfc fix(converter): skip if not Pincipled BSDF (#85) 2022-03-09 11:07:35 +00:00
izzy lyseggen 25a1ec1cd1 ci: fix py 3.9 package install (#83)
* ci: test upgrade py

* ci: how about now?

* ci: we did it! 💃
2022-02-23 16:42:01 +00:00
izzy lyseggen 8296e48c28 Merge pull request #81 from specklesystems/izzy/displayvals
fix(convert): new `displayValue` to native & specklepy update
2022-02-23 11:56:15 +00:00
izzy lyseggen ca81ac6fd6 feat(convert): list displayvals to native 2022-02-23 11:50:33 +00:00
izzy lyseggen 88212b94b6 fix(users): none commit bug 2022-02-23 11:50:21 +00:00
izzy lyseggen 3375a04007 chore: update specklepy 2022-02-23 11:06:56 +00:00
11 changed files with 732 additions and 662 deletions
+25 -12
View File
@@ -20,8 +20,8 @@ jobs:
- checkout
- attach_workspace:
at: ./
- run:
name: Install specklepy with python 3.7
- run:
name: Install specklepy with python 3.7 for Blender v2.93
shell: powershell.exe
command: |
$pyarr=(python --version).split(' ')[1].split('.')
@@ -29,28 +29,41 @@ jobs:
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
python -m pip install --target=./modules-$pyver specklepy==$specklepy
- run:
name: Install python 3.9 and specklepy
- run:
name: Install python 3.9 and specklepy for Blender v3.0
shell: powershell.exe
command: |
choco install python --version=3.9.2
$pyarr=(C:\Python39\python.exe --version).split(' ')[1].split('.')
choco upgrade python --version=3.9.7
refreshenv
$pyarr=(py --version).split(' ')[1].split('.')
$pyver=($pyarr[0..1] -join '.')
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
C:\Python39\python.exe -m pip install --target=./modules-$pyver specklepy==$specklepy
py -m pip install --target=./modules-$pyver specklepy==$specklepy
- run:
name: Install python 3.10 and specklepy for Blender v3.1
shell: powershell.exe
command: |
choco upgrade python --version=3.10.2
refreshenv
$pyarr=(py --version).split(' ')[1].split('.')
$pyver=($pyarr[0..1] -join '.')
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
py -m pip install --target=./modules-$pyver specklepy==$specklepy
- run:
name: Patch
shell: powershell.exe
command:
| # If no tag, use 0.0.0.1 and don't make any YML (for testing only!)
$tag = if([string]::IsNullOrEmpty($env:CIRCLE_TAG)) { "0.0.1" } else { $env:CIRCLE_TAG }
$semver = $tag.replace("-beta","")
$version = "$($semver).$($env:CIRCLE_BUILD_NUM)"
$tag = if([string]::IsNullOrEmpty($env:CIRCLE_TAG)) { "0.0.0" } else { $env:CIRCLE_TAG }
$semver = if($tag.Contains('/')) {$tag.Split("/")[1] } else { $tag }
$ver = if($semver.Contains('-')) {$semver.Split("-")[0] } else { $semver }
$version = "$($ver).$($env:CIRCLE_BUILD_NUM)"
$channel = "latest"
if($tag -like "*-beta") { $channel = "beta" }
# only create the yml if we have a tag
New-Item -Force "speckle-sharp-ci-tools/Installers/blender/$channel.yml" -ItemType File -Value "version: $version"
New-Item -Force "speckle-sharp-ci-tools/Installers/blender/$channel.yml" -ItemType File -Value "version: $semver"
echo $version
ls
python patch_version.py $version
@@ -79,7 +92,7 @@ jobs:
root: ./
paths:
- modules-*
get-ci-tools: # Clones our ci tools and persists them to the workspace
docker:
- image: cimg/base:2021.01
+1 -1
View File
@@ -95,7 +95,7 @@ def register():
for cls in speckle_classes:
register_class(cls)
metrics.set_host_app("Blender")
metrics.set_host_app("blender", f"blender {bpy.app.version_string}")
"""
Register all new properties
+2 -1
View File
@@ -3,7 +3,8 @@ from bpy_speckle.convert.to_native import convert_to_native
def get_speckle_subobjects(attr, scale, name):
subobjects = []
for key in attr.keys():
keys = attr.keys() if isinstance(attr, dict) else attr.get_dynamic_member_names()
for key in keys:
if isinstance(attr[key], dict):
subtype = attr[key].get("type", None)
if subtype:
+25 -24
View File
@@ -17,7 +17,6 @@ SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve)
CAN_CONVERT_TO_NATIVE = (
Mesh,
Brep,
*SUPPORTED_CURVES,
Transform,
BlockDefinition,
@@ -28,10 +27,9 @@ CAN_CONVERT_TO_NATIVE = (
def can_convert_to_native(speckle_object):
if type(speckle_object) in CAN_CONVERT_TO_NATIVE:
return True
display = getattr(
speckle_object, "displayMesh", getattr(speckle_object, "displayValue", None)
)
if display:
if getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
):
return True
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
@@ -43,24 +41,34 @@ def convert_to_native(speckle_object, name=None):
speckle_name = (
name
or getattr(speckle_object, "name", None)
or speckle_object.speckle_type + f" -- {speckle_object.id}"
or f"{speckle_object.speckle_type} -- {speckle_object.id}"
)
if speckle_type not in CAN_CONVERT_TO_NATIVE:
elements = getattr(speckle_object, "elements", []) or []
display = getattr(
speckle_object, "displayMesh", getattr(speckle_object, "displayValue", None)
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
)
if not display:
if not elements and not display:
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return
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
if isinstance(display, list):
for item in display:
item.parent_speckle_type = speckle_object.speckle_type
convert_to_native(item)
else:
display.parent_speckle_type = speckle_object.speckle_type
return convert_to_native(display, speckle_name)
converted = []
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)
return converted
units = getattr(speckle_object, "units", None)
if units:
@@ -69,8 +77,6 @@ def convert_to_native(speckle_object, name=None):
try:
if speckle_type is Mesh:
obj_data = mesh_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type is Brep:
obj_data = brep_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type in SUPPORTED_CURVES:
obj_data = icurve_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type is Transform:
@@ -113,13 +119,6 @@ def convert_to_native(speckle_object, name=None):
return blender_object
def brep_to_native(speckle_brep, name, scale=1.0):
display = getattr(
speckle_brep, "displayMesh", getattr(speckle_brep, "displayValue", None)
)
return mesh_to_native(display, name, scale) if display else None
def mesh_to_native(speckle_mesh, name, scale=1.0):
if name in bpy.data.meshes.keys():
@@ -381,6 +380,8 @@ def block_instance_to_native(instance: BlockInstance, scale=1.0):
native_def = block_def_to_native(instance.blockDefinition, scale)
native_instance = bpy.data.objects.new(name, None)
add_custom_properties(instance, native_instance)
native_instance["name"] = getattr(instance, 'name', None) or instance.blockDefinition.name
# hide the instance axes so they don't clutter the viewport
native_instance.empty_display_size = 0
native_instance.instance_collection = native_def
+14 -5
View File
@@ -103,9 +103,13 @@ def bezier_to_speckle(matrix, spline, scale, name=None):
points.append(tuple(matrix @ bp.handle_right * scale))
if closed:
points.append(tuple(matrix @ spline.bezier_points[-1].handle_right * scale))
points.append(tuple(matrix @ spline.bezier_points[0].handle_left * scale))
points.append(tuple(matrix @ spline.bezier_points[0].co * scale))
points.extend(
(
tuple(matrix @ spline.bezier_points[-1].handle_right * scale),
tuple(matrix @ spline.bezier_points[0].handle_left * scale),
tuple(matrix @ spline.bezier_points[0].co * scale),
)
)
num_points = len(points)
@@ -168,7 +172,7 @@ def poly_to_speckle(matrix, spline, scale, name=None):
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Polyline(
name=name,
closed=spline.use_cyclic_u,
closed=bool(spline.use_cyclic_u),
value=list(sum(points, ())), # magic (flatten list of tuples)
length=length,
domain=domain,
@@ -245,10 +249,15 @@ def material_to_speckle(blender_object) -> RenderMaterial:
return
blender_mat = blender_object.data.materials[0]
if not blender_mat:
return
speckle_mat = RenderMaterial()
speckle_mat.name = blender_mat.name
if blender_mat.use_nodes is True:
if blender_mat.use_nodes is True and blender_mat.node_tree.nodes.get(
"Principled BSDF"
):
inputs = blender_mat.node_tree.nodes["Principled BSDF"].inputs
speckle_mat.diffuse = to_argb_int(inputs["Base Color"].default_value)
speckle_mat.emissive = to_argb_int(inputs["Emission"].default_value)
+68 -49
View File
@@ -1,10 +1,25 @@
import base64
from typing import Tuple
import bpy, struct, idprop
from specklepy.objects.base import Base
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
from bpy_speckle.functions import _report
IGNORED_PROPERTY_KEYS = {
"id",
"elements",
"displayMesh",
"displayValue",
"speckle_type",
"parameters",
"faces",
"colors",
"vertices",
"renderMaterial",
"textureCoordinates",
"totalChildrenCount"
}
def to_rgba(argb_int: int) -> Tuple[float]:
"""Converts the int representation of a colour into a percent RGBA tuple"""
@@ -23,7 +38,6 @@ def to_argb_int(diffuse_colour) -> int:
return int.from_bytes(diffuse_colour, byteorder="big", signed=True)
def add_custom_properties(speckle_object, blender_object):
if blender_object is None:
return
@@ -34,12 +48,25 @@ def add_custom_properties(speckle_object, blender_object):
app_id = getattr(speckle_object, "applicationId", None)
if app_id:
blender_object["applicationId"] = speckle_object.applicationId
keys = speckle_object.get_dynamic_member_names() if "Geometry" in speckle_object.speckle_type else (set(speckle_object.get_member_names()) - IGNORED_PROPERTY_KEYS)
for key in keys:
val = getattr(speckle_object, key, None)
if val is None:
continue
for key in speckle_object.get_dynamic_member_names():
if isinstance(speckle_object[key], (int, str, float)):
blender_object[key] = speckle_object[key]
elif isinstance(speckle_object[key], (dict, list)):
blender_object[key] = serializer.traverse_value(speckle_object[key])
if isinstance(val, (int, str, float)):
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:
blender_object[key] = items
elif isinstance(val,dict):
for (k,v) in val.items():
if not isinstance(v, Base):
blender_object[k] = v
def add_blender_material(speckle_object, blender_object) -> None:
@@ -152,73 +179,65 @@ def add_colors(speckle_mesh, blender_mesh):
def add_uv_coords(speckle_mesh, blender_mesh):
if not hasattr(speckle_mesh, "properties"):
s_uvs = speckle_mesh.textureCoordinates
if not s_uvs:
return
try:
uv = []
sprops = speckle_mesh.properties
if sprops:
texKey = ""
if "texture_coordinates" in sprops.keys():
texKey = "texture_coordinates"
elif "TextureCoordinates" in sprops.keys():
texKey = "TextureCoordinates"
if len(s_uvs) // 2 == len(blender_mesh.verts):
uv.extend(
(float(s_uvs[i]), float(s_uvs[i + 1]))
for i in range(0, len(s_uvs), 2)
)
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}"
)
return
if texKey != "":
# Make UVs
uv_layer = blender_mesh.loops.layers.uv.verify()
try:
decoded = base64.b64decode(sprops[texKey]).decode("utf-8")
s_uvs = decoded.split()
uv = []
if len(s_uvs) // 2 == len(blender_mesh.verts):
for i in range(0, len(s_uvs), 2):
uv.append((float(s_uvs[i]), float(s_uvs[i + 1])))
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}"
)
# Make UVs
uv_layer = blender_mesh.loops.layers.uv.verify()
for f in blender_mesh.faces:
for l in f.loops:
luv = l[uv_layer]
luv.uv = uv[l.vert.index]
except:
_report("Failed to decode texture coordinates.")
raise
del speckle_mesh.properties[texKey]
for f in blender_mesh.faces:
for l in f.loops:
luv = l[uv_layer]
luv.uv = uv[l.vert.index]
except:
_report("Failed to decode texture coordinates.")
raise
ignored_keys = (
ignored_keys = {
"id",
"speckle",
"speckle_type"
"_speckle_type",
"_speckle_name",
"_speckle_transform",
"_RNA_UI",
"elements",
"transform",
"_units",
"_chunkable",
)
}
def get_blender_custom_properties(obj, max_depth=1000):
if max_depth < 0:
return obj
if hasattr(obj, "keys"):
keys = set(obj.keys()) - ignored_keys
return {
key: get_blender_custom_properties(obj[key], max_depth - 1)
for key in obj.keys()
if key not in ignored_keys and not key.startswith("_")
for key in keys
if not key.startswith("_")
}
elif isinstance(obj, (list, tuple, idprop.types.IDPropertyArray)):
if isinstance(obj, (list, tuple, idprop.types.IDPropertyArray)):
return [get_blender_custom_properties(o, max_depth - 1) for o in obj]
else:
return obj
return obj
"""
+11 -10
View File
@@ -25,7 +25,7 @@ from bpy_speckle.clients import speckle_clients
from bpy_speckle.operators.users import add_user_stream
from specklepy.api import operations
from specklepy.api.credentials import StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from specklepy.api.resources.stream import Stream
from specklepy.transports.server import ServerTransport
from specklepy.objects.geometry import *
@@ -75,10 +75,10 @@ def get_objects_collections_recursive(base, parent_col=None) -> List:
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):
for item in value:
if isinstance(item, Base):
objects.append(item)
objects.extend(item for item in value if isinstance(item, Base))
if isinstance(value, Base):
col = parent_col.children.get(name)
if not col:
@@ -127,7 +127,9 @@ def bases_to_native(context, collections, scale, stream_id, func=None):
def base_to_native(context, base, scale, stream_id, col, existing, func=None):
new_objects = [convert_to_native(base)]
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))
@@ -152,8 +154,7 @@ def base_to_native(context, base, scale, stream_id, col, existing, func=None):
if (
new_object is None
): # Make sure that the injected function returned an object
new_obj = new_object
_report("Script '{}' returned None.".format(func.__module__))
_report(f"Script '{func.__module__}' returned None.")
continue
new_object.speckle.stream_id = stream_id
@@ -161,7 +162,7 @@ def base_to_native(context, base, scale, stream_id, col, existing, func=None):
if new_object.speckle.object_id in existing.keys():
name = existing[new_object.speckle.object_id].name
existing[new_object.speckle.object_id].name = name + "__deleted"
existing[new_object.speckle.object_id].name = f"{name}__deleted"
new_object.name = name
col.objects.unlink(existing[new_object.speckle.object_id])
@@ -250,7 +251,7 @@ class ReceiveStreamObjects(bpy.types.Operator):
client = speckle_clients[int(context.scene.speckle.active_user)]
stream = client.stream.get(id=bstream.id)
stream = client.stream.get(id=bstream.id, branch_limit=20)
if stream.branches.totalCount < 1:
return {"CANCELLED"}
@@ -518,7 +519,7 @@ class AddStreamFromURL(bpy.types.Operator):
user = speckle.users[user_index]
client = speckle_clients[user_index]
stream = client.stream.get(wrapper.stream_id)
stream = client.stream.get(wrapper.stream_id, branch_limit=20)
if not isinstance(stream, Stream):
raise SpeckleException("Could not get the requested stream")
+5 -4
View File
@@ -6,6 +6,7 @@ from bpy_speckle.functions import _report
from bpy_speckle.clients import speckle_clients
from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import get_local_accounts
from datetime import datetime
class LoadUsers(bpy.types.Operator):
@@ -78,10 +79,10 @@ def add_user_stream(user, stream):
for c in b.commits.items:
commit = branch.commits.add()
commit.id = commit.name = c.id
commit.message = c.message
commit.message = c.message or ""
commit.author_name = c.authorName
commit.author_id = c.authorId
commit.created_at = c.createdAt
commit.created_at = datetime.strftime(c.createdAt, "%Y-%m-%d %H:%M:%S.%f%Z")
commit.source_application = str(c.sourceApplication)
if hasattr(s, "baseProperties"):
@@ -110,7 +111,7 @@ class LoadUserStreams(bpy.types.Operator):
try:
streams = client.stream.list(stream_limit=20)
except Exception as e:
_report("Failed to retrieve streams: {}".format(e))
_report(f"Failed to retrieve streams: {e}")
return
if not streams:
_report("Failed to retrieve streams.")
@@ -121,7 +122,7 @@ class LoadUserStreams(bpy.types.Operator):
default_units = "Meters"
for s in streams:
sstream = client.stream.get(id=s.id)
sstream = client.stream.get(id=s.id, branch_limit=20)
add_user_stream(user, sstream)
bpy.context.view_layer.update()
+6 -8
View File
@@ -12,7 +12,7 @@ from bpy.props import (
EnumProperty,
)
import datetime
from datetime import datetime
"""
Compatibility
@@ -177,7 +177,7 @@ class VIEW3D_PT_SpeckleActiveStream(bpy.types.Panel):
stream = user.streams[user.active_stream]
# user.active_stream = min(user.active_stream, len(user.streams) - 1)
row = col.row()
row.label(text="{} ({})".format(stream.name, stream.id))
row.label(text=f"{stream.name} ({stream.id})")
row.operator("speckle.stream_copy_id", text="", icon="COPY_ID")
col.separator()
@@ -205,13 +205,11 @@ class VIEW3D_PT_SpeckleActiveStream(bpy.types.Panel):
row.label(text=line)
area.separator()
dt = datetime.datetime.strptime(
commit.created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
)
col.label(text="{}".format(dt.ctime()))
col.label(
text="{} ({})".format(commit.author_name, commit.author_id)
dt = datetime.strptime(
commit.created_at, "%Y-%m-%d %H:%M:%S.%f%Z"
)
col.label(text=f"{dt.ctime()}")
col.label(text=f"{commit.author_name} ({commit.author_id})")
col.label(text=commit.source_application)
else:
col.label(text="No branches found!")
Generated
+572 -544
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -6,14 +6,13 @@ authors = ["izzy lyseggen <izzy.lyseggen@gmail.com>"]
license = "Apache-2.0"
[tool.poetry.dependencies]
python = ">=3.7,<3.8"
specklepy = "^2.5.1"
python = ">=3.7, <4.0.0"
specklepy = "^2.6.6"
[tool.poetry.dev-dependencies]
devtools = "^0.6.1"
numpy = "^1.20.2"
bpy = "^2.82.1"
bpy-build = "^2.1.0"
fake-bpy-module-latest = "^20220401"
black = "^21.12b0"
pylint = "^2.12.2"