Add customizer support for OpenSCAD
This also includes sending metadata and part of the concatenated gzip, not in the s3 metadata as that has a 2kb limit. Resolves #320
This commit is contained in:
@@ -8,7 +8,6 @@ import {
|
||||
CadhubNumberParam,
|
||||
CadhubStringChoiceParam,
|
||||
CadhubNumberChoiceParam,
|
||||
CadhubChoiceParam,
|
||||
} from './customizerConverter'
|
||||
|
||||
const Customizer = () => {
|
||||
@@ -82,17 +81,22 @@ const Customizer = () => {
|
||||
{customizerParams.map((param, index) => {
|
||||
const otherProps = {
|
||||
value: currentParameters[param.name],
|
||||
onChange: (value) => updateCustomizerParam(param.name, param.type == 'number' ? Number(value) : value),
|
||||
onChange: (value) =>
|
||||
updateCustomizerParam(
|
||||
param.name,
|
||||
param.type == 'number' ? Number(value) : value
|
||||
),
|
||||
}
|
||||
if(param.input === 'choice-string' || param.input === 'choice-number'){
|
||||
return <StringChoiceParam key={index} param={param} {...otherProps} />
|
||||
// }else if(param.input === 'choice-number'){
|
||||
// return <StringChoiceParam key={index} param={param} {...otherProps} />
|
||||
}else if (param.type === 'string') {
|
||||
return <StringParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.type === 'number') {
|
||||
return <NumberParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.type === 'boolean') {
|
||||
if (
|
||||
param.input === 'choice-string' ||
|
||||
param.input === 'choice-number'
|
||||
) {
|
||||
return <ChoiceParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.input === 'default-string') {
|
||||
return <StringParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.input === 'default-number') {
|
||||
return <NumberParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.input === 'default-boolean') {
|
||||
return <BooleanParam key={index} param={param} {...otherProps} />
|
||||
}
|
||||
return <div key={index}>{JSON.stringify(param)}</div>
|
||||
@@ -180,12 +184,12 @@ function StringParam({
|
||||
)
|
||||
}
|
||||
|
||||
function StringChoiceParam({
|
||||
function ChoiceParam({
|
||||
param,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
param: CadhubChoiceParam
|
||||
param: CadhubStringChoiceParam | CadhubNumberChoiceParam
|
||||
value: any
|
||||
onChange: Function
|
||||
}) {
|
||||
@@ -196,7 +200,11 @@ function StringChoiceParam({
|
||||
value={value}
|
||||
onChange={({ target }) => onChange(target?.value)}
|
||||
>
|
||||
{param.options.map(opt=><option value={opt.value} key={opt.name}>{opt.name}</option>)}
|
||||
{param.options.map((opt) => (
|
||||
<option value={opt.value} key={opt.name}>
|
||||
{opt.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</CustomizerParamBase>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// CadHub
|
||||
|
||||
type CadhubTypeNames = 'number' | 'string' | 'boolean'
|
||||
type CadhubInputNames = 'default-number' | 'default-string' | 'default-boolean' | 'choice-string' | 'choice-number'
|
||||
type CadhubInputNames =
|
||||
| 'default-number'
|
||||
| 'default-string'
|
||||
| 'default-boolean'
|
||||
| 'choice-string'
|
||||
| 'choice-number'
|
||||
|
||||
export interface CadhubStringOption {
|
||||
name: string
|
||||
@@ -29,6 +34,7 @@ export interface CadhubStringParam extends CadhubParamBase {
|
||||
}
|
||||
export interface CadhubBooleanParam extends CadhubParamBase {
|
||||
type: 'boolean'
|
||||
input: 'default-boolean'
|
||||
initial?: boolean
|
||||
}
|
||||
export interface CadhubNumberParam extends CadhubParamBase {
|
||||
@@ -45,13 +51,13 @@ export interface CadhubStringChoiceParam extends CadhubParamBase {
|
||||
type: 'string'
|
||||
input: 'choice-string'
|
||||
initial: string
|
||||
options: Array<CadhubStringOption>
|
||||
options: Array<CadhubStringOption>
|
||||
}
|
||||
export interface CadhubNumberChoiceParam extends CadhubParamBase {
|
||||
type: 'number'
|
||||
input: 'choice-number'
|
||||
initial: number
|
||||
options: Array<CadhubNumberOption>
|
||||
options: Array<CadhubNumberOption>
|
||||
}
|
||||
|
||||
export type CadhubParams =
|
||||
@@ -60,91 +66,3 @@ export type CadhubParams =
|
||||
| CadhubNumberParam
|
||||
| CadhubStringChoiceParam
|
||||
| CadhubNumberChoiceParam
|
||||
|
||||
// OpenSCAD
|
||||
const openscadValues = `
|
||||
// slider widget for number with max. value
|
||||
sliderWithMax =34; // [50]
|
||||
|
||||
// slider widget for number in range
|
||||
sliderWithRange =34; // [10:100]
|
||||
|
||||
//step slider for number
|
||||
stepSlider=2; //[0:5:100]
|
||||
|
||||
// slider widget for number in range
|
||||
sliderCentered =0; // [-10:0.1:10]
|
||||
|
||||
// spinbox with step size 1
|
||||
Spinbox= 5;
|
||||
|
||||
// Text box for string
|
||||
String="hello";
|
||||
|
||||
// Text box for string with length 8
|
||||
String2="length"; //8
|
||||
|
||||
//description
|
||||
Variable = true;
|
||||
`
|
||||
|
||||
const openscadConverted: CadhubParams[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderWithMax',
|
||||
caption: 'slider widget for number with max. value',
|
||||
initial: 34,
|
||||
step: 1,
|
||||
max: 50,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderWithRange',
|
||||
caption: 'slider widget for number in range',
|
||||
initial: 34,
|
||||
step: 1,
|
||||
min: 10,
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'stepSlider',
|
||||
caption: 'step slider for number',
|
||||
initial: 2,
|
||||
step: 5,
|
||||
min: 0,
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderCentered',
|
||||
caption: 'slider widget for number in range',
|
||||
initial: 0,
|
||||
step: 0.1,
|
||||
min: -10,
|
||||
max: 10,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'Spinbox',
|
||||
caption: 'spinbox with step size 1',
|
||||
initial: 5,
|
||||
step: 1,
|
||||
},
|
||||
|
||||
{
|
||||
type: 'string',
|
||||
name: 'String',
|
||||
caption: 'Text box for string',
|
||||
initial: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'String2',
|
||||
caption: 'Text box for string with length 8',
|
||||
initial: 'length',
|
||||
maxLength: 8,
|
||||
},
|
||||
|
||||
{ type: 'boolean', name: 'Variable', caption: 'description', initial: true },
|
||||
]
|
||||
|
||||
@@ -22,7 +22,7 @@ const IdeConsole = () => {
|
||||
{time?.toLocaleString()}
|
||||
</div>
|
||||
<div className={(type === 'error' ? 'text-red-400' : '') + ' pl-4'}>
|
||||
{message.split('\n').map((line, index) => {
|
||||
{(message || '').split('\n').map((line, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
{line.startsWith('ECHO:') ? (
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
timeoutErrorMessage,
|
||||
RenderArgs,
|
||||
DefaultKernelExport,
|
||||
splitGziped,
|
||||
} from './common'
|
||||
|
||||
export const render: DefaultKernelExport['render'] = async ({
|
||||
@@ -41,11 +42,19 @@ export const render: DefaultKernelExport['render'] = async ({
|
||||
return createUnhealthyResponse(new Date(), timeoutErrorMessage)
|
||||
}
|
||||
const data = await response.json()
|
||||
const geometry = await stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage } = splitGziped(text)
|
||||
return {
|
||||
data: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type: 'geometry',
|
||||
data: geometry,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
})
|
||||
} catch (e) {
|
||||
|
||||
@@ -13,8 +13,8 @@ export const stlToGeometry = (url) =>
|
||||
|
||||
export interface RenderArgs {
|
||||
code: State['code']
|
||||
parameters?: RawCustomizerParams
|
||||
settings: {
|
||||
parameters?: RawCustomizerParams
|
||||
camera: State['camera']
|
||||
viewerSize: State['viewerSize']
|
||||
quality: State['objectData']['quality']
|
||||
@@ -103,3 +103,16 @@ export type RenderResponse = HealthyResponse | ErrorResponse
|
||||
export interface DefaultKernelExport {
|
||||
render: (arg: RenderArgs) => Promise<RenderResponse>
|
||||
}
|
||||
|
||||
export const splitGziped = (text: string) => {
|
||||
const concatSplitStr = 'cadhub-concat-split'
|
||||
const splitIndex = text.indexOf(concatSplitStr)
|
||||
const json = text.slice(splitIndex + concatSplitStr.length)
|
||||
|
||||
try {
|
||||
return JSON.parse(json)
|
||||
} catch (e) {
|
||||
console.log(json, e)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DefaultKernelExport } from './common'
|
||||
import type { CadPackage } from 'src/helpers/hooks/useIdeState'
|
||||
|
||||
import openscad from './openScadController'
|
||||
import openscad from './openScad/openScadController'
|
||||
import cadquery from './cadQueryController'
|
||||
import jscad from './jsCad/jsCadController'
|
||||
|
||||
|
||||
@@ -130,7 +130,6 @@ const workerHelper = new WorkerHelper()
|
||||
|
||||
export const render: DefaultKernelExport['render'] = async ({
|
||||
code,
|
||||
parameters,
|
||||
settings,
|
||||
}: RenderArgs) => {
|
||||
if (!scriptWorker) {
|
||||
@@ -169,11 +168,11 @@ export const render: DefaultKernelExport['render'] = async ({
|
||||
}
|
||||
})
|
||||
|
||||
workerHelper.resolver()
|
||||
workerHelper.resolver(null)
|
||||
scriptWorker.postMessage({ action: 'init', baseURI, alias: [] })
|
||||
}
|
||||
|
||||
return workerHelper.render(code, parameters)
|
||||
return workerHelper.render(code, settings.parameters)
|
||||
}
|
||||
|
||||
const jsCadController: DefaultKernelExport = {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { CadhubNumberChoiceParam, CadhubNumberOption, CadhubParams, CadhubStringChoiceParam, CadhubStringOption } from 'src/components/Customizer/customizerConverter'
|
||||
import {
|
||||
CadhubNumberChoiceParam,
|
||||
CadhubNumberOption,
|
||||
CadhubParams,
|
||||
CadhubStringChoiceParam,
|
||||
CadhubStringOption,
|
||||
} from 'src/components/Customizer/customizerConverter'
|
||||
|
||||
type JscadTypeNames =
|
||||
| 'group'
|
||||
@@ -19,6 +25,7 @@ interface JscadParamBase {
|
||||
type: JscadTypeNames
|
||||
caption: string
|
||||
name: string
|
||||
initial?: number | string | boolean
|
||||
}
|
||||
interface JscadGroupParam extends JscadParamBase {
|
||||
type: 'group'
|
||||
@@ -81,6 +88,10 @@ type JsCadParams =
|
||||
export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
return input
|
||||
.map((param): CadhubParams => {
|
||||
const common: { caption: string; name: string } = {
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
}
|
||||
switch (param.type) {
|
||||
case 'slider':
|
||||
case 'number':
|
||||
@@ -88,8 +99,7 @@ export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'default-number',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
...common,
|
||||
initial: param.initial,
|
||||
min: param.min,
|
||||
max: param.max,
|
||||
@@ -105,8 +115,7 @@ export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'default-string',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
...common,
|
||||
initial: param.initial,
|
||||
placeholder:
|
||||
param.type === 'text' ||
|
||||
@@ -123,43 +132,38 @@ export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
return {
|
||||
type: 'boolean',
|
||||
input: 'default-boolean',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
...common,
|
||||
initial: !!param.initial,
|
||||
}
|
||||
case 'choice':
|
||||
case 'radio':
|
||||
if(typeof param.values[0] === 'number'){
|
||||
let options:Array<CadhubNumberOption> = []
|
||||
let captions = param.captions || param.values
|
||||
param.values.forEach((value,i)=>{
|
||||
options[i] = {name:String(captions[i]), value:Number(value)}
|
||||
})
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'choice-number',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
initial: Number(param.initial),
|
||||
options
|
||||
}
|
||||
}else{
|
||||
let options:Array<CadhubStringOption> = []
|
||||
let captions = param.captions || param.values
|
||||
param.values.forEach((value,i)=>{
|
||||
options[i] = {name:String(captions[i]), value:String(value)}
|
||||
})
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'choice-string',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
initial: String(param.initial),
|
||||
options
|
||||
}
|
||||
case 'choice':
|
||||
case 'radio':
|
||||
if (typeof param.values[0] === 'number') {
|
||||
const options: Array<CadhubNumberOption> = []
|
||||
const captions = param.captions || param.values
|
||||
param.values.forEach((value, i) => {
|
||||
options[i] = { name: String(captions[i]), value: Number(value) }
|
||||
})
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'choice-number',
|
||||
...common,
|
||||
initial: Number(param.initial),
|
||||
options,
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
const options: Array<CadhubStringOption> = []
|
||||
const captions = param.captions || param.values
|
||||
param.values.forEach((value, i) => {
|
||||
options[i] = { name: String(captions[i]), value: String(value) }
|
||||
})
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'choice-string',
|
||||
...common,
|
||||
initial: String(param.initial),
|
||||
options,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter((a) => a)
|
||||
|
||||
@@ -5,7 +5,9 @@ import {
|
||||
createUnhealthyResponse,
|
||||
timeoutErrorMessage,
|
||||
RenderArgs,
|
||||
} from './common'
|
||||
splitGziped,
|
||||
} from '../common'
|
||||
import { openScadToCadhubParams } from './openScadParams'
|
||||
|
||||
export const render = async ({ code, settings }: RenderArgs) => {
|
||||
const pixelRatio = window.devicePixelRatio || 1
|
||||
@@ -17,6 +19,7 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
||||
const body = JSON.stringify({
|
||||
settings: {
|
||||
size,
|
||||
parameters: settings.parameters,
|
||||
camera: {
|
||||
// rounding to give our caching a chance to sometimes work
|
||||
...settings.camera,
|
||||
@@ -56,15 +59,25 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
||||
}
|
||||
const data = await response.json()
|
||||
const type = data.type !== 'stl' ? 'png' : 'geometry'
|
||||
const newData =
|
||||
data.type !== 'stl'
|
||||
? fetch(data.url).then((a) => a.blob())
|
||||
: stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage, customizerParams } = splitGziped(text)
|
||||
return {
|
||||
data:
|
||||
data.type !== 'stl'
|
||||
? blob
|
||||
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
customizerParams,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type,
|
||||
data: await newData,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
customizerParams: openScadToCadhubParams(newData.customizerParams || []),
|
||||
})
|
||||
} catch (e) {
|
||||
return createUnhealthyResponse(new Date())
|
||||
@@ -93,12 +106,22 @@ export const stl = async ({ code, settings }: RenderArgs) => {
|
||||
return createUnhealthyResponse(new Date(), timeoutErrorMessage)
|
||||
}
|
||||
const data = await response.json()
|
||||
const geometry = await stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage, customizerParams } = splitGziped(text)
|
||||
return {
|
||||
data: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
customizerParams,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type: 'geometry',
|
||||
data: geometry,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
customizerParams: openScadToCadhubParams(newData.customizerParams || []),
|
||||
})
|
||||
} catch (e) {
|
||||
return createUnhealthyResponse(new Date())
|
||||
102
app/web/src/helpers/cadPackages/openScad/openScadParams.ts
Normal file
102
app/web/src/helpers/cadPackages/openScad/openScadParams.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { CadhubParams } from 'src/components/Customizer/customizerConverter'
|
||||
|
||||
interface OpenScadParamsBase {
|
||||
caption: string
|
||||
name: string
|
||||
group: string
|
||||
initial: number | string | boolean | number[]
|
||||
type: 'string' | 'number' | 'boolean'
|
||||
}
|
||||
|
||||
interface OpenScadNumberParam extends OpenScadParamsBase {
|
||||
type: 'number'
|
||||
initial: number | number[]
|
||||
max?: number
|
||||
min?: number
|
||||
step?: number
|
||||
options?: { name: string; value: number }[]
|
||||
}
|
||||
interface OpenScadStringParam extends OpenScadParamsBase {
|
||||
type: 'string'
|
||||
initial: string
|
||||
maxLength?: number
|
||||
options?: { name: string; value: string }[]
|
||||
}
|
||||
interface OpenScadBooleanParam extends OpenScadParamsBase {
|
||||
type: 'boolean'
|
||||
initial: boolean
|
||||
}
|
||||
|
||||
export type OpenScadParams =
|
||||
| OpenScadNumberParam
|
||||
| OpenScadStringParam
|
||||
| OpenScadBooleanParam
|
||||
|
||||
export function openScadToCadhubParams(
|
||||
input: OpenScadParams[]
|
||||
): CadhubParams[] {
|
||||
return input
|
||||
.map((param): CadhubParams => {
|
||||
const common: { caption: string; name: string } = {
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
}
|
||||
switch (param.type) {
|
||||
case 'boolean':
|
||||
return {
|
||||
type: 'boolean',
|
||||
input: 'default-boolean',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -51,13 +51,12 @@ show_object(result)
|
||||
|
||||
const jscad = require('@jscad/modeling')
|
||||
// https://openjscad.xyz/docs/module-modeling_primitives.html
|
||||
const { circle, rectangle, cube, cuboid, sphere, cylinder } = jscad.primitives
|
||||
const { cuboid, cylinder } = jscad.primitives
|
||||
|
||||
const { rotate, scale, translate } = jscad.transforms
|
||||
const { rotate, translate } = jscad.transforms
|
||||
const { degToRad } = jscad.utils // because jscad uses radians for rotations
|
||||
const { colorize } = jscad.colors
|
||||
// https://openjscad.xyz/docs/module-modeling_booleans.html
|
||||
const { union, intersect, subtract } = jscad.booleans
|
||||
const { subtract } = jscad.booleans
|
||||
|
||||
function main({//@jscad-params
|
||||
// Box example
|
||||
@@ -66,6 +65,7 @@ function main({//@jscad-params
|
||||
height=10, // Height
|
||||
hole=3,// Hole for cables diameter (0=no hole)
|
||||
wall=1, // wall {min:0.5, step:0.5}
|
||||
flip=0, // print orientation {type: 'choice', values: [0, 90, 180]}
|
||||
}){
|
||||
|
||||
let wallOffset = wall * 2
|
||||
@@ -78,7 +78,7 @@ function main({//@jscad-params
|
||||
translate([width/2-wall/2], rotate([0, degToRad(90), 0 ], cylinder({radius:hole/2, height:wall})))
|
||||
)
|
||||
}
|
||||
return rotate([0,0, degToRad(90)], model)
|
||||
return rotate([degToRad(flip), 0, degToRad(90)], model)
|
||||
}
|
||||
|
||||
module.exports = {main}
|
||||
@@ -281,8 +281,8 @@ export const requestRender = ({
|
||||
: cadPackages[state.ideType].render
|
||||
return renderFn({
|
||||
code,
|
||||
parameters,
|
||||
settings: {
|
||||
parameters,
|
||||
camera,
|
||||
viewerSize,
|
||||
quality,
|
||||
|
||||
Reference in New Issue
Block a user