mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-20 06:27:04 +01:00
better logo (demo)
This commit is contained in:
BIN
assets/logo_build/img.jpg.glb
Normal file
BIN
assets/logo_build/img.jpg.glb
Normal file
Binary file not shown.
BIN
assets/logo_build/location.glb
Normal file
BIN
assets/logo_build/location.glb
Normal file
Binary file not shown.
@@ -2,11 +2,15 @@
|
|||||||
export const settings = {
|
export const settings = {
|
||||||
preloadModels: [
|
preloadModels: [
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// new URL('../../assets/fox.glb', import.meta.url).href,
|
new URL('../../assets/fox.glb', import.meta.url).href,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// new URL('../../assets/logo.glb', import.meta.url).href,
|
new URL('../../assets/logo_build/base.glb', import.meta.url).href,
|
||||||
|
// @ts-ignore
|
||||||
|
new URL('../../assets/logo_build/location.glb', import.meta.url).href,
|
||||||
|
// @ts-ignore
|
||||||
|
new URL('../../assets/logo_build/img.jpg.glb', import.meta.url).href,
|
||||||
// Websocket URLs automatically listen for new models from the python backend
|
// Websocket URLs automatically listen for new models from the python backend
|
||||||
"ws://192.168.1.132:32323/"
|
// "ws://192.168.1.132:32323/"
|
||||||
],
|
],
|
||||||
displayLoadingEveryMs: 1000, /* How often to display partially loaded models */
|
displayLoadingEveryMs: 1000, /* How often to display partially loaded models */
|
||||||
checkServerEveryMs: 100, /* How often to check for a new server */
|
checkServerEveryMs: 100, /* How often to check for a new server */
|
||||||
|
|||||||
@@ -27,13 +27,9 @@ def _get_app() -> web.Application:
|
|||||||
"""Required by aiohttp-devtools"""
|
"""Required by aiohttp-devtools"""
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
from logo import build_logo
|
from logo import build_logo
|
||||||
from build123d import Axis
|
logo, img_location, img_path = build_logo()
|
||||||
logo = build_logo()
|
|
||||||
server.show_cad(logo, 'Logo')
|
server.show_cad(logo, 'Logo')
|
||||||
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')
|
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)
|
server.show_image(img_path, img_location, 20)
|
||||||
return server.app
|
return server.app
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from build123d import *
|
from build123d import *
|
||||||
|
|
||||||
|
ASSETS_DIR = os.getenv('ASSETS_DIR', os.path.join(os.path.dirname(__file__), '..', 'assets'))
|
||||||
|
|
||||||
def build_logo(text: bool = True) -> Part:
|
|
||||||
|
def build_logo(text: bool = True) -> Tuple[Part, Location, str]:
|
||||||
"""Builds the CAD part of the logo"""
|
"""Builds the CAD part of the logo"""
|
||||||
with BuildPart(Plane.XY.offset(50)) as logo_obj:
|
with BuildPart(Plane.XY.offset(50)) as logo_obj:
|
||||||
Box(22, 40, 30)
|
Box(22, 40, 30)
|
||||||
@@ -18,29 +21,38 @@ def build_logo(text: bool = True) -> Part:
|
|||||||
Text('Yet Another\nCAD Viewer', 7, font_path='/usr/share/fonts/TTF/OpenSans-Regular.ttf')
|
Text('Yet Another\nCAD Viewer', 7, font_path='/usr/share/fonts/TTF/OpenSans-Regular.ttf')
|
||||||
extrude(amount=1)
|
extrude(amount=1)
|
||||||
|
|
||||||
return logo_obj.part
|
logo_img_location = logo_obj.faces().group_by(Axis.X)[0].face().center_location # Avoid overlapping:
|
||||||
|
logo_img_location.position = Vector(logo_img_location.position.X - 4e-2, logo_img_location.position.Y,
|
||||||
|
logo_img_location.position.Z)
|
||||||
|
logo_img_path = os.path.join(ASSETS_DIR, 'img.jpg')
|
||||||
|
return logo_obj.part, logo_img_location, logo_img_path
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
# Start an offline "server" to export the CAD part of the logo in a way compatible with the frontend
|
# Start an offline server to export the CAD part of the logo in a way compatible with the frontend
|
||||||
|
# If this is not set, the server will auto-start on import and show_* calls will provide live updates
|
||||||
os.environ['YACV_DISABLE_SERVER'] = '1'
|
os.environ['YACV_DISABLE_SERVER'] = '1'
|
||||||
from yacv_server import show_object, server
|
from yacv_server import show, show_image
|
||||||
|
|
||||||
ASSETS_DIR = os.getenv('ASSETS_DIR', os.path.join(os.path.dirname(__file__), '..', 'assets'))
|
|
||||||
|
|
||||||
# Add the CAD part of the logo to the server
|
# Add the CAD part of the logo to the server
|
||||||
obj = build_logo()
|
logo, img_location, img_path = build_logo()
|
||||||
# DEBUG: Shape(obj).export_stl(os.path.join(ASSETS_DIR, 'logo.stl'))
|
show(logo, 'base')
|
||||||
show_object(obj, 'logo')
|
show(img_location, 'location')
|
||||||
|
show_image(img_path, img_location, 20)
|
||||||
# Save the complete logo to a single GLB file
|
|
||||||
with open(os.path.join(ASSETS_DIR, 'logo.glb'), 'wb') as f:
|
|
||||||
async def writer():
|
|
||||||
f.write(await server.export('logo'))
|
|
||||||
|
|
||||||
|
|
||||||
asyncio.run(writer())
|
async def exporter():
|
||||||
|
# We need access to the actual server object for advanced features like exporting to file
|
||||||
|
from yacv_server import server
|
||||||
|
for name in server.shown_object_names():
|
||||||
|
print(f'Exporting {name} to GLB...')
|
||||||
|
with open(os.path.join(ASSETS_DIR, 'logo_build', f'{name}.glb'), 'wb') as f:
|
||||||
|
f.write(await server.export(name))
|
||||||
|
|
||||||
print('Logo saved to', os.path.join(ASSETS_DIR, 'logo.glb'))
|
|
||||||
|
# Save the complete logo to multiple GLB files (async required)
|
||||||
|
asyncio.run(exporter())
|
||||||
|
|
||||||
|
print('Logo saved!')
|
||||||
|
|||||||
@@ -58,3 +58,7 @@ class BufferedPubSub(Generic[T]):
|
|||||||
yield v
|
yield v
|
||||||
finally: # When aclose() is called
|
finally: # When aclose() is called
|
||||||
await self._unsubscribe(q)
|
await self._unsubscribe(q)
|
||||||
|
|
||||||
|
def buffer(self) -> List[T]:
|
||||||
|
"""Returns a shallow copy of the list of buffered events"""
|
||||||
|
return self._buffer[:]
|
||||||
@@ -243,23 +243,25 @@ class Server:
|
|||||||
response.headers['Content-Disposition'] = f'attachment; filename="{request.match_info["name"]}.glb"'
|
response.headers['Content-Disposition'] = f'attachment; filename="{request.match_info["name"]}.glb"'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def shown_object_names(self) -> list[str]:
|
||||||
|
"""Returns the names of all objects that have been shown"""
|
||||||
|
return list([obj.name for obj in self.show_events.buffer()])
|
||||||
|
|
||||||
async def export(self, name: str) -> bytes:
|
async def export(self, name: str) -> bytes:
|
||||||
"""Export the given previously-shown object to a single GLB file, building it if necessary."""
|
"""Export the given previously-shown object to a single GLB file, building it if necessary."""
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
# Check that the object to build exists and grab it if it does
|
# Check that the object to build exists and grab it if it does
|
||||||
found = False
|
found = False
|
||||||
obj: Optional[TopoDS_Shape] = None
|
obj: Optional[TopoDS_Shape] = None
|
||||||
kwargs: Optional[Dict[str, any]] = None
|
kwargs: Optional[Dict[str, any]] = None
|
||||||
subscription = self.show_events.subscribe(include_future=False)
|
subscription = self.show_events.buffer()
|
||||||
try:
|
for data in subscription:
|
||||||
async for data in subscription:
|
|
||||||
if data.name == name:
|
if data.name == name:
|
||||||
obj = data.obj
|
obj = data.obj
|
||||||
kwargs = data.kwargs
|
kwargs = data.kwargs
|
||||||
found = True # Required because obj could be None
|
found = True # Required because obj could be None
|
||||||
break
|
break
|
||||||
finally:
|
|
||||||
await subscription.aclose()
|
|
||||||
if not found:
|
if not found:
|
||||||
raise web.HTTPNotFound(text=f'No object named {name} was previously shown')
|
raise web.HTTPNotFound(text=f'No object named {name} was previously shown')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user