mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
add support for loading images as quads
This commit is contained in:
BIN
assets/img.jpg
Normal file
BIN
assets/img.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
87
poetry.lock
generated
87
poetry.lock
generated
@@ -1029,6 +1029,91 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
ptyprocess = ">=0.5"
|
ptyprocess = ">=0.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pillow"
|
||||||
|
version = "10.2.0"
|
||||||
|
description = "Python Imaging Library (Fork)"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"},
|
||||||
|
{file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"},
|
||||||
|
{file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"},
|
||||||
|
{file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"},
|
||||||
|
{file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"},
|
||||||
|
{file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"},
|
||||||
|
{file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"},
|
||||||
|
{file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"},
|
||||||
|
{file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"},
|
||||||
|
{file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||||
|
fpx = ["olefile"]
|
||||||
|
mic = ["olefile"]
|
||||||
|
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||||
|
typing = ["typing-extensions"]
|
||||||
|
xmp = ["defusedxml"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prompt-toolkit"
|
name = "prompt-toolkit"
|
||||||
version = "3.0.43"
|
version = "3.0.43"
|
||||||
@@ -1611,4 +1696,4 @@ multidict = ">=4.0"
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "92566c9fc24a286eea553f28b583fe6de53d7ecb595be508a0ce4ae9ca9f58c6"
|
content-hash = "16d385dac0b8683b9d66b91696658ecf47a60fd19e08278f189c79858fe95563"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ aiohttp-devtools = "^1.1.2"
|
|||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
pygltflib = "^1.16.1"
|
pygltflib = "^1.16.1"
|
||||||
|
pillow = "^10.2.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import os
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
from build123d import Vector
|
||||||
|
|
||||||
from server import Server
|
from server import Server
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ if 'YACV_DISABLE_SERVER' not in os.environ:
|
|||||||
# Expose some nice aliases using the default server instance
|
# Expose some nice aliases using the default server instance
|
||||||
show = server.show
|
show = server.show
|
||||||
show_object = show
|
show_object = show
|
||||||
|
show_image = server.show_image
|
||||||
show_all = server.show_cad_all
|
show_all = server.show_cad_all
|
||||||
|
|
||||||
|
|
||||||
@@ -26,9 +28,13 @@ def _get_app() -> web.Application:
|
|||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
from logo import build_logo
|
from logo import build_logo
|
||||||
from build123d import Axis
|
from build123d import Axis
|
||||||
logo = build_logo(False)
|
logo = build_logo()
|
||||||
server.show_cad(logo, 'Logo')
|
server.show_cad(logo, 'Logo')
|
||||||
server.show_cad(logo.faces().group_by(Axis.X)[0].face().center_location, 'Location')
|
img_location = logo.faces().group_by(Axis.X)[0].face().center_location # Avoid overlapping:
|
||||||
|
img_location.position = Vector(img_location.position.X - 1e-2, img_location.position.Y, img_location.position.Z)
|
||||||
|
server.show_cad(img_location, 'Location')
|
||||||
|
img_path = os.path.join(os.path.dirname(__file__), '..', 'assets', 'img.jpg')
|
||||||
|
server.show_image(img_path, img_location, 20)
|
||||||
return server.app
|
return server.app
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
"""
|
"""
|
||||||
Utilities to work with CAD objects
|
Utilities to work with CAD objects
|
||||||
"""
|
"""
|
||||||
|
import hashlib
|
||||||
from typing import Optional, Union, List, Tuple
|
from typing import Optional, Union, List, Tuple
|
||||||
|
|
||||||
from OCP.TopLoc import TopLoc_Location
|
from OCP.TopLoc import TopLoc_Location
|
||||||
from OCP.TopoDS import TopoDS_Shape
|
from OCP.TopoDS import TopoDS_Shape
|
||||||
|
|
||||||
|
from gltf import GLTFMgr
|
||||||
|
|
||||||
CADLike = Union[TopoDS_Shape, TopLoc_Location] # Faces, Edges, Vertices and Locations for now
|
CADLike = Union[TopoDS_Shape, TopLoc_Location] # Faces, Edges, Vertices and Locations for now
|
||||||
|
|
||||||
|
|
||||||
@@ -54,4 +57,68 @@ def grab_all_cad() -> List[Tuple[str, CADLike]]:
|
|||||||
shapes.append((key, shape))
|
shapes.append((key, shape))
|
||||||
return shapes
|
return shapes
|
||||||
|
|
||||||
# TODO: Image to CAD utility and show_image shortcut on server.
|
|
||||||
|
def image_to_gltf(source: str | bytes, center: any, ppmm: int, name: Optional[str] = None,
|
||||||
|
save_mime: str = 'image/jpeg') -> Tuple[bytes, str]:
|
||||||
|
"""Convert an image to a GLTF CAD object, indicating the center location and pixels per millimeter."""
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
from build123d import Plane
|
||||||
|
from build123d import Location
|
||||||
|
from build123d import Vector
|
||||||
|
|
||||||
|
# Handle arguments
|
||||||
|
if name is None:
|
||||||
|
if isinstance(source, str):
|
||||||
|
name = os.path.basename(source)
|
||||||
|
else:
|
||||||
|
hasher = hashlib.md5()
|
||||||
|
hasher.update(source)
|
||||||
|
name = 'image_' + hasher.hexdigest()
|
||||||
|
format: str
|
||||||
|
if save_mime == 'image/jpeg':
|
||||||
|
format = 'JPEG'
|
||||||
|
elif save_mime == 'image/png':
|
||||||
|
format = 'PNG'
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unsupported save MIME type (for GLTF files): {save_mime}')
|
||||||
|
|
||||||
|
# Get the plane of the image
|
||||||
|
center_loc = get_shape(center)
|
||||||
|
if not isinstance(center_loc, TopLoc_Location):
|
||||||
|
raise ValueError('Center location not valid')
|
||||||
|
plane = Plane(Location(center_loc))
|
||||||
|
# Convert coordinates system
|
||||||
|
plane.origin = Vector(plane.origin.X, plane.origin.Z, -plane.origin.Y)
|
||||||
|
plane.z_dir = -plane.y_dir
|
||||||
|
plane.y_dir = plane.z_dir
|
||||||
|
|
||||||
|
def vert(v: Vector) -> Tuple[float, float, float]:
|
||||||
|
return v.X, v.Y, v.Z
|
||||||
|
|
||||||
|
# Load the image to a byte buffer
|
||||||
|
img = Image.open(source)
|
||||||
|
img_buf = io.BytesIO()
|
||||||
|
img.save(img_buf, format=format)
|
||||||
|
img_buf = img_buf.getvalue()
|
||||||
|
|
||||||
|
# Build the gltf
|
||||||
|
mgr = GLTFMgr(image=(img_buf, save_mime))
|
||||||
|
mgr.add_face([
|
||||||
|
vert(plane.origin - plane.x_dir * img.width / (2 * ppmm) - plane.y_dir * img.height / (2 * ppmm)),
|
||||||
|
vert(plane.origin + plane.x_dir * img.width / (2 * ppmm) - plane.y_dir * img.height / (2 * ppmm)),
|
||||||
|
vert(plane.origin + plane.x_dir * img.width / (2 * ppmm) + plane.y_dir * img.height / (2 * ppmm)),
|
||||||
|
vert(plane.origin - plane.x_dir * img.width / (2 * ppmm) + plane.y_dir * img.height / (2 * ppmm)),
|
||||||
|
], [
|
||||||
|
(0, 2, 1),
|
||||||
|
(0, 3, 2),
|
||||||
|
], [
|
||||||
|
(0, 0),
|
||||||
|
(1, 0),
|
||||||
|
(1, 1),
|
||||||
|
(0, 1),
|
||||||
|
])
|
||||||
|
|
||||||
|
# Return the GLTF binary blob and the suggested name of the image
|
||||||
|
return b''.join(mgr.gltf.save_to_bytes()), name
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ _checkerboard_image_bytes = base64.decodebytes(
|
|||||||
class GLTFMgr:
|
class GLTFMgr:
|
||||||
"""A utility class to build our GLTF2 objects easily and incrementally"""
|
"""A utility class to build our GLTF2 objects easily and incrementally"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, image: Tuple[bytes, str] = (_checkerboard_image_bytes, 'image/png')):
|
||||||
self.gltf = GLTF2(
|
self.gltf = GLTF2(
|
||||||
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
|
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
|
||||||
scene=0,
|
scene=0,
|
||||||
@@ -20,14 +20,13 @@ class GLTFMgr:
|
|||||||
nodes=[Node(mesh=0)],
|
nodes=[Node(mesh=0)],
|
||||||
meshes=[Mesh(primitives=[])],
|
meshes=[Mesh(primitives=[])],
|
||||||
accessors=[],
|
accessors=[],
|
||||||
bufferViews=[BufferView(buffer=0, byteLength=len(_checkerboard_image_bytes), byteOffset=0)],
|
bufferViews=[BufferView(buffer=0, byteLength=len(image[0]), byteOffset=0)],
|
||||||
buffers=[Buffer(byteLength=len(_checkerboard_image_bytes))],
|
buffers=[Buffer(byteLength=len(image[0]))],
|
||||||
samplers=[Sampler(magFilter=NEAREST)],
|
samplers=[Sampler(magFilter=NEAREST)],
|
||||||
textures=[Texture(source=0, sampler=0)],
|
textures=[Texture(source=0, sampler=0)],
|
||||||
images=[Image(bufferView=0, mimeType='image/png')],
|
images=[Image(bufferView=0, mimeType=image[1])],
|
||||||
)
|
)
|
||||||
self.gltf.set_binary_blob(_checkerboard_image_bytes)
|
self.gltf.set_binary_blob(image[0])
|
||||||
# TODO: Custom image support for loading textured planes as CAD objects
|
|
||||||
|
|
||||||
def add_face(self, vertices_raw: List[Tuple[float, float, float]], indices_raw: List[Tuple[int, int, int]],
|
def add_face(self, vertices_raw: List[Tuple[float, float, float]], indices_raw: List[Tuple[int, int, int]],
|
||||||
tex_coord_raw: List[Tuple[float, float]]):
|
tex_coord_raw: List[Tuple[float, float]]):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from aiohttp import web
|
|||||||
from build123d import Shape, Axis, Location, Vector
|
from build123d import Shape, Axis, Location, Vector
|
||||||
from dataclasses_json import dataclass_json
|
from dataclasses_json import dataclass_json
|
||||||
|
|
||||||
from cad import get_shape, grab_all_cad
|
from cad import get_shape, grab_all_cad, image_to_gltf
|
||||||
from mylogger import logger
|
from mylogger import logger
|
||||||
from pubsub import BufferedPubSub
|
from pubsub import BufferedPubSub
|
||||||
from tessellate import _hashcode, tessellate
|
from tessellate import _hashcode, tessellate
|
||||||
@@ -190,7 +190,7 @@ class Server:
|
|||||||
self.show_cad(any_object, name, **kwargs)
|
self.show_cad(any_object, name, **kwargs)
|
||||||
|
|
||||||
def show_gltf(self, gltf: bytes, name: Optional[str] = None, **kwargs):
|
def show_gltf(self, gltf: bytes, name: Optional[str] = None, **kwargs):
|
||||||
"""Publishes any single-file GLTF object to the server (GLB format recommended)."""
|
"""Publishes any single-file GLTF object to the server."""
|
||||||
start = time.time()
|
start = time.time()
|
||||||
# Precompute the info and send it to the client as if it was a CAD object
|
# Precompute the info and send it to the client as if it was a CAD object
|
||||||
precomputed_info = self._show_common(name, _hashcode(gltf, **kwargs), start, kwargs=kwargs)
|
precomputed_info = self._show_common(name, _hashcode(gltf, **kwargs), start, kwargs=kwargs)
|
||||||
@@ -200,6 +200,14 @@ class Server:
|
|||||||
publish_to.publish_nowait(b'') # Signal the end of the stream
|
publish_to.publish_nowait(b'') # Signal the end of the stream
|
||||||
self.object_events[precomputed_info.name] = publish_to
|
self.object_events[precomputed_info.name] = publish_to
|
||||||
|
|
||||||
|
def show_image(self, source: str | bytes, center: any, ppmm: int, name: Optional[str] = None,
|
||||||
|
save_mime: str = 'image/jpeg', **kwargs):
|
||||||
|
"""Publishes an image as a quad GLTF object, indicating the center location and pixels per millimeter."""
|
||||||
|
# Convert the image to a GLTF CAD object
|
||||||
|
gltf, name = image_to_gltf(source, center, ppmm, name, save_mime)
|
||||||
|
# Publish it like any other GLTF object
|
||||||
|
self.show_gltf(gltf, name, **kwargs)
|
||||||
|
|
||||||
def show_cad(self, obj: Union[TopoDS_Shape, any], name: Optional[str] = None, **kwargs):
|
def show_cad(self, obj: Union[TopoDS_Shape, any], name: Optional[str] = None, **kwargs):
|
||||||
"""Publishes a CAD object to the server"""
|
"""Publishes a CAD object to the server"""
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|||||||
Reference in New Issue
Block a user