This commit is contained in:
izzy lyseggen 2022-05-02 16:44:59 +01:00
Коммит 2720d8bbf5
6 изменённых файлов: 1479 добавлений и 0 удалений

117
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,117 @@
.tool-versions
.envrc
reports/
deps_windows_py39/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Jetbrains stuff:
.idea
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# other
scratch.py
settings.json

39
README.md Normal file
Просмотреть файл

@ -0,0 +1,39 @@
# Cinema 4D 26: One-Click Send to Speckle
## Introduction
This script allows you to send a Cinema4D model to Speckle with one click! Simply paste in a URL, execute the script, and away you go 🚀
![c4d-send](https://user-images.githubusercontent.com/7717434/166261286-eec09b76-2b0d-4651-bddf-8842e6c8b5c1.gif)
In order to achieve this, the script will (1) export your entire model to an `STL` file, (2) convert that file to Speckle, and (3) send and commit the converted mesh.
It is recommended that you have [Speckle Manager](https://speckle.guide/user/manager.html) installed before using this script, however you can also use a [token](https://speckle.guide/dev/tokens.html#personal-access-tokens) to authenticate yourself instead.
## Installation
### Windows
1. Extract the dependencies from `deps_windows_py39.zip`
2. Copy the contents of the extracted `deps_windows_py39` folder into your `%APPDATA%\Maxon\python\python39\libs`
![c4d-deps](https://user-images.githubusercontent.com/7717434/166263648-e0694f8f-f0a9-44ef-8589-024288dd32aa.png)
2. Copy the `send_to_speckle.py` script into your `%APPDATA%\Maxon\Maxon Cinema 4D R26_7DC20B77\library\scripts` (or load it in from wherever you like to save your Cinema4D python scripts)
### Mac
I was not able to get this on an M1 Pro mac, but feel free to try this manual installation out as you may have better luck.
1. Using Python 3.9, `pip install specklepy numpy-stl` into `~/Library/Preferences/MAXON/python39/libs` (**NOTE:** it is critical that you use Python 3.9 as the major version needs to match the one bundled with Cinema4D)
2. Copy the `send_to_speckle.py` script into your C4D scripts folder
## Usage
1. Load up the `send_to_speckle.py` script in the script tab
2. Paste in the url of the stream or branch you want to send to in the `STREAM_URL` field (defaults to `main` branch)
3. Optional: if you _don't_ have [Speckle Manager](https://speckle.guide/user/manager.html) installed with a Speckle account added to it, you can provide an authentication token to `TOKEN` field
![c4d-send](https://user-images.githubusercontent.com/7717434/166261286-eec09b76-2b0d-4651-bddf-8842e6c8b5c1.gif)
Note that C4D may become unresponsive for a minute or two until the operation is complete.

Двоичные данные
deps_windows_py39.zip Normal file

Двоичный файл не отображается.

1186
poetry.lock сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

18
pyproject.toml Normal file
Просмотреть файл

@ -0,0 +1,18 @@
[tool.poetry]
name = "oneclick-c4d"
version = "0.1.0"
description = ""
authors = ["izzy lyseggen <izzy.lyseggen@gmail.com>"]
[tool.poetry.dependencies]
python = ">=3.9, <3.10"
specklepy = "^2.6.7"
numpy-stl = "^2.16.3"
[tool.poetry.dev-dependencies]
black = "^22.3.0"
pylint = "^2.13.7"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

119
send_to_speckle.py Normal file
Просмотреть файл

@ -0,0 +1,119 @@
import os
import c4d
import stl
from specklepy.api import operations
from specklepy.api.wrapper import StreamWrapper
from specklepy.objects.geometry import Mesh
from specklepy.logging.exceptions import SpeckleException
# the url to the stream or branch you want to send to (if not a branch url, it will default to the main branch)
STREAM_URL = "https://latest.speckle.dev/streams/0c6ad366c4/branches/c4d_tests"
# the file will get exported to an STL in this folder right next to your c4d file
STL_EXPORT_FOLDER_NAME = "stl_export"
# if you have a account on Speckle Manager, you don't need this
TOKEN = ""
def export_stl() -> str:
"""Export the current file to an STL in a subfolder next to this file's location"""
active_doc = c4d.documents.GetActiveDocument()
path = active_doc.GetDocumentPath()
export_folder = os.path.join(path, STL_EXPORT_FOLDER_NAME)
os.makedirs(export_folder, exist_ok=True)
export_path = os.path.join(
export_folder, f"{os.path.splitext(active_doc.GetDocumentName())[0]} EXPORT.stl"
)
saved = c4d.documents.SaveDocument(
active_doc,
export_path,
saveflags=c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST,
format=c4d.FORMAT_STL_EXPORT,
)
if not saved:
raise SpeckleException("Failed to export file to STL")
print(f"Exported STL to {export_path}")
return export_path
def convert_stl(stl_file_path: str) -> Mesh:
"""
Convert STL file into a Speckle Mesh
(from the [speckle server import service](https://github.com/specklesystems/speckle-server/blob/main/packages/fileimport-service/stl/import_file.py))
"""
# Parse input
stl_mesh = stl.mesh.Mesh.from_file(stl_file_path)
print(
f"Parsed mesh with {stl_mesh.points.shape[0]} faces ({stl_mesh.points.shape[0] * 3} vertices)"
)
# Construct speckle obj
vertices = stl_mesh.points.flatten().tolist()
faces = []
for i in range(stl_mesh.points.shape[0]):
faces.extend([0, 3 * i, 3 * i + 1, 3 * i + 2])
speckle_mesh = Mesh(
vertices=vertices, faces=faces, colors=[], textureCoordinates=[]
)
print("Constructed Speckle Mesh object")
return speckle_mesh
def send_to_speckle(
wrapper: StreamWrapper, speckle_mesh: Mesh, commit_msg: str = None
) -> str:
"""Send the mesh to speckle and create a commit"""
client = wrapper.get_client(TOKEN or None)
if wrapper.branch_name and not client.branch.get(
wrapper.stream_id, wrapper.branch_name
):
client.branch.create(
wrapper.stream_id,
wrapper.branch_name,
"File upload branch" if wrapper.branch_name == "uploads" else "",
)
obj_id = operations.send(base=speckle_mesh, transports=[wrapper.get_transport()])
return client.commit.create(
wrapper.stream_id,
obj_id,
wrapper.branch_name or "main",
commit_msg or "STL file upload",
source_application="cinema4D",
)
def main() -> None:
w = StreamWrapper(STREAM_URL)
acct = w.get_account()
if not acct.token or TOKEN:
raise SpeckleException(
"No token available. Please either add a Speckle Account to Speckle Manager or provide a token in `TOKEN`"
)
stl_path = export_stl()
speckle_mesh = convert_stl(stl_path)
commit_id = send_to_speckle(
w, speckle_mesh, f"File upload: {os.path.basename(stl_path)}"
)
print(
f"File uploaded to\n{w.server_url}/streams/{w.stream_id}/commits/{commit_id}\n"
)
if __name__ == "__main__":
main()