diff --git a/core/src/main/java/com/vzome/core/exporters/POVRayExporter.java b/core/src/main/java/com/vzome/core/exporters/POVRayExporter.java
index ad8e80f75..1f0bb682c 100644
--- a/core/src/main/java/com/vzome/core/exporters/POVRayExporter.java
+++ b/core/src/main/java/com/vzome/core/exporters/POVRayExporter.java
@@ -23,6 +23,7 @@
import com.vzome.core.math.symmetry.Embedding;
import com.vzome.core.render.RenderedManifestation;
import com.vzome.core.viewing.CameraIntf;
+import com.vzome.xml.ResourceLoader;
/**
* Renders out to POV-Ray using #declare statements to reuse geometry.
@@ -67,18 +68,8 @@ public void doExport( File povFile, Writer writer, int height, int width ) throw
output .println( "#declare parallel_proj = " + (mScene .isPerspective()?0:1) + ";" );
output .println();
- InputStream input = getClass() .getClassLoader()
- .getResourceAsStream( PREAMBLE_FILE );
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buf = new byte[1024];
- int num;
- try {
- while ( ( num = input .read( buf, 0, 1024 )) > 0 )
- out .write( buf, 0, num );
- } catch (IOException e) {
- e.printStackTrace();
- }
- output .println( new String( out .toByteArray() ) );
+ String preamble = ResourceLoader.loadStringResource( PREAMBLE_FILE );
+ output .println( preamble );
output .println();
for ( int i = 0; i<3; i++ ) {
diff --git a/online/src/app/classic/menus/filemenu.jsx b/online/src/app/classic/menus/filemenu.jsx
index 67ca6ff52..ef7f83f74 100644
--- a/online/src/app/classic/menus/filemenu.jsx
+++ b/online/src/app/classic/menus/filemenu.jsx
@@ -9,7 +9,7 @@ import { saveFileAs, openFile, saveTextFileAs, saveTextFile } from "../../../vie
import { CommandAction, Divider, Menu, MenuAction, MenuItem, SubMenu } from "../../framework/menus.jsx";
import { UrlDialog } from '../dialogs/webloader.jsx'
import { SvgPreviewDialog } from "../dialogs/svgpreview.jsx";
-import { useCamera } from "../../../viewer/context/camera.jsx";
+import { INITIAL_DISTANCE, useCamera } from "../../../viewer/context/camera.jsx";
import { useImageCapture } from "../../../viewer/context/export.jsx";
const queryParams = new URLSearchParams( window.location.search );
@@ -33,7 +33,7 @@ export const FileMenu = () =>
{
const { rootController, state, setState,
createDesign, openDesignFile, fetchDesignUrl, importMeshFile, guard, edited } = useEditor();
- const { state: cameraState } = useCamera();
+ const { state: cameraState, mapViewToWorld } = useCamera();
const [ showDialog, setShowDialog ] = createSignal( false );
const fields = () => controllerProperty( rootController(), 'fields', 'fields', true );
@@ -98,7 +98,11 @@ export const FileMenu = () =>
const exportAs = ( extension, mimeType, format=extension, params={} ) => evt =>
{
const camera = unwrap( cameraState.camera );
+ camera .magnification = Math.log( camera.distance / INITIAL_DISTANCE );
+
const lighting = unwrap( cameraState.lighting );
+ lighting .directionalLights .forEach( light => light .worldDirection = mapViewToWorld( light.direction ) );
+
controllerExportAction( rootController(), format, { camera, lighting, ...params } )
.then( text => {
const name = (state.designName || 'untitled') .concat( "." + extension );
@@ -163,7 +167,7 @@ export const FileMenu = () =>
-
+
diff --git a/online/src/viewer/context/camera.jsx b/online/src/viewer/context/camera.jsx
index 6feb4c231..553cf6c25 100644
--- a/online/src/viewer/context/camera.jsx
+++ b/online/src/viewer/context/camera.jsx
@@ -1,6 +1,6 @@
import { createContext, createEffect, useContext } from 'solid-js';
-import { PerspectiveCamera } from "three";
+import { PerspectiveCamera, Vector3 } from "three";
import { createStore } from 'solid-js/store';
@@ -154,6 +154,13 @@ const CameraProvider = ( props ) =>
}
const trackballProps = { camera: trackballCamera, sync }; // no need (or desire) for reactivity here
+ const mapViewToWorld = ( [ x, y, z ] ) =>
+ {
+ const vec = new Vector3( x, y, z );
+ vec .transformDirection( trackballCamera.matrixWorldInverse );
+ return [ vec.x, vec.y, vec.z ];
+ }
+
const setCamera = loadedCamera =>
{
setState( 'camera', loadedCamera );
@@ -179,7 +186,7 @@ const CameraProvider = ( props ) =>
const providerValue = {
name: props.name,
perspectiveProps, trackballProps, state,
- resetCamera, setCamera, setLighting, togglePerspective, toggleOutlines, setDistance,
+ resetCamera, setCamera, setLighting, togglePerspective, toggleOutlines, setDistance, mapViewToWorld,
};
// The perspectiveProps is used to initialize PerspectiveCamera in clients.
diff --git a/online/src/worker/java/java/util/UUID.java b/online/src/worker/java/java/util/UUID.java
index 578367f58..62cabc952 100644
--- a/online/src/worker/java/java/util/UUID.java
+++ b/online/src/worker/java/java/util/UUID.java
@@ -13,7 +13,7 @@ private UUID( String s )
public static UUID randomUUID()
{
- return new UUID( Double.toString( Math.random() ) );
+ return new UUID( Double.toString( Math.random() ) .substring( 2 ) );
}
public String toString()
diff --git a/online/src/worker/legacy/core-java.js b/online/src/worker/legacy/core-java.js
index 351fd68bd..e8211f115 100644
--- a/online/src/worker/legacy/core-java.js
+++ b/online/src/worker/legacy/core-java.js
@@ -11,7 +11,7 @@ import { java, javaemul } from "./candies/j4ts-2.1.0-SNAPSHOT/bundle.js"
this.value = s;
}
static randomUUID() {
- return new UUID(/* toString */ ('' + (Math.random())));
+ return new UUID(/* toString */ ('' + (Math.random())).substring(2));
}
toString() {
return this.value;
@@ -3952,10 +3952,6 @@ export var com;
this.orbits = new com.vzome.core.math.symmetry.OrbitSet(symmetry);
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$() {
- return this.getOrientations(false);
- }
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit, orientation) {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
}
@@ -3983,6 +3979,10 @@ export var com;
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$() {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getOrientations(rowMajor) {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
@@ -16761,10 +16761,6 @@ export var com;
this.setStyle(styleName);
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$() {
- return this.getOrientations(false);
- }
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit, orientation) {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
}
@@ -16792,6 +16788,10 @@ export var com;
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$() {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getOrientations(rowMajor) {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
@@ -36960,21 +36960,8 @@ export var com;
this.output.println$();
this.output.println$java_lang_Object("#declare parallel_proj = " + (this.mScene.isPerspective() ? 0 : 1) + ";");
this.output.println$();
- const input = this.constructor.getClassLoader().getResourceAsStream(POVRayExporter.PREAMBLE_FILE);
- const out = new java.io.ByteArrayOutputStream();
- const buf = (s => { let a = []; while (s-- > 0)
- a.push(0); return a; })(1024);
- let num;
- try {
- while (((num = input.read(buf, 0, 1024)) > 0)) {
- out.write(buf, 0, num);
- }
- ;
- }
- catch (e) {
- console.error(e.message, e);
- }
- this.output.println$java_lang_Object(new String(out.toByteArray()));
+ const preamble = com.vzome.xml.ResourceLoader.loadStringResource(POVRayExporter.PREAMBLE_FILE);
+ this.output.println$java_lang_Object(preamble);
this.output.println$();
for (let i = 0; i < 3; i++) {
{
@@ -48051,10 +48038,6 @@ export var com;
this.__parent = __parent;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$() {
- return this.getOrientations(false);
- }
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit, orientation) {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
}
@@ -48082,6 +48065,10 @@ export var com;
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$() {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getOrientations(rowMajor) {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
diff --git a/online/src/worker/legacy/exporters.js b/online/src/worker/legacy/exporters.js
index aeec13234..e7d158997 100644
--- a/online/src/worker/legacy/exporters.js
+++ b/online/src/worker/legacy/exporters.js
@@ -10,7 +10,7 @@ const exporterClasses = {
'off' : 'OffExporter',
'ply' : 'PlyExporter',
'vrml' : 'VRMLExporter',
- 'pov' : 'PovRayExporter',
+ 'pov' : 'POVRayExporter',
'partgeom' : 'PartGeometryExporter',
'openscad' : 'OpenScadExporter',
'math' : 'MathTableExporter',
@@ -29,44 +29,6 @@ const exporterClasses = {
// 'FORMAT' : 'VefModelExporter',
}
-export const export3d = ( scene, configuration ) =>
-{
- const { format, height, width } = configuration;
- const { renderedModel } = scene;
- const exporter = new com.vzome.core.exporters[ exporterClasses[ format ] ]();
- const out = new java.io.StringWriter();
- exporter .exportGeometry( renderedModel, null, out, height, width );
- return out.toString();
-}
-
-const createDocument = ( legacyDesign, camera, lighting ) =>
-{
- // TODO
- return {
- // CameraIntf getCameraModel();
-
- // Lights getSceneLighting();
-
- // RenderedModel getRenderedModel();
-
- // ToolsModel getToolsModel();
-
- // Element getDetailsXml( Document dom, boolean b );
-
- // EditorModel getEditorModel();
- }
-}
-
-export const export3dDocument = ( legacyDesign, camera, lighting, configuration ) =>
-{
- const { format, height, width } = configuration;
- const exporter = new com.vzome.core.exporters[ exporterClasses[ format ] ]();
- const out = new java.io.StringWriter();
- const document = createDocument( legacyDesign, camera, lighting );
- exporter .exportDocument( document, null, out, height, width );
- return out.toString();
-}
-
const parseColor = input =>
{
const m = input .match( /^#([0-9a-f]{6})$/i )[1];
@@ -86,7 +48,9 @@ const createLights = lighting =>
const lights = new com.vzome.core.viewing.Lights();
lights .setBackgroundColor( parseColor( backgroundColor ) );
lights .setAmbientColor( parseColor( ambientColor ) );
- for ( const { direction: [x,y,z], color } of directionalLights ) {
+ for ( const { worldDirection: [x,y,z], color } of directionalLights ) {
+ // Because we are using worldDirection rather than direction, these vectors are in world coordinates already.
+ // Apparently, POVRayExporter is the only exporter that uses directional lights.
lights .addDirectionLight( parseColor( color ), new com.vzome.core.math.RealVector( x, y, z ) );
}
return lights;
@@ -110,6 +74,49 @@ const createProjectionMatrix = ( camera, aspectRatio ) =>
return com.vzome.core.math.RealMatrix4.perspective( fovX, aspectRatio, near, far );
}
+const createCamera = ( camera ) =>
+{
+ const { distance, width, perspective, lookAt, up, lookDir, magnification } = camera; // This camera always comes from the client context
+ const halfX = width / 2;
+ const fov = 2 * Math.atan( halfX / distance );
+ let [ x, y, z ] = lookAt;
+ const lookAtRV = new com.vzome.core.math.RealVector( x, y, z );
+ [ x, y, z ] = up;
+ const upRV = new com.vzome.core.math.RealVector( x, y, z );
+ [ x, y, z ] = lookDir;
+ const lookDirRV = new com.vzome.core.math.RealVector( x, y, z );
+ return {
+ isPerspective: () => perspective,
+ getFieldOfView: () => fov,
+ getViewDistance: () => distance,
+ getMagnification: () => magnification,
+ getLookAtPointRV: () => lookAtRV,
+ getLookDirectionRV: () => lookDirRV,
+ getUpDirectionRV: () => upRV,
+
+ // POVRayExporter will call this to map light directions to world coordinates, in the Java code,
+ // but here in Javascript our light directions are *already* in world coordinates.
+ mapViewToWorld: rv => rv,
+ }
+}
+
+const createDocument = ( legacyDesign, camera, lighting ) =>
+ {
+ const { renderedModel, editor, toolsModel } = legacyDesign;
+ const lights = createLights( lighting );
+ const cameraModel = createCamera( camera );
+ return {
+ getCameraModel: () => cameraModel,
+ getSceneLighting: () => lights,
+ getRenderedModel: () => renderedModel,
+ getToolsModel: () => toolsModel,
+ getEditorModel: () => editor,
+ getDetailsXml: ( dom, deep ) => null, // TODO: implement this so more exporters work
+ }
+ }
+
+////////////////////////////////////////////// main entry points:
+
export const export2d = ( scene, configuration ) =>
{
const { format, height, width, useShapes, drawOutlines, monochrome, showBackground, useLighting } = configuration;
@@ -123,4 +130,26 @@ export const export2d = ( scene, configuration ) =>
const out = new java.io.StringWriter();
exporter .export( snapshot, out, drawOutlines, monochrome, showBackground );
return out.toString();
-}
\ No newline at end of file
+}
+
+export const export3d = ( scene, configuration ) =>
+ {
+ const { format, height, width } = configuration;
+ const { renderedModel } = scene;
+ const exporter = new com.vzome.core.exporters[ exporterClasses[ format ] ]();
+ const out = new java.io.StringWriter();
+ exporter .exportGeometry( renderedModel, null, out, height, width );
+ return out.toString();
+ }
+
+export const export3dDocument = ( legacyDesign, camera, lighting, configuration ) =>
+ {
+ const { format, height, width } = configuration;
+ const exporter = new com.vzome.core.exporters[ exporterClasses[ format ] ]();
+ const out = new java.io.StringWriter();
+ // Satisfy the DocumentIntf contract required by DocumentExporter
+ const document = createDocument( legacyDesign, camera, lighting );
+ exporter .exportDocument( document, null, out, height, width );
+ return out.toString();
+ }
+
\ No newline at end of file
diff --git a/online/src/worker/legacy/ts/com/vzome/core/exporters/POVRayExporter.ts b/online/src/worker/legacy/ts/com/vzome/core/exporters/POVRayExporter.ts
index a50f81d89..5d4b5fc31 100644
--- a/online/src/worker/legacy/ts/com/vzome/core/exporters/POVRayExporter.ts
+++ b/online/src/worker/legacy/ts/com/vzome/core/exporters/POVRayExporter.ts
@@ -48,16 +48,8 @@ namespace com.vzome.core.exporters {
this.output.println$();
this.output.println$java_lang_Object("#declare parallel_proj = " + (this.mScene.isPerspective() ? 0 : 1) + ";");
this.output.println$();
- const input: java.io.InputStream = (this.constructor).getClassLoader().getResourceAsStream(POVRayExporter.PREAMBLE_FILE);
- const out: java.io.ByteArrayOutputStream = new java.io.ByteArrayOutputStream();
- const buf: number[] = (s => { let a=[]; while(s-->0) a.push(0); return a; })(1024);
- let num: number;
- try {
- while(((num = input.read(buf, 0, 1024)) > 0)) {out.write(buf, 0, num)};
- } catch(e) {
- console.error(e.message, e);
- }
- this.output.println$java_lang_Object(new String(out.toByteArray()));
+ const preamble: string = com.vzome.xml.ResourceLoader.loadStringResource(POVRayExporter.PREAMBLE_FILE);
+ this.output.println$java_lang_Object(preamble);
this.output.println$();
for(let i: number = 0; i < 3; i++) {{
const color: com.vzome.core.construction.Color = this.mLights.getDirectionalLightColor(i);
diff --git a/online/src/worker/legacy/ts/core-java.ts b/online/src/worker/legacy/ts/core-java.ts
index ffa35e8eb..43cd60a9e 100644
--- a/online/src/worker/legacy/ts/core-java.ts
+++ b/online/src/worker/legacy/ts/core-java.ts
@@ -57,7 +57,7 @@ namespace java.util {
}
public static randomUUID(): UUID {
- return new UUID(/* toString */(''+(Math.random())));
+ return new UUID(/* toString */(''+(Math.random())).substring(2));
}
public toString(): string {
@@ -4135,10 +4135,6 @@ namespace com.vzome.core.render {
export namespace RenderedModel {
export class SymmetryOrbitSource implements com.vzome.core.editor.api.OrbitSource {
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$(): number[][] {
- return this.getOrientations(false);
- }
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit: string, orientation: number): com.vzome.core.math.symmetry.Axis {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
@@ -4163,6 +4159,10 @@ namespace com.vzome.core.render {
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$(): number[][] {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
public getOrientations(rowMajor?: any): number[][] {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
@@ -17037,10 +17037,6 @@ namespace com.vzome.core.editor {
}
namespace com.vzome.core.editor {
export class SymmetrySystem implements com.vzome.core.editor.api.OrbitSource {
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$(): number[][] {
- return this.getOrientations(false);
- }
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit: string, orientation: number): com.vzome.core.math.symmetry.Axis {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
@@ -17065,6 +17061,10 @@ namespace com.vzome.core.editor {
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$(): number[][] {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
public getOrientations(rowMajor?: any): number[][] {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
@@ -36209,16 +36209,8 @@ namespace com.vzome.core.exporters {
this.output.println$();
this.output.println$java_lang_Object("#declare parallel_proj = " + (this.mScene.isPerspective() ? 0 : 1) + ";");
this.output.println$();
- const input: java.io.InputStream = (this.constructor).getClassLoader().getResourceAsStream(POVRayExporter.PREAMBLE_FILE);
- const out: java.io.ByteArrayOutputStream = new java.io.ByteArrayOutputStream();
- const buf: number[] = (s => { let a=[]; while(s-->0) a.push(0); return a; })(1024);
- let num: number;
- try {
- while(((num = input.read(buf, 0, 1024)) > 0)) {out.write(buf, 0, num)};
- } catch(e) {
- console.error(e.message, e);
- }
- this.output.println$java_lang_Object(new String(out.toByteArray()));
+ const preamble: string = com.vzome.xml.ResourceLoader.loadStringResource(POVRayExporter.PREAMBLE_FILE);
+ this.output.println$java_lang_Object(preamble);
this.output.println$();
for(let i: number = 0; i < 3; i++) {{
const color: com.vzome.core.construction.Color = this.mLights.getDirectionalLightColor(i);
@@ -46085,10 +46077,6 @@ namespace com.vzome.core.edits {
export class ReplaceWithShape$0 implements com.vzome.core.editor.api.OrbitSource {
public __parent: any;
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
- getOrientations$(): number[][] {
- return this.getOrientations(false);
- }
- /* Default method injected from com.vzome.core.editor.api.OrbitSource */
getZone(orbit: string, orientation: number): com.vzome.core.math.symmetry.Axis {
return this.getSymmetry().getDirection(orbit).getAxis(com.vzome.core.math.symmetry.Symmetry.PLUS, orientation);
}
@@ -46112,6 +46100,10 @@ namespace com.vzome.core.edits {
return embedding;
}
/* Default method injected from com.vzome.core.editor.api.OrbitSource */
+ getOrientations$(): number[][] {
+ return this.getOrientations(false);
+ }
+ /* Default method injected from com.vzome.core.editor.api.OrbitSource */
public getOrientations(rowMajor?: any): number[][] {
if (((typeof rowMajor === 'boolean') || rowMajor === null)) {
let __args = arguments;
diff --git a/online/src/worker/legacy/ts/java/util/UUID.ts b/online/src/worker/legacy/ts/java/util/UUID.ts
index 1f0a0cc3d..7ad9fc4f6 100644
--- a/online/src/worker/legacy/ts/java/util/UUID.ts
+++ b/online/src/worker/legacy/ts/java/util/UUID.ts
@@ -9,7 +9,7 @@ namespace java.util {
}
public static randomUUID(): UUID {
- return new UUID(/* toString */(''+(Math.random())));
+ return new UUID(/* toString */(''+(Math.random())).substring(2));
}
public toString(): string {