diff --git a/web/app/cad/craft/craftPlugin.js b/web/app/cad/craft/craftPlugin.js index d51727e5..674595fa 100644 --- a/web/app/cad/craft/craftPlugin.js +++ b/web/app/cad/craft/craftPlugin.js @@ -50,6 +50,12 @@ export function activate({streams, services}) { pointer: modifications.length - 1 }); } + + function rebuild() { + const mods = streams.craft.modifications.value; + reset([]); + streams.craft.modifications.next(mods); + } function runRequest(request) { let op = services.operation.get(request.type); @@ -79,7 +85,7 @@ export function activate({streams, services}) { } services.craft = { - modify, modifyInHistoryAndStep, reset, runRequest, + modify, modifyInHistoryAndStep, reset, runRequest, rebuild, historyTravel: historyTravel(streams.craft.modifications) }; diff --git a/web/app/cad/craft/ui/HistoryTimeline.jsx b/web/app/cad/craft/ui/HistoryTimeline.jsx index 6293fc44..99b24384 100644 --- a/web/app/cad/craft/ui/HistoryTimeline.jsx +++ b/web/app/cad/craft/ui/HistoryTimeline.jsx @@ -19,19 +19,20 @@ import {aboveElement} from '../../../../../modules/ui/positionUtils'; inProgressOperation: insertOperationReq.type, getOperation: type => operationRegistry[type]||EMPTY_OBJECT }))) -@mapContext(({streams}) => ({ +@mapContext(({streams, services}) => ({ remove: atIndex => streams.craft.modifications.update(modifications => removeAndDropDependants(modifications, atIndex)), cancel: () => streams.craft.modifications.update(modifications => finishHistoryEditing(modifications)), - setHistoryPointer: pointer => streams.craft.modifications.update(({history}) => ({history, pointer})) + setHistoryPointer: pointer => streams.craft.modifications.update(({history}) => ({history, pointer})), + rebuild: () => services.craft.rebuild() })) export default class HistoryTimeline extends React.Component { render() { - let {history, pointer, setHistoryPointer, remove, getOperation, inProgressOperation} = this.props; + let {history, pointer, setHistoryPointer, rebuild, getOperation, inProgressOperation} = this.props; let scrolly; let eof = history.length-1; return
- +
scrolly.scrollLeft -= 60}>
scrolly = el}> {history.map((m, i) => @@ -102,10 +103,13 @@ function Handle() { ; } -function Controls({pointer, eoh, setHistoryPointer}) { +function Controls({rebuild, history, pointer, eoh, setHistoryPointer, }) { const noB = pointer===-1; const noF = pointer===eoh; return +
setHistoryPointer(pointer-1)}>
diff --git a/web/app/cad/expressions/expressionsPlugin.js b/web/app/cad/expressions/expressionsPlugin.js index dcfdeb40..81802e2a 100644 --- a/web/app/cad/expressions/expressionsPlugin.js +++ b/web/app/cad/expressions/expressionsPlugin.js @@ -1,6 +1,6 @@ -import {state, stream, merge} from 'lstream'; -import {indexArray} from '../../../../modules/gems/iterables'; -import {NOOP} from '../../../../modules/gems/func'; +import {merge, state} from 'lstream'; +import {indexArray} from 'gems/iterables'; +import {NOOP} from 'gems/func'; export function defineStreams(ctx) { const script = state(''); @@ -39,8 +39,10 @@ export function activate(ctx) { return value; } ctx.services.expressions = { - reevaluateExpressions, load, evaluateExpression + reevaluateExpressions, load, evaluateExpression, + signature: '' }; + ctx.streams.expressions.list.attach(list => ctx.services.expressions.signature = Date.now() + ''); ctx.services.action.registerAction({ id: 'expressionsUpdateTable', appearance: { diff --git a/web/app/cad/sketch/inPlaceSketcher.js b/web/app/cad/sketch/inPlaceSketcher.js index 1152b5e9..efd1d23d 100644 --- a/web/app/cad/sketch/inPlaceSketcher.js +++ b/web/app/cad/sketch/inPlaceSketcher.js @@ -19,7 +19,7 @@ export class InPlaceSketcher { return !!this.face } - enter(face) { + enter(face, headless) { let viewer3d = this.ctx.services.viewer; this.face = face; this.face.ext.view.sketchGroup.visible = false; @@ -34,6 +34,7 @@ export class InPlaceSketcher { container.appendChild(canvas); this.viewer = new Viewer(canvas, IO); + this.viewer.parametricManager.externalConstantResolver = this.ctx.services.expressions.evaluateExpression; this.ctx.streams.sketcherApp = this.viewer.streams; this.syncWithCamera(); @@ -45,7 +46,7 @@ export class InPlaceSketcher { this.viewer.io.loadSketch(sketchData); this.ctx.streams.sketcher.sketchingFace.value = face; } - + get sketchStorageKey() { return this.ctx.services.project.sketchStorageKey(this.face.id); } @@ -106,7 +107,9 @@ export class InPlaceSketcher { }; save() { - this.ctx.services.storage.set(this.sketchStorageKey, this.viewer.io.serializeSketch()); + this.ctx.services.storage.set(this.sketchStorageKey, this.viewer.io.serializeSketch({ + expressionsSignature: this.ctx.services.expressions.signature + })); } } diff --git a/web/app/cad/sketch/sketcherPlugin.js b/web/app/cad/sketch/sketcherPlugin.js index bfda96ad..e78b24af 100644 --- a/web/app/cad/sketch/sketcherPlugin.js +++ b/web/app/cad/sketch/sketcherPlugin.js @@ -5,6 +5,9 @@ import {InPlaceSketcher} from './inPlaceSketcher'; import sketcherUIContrib from './sketcherUIContrib'; import initReassignSketchMode from './reassignSketchMode'; import sketcherStreams from '../../sketcher/sketcherStreams'; +import {Viewer} from "../../sketcher/viewer2d"; +import {IO} from "../../sketcher/io"; +import {DelegatingPanTool} from "../../sketcher/tools/pan"; export function defineStreams(ctx) { ctx.streams.sketcher = { @@ -55,11 +58,34 @@ export function activate(ctx) { return services.storage.remove(sketchStorageKey); } + const headlessCanvas = document.createElement('canvas'); + document.createElement('div').appendChild(headlessCanvas); + function readSketch(sketchId) { let savedSketch = getSketchData(sketchId); if (savedSketch === null) { return null; } + + let signature = services.expressions.signature; + if (savedSketch && (!savedSketch.metadata || savedSketch.expressionsSignature !== signature)) { + try { + const viewer = new Viewer(headlessCanvas, IO); + viewer.parametricManager.externalConstantResolver = services.expressions.evaluateExpression; + viewer.historyManager.init(savedSketch); + viewer.io.loadSketch(savedSketch); + viewer.parametricManager.refresh(); + services.storage.set(services.project.sketchStorageKey(sketchId), viewer.io.serializeSketch({ + expressionsSignature: signature + }), true); + savedSketch = getSketchData(sketchId); + } catch (e) { + console.error(e); + return null; + } + } + + try { return ReadSketch(JSON.parse(savedSketch), sketchId, true); } catch (e) { @@ -132,7 +158,14 @@ export function activate(ctx) { } } }); - + streams.expressions.table.attach(() => { + if (inPlaceEditor.viewer !== null) { + inPlaceEditor.viewer.parametricManager.refresh(); + } + updateAllSketches(); + }); + + services.sketcher = { sketchFace, sketchFace2D, updateAllSketches, getAllSketches, readSketch, hasSketch, inPlaceEditor, reassignSketch, reassignSketchMode: initReassignSketchMode(ctx) diff --git a/web/app/cad/storagePlugin.js b/web/app/cad/storagePlugin.js index 5c9907a1..fd13820d 100644 --- a/web/app/cad/storagePlugin.js +++ b/web/app/cad/storagePlugin.js @@ -8,9 +8,11 @@ export function defineStreams(ctx) { export function activate({services, streams}) { - function set(key, value) { + function set(key, value, quiet) { localStorage.setItem(key, value); - notify(key); + if (!quiet) { + notify(key); + } } function get(key) { diff --git a/web/app/cad/tpi/tpiPlugin.js b/web/app/cad/tpi/tpiPlugin.js index 9664183f..e55271a7 100644 --- a/web/app/cad/tpi/tpiPlugin.js +++ b/web/app/cad/tpi/tpiPlugin.js @@ -12,7 +12,7 @@ export function activate({streams, services}) { return sceneSolid; } function addOnScene(sceneSolid, skin) { - services.cadRegistry.update(null, [sceneSolid]); + streams.craft.models.next([sceneSolid]); services.viewer.render(); } services.tpi = Object.assign({ diff --git a/web/app/math/vec.js b/web/app/math/vec.js index bb2520f0..65fccc89 100644 --- a/web/app/math/vec.js +++ b/web/app/math/vec.js @@ -1,6 +1,6 @@ export {dotVM} from 'numeric'; -function scalarOperand(v, out, func) { +export function scalarOperand(v, out, func) { for (let i = 0; i < v.length; i++) { out[i] = func(v[i]); } diff --git a/web/app/sketcher/io.js b/web/app/sketcher/io.js index 142c4d52..47502c69 100644 --- a/web/app/sketcher/io.js +++ b/web/app/sketcher/io.js @@ -43,8 +43,8 @@ IO.prototype.loadSketch = function(sketchData) { return this._loadSketch(JSON.parse(sketchData)); }; -IO.prototype.serializeSketch = function() { - return JSON.stringify(this._serializeSketch()); +IO.prototype.serializeSketch = function(metadata) { + return JSON.stringify(this._serializeSketch(metadata)); }; IO.prototype._loadSketch = function(sketch) { @@ -333,7 +333,7 @@ IO.prototype.cleanUpData = function() { } }; -IO.prototype._serializeSketch = function() { +IO.prototype._serializeSketch = function(metadata) { var sketch = {}; //sketch.boundary = boundary; sketch['layers'] = []; @@ -408,6 +408,7 @@ IO.prototype._serializeSketch = function() { if (constantDefinition !== undefined && constantDefinition != null && !/^\s*$/.test(constantDefinition)) { sketch['constants'] = constantDefinition; } + sketch.metadata = metadata; return sketch; }; diff --git a/web/app/sketcher/parametric.js b/web/app/sketcher/parametric.js index 494cdaea..a2886cfb 100644 --- a/web/app/sketcher/parametric.js +++ b/web/app/sketcher/parametric.js @@ -19,6 +19,7 @@ class ParametricManager { this.viewer.params.define('constantDefinition', null); this.viewer.params.subscribe('constantDefinition', 'parametricManager', this.onConstantsExternalChange, this)(); this.constantResolver = this.createConstantResolver(); + this.externalConstantResolver = null; this.messageSink = msg => alert(msg); } @@ -28,9 +29,11 @@ class ParametricManager { } ParametricManager.prototype.createConstantResolver = function() { - var pm = this; - return function(value) { - var _value = pm.constantTable[value]; + return value => { + var _value = this.constantTable[value]; + if (_value === undefined && this.externalConstantResolver) { + _value = this.externalConstantResolver(value); + } if (_value !== undefined) { value = _value; } else if (typeof(value) != 'number') {