From 146da84b62a9c617f0259d0e46815758f0cd5810 Mon Sep 17 00:00:00 2001 From: lf94 Date: Fri, 19 Nov 2021 23:36:57 -0500 Subject: [PATCH 01/11] Initial work to support curv --- app/api/db/schema.prisma | 1 + app/api/src/docker/curv/Dockerfile | 55 ++++++ app/api/src/docker/curv/curv.ts | 46 +++++ app/api/src/docker/curv/runCurv.ts | 182 ++++++++++++++++++ app/api/src/docker/docker-compose.yml | 16 ++ app/api/src/docker/serverless.yml | 18 ++ app/api/src/graphql/projects.sdl.ts | 1 + .../src/components/CadPackage/CadPackage.tsx | 7 +- .../src/components/IdeEditor/IdeEditor.tsx | 1 + .../IdeProjectCell/IdeProjectCell.tsx | 2 +- .../NavPlusButton/NavPlusButton.tsx | 7 + .../cadPackages/curv/curvController.ts | 143 ++++++++++++++ .../helpers/cadPackages/curv/curvParams.ts | 90 +++++++++ .../helpers/cadPackages/curv/initialCode.scad | 8 + .../src/helpers/cadPackages/curv/userGuide.md | 9 + app/web/src/helpers/cadPackages/index.ts | 7 + 16 files changed, 591 insertions(+), 2 deletions(-) create mode 100644 app/api/src/docker/curv/Dockerfile create mode 100644 app/api/src/docker/curv/curv.ts create mode 100644 app/api/src/docker/curv/runCurv.ts create mode 100644 app/web/src/helpers/cadPackages/curv/curvController.ts create mode 100644 app/web/src/helpers/cadPackages/curv/curvParams.ts create mode 100644 app/web/src/helpers/cadPackages/curv/initialCode.scad create mode 100644 app/web/src/helpers/cadPackages/curv/userGuide.md diff --git a/app/api/db/schema.prisma b/app/api/db/schema.prisma index d91dda8..163f4da 100644 --- a/app/api/db/schema.prisma +++ b/app/api/db/schema.prisma @@ -38,6 +38,7 @@ enum CadPackage { openscad cadquery jscad // TODO #422, add jscad to db schema when were ready to enable saving of jscad projects + curv } model Project { diff --git a/app/api/src/docker/curv/Dockerfile b/app/api/src/docker/curv/Dockerfile new file mode 100644 index 0000000..ffda554 --- /dev/null +++ b/app/api/src/docker/curv/Dockerfile @@ -0,0 +1,55 @@ +FROM public.ecr.aws/lts/ubuntu:20.04_stable + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update --fix-missing -qq +RUN apt-get -y -qq install git software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb unzip maim clang cmake git-core libboost-all-dev libopenexr-dev libtbb-dev libglm-dev libpng-dev libeigen3-dev dbus-x11 libxcursor-dev libxinerama-dev libxrandr-dev libglu1-mesa-dev libgles2-mesa-dev libgl1-mesa-dev libxi-dev +RUN git clone https://github.com/curv3d/curv.git +RUN cd curv +RUN git submodule init && git submodule update +RUN mkdir build +RUN cd build +RUN sed -i 's/set(LEAN_BUILD 0)/set(LEAN_BUILD 1)/' ../CMakeLists.txt +RUN cmake .. +RUN make +RUN make install + +# install node14, see comment at the top of node14source_setup.sh +ADD src/docker/common/node14source_setup.sh /nodesource_setup.sh +RUN ["chmod", "+x", "/nodesource_setup.sh"] +RUN bash nodesource_setup.sh +RUN apt-get install -y nodejs + +# Install aws-lambda-cpp build dependencies, this is for the post install script in aws-lambda-ric (in package.json) +RUN apt-get update && \ + apt-get install -y \ + g++ \ + make \ + cmake \ + unzip \ + automake autoconf libtool \ + libcurl4-openssl-dev + +# Add the lambda emulator for local dev, (see entrypoint.sh for where it's used), +# I have the file locally (gitignored) to speed up build times (as it downloads everytime), +# but you can use the http version of the below ADD command or download it yourself from that url. +ADD src/docker/common/aws-lambda-rie /usr/local/bin/aws-lambda-rie +# ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/download/v1.0/aws-lambda-rie /usr/local/bin/aws-lambda-rie +RUN ["chmod", "+x", "/usr/local/bin/aws-lambda-rie"] + +WORKDIR /var/task/ +COPY package*.json /var/task/ +RUN npm install +RUN npm install aws-lambda-ric@1.0.0 + +RUN echo "cadhub-concat-split" > /var/task/cadhub-concat-split + +# using built javascript from dist +# run `yarn rw build` before bulding this image +COPY dist/docker/openscad/* /var/task/js/ +COPY dist/docker/common/* /var/task/common/ +COPY src/docker/common/entrypoint.sh /entrypoint.sh +RUN ["chmod", "+x", "/entrypoint.sh"] + +ENTRYPOINT ["sh", "/entrypoint.sh"] +CMD [ "js/curv.render" ] diff --git a/app/api/src/docker/curv/curv.ts b/app/api/src/docker/curv/curv.ts new file mode 100644 index 0000000..a81eb0b --- /dev/null +++ b/app/api/src/docker/curv/curv.ts @@ -0,0 +1,46 @@ +import { runCurv, stlExport } from './runCurv' +import middy from 'middy' +import { cors } from 'middy/middlewares' +import { loggerWrap, storeAssetAndReturnUrl } from '../common/utils' + +const preview = async (req, _context, callback) => { + _context.callbackWaitsForEmptyEventLoop = false + const eventBody = Buffer.from(req.body, 'base64').toString('ascii') + console.log('eventBody', eventBody) + + const { file, settings } = JSON.parse(eventBody) + const { error, consoleMessage, fullPath } = await runCurv({ + file, + settings, + }) + await storeAssetAndReturnUrl({ + error, + callback, + fullPath, + consoleMessage, + }) +} + +const stl = async (req, _context, callback) => { + _context.callbackWaitsForEmptyEventLoop = false + const eventBody = Buffer.from(req.body, 'base64').toString('ascii') + + console.log(eventBody, 'eventBody') + + const { file, settings } = JSON.parse(eventBody) + const { error, consoleMessage, fullPath } = await stlExport({ + file, + settings, + }) + await storeAssetAndReturnUrl({ + error, + callback, + fullPath, + consoleMessage, + }) +} + +module.exports = { + stl: middy(loggerWrap(stl)).use(cors()), + preview: middy(loggerWrap(preview)).use(cors()), +} diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts new file mode 100644 index 0000000..70c7b08 --- /dev/null +++ b/app/api/src/docker/curv/runCurv.ts @@ -0,0 +1,182 @@ +import { writeFiles, runCommand } from '../common/utils' +import { nanoid } from 'nanoid' +const { readFile } = require('fs/promises') +const fs = require('fs'); +const { spawn } = require('child_process'); + +function* getXDisplayNumber() { + const startValue = 99; + let i = startValue; + while(true) { + i -= 1; + + // Never hit zero since 0 is usually used by desktop users. + if (i <= 0) i = startValue; + yield ':' + i; + } +} + + +export const runCurv = async ({ + file, + settings: { + viewAll = false, + size: { x = 500, y = 500 } = {}, + parameters, + camera: { + position = { x: 40, y: 40, z: 40 }, + rotation = { x: 55, y: 0, z: 25 }, + dist = 200, + } = {}, + } = {}, // TODO add view settings +} = {}): Promise<{ + error?: string + consoleMessage?: string + fullPath?: string + customizerPath?: string +}> => { + const tempFile = await writeFiles( + [ + { file, fileName: 'main.curv' }, + { + file: JSON.stringify({ + parameterSets: { default: parameters }, + fileFormatVersion: '1', + }), + fileName: 'params.json', + }, + ], + 'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug: + ) + const { x: rx, y: ry, z: rz } = rotation + const { x: px, y: py, z: pz } = position + const cameraArg = `--camera=${px},${py},${pz},${rx},${ry},${rz},${dist}` + const fullPath = `/tmp/${tempFile}/output.gz` + const imPath = `/tmp/${tempFile}/output.png` + const customizerPath = `/tmp/${tempFile}/customizer.param` + const summaryPath = `/tmp/${tempFile}/summary.json` // contains camera info + + const code = file; + const DISPLAY = getXDisplayNumber().next().value; + + const xvfbProcess = spawn( + 'Xvfb', + [DISPLAY, '-ac', '-nocursor', '-screen', '0', '480x500x24'], + ); + + const curvProcess = spawn( + 'curv', + ['-' ], + { env: Object.assign({}, process.env, { DISPLAY, PATH: '/usr/local/bin' }) } + ); + + curvProcess.stdin.write(code); + curvProcess.stdin.end(); + + let statusSet = false; + let contentTypeSet = false; + + curvProcess.stderr.on('data', (buf) => { + const data = buf.toString('utf8'); + if (data.indexOf('shape') >= 0) { + setTimeout(() => { + const screenshotProcess = spawn('maim', ['--hidecursor', imPath], { env: { DISPLAY } }); + screenshotProcess.on('close', () => { + curvProcess.kill(); + xvfbProcess.kill(); + }); + }, 1000); + } + + if (data.indexOf('ERROR') < 0) { return; } + curvProcess.kill(); + xvfbProcess.kill(); + }); + + + try { + const files: string[] = await Promise.all( + [customizerPath, summaryPath].map((path) => + readFile(path, { encoding: 'ascii' }) + ) + ) + const [params, cameraInfo] = files.map((fileStr: string) => + JSON.parse(fileStr) + ) + await writeFiles( + [ + { + file: JSON.stringify({ + cameraInfo: viewAll ? cameraInfo.camera : undefined, + customizerParams: params.parameters, + consoleMessage, + type: 'png', + }), + fileName: 'metadata.json', + }, + ], + tempFile + ) + await runCommand( + `cat ${imPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, + 15000 + ) + return { consoleMessage, fullPath, customizerPath } + } catch (dirtyError) { + return { error: dirtyError } + } +} + +export const stlExport = async ({ file, settings: { parameters } } = {}) => { + const tempFile = await writeFiles( + [ + { file, fileName: 'main.curv' }, + { + file: JSON.stringify({ + parameterSets: { default: parameters }, + fileFormatVersion: '1', + }), + fileName: 'params.json', + }, + ], + 'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug: + ) + const fullPath = `/tmp/${tempFile}/output.gz` + const stlPath = `/tmp/${tempFile}/output.stl` + const customizerPath = `/tmp/${tempFile}/customizer.param` + const command = [ + 'curv', + '-o', stlPath, + '-O jit', + '-O vsize=0.4', + `/tmp/${tempFile}/main.curv`, + ].join(' ') + + try { + // lambda will time out before this, we might need to look at background jobs if we do git integration stl generation + const consoleMessage = await runCommand(command, 60000) + const params = JSON.parse( + await readFile(customizerPath, { encoding: 'ascii' }) + ).parameters + await writeFiles( + [ + { + file: JSON.stringify({ + customizerParams: params, + consoleMessage, + type: 'stl', + }), + fileName: 'metadata.json', + }, + ], + tempFile + ) + await runCommand( + `cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, + 15000 + ) + return { consoleMessage, fullPath, customizerPath } + } catch (error) { + return { error, fullPath } + } +} diff --git a/app/api/src/docker/docker-compose.yml b/app/api/src/docker/docker-compose.yml index d98992a..892d57a 100644 --- a/app/api/src/docker/docker-compose.yml +++ b/app/api/src/docker/docker-compose.yml @@ -45,3 +45,19 @@ services: AWS_ACCESS_KEY_ID: "${DEV_AWS_ACCESS_KEY_ID}" BUCKET: "${DEV_BUCKET}" + curv-preview: + build: + context: ../../ + dockerfile: ./src/docker/curv/Dockerfile + image: curv + command: js/curv.preview + # Adding volumes so that the containers can be restarted for js only changes in local dev + volumes: + - ../../dist/docker/openscad:/var/task/js/ + - ../../dist/docker/common:/var/task/common/ + ports: + - "5052:8080" + environment: + AWS_SECRET_ACCESS_KEY: "${DEV_AWS_SECRET_ACCESS_KEY}" + AWS_ACCESS_KEY_ID: "${DEV_AWS_ACCESS_KEY_ID}" + BUCKET: "${DEV_BUCKET}" diff --git a/app/api/src/docker/serverless.yml b/app/api/src/docker/serverless.yml index a033f88..78e22f3 100644 --- a/app/api/src/docker/serverless.yml +++ b/app/api/src/docker/serverless.yml @@ -23,6 +23,9 @@ provider: cadqueryimage: path: ../../ file: ./src/docker/cadquery/Dockerfile + curvimage: + path: ../../ + file: ./src/docker/curv/Dockerfile apiGateway: metrics: true binaryMediaTypes: @@ -99,6 +102,21 @@ functions: timeout: 30 environment: BUCKET: cad-preview-bucket-prod-001 + curvpreview: + image: + name: curvimage + command: + - js/curv.preview + entryPoint: + - '/entrypoint.sh' + events: + - http: + path: curv/preview + method: post + cors: true + timeout: 25 + environment: + BUCKET: cad-preview-bucket-prod-001 # The following are a few example events you can configure # NOTE: Please make sure to change your handler code to work with those events # Check the event documentation for details diff --git a/app/api/src/graphql/projects.sdl.ts b/app/api/src/graphql/projects.sdl.ts index 32e4890..8669a9d 100644 --- a/app/api/src/graphql/projects.sdl.ts +++ b/app/api/src/graphql/projects.sdl.ts @@ -23,6 +23,7 @@ export const schema = gql` openscad cadquery jscad + curv } type Query { diff --git a/app/web/src/components/CadPackage/CadPackage.tsx b/app/web/src/components/CadPackage/CadPackage.tsx index 76ddb3c..fef563b 100644 --- a/app/web/src/components/CadPackage/CadPackage.tsx +++ b/app/web/src/components/CadPackage/CadPackage.tsx @@ -1,4 +1,4 @@ -export type CadPackageType = 'openscad' | 'cadquery' | 'jscad' | 'INIT' +export type CadPackageType = 'openscad' | 'cadquery' | 'jscad' | 'curv' | 'INIT' interface CadPackageConfig { label: string @@ -23,6 +23,11 @@ export const cadPackageConfigs: { [key in CadPackageType]: CadPackageConfig } = buttonClasses: 'bg-ch-purple-500', dotClasses: 'bg-yellow-300', }, + curv: { + label: 'Curv', + buttonClasses: 'bg-ch-purple-500', + dotClasses: 'bg-yellow-300', + }, INIT: { label: '', buttonClasses: '', diff --git a/app/web/src/components/IdeEditor/IdeEditor.tsx b/app/web/src/components/IdeEditor/IdeEditor.tsx index 2e6ed8f..20a2bee 100644 --- a/app/web/src/components/IdeEditor/IdeEditor.tsx +++ b/app/web/src/components/IdeEditor/IdeEditor.tsx @@ -18,6 +18,7 @@ const IdeEditor = ({ Loading }) => { cadquery: 'python', openscad: 'cpp', jscad: 'javascript', + curv: 'javascript', INIT: '', } const monaco = useMonaco() diff --git a/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx b/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx index 34ee067..0473d30 100644 --- a/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx +++ b/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx @@ -35,7 +35,7 @@ export interface Project { code: string mainImage: string createdAt: string - cadPackage: 'openscad' | 'cadquery' + cadPackage: 'openscad' | 'cadquery' | 'curv' user: { id: string userName: string diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index d36346e..0fbe7a0 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -95,6 +95,13 @@ const menuOptions: { dotClasses: 'bg-yellow-300', ideType: 'jscad', }, + { + name: 'Curv', + sub: 'beta', + bgClasses: 'bg-ch-blue-700', + dotClasses: 'bg-blue-800', + ideType: 'curv', + }, ] const NavPlusButton: React.FC = () => { diff --git a/app/web/src/helpers/cadPackages/curv/curvController.ts b/app/web/src/helpers/cadPackages/curv/curvController.ts new file mode 100644 index 0000000..8323a8b --- /dev/null +++ b/app/web/src/helpers/cadPackages/curv/curvController.ts @@ -0,0 +1,143 @@ +import { + lambdaBaseURL, + stlToGeometry, + createHealthyResponse, + createUnhealthyResponse, + timeoutErrorMessage, + RenderArgs, + splitGziped, +} from '../common' +import { CurvToCadhubParams } from './openScadParams' +import type { XYZ, Camera } from 'src/helpers/hooks/useIdeState' + +export const render = async ({ code, settings }: RenderArgs) => { + const pixelRatio = window.devicePixelRatio || 1 + const size = { + x: Math.round(settings.viewerSize?.width * pixelRatio), + y: Math.round(settings.viewerSize?.height * pixelRatio), + } + const round1dec = (number) => Math.round((number + Number.EPSILON) * 10) / 10 + const body = JSON.stringify({ + settings: { + size, + viewAll: settings.viewAll, + parameters: settings.parameters, + camera: { + // rounding to give our caching a chance to sometimes work + ...settings.camera, + dist: round1dec(settings.camera.dist), + position: { + x: round1dec(settings.camera.position.x), + y: round1dec(settings.camera.position.y), + z: round1dec(settings.camera.position.z), + }, + rotation: { + x: round1dec(settings.camera.rotation.x), + y: round1dec(settings.camera.rotation.y), + z: round1dec(settings.camera.rotation.z), + }, + }, + }, + file: code, + }) + if (!settings.camera.position) { + return + } + try { + const response = await fetch(lambdaBaseURL + '/curv/preview', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body, + }) + if (response.status === 400) { + const { error } = await response.json() + const cleanedErrorMessage = cleanError(error) + return createUnhealthyResponse(new Date(), cleanedErrorMessage) + } + if (response.status === 502) { + return createUnhealthyResponse(new Date(), timeoutErrorMessage) + } + const blob = await response.blob() + const text = await new Response(blob).text() + const { consoleMessage, customizerParams, type, cameraInfo } = + splitGziped(text) + const vecArray2Obj = (arr: number[]): XYZ => ({ + x: arr[0], + y: arr[1], + z: arr[2], + }) + const camera: Camera = cameraInfo + ? { + dist: cameraInfo?.distance, + position: vecArray2Obj(cameraInfo?.translation), + rotation: vecArray2Obj(cameraInfo?.rotation), + isScadUpdate: true, + } + : undefined + return createHealthyResponse({ + type: type !== 'stl' ? 'png' : 'geometry', + data: + type !== 'stl' + ? blob + : await stlToGeometry(window.URL.createObjectURL(blob)), + consoleMessage, + camera, + date: new Date(), + customizerParams: curvToCadhubParams(customizerParams || []), + }) + } catch (e) { + return createUnhealthyResponse(new Date()) + } +} + +export const stl = async ({ code /*settings*/ }: RenderArgs) => { + const body = JSON.stringify({ + settings: {}, + file: code, + }) + try { + const response = await fetch(lambdaBaseURL + '/curv/stl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body, + }) + if (response.status === 400) { + const { error } = await response.json() + const cleanedErrorMessage = cleanError(error) + return createUnhealthyResponse(new Date(), cleanedErrorMessage) + } + if (response.status === 502) { + return createUnhealthyResponse(new Date(), timeoutErrorMessage) + } + const blob = await response.blob() + const text = await new Response(blob).text() + const { consoleMessage, customizerParams, type } = splitGziped(text) + return createHealthyResponse({ + type: type !== 'stl' ? 'png' : 'geometry', + data: + type !== 'stl' + ? blob + : await stlToGeometry(window.URL.createObjectURL(blob)), + consoleMessage, + date: new Date(), + customizerParams: openScadToCadhubParams(customizerParams || []), + }) + } catch (e) { + return createUnhealthyResponse(new Date()) + } +} + +const curv = { + render, + stl, +} + +export default curv + +function cleanError(error) { + return error.replace(/["|']\/tmp\/.+\/main.curv["|']/g, "'main.curv'") +} diff --git a/app/web/src/helpers/cadPackages/curv/curvParams.ts b/app/web/src/helpers/cadPackages/curv/curvParams.ts new file mode 100644 index 0000000..a0f4018 --- /dev/null +++ b/app/web/src/helpers/cadPackages/curv/curvParams.ts @@ -0,0 +1,90 @@ +import { CadhubParams } from 'src/components/Customizer/customizerConverter' + +interface CurvParamsBase { + caption: string + name: string + group: string + initial: number | string | number[] + type: 'string' | 'number' +} + +interface CurvNumberParam extends CurvParamsBase { + type: 'number' + initial: number | number[] + max?: number + min?: number + step?: number + options?: { name: string; value: number }[] +} +interface CurvStringParam extends CurvParamsBase { + type: 'string' + initial: string + maxLength?: number + options?: { name: string; value: string }[] +} + +export type CurvParams = + | CurvNumberParam + | CurvStringParam + +export function openScadToCadhubParams( + input: CurvParams[] +): CadhubParams[] { + return input + .map((param): CadhubParams => { + const common: { caption: string; name: string } = { + caption: param.caption, + name: param.name, + } + switch (param.type) { + case 'string': + if (!Array.isArray(param?.options)) { + return { + type: 'string', + input: 'default-string', + ...common, + initial: param.initial, + maxLength: param.maxLength, + } + } else { + return { + type: 'string', + input: 'choice-string', + ...common, + initial: param.initial, + options: param.options, + } + } + case 'number': + if ( + !Array.isArray(param?.options) && + !Array.isArray(param?.initial) + ) { + return { + type: 'number', + input: 'default-number', + ...common, + initial: param.initial, + min: param.min, + max: param.max, + step: param.step, + } + } else if ( + Array.isArray(param?.options) && + !Array.isArray(param?.initial) + ) { + return { + type: 'number', + input: 'choice-number', + ...common, + initial: param.initial, + options: param.options, + } + } // TODO else vector + break + default: + return + } + }) + .filter((a) => a) +} diff --git a/app/web/src/helpers/cadPackages/curv/initialCode.scad b/app/web/src/helpers/cadPackages/curv/initialCode.scad new file mode 100644 index 0000000..129a2d3 --- /dev/null +++ b/app/web/src/helpers/cadPackages/curv/initialCode.scad @@ -0,0 +1,8 @@ +// sphere box + +// ^ first comment is used for download title (i.e "involute-donut.stl") + +(smooth 1).union [ + box, + sphere +] diff --git a/app/web/src/helpers/cadPackages/curv/userGuide.md b/app/web/src/helpers/cadPackages/curv/userGuide.md new file mode 100644 index 0000000..4b3a835 --- /dev/null +++ b/app/web/src/helpers/cadPackages/curv/userGuide.md @@ -0,0 +1,9 @@ +--- +title: Curv +Written with: [Domain-Specific Language](https://martinfowler.com/dsl.html) +Kernal type: Signed distance functions +Maintained by: [Doug Moen and contributors](https://github.com/curv/curv/graphs/contributors) +Documentation: [curv3d.org](https://curv3d.org) +--- + +Curv is a programming language for creating art using mathematics. It’s a 2D and 3D geometric modelling tool that supports full colour, animation and 3D printing. diff --git a/app/web/src/helpers/cadPackages/index.ts b/app/web/src/helpers/cadPackages/index.ts index ea420c6..28589d9 100644 --- a/app/web/src/helpers/cadPackages/index.ts +++ b/app/web/src/helpers/cadPackages/index.ts @@ -13,16 +13,22 @@ import jscad from './jsCad/jsCadController' import jsCadGuide from 'src/helpers/cadPackages/jsCad/userGuide.md' import jsCadInitialCode from 'src/helpers/cadPackages/jsCad/initialCode.jscad.js' +import curv from './curv/curvController' +import curvGuide from 'src/helpers/cadPackages/curv/userGuide.md' +import curvInitialCode from 'src/helpers/cadPackages/curv/initialCode.py' + export const cadPackages: { [key in CadPackageType]: DefaultKernelExport } = { openscad, cadquery, jscad, + curv, } export const initGuideMap: { [key in CadPackageType]: string } = { openscad: openScadGuide, cadquery: cadQueryGuide, jscad: jsCadGuide, + curv: curvGuide, INIT: '', } @@ -30,5 +36,6 @@ export const initCodeMap: { [key in CadPackageType]: string } = { openscad: openScadInitialCode, cadquery: cadQueryInitialCode, jscad: jsCadInitialCode, + curv: curvInitialCode, INIT: '', } -- 2.39.5 From 8bdfec02d9e42672a477b89189f0108189db962f Mon Sep 17 00:00:00 2001 From: lf94 Date: Sat, 20 Nov 2021 13:05:23 -0500 Subject: [PATCH 02/11] Correct the initial code file location --- app/web/src/helpers/cadPackages/curv/initialCode.curv | 6 ++++++ app/web/src/helpers/cadPackages/curv/initialCode.scad | 8 -------- app/web/src/helpers/cadPackages/index.ts | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 app/web/src/helpers/cadPackages/curv/initialCode.curv delete mode 100644 app/web/src/helpers/cadPackages/curv/initialCode.scad diff --git a/app/web/src/helpers/cadPackages/curv/initialCode.curv b/app/web/src/helpers/cadPackages/curv/initialCode.curv new file mode 100644 index 0000000..3f4c4a1 --- /dev/null +++ b/app/web/src/helpers/cadPackages/curv/initialCode.curv @@ -0,0 +1,6 @@ +// sphere box + +(smooth 1).union [ + box, + sphere +] diff --git a/app/web/src/helpers/cadPackages/curv/initialCode.scad b/app/web/src/helpers/cadPackages/curv/initialCode.scad deleted file mode 100644 index 129a2d3..0000000 --- a/app/web/src/helpers/cadPackages/curv/initialCode.scad +++ /dev/null @@ -1,8 +0,0 @@ -// sphere box - -// ^ first comment is used for download title (i.e "involute-donut.stl") - -(smooth 1).union [ - box, - sphere -] diff --git a/app/web/src/helpers/cadPackages/index.ts b/app/web/src/helpers/cadPackages/index.ts index 28589d9..108469d 100644 --- a/app/web/src/helpers/cadPackages/index.ts +++ b/app/web/src/helpers/cadPackages/index.ts @@ -15,7 +15,7 @@ import jsCadInitialCode from 'src/helpers/cadPackages/jsCad/initialCode.jscad.js import curv from './curv/curvController' import curvGuide from 'src/helpers/cadPackages/curv/userGuide.md' -import curvInitialCode from 'src/helpers/cadPackages/curv/initialCode.py' +import curvInitialCode from 'src/helpers/cadPackages/curv/initialCode.curv' export const cadPackages: { [key in CadPackageType]: DefaultKernelExport } = { openscad, -- 2.39.5 From b1ff7796b965b64e70a077c0cb8bb3b7583985b6 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 21 Nov 2021 17:49:22 +1100 Subject: [PATCH 03/11] Preview and stl mvp working --- .vscode/settings.json | 3 +- app/api/src/docker/aws-emulator.js | 4 + app/api/src/docker/curv/Dockerfile | 32 +++++--- app/api/src/docker/curv/runCurv.ts | 81 +++---------------- app/api/src/docker/docker-compose.yml | 21 +++-- app/web/config/webpack.config.js | 2 +- .../src/components/IdeEditor/IdeEditor.tsx | 2 +- .../cadPackages/curv/curvController.ts | 22 +---- 8 files changed, 57 insertions(+), 110 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index aaa161b..78eaf8e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,10 @@ { "cSpell.words": [ "Cadhub", + "cadquery", + "curv", "Customizer", "Hutten", - "cadquery", "jscad", "openscad", "sendmail" diff --git a/app/api/src/docker/aws-emulator.js b/app/api/src/docker/aws-emulator.js index 239d8a0..6b99ce7 100644 --- a/app/api/src/docker/aws-emulator.js +++ b/app/api/src/docker/aws-emulator.js @@ -34,8 +34,12 @@ const makeRequest = (route, port) => [ app.post(...makeRequest('/openscad/preview', 5052)) app.post(...makeRequest('/openscad/stl', 5053)) + app.post(...makeRequest('/cadquery/stl', 5060)) +app.post(...makeRequest('/curv/preview', 5070)) +app.post(...makeRequest('/curv/stl', 5071)) + app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) diff --git a/app/api/src/docker/curv/Dockerfile b/app/api/src/docker/curv/Dockerfile index ffda554..1dae1b0 100644 --- a/app/api/src/docker/curv/Dockerfile +++ b/app/api/src/docker/curv/Dockerfile @@ -2,17 +2,27 @@ FROM public.ecr.aws/lts/ubuntu:20.04_stable ARG DEBIAN_FRONTEND=noninteractive + RUN apt-get update --fix-missing -qq -RUN apt-get -y -qq install git software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb unzip maim clang cmake git-core libboost-all-dev libopenexr-dev libtbb-dev libglm-dev libpng-dev libeigen3-dev dbus-x11 libxcursor-dev libxinerama-dev libxrandr-dev libglu1-mesa-dev libgles2-mesa-dev libgl1-mesa-dev libxi-dev -RUN git clone https://github.com/curv3d/curv.git -RUN cd curv -RUN git submodule init && git submodule update -RUN mkdir build -RUN cd build -RUN sed -i 's/set(LEAN_BUILD 0)/set(LEAN_BUILD 1)/' ../CMakeLists.txt -RUN cmake .. -RUN make -RUN make install +RUN apt-get update --fix-missing && apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb + +RUN apt-get update -qq + +RUN apt-get -y -qq install git +RUN apt-get update --fix-missing && apt-get -y --fix-broken install python-pycurl python-apt +RUN apt-get -y -qq --fix-broken install software-properties-common + +RUN apt-get -y -qq install xvfb unzip maim clang cmake +RUN apt-get -y -qq install git-core libboost-all-dev +RUN apt-get -y -qq install libopenexr-dev libtbb-dev +RUN apt-get -y -qq install libglm-dev libpng-dev +RUN apt-get -y -qq install libeigen3-dev dbus-x11 +RUN apt-get -y -qq install libxcursor-dev libxinerama-dev +RUN apt-get -y -qq install libxrandr-dev libglu1-mesa-dev +RUN apt-get -y -qq install libgles2-mesa-dev libgl1-mesa-dev +RUN apt-get -y -qq install libxi-dev + +RUN git clone --recursive https://github.com/curv3d/curv; cd curv; make; make install # install node14, see comment at the top of node14source_setup.sh ADD src/docker/common/node14source_setup.sh /nodesource_setup.sh @@ -46,7 +56,7 @@ RUN echo "cadhub-concat-split" > /var/task/cadhub-concat-split # using built javascript from dist # run `yarn rw build` before bulding this image -COPY dist/docker/openscad/* /var/task/js/ +COPY dist/docker/curv/* /var/task/js/ COPY dist/docker/common/* /var/task/common/ COPY src/docker/common/entrypoint.sh /entrypoint.sh RUN ["chmod", "+x", "/entrypoint.sh"] diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts index 70c7b08..767d529 100644 --- a/app/api/src/docker/curv/runCurv.ts +++ b/app/api/src/docker/curv/runCurv.ts @@ -1,21 +1,5 @@ import { writeFiles, runCommand } from '../common/utils' import { nanoid } from 'nanoid' -const { readFile } = require('fs/promises') -const fs = require('fs'); -const { spawn } = require('child_process'); - -function* getXDisplayNumber() { - const startValue = 99; - let i = startValue; - while(true) { - i -= 1; - - // Never hit zero since 0 is usually used by desktop users. - if (i <= 0) i = startValue; - yield ':' + i; - } -} - export const runCurv = async ({ file, @@ -54,61 +38,23 @@ export const runCurv = async ({ const fullPath = `/tmp/${tempFile}/output.gz` const imPath = `/tmp/${tempFile}/output.png` const customizerPath = `/tmp/${tempFile}/customizer.param` - const summaryPath = `/tmp/${tempFile}/summary.json` // contains camera info - - const code = file; - const DISPLAY = getXDisplayNumber().next().value; - - const xvfbProcess = spawn( - 'Xvfb', - [DISPLAY, '-ac', '-nocursor', '-screen', '0', '480x500x24'], - ); - - const curvProcess = spawn( - 'curv', - ['-' ], - { env: Object.assign({}, process.env, { DISPLAY, PATH: '/usr/local/bin' }) } - ); - - curvProcess.stdin.write(code); - curvProcess.stdin.end(); - - let statusSet = false; - let contentTypeSet = false; - - curvProcess.stderr.on('data', (buf) => { - const data = buf.toString('utf8'); - if (data.indexOf('shape') >= 0) { - setTimeout(() => { - const screenshotProcess = spawn('maim', ['--hidecursor', imPath], { env: { DISPLAY } }); - screenshotProcess.on('close', () => { - curvProcess.kill(); - xvfbProcess.kill(); - }); - }, 1000); - } - - if (data.indexOf('ERROR') < 0) { return; } - curvProcess.kill(); - xvfbProcess.kill(); - }); + const command = [ + 'xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" curv', + `-o ${imPath}`, + `-O xsize=${x}`, + `-O ysize=${y}`, + `-O bg=webRGB[26,26,29]`, // #1A1A1D + `/tmp/${tempFile}/main.curv`, + ].join(' ') + console.log('command', command) try { - const files: string[] = await Promise.all( - [customizerPath, summaryPath].map((path) => - readFile(path, { encoding: 'ascii' }) - ) - ) - const [params, cameraInfo] = files.map((fileStr: string) => - JSON.parse(fileStr) - ) + const consoleMessage = await runCommand(command, 15000) await writeFiles( [ { file: JSON.stringify({ - cameraInfo: viewAll ? cameraInfo.camera : undefined, - customizerParams: params.parameters, consoleMessage, type: 'png', }), @@ -143,7 +89,6 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { ) const fullPath = `/tmp/${tempFile}/output.gz` const stlPath = `/tmp/${tempFile}/output.stl` - const customizerPath = `/tmp/${tempFile}/customizer.param` const command = [ 'curv', '-o', stlPath, @@ -155,14 +100,10 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { try { // lambda will time out before this, we might need to look at background jobs if we do git integration stl generation const consoleMessage = await runCommand(command, 60000) - const params = JSON.parse( - await readFile(customizerPath, { encoding: 'ascii' }) - ).parameters await writeFiles( [ { file: JSON.stringify({ - customizerParams: params, consoleMessage, type: 'stl', }), @@ -175,7 +116,7 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { `cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, 15000 ) - return { consoleMessage, fullPath, customizerPath } + return { consoleMessage, fullPath } } catch (error) { return { error, fullPath } } diff --git a/app/api/src/docker/docker-compose.yml b/app/api/src/docker/docker-compose.yml index 892d57a..b6be985 100644 --- a/app/api/src/docker/docker-compose.yml +++ b/app/api/src/docker/docker-compose.yml @@ -53,11 +53,20 @@ services: command: js/curv.preview # Adding volumes so that the containers can be restarted for js only changes in local dev volumes: - - ../../dist/docker/openscad:/var/task/js/ + - ../../dist/docker/curv:/var/task/js/ - ../../dist/docker/common:/var/task/common/ ports: - - "5052:8080" - environment: - AWS_SECRET_ACCESS_KEY: "${DEV_AWS_SECRET_ACCESS_KEY}" - AWS_ACCESS_KEY_ID: "${DEV_AWS_ACCESS_KEY_ID}" - BUCKET: "${DEV_BUCKET}" + - "5070:8080" + curv-stl: + build: + context: ../../ + dockerfile: ./src/docker/curv/Dockerfile + image: curv + command: js/curv.stl + # Adding volumes so that the containers can be restarted for js only changes in local dev + volumes: + - ../../dist/docker/curv:/var/task/js/ + - ../../dist/docker/common:/var/task/common/ + ports: + - "5071:8080" + diff --git a/app/web/config/webpack.config.js b/app/web/config/webpack.config.js index 103151b..f9b7db7 100644 --- a/app/web/config/webpack.config.js +++ b/app/web/config/webpack.config.js @@ -6,7 +6,7 @@ module.exports = (config, { env }) => { } }) config.module.rules.push({ - test: /\.(md|jscad\.js|py|scad)$/i, + test: /\.(md|jscad\.js|py|scad|curv)$/i, use: 'raw-loader', }); return config diff --git a/app/web/src/components/IdeEditor/IdeEditor.tsx b/app/web/src/components/IdeEditor/IdeEditor.tsx index 20a2bee..b0dd204 100644 --- a/app/web/src/components/IdeEditor/IdeEditor.tsx +++ b/app/web/src/components/IdeEditor/IdeEditor.tsx @@ -18,7 +18,7 @@ const IdeEditor = ({ Loading }) => { cadquery: 'python', openscad: 'cpp', jscad: 'javascript', - curv: 'javascript', + curv: 'python', INIT: '', } const monaco = useMonaco() diff --git a/app/web/src/helpers/cadPackages/curv/curvController.ts b/app/web/src/helpers/cadPackages/curv/curvController.ts index 8323a8b..e972b68 100644 --- a/app/web/src/helpers/cadPackages/curv/curvController.ts +++ b/app/web/src/helpers/cadPackages/curv/curvController.ts @@ -7,8 +7,6 @@ import { RenderArgs, splitGziped, } from '../common' -import { CurvToCadhubParams } from './openScadParams' -import type { XYZ, Camera } from 'src/helpers/hooks/useIdeState' export const render = async ({ code, settings }: RenderArgs) => { const pixelRatio = window.devicePixelRatio || 1 @@ -61,21 +59,8 @@ export const render = async ({ code, settings }: RenderArgs) => { } const blob = await response.blob() const text = await new Response(blob).text() - const { consoleMessage, customizerParams, type, cameraInfo } = + const { consoleMessage, type } = splitGziped(text) - const vecArray2Obj = (arr: number[]): XYZ => ({ - x: arr[0], - y: arr[1], - z: arr[2], - }) - const camera: Camera = cameraInfo - ? { - dist: cameraInfo?.distance, - position: vecArray2Obj(cameraInfo?.translation), - rotation: vecArray2Obj(cameraInfo?.rotation), - isScadUpdate: true, - } - : undefined return createHealthyResponse({ type: type !== 'stl' ? 'png' : 'geometry', data: @@ -83,9 +68,7 @@ export const render = async ({ code, settings }: RenderArgs) => { ? blob : await stlToGeometry(window.URL.createObjectURL(blob)), consoleMessage, - camera, date: new Date(), - customizerParams: curvToCadhubParams(customizerParams || []), }) } catch (e) { return createUnhealthyResponse(new Date()) @@ -115,7 +98,7 @@ export const stl = async ({ code /*settings*/ }: RenderArgs) => { } const blob = await response.blob() const text = await new Response(blob).text() - const { consoleMessage, customizerParams, type } = splitGziped(text) + const { consoleMessage, type } = splitGziped(text) return createHealthyResponse({ type: type !== 'stl' ? 'png' : 'geometry', data: @@ -124,7 +107,6 @@ export const stl = async ({ code /*settings*/ }: RenderArgs) => { : await stlToGeometry(window.URL.createObjectURL(blob)), consoleMessage, date: new Date(), - customizerParams: openScadToCadhubParams(customizerParams || []), }) } catch (e) { return createUnhealthyResponse(new Date()) -- 2.39.5 From 0face9b9c1a374b60070a1b1b304d5cb32260edb Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 21 Nov 2021 18:12:56 +1100 Subject: [PATCH 04/11] Prepare changes for review and preview build --- app/api/db/schema.prisma | 4 ++-- .../src/components/CaptureButton/CaptureButton.tsx | 2 ++ app/web/src/components/EditorMenu/helpers.ts | 2 +- app/web/src/components/IdeViewer/IdeViewer.tsx | 2 ++ app/web/src/components/IdeViewer/PureIdeViewer.tsx | 4 ++++ .../src/components/NavPlusButton/NavPlusButton.tsx | 14 +++++++------- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/api/db/schema.prisma b/app/api/db/schema.prisma index 163f4da..9ec2844 100644 --- a/app/api/db/schema.prisma +++ b/app/api/db/schema.prisma @@ -37,8 +37,8 @@ model User { enum CadPackage { openscad cadquery - jscad // TODO #422, add jscad to db schema when were ready to enable saving of jscad projects - curv + jscad + // curv // TODO uncomment when ready for users to save curv projects } model Project { diff --git a/app/web/src/components/CaptureButton/CaptureButton.tsx b/app/web/src/components/CaptureButton/CaptureButton.tsx index 598a0d3..aa2736f 100644 --- a/app/web/src/components/CaptureButton/CaptureButton.tsx +++ b/app/web/src/components/CaptureButton/CaptureButton.tsx @@ -25,6 +25,7 @@ const CaptureButtonViewer = ({ const threeInstance = React.useRef(null) const [dataType, dataTypeSetter] = useState(state?.objectData?.type) const [artifact, artifactSetter] = useState(state?.objectData?.data) + const [ideType] = useState(state?.ideType) const [isLoading, isLoadingSetter] = useState(false) const [camera, cameraSetter] = useState(null) const getThreeInstance = (_threeInstance) => { @@ -70,6 +71,7 @@ const CaptureButtonViewer = ({ isLoading={isLoading} camera={camera} isMinimal + ideType={ideType} /> ) } diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index 466a58a..039c5ee 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -69,7 +69,7 @@ export const makeStlDownloadHandler = } else { thunkDispatch((dispatch, getState) => { const state = getState() - const specialCadProcess = ideType === 'openscad' && 'stl' + const specialCadProcess = (ideType === 'openscad' || ideType === 'curv') && 'stl' dispatch({ type: 'setLoading' }) requestRender({ state, diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 51ea4a4..287f126 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -10,6 +10,7 @@ const IdeViewer = ({ const { state, thunkDispatch } = useIdeContext() const dataType = state.objectData?.type const artifact = state.objectData?.data + const ideType = state.ideType const onInit = (threeInstance) => { thunkDispatch({ type: 'setThreeInstance', payload: threeInstance }) @@ -44,6 +45,7 @@ const IdeViewer = ({ onCameraChange={onCameraChange} isLoading={state.isLoading} camera={state?.camera} + ideType={ideType} /> ) } diff --git a/app/web/src/components/IdeViewer/PureIdeViewer.tsx b/app/web/src/components/IdeViewer/PureIdeViewer.tsx index 39b79d3..3f03d85 100644 --- a/app/web/src/components/IdeViewer/PureIdeViewer.tsx +++ b/app/web/src/components/IdeViewer/PureIdeViewer.tsx @@ -169,6 +169,7 @@ export function PureIdeViewer({ isMinimal = false, scadRatio = 1, camera, + ideType }: { dataType: 'INIT' | ArtifactTypes artifact: any @@ -178,6 +179,7 @@ export function PureIdeViewer({ isMinimal?: boolean scadRatio?: number camera?: State['camera'] + ideType?: State['ideType'] }) { const [isDragging, setIsDragging] = useState(false) const [image, setImage] = useState() @@ -216,6 +218,8 @@ export function PureIdeViewer({ )}
{ -- 2.39.5 From fe059384d39738e80e43f60bc349c8d1efa6be7a Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Mon, 22 Nov 2021 20:05:10 +1100 Subject: [PATCH 05/11] Run curv inside of /tmp When exporting an stl it writes temporary files which is not allowed when deployed to aws unless it's in temp. --- app/api/src/docker/cadquery/cadquery.ts | 3 ++- app/api/src/docker/cadquery/runCQ.ts | 2 +- app/api/src/docker/common/utils.ts | 2 ++ app/api/src/docker/curv/curv.ts | 6 ++++-- app/api/src/docker/curv/runCurv.ts | 12 ++++++----- app/api/src/docker/openscad/openscad.ts | 6 ++++-- app/api/src/docker/openscad/runScad.ts | 5 +++-- app/api/src/docker/serverless.yml | 17 +++++++++++++-- .../src/components/IdeViewer/IdeViewer.tsx | 2 +- .../components/IdeViewer/PureIdeViewer.tsx | 4 ++-- .../cadPackages/curv/curvController.ts | 21 ------------------- 11 files changed, 41 insertions(+), 39 deletions(-) diff --git a/app/api/src/docker/cadquery/cadquery.ts b/app/api/src/docker/cadquery/cadquery.ts index 9c41ba5..6712876 100644 --- a/app/api/src/docker/cadquery/cadquery.ts +++ b/app/api/src/docker/cadquery/cadquery.ts @@ -9,12 +9,13 @@ const stl = async (req, _context, callback) => { console.log('eventBody', eventBody) const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath } = await runCQ({ file, settings }) + const { error, consoleMessage, fullPath, tempFile } = await runCQ({ file, settings }) await storeAssetAndReturnUrl({ error, callback, fullPath, consoleMessage, + tempFile }) } diff --git a/app/api/src/docker/cadquery/runCQ.ts b/app/api/src/docker/cadquery/runCQ.ts index 2f73e68..6a1db1d 100644 --- a/app/api/src/docker/cadquery/runCQ.ts +++ b/app/api/src/docker/cadquery/runCQ.ts @@ -53,7 +53,7 @@ export const runCQ = async ({ 15000, true ) - return { consoleMessage, fullPath } + return { consoleMessage, fullPath, tempFile } } catch (error) { return { error: consoleMessage || error, fullPath } } diff --git a/app/api/src/docker/common/utils.ts b/app/api/src/docker/common/utils.ts index 16cf418..33bfda6 100644 --- a/app/api/src/docker/common/utils.ts +++ b/app/api/src/docker/common/utils.ts @@ -104,11 +104,13 @@ export async function storeAssetAndReturnUrl({ callback, fullPath, consoleMessage, + tempFile }: { error: string callback: Function fullPath: string consoleMessage: string + tempFile: string }) { if (error) { const response = { diff --git a/app/api/src/docker/curv/curv.ts b/app/api/src/docker/curv/curv.ts index a81eb0b..cdcf3da 100644 --- a/app/api/src/docker/curv/curv.ts +++ b/app/api/src/docker/curv/curv.ts @@ -9,7 +9,7 @@ const preview = async (req, _context, callback) => { console.log('eventBody', eventBody) const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath } = await runCurv({ + const { error, consoleMessage, fullPath, tempFile } = await runCurv({ file, settings, }) @@ -18,6 +18,7 @@ const preview = async (req, _context, callback) => { callback, fullPath, consoleMessage, + tempFile, }) } @@ -28,7 +29,7 @@ const stl = async (req, _context, callback) => { console.log(eventBody, 'eventBody') const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath } = await stlExport({ + const { error, consoleMessage, fullPath, tempFile } = await stlExport({ file, settings, }) @@ -37,6 +38,7 @@ const stl = async (req, _context, callback) => { callback, fullPath, consoleMessage, + tempFile, }) } diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts index 767d529..9d349a5 100644 --- a/app/api/src/docker/curv/runCurv.ts +++ b/app/api/src/docker/curv/runCurv.ts @@ -18,6 +18,7 @@ export const runCurv = async ({ consoleMessage?: string fullPath?: string customizerPath?: string + tempFile?: string }> => { const tempFile = await writeFiles( [ @@ -67,7 +68,7 @@ export const runCurv = async ({ `cat ${imPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, 15000 ) - return { consoleMessage, fullPath, customizerPath } + return { consoleMessage, fullPath, customizerPath, tempFile } } catch (dirtyError) { return { error: dirtyError } } @@ -90,11 +91,12 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { const fullPath = `/tmp/${tempFile}/output.gz` const stlPath = `/tmp/${tempFile}/output.stl` const command = [ - 'curv', + '(cd /tmp && curv', '-o', stlPath, '-O jit', - '-O vsize=0.4', + '-O vsize=0.6', `/tmp/${tempFile}/main.curv`, + ')', ].join(' ') try { @@ -113,10 +115,10 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { tempFile ) await runCommand( - `cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, + `cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath} && rm ${stlPath}`, 15000 ) - return { consoleMessage, fullPath } + return { consoleMessage, fullPath, tempFile } } catch (error) { return { error, fullPath } } diff --git a/app/api/src/docker/openscad/openscad.ts b/app/api/src/docker/openscad/openscad.ts index 752c8c5..823f1a5 100644 --- a/app/api/src/docker/openscad/openscad.ts +++ b/app/api/src/docker/openscad/openscad.ts @@ -9,7 +9,7 @@ const preview = async (req, _context, callback) => { console.log('eventBody', eventBody) const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath } = await runScad({ + const { error, consoleMessage, fullPath, tempFile } = await runScad({ file, settings, }) @@ -18,6 +18,7 @@ const preview = async (req, _context, callback) => { callback, fullPath, consoleMessage, + tempFile, }) } @@ -28,7 +29,7 @@ const stl = async (req, _context, callback) => { console.log(eventBody, 'eventBody') const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath } = await stlExport({ + const { error, consoleMessage, fullPath, tempFile } = await stlExport({ file, settings, }) @@ -37,6 +38,7 @@ const stl = async (req, _context, callback) => { callback, fullPath, consoleMessage, + tempFile, }) } diff --git a/app/api/src/docker/openscad/runScad.ts b/app/api/src/docker/openscad/runScad.ts index c176931..de34352 100644 --- a/app/api/src/docker/openscad/runScad.ts +++ b/app/api/src/docker/openscad/runScad.ts @@ -25,6 +25,7 @@ export const runScad = async ({ consoleMessage?: string fullPath?: string customizerPath?: string + tempFile?: string }> => { const tempFile = await writeFiles( [ @@ -88,7 +89,7 @@ export const runScad = async ({ `cat ${imPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, 15000 ) - return { consoleMessage, fullPath, customizerPath } + return { consoleMessage, fullPath, customizerPath, tempFile } } catch (dirtyError) { return { error: cleanOpenScadError(dirtyError) } } @@ -143,7 +144,7 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { `cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`, 15000 ) - return { consoleMessage, fullPath, customizerPath } + return { consoleMessage, fullPath, customizerPath, tempFile } } catch (error) { return { error, fullPath } } diff --git a/app/api/src/docker/serverless.yml b/app/api/src/docker/serverless.yml index 78e22f3..af39194 100644 --- a/app/api/src/docker/serverless.yml +++ b/app/api/src/docker/serverless.yml @@ -87,6 +87,7 @@ functions: timeout: 30 environment: BUCKET: cad-preview-bucket-prod-001 + cadquerystl: image: name: cadqueryimage @@ -102,6 +103,7 @@ functions: timeout: 30 environment: BUCKET: cad-preview-bucket-prod-001 + curvpreview: image: name: curvimage @@ -115,8 +117,19 @@ functions: method: post cors: true timeout: 25 - environment: - BUCKET: cad-preview-bucket-prod-001 + curvstl: + image: + name: curvimage + command: + - js/curv.stl + entryPoint: + - '/entrypoint.sh' + events: + - http: + path: curv/stl + method: post + cors: true + timeout: 30 # The following are a few example events you can configure # NOTE: Please make sure to change your handler code to work with those events # Check the event documentation for details diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 287f126..3a0b63b 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -25,7 +25,7 @@ const IdeViewer = ({ }) thunkDispatch((dispatch, getState) => { const state = getState() - if (['png', 'INIT'].includes(state?.objectData?.type)) { + if (['png', 'INIT'].includes(state?.objectData?.type) && (ideType === 'openscad' || state?.objectData?.type === 'INIT' || !state?.objectData?.type)) { dispatch({ type: 'setLoading' }) requestRender({ state, diff --git a/app/web/src/components/IdeViewer/PureIdeViewer.tsx b/app/web/src/components/IdeViewer/PureIdeViewer.tsx index 3f03d85..56ec2a7 100644 --- a/app/web/src/components/IdeViewer/PureIdeViewer.tsx +++ b/app/web/src/components/IdeViewer/PureIdeViewer.tsx @@ -218,7 +218,7 @@ export function PureIdeViewer({ )}
setIsDragging(true)} onInit={onInit} - onCameraChange={onCameraChange} + onCameraChange={() => {onCameraChange(); setIsDragging(false)}} controlsRef={controlsRef} camera={camera} /> diff --git a/app/web/src/helpers/cadPackages/curv/curvController.ts b/app/web/src/helpers/cadPackages/curv/curvController.ts index e972b68..af452ce 100644 --- a/app/web/src/helpers/cadPackages/curv/curvController.ts +++ b/app/web/src/helpers/cadPackages/curv/curvController.ts @@ -14,33 +14,12 @@ export const render = async ({ code, settings }: RenderArgs) => { x: Math.round(settings.viewerSize?.width * pixelRatio), y: Math.round(settings.viewerSize?.height * pixelRatio), } - const round1dec = (number) => Math.round((number + Number.EPSILON) * 10) / 10 const body = JSON.stringify({ settings: { size, - viewAll: settings.viewAll, - parameters: settings.parameters, - camera: { - // rounding to give our caching a chance to sometimes work - ...settings.camera, - dist: round1dec(settings.camera.dist), - position: { - x: round1dec(settings.camera.position.x), - y: round1dec(settings.camera.position.y), - z: round1dec(settings.camera.position.z), - }, - rotation: { - x: round1dec(settings.camera.rotation.x), - y: round1dec(settings.camera.rotation.y), - z: round1dec(settings.camera.rotation.z), - }, - }, }, file: code, }) - if (!settings.camera.position) { - return - } try { const response = await fetch(lambdaBaseURL + '/curv/preview', { method: 'POST', -- 2.39.5 From ca22ec28fc591e332932cadb8b253eb105a7391c Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Mon, 29 Nov 2021 14:07:02 +1100 Subject: [PATCH 06/11] Lock in specific curv commit for reproducible builds see: https://discord.com/channels/412182089279209474/886321278821216277/912507472441401385 --- app/api/src/docker/curv/Dockerfile | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/app/api/src/docker/curv/Dockerfile b/app/api/src/docker/curv/Dockerfile index 1dae1b0..3c6a8df 100644 --- a/app/api/src/docker/curv/Dockerfile +++ b/app/api/src/docker/curv/Dockerfile @@ -8,21 +8,23 @@ RUN apt-get update --fix-missing && apt-get -y -qq install software-properties-c RUN apt-get update -qq -RUN apt-get -y -qq install git -RUN apt-get update --fix-missing && apt-get -y --fix-broken install python-pycurl python-apt -RUN apt-get -y -qq --fix-broken install software-properties-common +RUN apt-get -y -qq install git \ + software-properties-common \ + xvfb unzip maim clang cmake \ + git-core libboost-all-dev \ + libopenexr-dev libtbb-dev \ + libglm-dev libpng-dev \ + libeigen3-dev dbus-x11 \ + libxcursor-dev libxinerama-dev \ + libxrandr-dev libglu1-mesa-dev \ + libgles2-mesa-dev libgl1-mesa-dev \ + libxi-dev -RUN apt-get -y -qq install xvfb unzip maim clang cmake -RUN apt-get -y -qq install git-core libboost-all-dev -RUN apt-get -y -qq install libopenexr-dev libtbb-dev -RUN apt-get -y -qq install libglm-dev libpng-dev -RUN apt-get -y -qq install libeigen3-dev dbus-x11 -RUN apt-get -y -qq install libxcursor-dev libxinerama-dev -RUN apt-get -y -qq install libxrandr-dev libglu1-mesa-dev -RUN apt-get -y -qq install libgles2-mesa-dev libgl1-mesa-dev -RUN apt-get -y -qq install libxi-dev - -RUN git clone --recursive https://github.com/curv3d/curv; cd curv; make; make install +# Use commit to make sure build is reproduceable +RUN git clone --recursive https://github.com/curv3d/curv && \ + cd curv && \ + git checkout b849eb57fba121f9f218dc065dc1f5ebc619836d && \ + make && make install # install node14, see comment at the top of node14source_setup.sh ADD src/docker/common/node14source_setup.sh /nodesource_setup.sh @@ -62,4 +64,4 @@ COPY src/docker/common/entrypoint.sh /entrypoint.sh RUN ["chmod", "+x", "/entrypoint.sh"] ENTRYPOINT ["sh", "/entrypoint.sh"] -CMD [ "js/curv.render" ] +CMD [ "js/curv.preview" ] -- 2.39.5 From e8ae6193e4e7040587737368c81a7ac462d05ec2 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 30 Nov 2021 08:01:24 +1100 Subject: [PATCH 07/11] Add curv to backend schema --- .../migrations/20211129205924_curv/migration.sql | 2 ++ app/api/db/schema.prisma | 2 +- app/api/src/graphql/projects.sdl.ts | 1 + app/web/src/components/Hero/Hero.tsx | 4 ++++ .../components/IdeProjectCell/IdeProjectCell.tsx | 2 +- .../src/components/NavPlusButton/NavPlusButton.tsx | 14 +++++++------- 6 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 app/api/db/migrations/20211129205924_curv/migration.sql diff --git a/app/api/db/migrations/20211129205924_curv/migration.sql b/app/api/db/migrations/20211129205924_curv/migration.sql new file mode 100644 index 0000000..405c759 --- /dev/null +++ b/app/api/db/migrations/20211129205924_curv/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "CadPackage" ADD VALUE 'curv'; diff --git a/app/api/db/schema.prisma b/app/api/db/schema.prisma index 9ec2844..e62813d 100644 --- a/app/api/db/schema.prisma +++ b/app/api/db/schema.prisma @@ -38,7 +38,7 @@ enum CadPackage { openscad cadquery jscad - // curv // TODO uncomment when ready for users to save curv projects + curv } model Project { diff --git a/app/api/src/graphql/projects.sdl.ts b/app/api/src/graphql/projects.sdl.ts index 8669a9d..2ead489 100644 --- a/app/api/src/graphql/projects.sdl.ts +++ b/app/api/src/graphql/projects.sdl.ts @@ -19,6 +19,7 @@ export const schema = gql` childForks: [Project]! } +# should match enum in api/db/schema.prisma enum CadPackage { openscad cadquery diff --git a/app/web/src/components/Hero/Hero.tsx b/app/web/src/components/Hero/Hero.tsx index a2b98d8..a85fa6d 100644 --- a/app/web/src/components/Hero/Hero.tsx +++ b/app/web/src/components/Hero/Hero.tsx @@ -348,6 +348,10 @@ function ChooseYourCharacter() { cadPackage: 'jscad', desc: 'A JavaScript Code-CAD library that will feel familiar to web developers, based on the same tech as OpenSCAD.', }, + // { // TODO add curv to this list. + // cadPackage: 'curv', + // desc: 'A language for creating 3D art', + // } ].map( ({ cadPackage, diff --git a/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx b/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx index 0473d30..a5c73b3 100644 --- a/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx +++ b/app/web/src/components/IdeProjectCell/IdeProjectCell.tsx @@ -35,7 +35,7 @@ export interface Project { code: string mainImage: string createdAt: string - cadPackage: 'openscad' | 'cadquery' | 'curv' + cadPackage: 'openscad' | 'cadquery' | 'jscad' | 'curv' user: { id: string userName: string diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index 326fe02..9a95c11 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -95,13 +95,13 @@ const menuOptions: { dotClasses: 'bg-yellow-300', ideType: 'jscad', }, - // { // TODO uncomment when ready for users to save curv projects - // name: 'Curv', - // sub: 'beta', - // bgClasses: 'bg-ch-blue-700', - // dotClasses: 'bg-blue-800', - // ideType: 'curv', - // }, + { + name: 'Curv', + sub: 'alpha ', + bgClasses: 'bg-ch-blue-700', + dotClasses: 'bg-blue-800', + ideType: 'curv', + }, ] const NavPlusButton: React.FC = () => { -- 2.39.5 From d4999d8f6384fe16e3b3e26e8ab3f1c6fa9b79ea Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 30 Nov 2021 11:57:29 +1100 Subject: [PATCH 08/11] Frontend changes to accommodate curv deploy --- app/web/src/components/CadPackage/CadPackage.tsx | 6 +++--- app/web/src/components/CaptureButton/CaptureButton.tsx | 2 +- app/web/src/components/Hero/Hero.tsx | 8 ++++---- app/web/src/components/NavPlusButton/NavPlusButton.tsx | 4 ++-- app/web/src/helpers/cadPackages/curv/userGuide.md | 8 +++++++- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/web/src/components/CadPackage/CadPackage.tsx b/app/web/src/components/CadPackage/CadPackage.tsx index fef563b..1de9b53 100644 --- a/app/web/src/components/CadPackage/CadPackage.tsx +++ b/app/web/src/components/CadPackage/CadPackage.tsx @@ -25,8 +25,8 @@ export const cadPackageConfigs: { [key in CadPackageType]: CadPackageConfig } = }, curv: { label: 'Curv', - buttonClasses: 'bg-ch-purple-500', - dotClasses: 'bg-yellow-300', + buttonClasses: 'bg-blue-600', + dotClasses: 'bg-green-500', }, INIT: { label: '', @@ -54,7 +54,7 @@ const CadPackage = ({ diff --git a/app/web/src/components/CaptureButton/CaptureButton.tsx b/app/web/src/components/CaptureButton/CaptureButton.tsx index aa2736f..b9a486d 100644 --- a/app/web/src/components/CaptureButton/CaptureButton.tsx +++ b/app/web/src/components/CaptureButton/CaptureButton.tsx @@ -34,7 +34,7 @@ const CaptureButtonViewer = ({ } const onCameraChange = (camera, isFirstCameraChange) => { const renderPromise = - state.ideType === 'openscad' && + (state.ideType === 'openscad' || state.ideType === 'curv') && requestRenderStateless({ state, camera, diff --git a/app/web/src/components/Hero/Hero.tsx b/app/web/src/components/Hero/Hero.tsx index a85fa6d..b941def 100644 --- a/app/web/src/components/Hero/Hero.tsx +++ b/app/web/src/components/Hero/Hero.tsx @@ -348,10 +348,10 @@ function ChooseYourCharacter() { cadPackage: 'jscad', desc: 'A JavaScript Code-CAD library that will feel familiar to web developers, based on the same tech as OpenSCAD.', }, - // { // TODO add curv to this list. - // cadPackage: 'curv', - // desc: 'A language for creating 3D art', - // } + { + cadPackage: 'curv', + desc: "Curv is a programming language for creating art using mathematics. It's a 2D and 3D geometric modelling tool.", + } ].map( ({ cadPackage, diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index 9a95c11..cf04324 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -98,8 +98,8 @@ const menuOptions: { { name: 'Curv', sub: 'alpha ', - bgClasses: 'bg-ch-blue-700', - dotClasses: 'bg-blue-800', + bgClasses: 'bg-blue-600', + dotClasses: 'bg-green-500', ideType: 'curv', }, ] diff --git a/app/web/src/helpers/cadPackages/curv/userGuide.md b/app/web/src/helpers/cadPackages/curv/userGuide.md index 4b3a835..e62fd43 100644 --- a/app/web/src/helpers/cadPackages/curv/userGuide.md +++ b/app/web/src/helpers/cadPackages/curv/userGuide.md @@ -6,4 +6,10 @@ Maintained by: [Doug Moen and contributors](https://github.com/curv/curv/graphs/ Documentation: [curv3d.org](https://curv3d.org) --- -Curv is a programming language for creating art using mathematics. It’s a 2D and 3D geometric modelling tool that supports full colour, animation and 3D printing. +Curv is a programming language for creating art using mathematics. It's a 2D and 3D geometric modelling tool that supports full colour, animation and 3D printing. + +### [Examples](https://github.com/curv3d/curv/tree/master/examples) + +- [Flog spiral](https://619b5e6c6689420008eedfe5--cadhubxyz.netlify.app/draft/curv#fetch_text_v1=https%3A%2F%2Fraw.githubusercontent.com%2Fcurv3d%2Fcurv%2Fmaster%2Fexamples%2Flog_spiral.curv) +- [Shreks donut](https://619b5e6c6689420008eedfe5--cadhubxyz.netlify.app/draft/curv#fetch_text_v1=https%3A%2F%2Fraw.githubusercontent.com%2Fcurv3d%2Fcurv%2Fmaster%2Fexamples%2Fshreks_donut.curv) +- [Wood grain](https://619b5e6c6689420008eedfe5--cadhubxyz.netlify.app/draft/curv#fetch_text_v1=https%3A%2F%2Fraw.githubusercontent.com%2Fcurv3d%2Fcurv%2Fmaster%2Fexamples%2Ffinial.curv) -- 2.39.5 From 9797405834f54b2cf64d6f883cfbbc3d5424fa10 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 30 Nov 2021 11:58:14 +1100 Subject: [PATCH 09/11] Use vcount instead of vsize, as it's independant of geometry size, This is good for CadHub usecase where we don't know anything about the user's project --- app/api/src/docker/curv/runCurv.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts index 9d349a5..fcabeef 100644 --- a/app/api/src/docker/curv/runCurv.ts +++ b/app/api/src/docker/curv/runCurv.ts @@ -4,14 +4,8 @@ import { nanoid } from 'nanoid' export const runCurv = async ({ file, settings: { - viewAll = false, size: { x = 500, y = 500 } = {}, parameters, - camera: { - position = { x: 40, y: 40, z: 40 }, - rotation = { x: 55, y: 0, z: 25 }, - dist = 200, - } = {}, } = {}, // TODO add view settings } = {}): Promise<{ error?: string @@ -33,9 +27,6 @@ export const runCurv = async ({ ], 'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug: ) - const { x: rx, y: ry, z: rz } = rotation - const { x: px, y: py, z: pz } = position - const cameraArg = `--camera=${px},${py},${pz},${rx},${ry},${rz},${dist}` const fullPath = `/tmp/${tempFile}/output.gz` const imPath = `/tmp/${tempFile}/output.png` const customizerPath = `/tmp/${tempFile}/customizer.param` @@ -94,7 +85,7 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { '(cd /tmp && curv', '-o', stlPath, '-O jit', - '-O vsize=0.6', + '-O vcount=350000', `/tmp/${tempFile}/main.curv`, ')', ].join(' ') -- 2.39.5 From 172e19165f281e14a9321b9f6378bcfde7c5bcf5 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 30 Nov 2021 15:15:54 +1100 Subject: [PATCH 10/11] Final tweaks for deploy virtual screen size does matter,and curv is a little more memory hungry than the other functions --- app/api/src/docker/common/utils.ts | 1 + app/api/src/docker/curv/runCurv.ts | 2 +- app/api/src/docker/serverless.yml | 1 + .../components/IdeViewer/PureIdeViewer.tsx | 2 +- app/web/src/helpers/cadPackages/common.ts | 2 +- .../helpers/cadPackages/curv/curvParams.ts | 90 ------------------- .../helpers/cadPackages/curv/initialCode.curv | 16 ++-- 7 files changed, 15 insertions(+), 99 deletions(-) delete mode 100644 app/web/src/helpers/cadPackages/curv/curvParams.ts diff --git a/app/api/src/docker/common/utils.ts b/app/api/src/docker/common/utils.ts index 33bfda6..373091d 100644 --- a/app/api/src/docker/common/utils.ts +++ b/app/api/src/docker/common/utils.ts @@ -126,6 +126,7 @@ export async function storeAssetAndReturnUrl({ try { buffer = await readFile(fullPath, { encoding: 'base64' }) + await runCommand(`rm -R /tmp/${tempFile}`) } catch (e) { console.log('read file error', e) const response = { diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts index fcabeef..59369d7 100644 --- a/app/api/src/docker/curv/runCurv.ts +++ b/app/api/src/docker/curv/runCurv.ts @@ -32,7 +32,7 @@ export const runCurv = async ({ const customizerPath = `/tmp/${tempFile}/customizer.param` const command = [ - 'xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" curv', + 'xvfb-run --auto-servernum --server-args "-screen 0 3840x2160x24" curv', `-o ${imPath}`, `-O xsize=${x}`, `-O ysize=${y}`, diff --git a/app/api/src/docker/serverless.yml b/app/api/src/docker/serverless.yml index af39194..f0a8ece 100644 --- a/app/api/src/docker/serverless.yml +++ b/app/api/src/docker/serverless.yml @@ -117,6 +117,7 @@ functions: method: post cors: true timeout: 25 + memorySize: 3008 curvstl: image: name: curvimage diff --git a/app/web/src/components/IdeViewer/PureIdeViewer.tsx b/app/web/src/components/IdeViewer/PureIdeViewer.tsx index 56ec2a7..592d8c5 100644 --- a/app/web/src/components/IdeViewer/PureIdeViewer.tsx +++ b/app/web/src/components/IdeViewer/PureIdeViewer.tsx @@ -230,7 +230,7 @@ export function PureIdeViewer({ setIsDragging(true)} onInit={onInit} - onCameraChange={() => {onCameraChange(); setIsDragging(false)}} + onCameraChange={(...args) => {onCameraChange(...args); setIsDragging(false)}} controlsRef={controlsRef} camera={camera} /> diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index bacd017..6ec40cf 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -5,7 +5,7 @@ import type { Camera } from 'src/helpers/hooks/useIdeState' export const lambdaBaseURL = process.env.CAD_LAMBDA_BASE_URL || - 'https://oxt2p7ddgj.execute-api.us-east-1.amazonaws.com/prod' + 'https://2inlbple1b.execute-api.us-east-1.amazonaws.com/prod2' export const stlToGeometry = (url) => new Promise((resolve, reject) => { diff --git a/app/web/src/helpers/cadPackages/curv/curvParams.ts b/app/web/src/helpers/cadPackages/curv/curvParams.ts deleted file mode 100644 index a0f4018..0000000 --- a/app/web/src/helpers/cadPackages/curv/curvParams.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { CadhubParams } from 'src/components/Customizer/customizerConverter' - -interface CurvParamsBase { - caption: string - name: string - group: string - initial: number | string | number[] - type: 'string' | 'number' -} - -interface CurvNumberParam extends CurvParamsBase { - type: 'number' - initial: number | number[] - max?: number - min?: number - step?: number - options?: { name: string; value: number }[] -} -interface CurvStringParam extends CurvParamsBase { - type: 'string' - initial: string - maxLength?: number - options?: { name: string; value: string }[] -} - -export type CurvParams = - | CurvNumberParam - | CurvStringParam - -export function openScadToCadhubParams( - input: CurvParams[] -): CadhubParams[] { - return input - .map((param): CadhubParams => { - const common: { caption: string; name: string } = { - caption: param.caption, - name: param.name, - } - switch (param.type) { - case 'string': - if (!Array.isArray(param?.options)) { - return { - type: 'string', - input: 'default-string', - ...common, - initial: param.initial, - maxLength: param.maxLength, - } - } else { - return { - type: 'string', - input: 'choice-string', - ...common, - initial: param.initial, - options: param.options, - } - } - case 'number': - if ( - !Array.isArray(param?.options) && - !Array.isArray(param?.initial) - ) { - return { - type: 'number', - input: 'default-number', - ...common, - initial: param.initial, - min: param.min, - max: param.max, - step: param.step, - } - } else if ( - Array.isArray(param?.options) && - !Array.isArray(param?.initial) - ) { - return { - type: 'number', - input: 'choice-number', - ...common, - initial: param.initial, - options: param.options, - } - } // TODO else vector - break - default: - return - } - }) - .filter((a) => a) -} diff --git a/app/web/src/helpers/cadPackages/curv/initialCode.curv b/app/web/src/helpers/cadPackages/curv/initialCode.curv index 3f4c4a1..d8aac90 100644 --- a/app/web/src/helpers/cadPackages/curv/initialCode.curv +++ b/app/web/src/helpers/cadPackages/curv/initialCode.curv @@ -1,6 +1,10 @@ -// sphere box - -(smooth 1).union [ - box, - sphere -] +let + N = 5; + C = red; + Twists = 6; +in +box [1,1,N] +>> colour C +>> twist (Twists*90*deg/N) +>> rotate {angle: 90*deg, axis: Y_axis} +>> bend{} -- 2.39.5 From fac1968a740e5c11de928edf5f2b7d41610c5cc7 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 30 Nov 2021 15:23:16 +1100 Subject: [PATCH 11/11] Format project --- app/api/src/docker/cadquery/cadquery.ts | 7 +++++-- app/api/src/docker/common/utils.ts | 2 +- app/api/src/docker/curv/runCurv.ts | 8 +++----- app/api/src/graphql/projects.sdl.ts | 2 +- app/web/src/components/EditorMenu/helpers.ts | 3 ++- app/web/src/components/Hero/Hero.tsx | 2 +- app/web/src/components/IdeViewer/IdeViewer.tsx | 7 ++++++- app/web/src/components/IdeViewer/PureIdeViewer.tsx | 13 ++++++++----- .../src/helpers/cadPackages/curv/curvController.ts | 3 +-- 9 files changed, 28 insertions(+), 19 deletions(-) diff --git a/app/api/src/docker/cadquery/cadquery.ts b/app/api/src/docker/cadquery/cadquery.ts index 6712876..30399ca 100644 --- a/app/api/src/docker/cadquery/cadquery.ts +++ b/app/api/src/docker/cadquery/cadquery.ts @@ -9,13 +9,16 @@ const stl = async (req, _context, callback) => { console.log('eventBody', eventBody) const { file, settings } = JSON.parse(eventBody) - const { error, consoleMessage, fullPath, tempFile } = await runCQ({ file, settings }) + const { error, consoleMessage, fullPath, tempFile } = await runCQ({ + file, + settings, + }) await storeAssetAndReturnUrl({ error, callback, fullPath, consoleMessage, - tempFile + tempFile, }) } diff --git a/app/api/src/docker/common/utils.ts b/app/api/src/docker/common/utils.ts index 373091d..d8e83cb 100644 --- a/app/api/src/docker/common/utils.ts +++ b/app/api/src/docker/common/utils.ts @@ -104,7 +104,7 @@ export async function storeAssetAndReturnUrl({ callback, fullPath, consoleMessage, - tempFile + tempFile, }: { error: string callback: Function diff --git a/app/api/src/docker/curv/runCurv.ts b/app/api/src/docker/curv/runCurv.ts index 59369d7..cdf6c54 100644 --- a/app/api/src/docker/curv/runCurv.ts +++ b/app/api/src/docker/curv/runCurv.ts @@ -3,10 +3,7 @@ import { nanoid } from 'nanoid' export const runCurv = async ({ file, - settings: { - size: { x = 500, y = 500 } = {}, - parameters, - } = {}, // TODO add view settings + settings: { size: { x = 500, y = 500 } = {}, parameters } = {}, // TODO add view settings } = {}): Promise<{ error?: string consoleMessage?: string @@ -83,7 +80,8 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => { const stlPath = `/tmp/${tempFile}/output.stl` const command = [ '(cd /tmp && curv', - '-o', stlPath, + '-o', + stlPath, '-O jit', '-O vcount=350000', `/tmp/${tempFile}/main.curv`, diff --git a/app/api/src/graphql/projects.sdl.ts b/app/api/src/graphql/projects.sdl.ts index 2ead489..5edd166 100644 --- a/app/api/src/graphql/projects.sdl.ts +++ b/app/api/src/graphql/projects.sdl.ts @@ -19,7 +19,7 @@ export const schema = gql` childForks: [Project]! } -# should match enum in api/db/schema.prisma + # should match enum in api/db/schema.prisma enum CadPackage { openscad cadquery diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index 039c5ee..024ca0a 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -69,7 +69,8 @@ export const makeStlDownloadHandler = } else { thunkDispatch((dispatch, getState) => { const state = getState() - const specialCadProcess = (ideType === 'openscad' || ideType === 'curv') && 'stl' + const specialCadProcess = + (ideType === 'openscad' || ideType === 'curv') && 'stl' dispatch({ type: 'setLoading' }) requestRender({ state, diff --git a/app/web/src/components/Hero/Hero.tsx b/app/web/src/components/Hero/Hero.tsx index b941def..1cfe25d 100644 --- a/app/web/src/components/Hero/Hero.tsx +++ b/app/web/src/components/Hero/Hero.tsx @@ -351,7 +351,7 @@ function ChooseYourCharacter() { { cadPackage: 'curv', desc: "Curv is a programming language for creating art using mathematics. It's a 2D and 3D geometric modelling tool.", - } + }, ].map( ({ cadPackage, diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 3a0b63b..d1045c3 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -25,7 +25,12 @@ const IdeViewer = ({ }) thunkDispatch((dispatch, getState) => { const state = getState() - if (['png', 'INIT'].includes(state?.objectData?.type) && (ideType === 'openscad' || state?.objectData?.type === 'INIT' || !state?.objectData?.type)) { + if ( + ['png', 'INIT'].includes(state?.objectData?.type) && + (ideType === 'openscad' || + state?.objectData?.type === 'INIT' || + !state?.objectData?.type) + ) { dispatch({ type: 'setLoading' }) requestRender({ state, diff --git a/app/web/src/components/IdeViewer/PureIdeViewer.tsx b/app/web/src/components/IdeViewer/PureIdeViewer.tsx index 592d8c5..33f5e46 100644 --- a/app/web/src/components/IdeViewer/PureIdeViewer.tsx +++ b/app/web/src/components/IdeViewer/PureIdeViewer.tsx @@ -169,7 +169,7 @@ export function PureIdeViewer({ isMinimal = false, scadRatio = 1, camera, - ideType + ideType, }: { dataType: 'INIT' | ArtifactTypes artifact: any @@ -218,9 +218,9 @@ export function PureIdeViewer({ )}
setIsDragging(true)} onInit={onInit} - onCameraChange={(...args) => {onCameraChange(...args); setIsDragging(false)}} + onCameraChange={(...args) => { + onCameraChange(...args) + setIsDragging(false) + }} controlsRef={controlsRef} camera={camera} /> diff --git a/app/web/src/helpers/cadPackages/curv/curvController.ts b/app/web/src/helpers/cadPackages/curv/curvController.ts index af452ce..88dd78d 100644 --- a/app/web/src/helpers/cadPackages/curv/curvController.ts +++ b/app/web/src/helpers/cadPackages/curv/curvController.ts @@ -38,8 +38,7 @@ export const render = async ({ code, settings }: RenderArgs) => { } const blob = await response.blob() const text = await new Response(blob).text() - const { consoleMessage, type } = - splitGziped(text) + const { consoleMessage, type } = splitGziped(text) return createHealthyResponse({ type: type !== 'stl' ? 'png' : 'geometry', data: -- 2.39.5