mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 16:33:15 +01:00
use construction role instead of _construction_ layer, first approach to sketch object explorer
This commit is contained in:
parent
4713cc1fc8
commit
05f238d08a
25 changed files with 747 additions and 490 deletions
|
|
@ -30,6 +30,10 @@ export class StreamBase {
|
|||
distinct() {
|
||||
return new DistinctStream(this);
|
||||
}
|
||||
|
||||
throttle(delay, accumulator) {
|
||||
return new ThrottleStream(this, delay, accumulator);
|
||||
}
|
||||
}
|
||||
|
||||
const {MapStream} = require('./map');
|
||||
|
|
@ -38,3 +42,4 @@ const {StateStream} = require('./state');
|
|||
const {PairwiseStream} = require('./pairwise');
|
||||
const {ScanStream} = require('./scan');
|
||||
const {DistinctStream} = require('./distinct');
|
||||
const {ThrottleStream} = require('./throttle');
|
||||
|
|
|
|||
26
modules/lstream/throttle.js
Normal file
26
modules/lstream/throttle.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import {StreamBase} from './base';
|
||||
import {Emitter} from './emitter';
|
||||
|
||||
export class ThrottleStream extends StreamBase {
|
||||
|
||||
constructor(stream, delay = 0, accumulator = v => v) {
|
||||
super();
|
||||
this.stream = stream;
|
||||
this.delay = delay;
|
||||
this.accumulator = accumulator;
|
||||
}
|
||||
|
||||
attach(observer) {
|
||||
let scheduled = false;
|
||||
let value = undefined;
|
||||
this.stream.attach(val => {
|
||||
value = this.accumulator(val);
|
||||
if (!scheduled) {
|
||||
setTimeout(() => {
|
||||
scheduled = false;
|
||||
observer(value);
|
||||
});
|
||||
}
|
||||
}, this.delay)
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
font-size: 10px;
|
||||
padding: 3px 7px;
|
||||
color: #555;
|
||||
pointer-events: auto;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: #333;
|
||||
|
|
|
|||
13
web/app/cad/dom/components/SketcherMode.jsx
Normal file
13
web/app/cad/dom/components/SketcherMode.jsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import connect from 'ui/connect';
|
||||
|
||||
@connect(streams => streams.sketcher.sketchingMode.map(sketchingMode => ({visible: sketchingMode})))
|
||||
export default class SketcherMode extends React.Component {
|
||||
|
||||
render() {
|
||||
if (!this.props.visible) {
|
||||
return null;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,14 @@
|
|||
import React from 'react';
|
||||
import ls from './SketcherToolbars.less';
|
||||
import Abs from 'ui/components/Abs';
|
||||
import {createPlugableToolbar} from './PlugableToolbar';
|
||||
import connect from 'ui/connect';
|
||||
|
||||
export default connect(streams => streams.ui.toolbars.sketcherToolbarsVisible.map(visible => ({visible})))(
|
||||
function SketcherToolbars({visible}) {
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
return <Abs right={0} className={ls.sketcherToolbars}>
|
||||
export default function SketcherToolbars({visible}) {
|
||||
return <div className={ls.sketcherToolbars}>
|
||||
<SketcherToolbarControl size='small'/>
|
||||
<SketcherToolbarConstraints size='medium' vertical/>
|
||||
<SketcherToolbarGeneral size='medium' vertical/>
|
||||
</Abs>;
|
||||
})
|
||||
</div>;
|
||||
}
|
||||
|
||||
const SketcherToolbarGeneral = createPlugableToolbar(streams => streams.ui.toolbars.sketcherGeneral);
|
||||
const SketcherToolbarConstraints = createPlugableToolbar(streams => streams.ui.toolbars.sketcherConstraints);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
.sketcherToolbars {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.sketcherToolbars > * {
|
||||
margin-right: 5px;
|
||||
max-height: 100%;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import SketcherToolbars from './SketcherToolbars';
|
|||
import CameraControl from './CameraControl';
|
||||
import HeadsUpHelper from './HeadsUpHelper';
|
||||
import {HeadsUpToolbar} from './HeadsUpToolbar';
|
||||
import {SketchObjectExplorer} from '../../../sketcher/components/SketchObjectExplorer';
|
||||
import SketcherMode from './SketcherMode';
|
||||
|
||||
|
||||
export default class View3d extends React.Component {
|
||||
|
|
@ -26,17 +28,37 @@ export default class View3d extends React.Component {
|
|||
<FloatView />
|
||||
<div className={ls.mainArea} >
|
||||
<div id='viewer-container' />
|
||||
<Abs left={0} right={0} top={0}>
|
||||
<HeadsUpToolbar/>
|
||||
<HeadsUpHelper/>
|
||||
<WizardManager/>
|
||||
<SketcherToolbars />
|
||||
</Abs>
|
||||
<BottomStack>
|
||||
<CameraControl />
|
||||
<HistoryTimeline />
|
||||
<PlugableControlBar/>
|
||||
</BottomStack>
|
||||
|
||||
<div className={ls.mainLayout}>
|
||||
<div className={ls.headsUp}>
|
||||
<HeadsUpToolbar/>
|
||||
<HeadsUpHelper/>
|
||||
</div>
|
||||
|
||||
<div className={ls.middleSection}>
|
||||
<SketcherMode>
|
||||
<div className={ls.overlayingPanel} >
|
||||
<SketchObjectExplorer />
|
||||
</div>
|
||||
</SketcherMode>
|
||||
<div className={ls.wizardArea} >
|
||||
<WizardManager/>
|
||||
</div>
|
||||
<SketcherMode>
|
||||
<div className={ls.spring} />
|
||||
<div className={ls.middleRight}>
|
||||
<SketcherToolbars />
|
||||
</div>
|
||||
</SketcherMode>
|
||||
</div>
|
||||
|
||||
<div className={ls.bottomStack}>
|
||||
<CameraControl />
|
||||
<HistoryTimeline />
|
||||
<PlugableControlBar/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<SelectedModificationInfo />
|
||||
</UISystem>;
|
||||
|
|
|
|||
|
|
@ -22,3 +22,52 @@
|
|||
overflow: hidden;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.mainLayout {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.headsUp {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.middleSection {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.overlayingPanel {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.wizardArea {
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.spring {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.middleRight {
|
||||
height: 100%;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.bottomStack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
|
@ -12,8 +12,7 @@ export function defineStreams({streams}) {
|
|||
headsUpQuickActions: state([]),
|
||||
sketcherGeneral: state([]),
|
||||
sketcherConstraints: state([]),
|
||||
sketcherControl: state([]),
|
||||
sketcherToolbarsVisible: state(false)
|
||||
sketcherControl: state([])
|
||||
},
|
||||
floatViews: state([]),
|
||||
sockets: {}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ import {Matrix4} from 'three/src/math/Matrix4';
|
|||
import {ORIGIN} from '../../math/l3space';
|
||||
import {CAMERA_MODE} from '../scene/viewer';
|
||||
import DPR from 'dpr';
|
||||
import sketcherStreams from '../../sketcher/sketcherStreams';
|
||||
|
||||
export class InPlaceSketcher {
|
||||
|
||||
constructor(ctx) {
|
||||
this.face = null; // should be only one in the state
|
||||
this.ctx = ctx;
|
||||
this.viewer = null;
|
||||
}
|
||||
|
||||
get inEditMode() {
|
||||
|
|
@ -32,6 +34,8 @@ export class InPlaceSketcher {
|
|||
|
||||
container.appendChild(canvas);
|
||||
this.viewer = new Viewer(canvas, IO);
|
||||
this.ctx.streams.sketcherApp = this.viewer.streams;
|
||||
|
||||
this.syncWithCamera();
|
||||
this.viewer.toolManager.setDefaultTool(new DelegatingPanTool(this.viewer, viewer3d.sceneSetup.renderer.domElement));
|
||||
viewer3d.sceneSetup.trackballControls.addEventListener( 'change', this.onCameraChange);
|
||||
|
|
@ -55,7 +59,9 @@ export class InPlaceSketcher {
|
|||
this.face = null;
|
||||
this.viewer.canvas.parentNode.removeChild(this.viewer.canvas);
|
||||
this.viewer.dispose();
|
||||
this.viewer = null;
|
||||
this.ctx.streams.sketcher.sketchingFace.value = null;
|
||||
this.ctx.streams.sketcherApp = null;
|
||||
viewer3d.requestRender();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,15 +74,18 @@ export function ReadSketch(sketch, sketchId, readConstructionSegments) {
|
|||
if (sketch.layers !== undefined) {
|
||||
for (let layer of sketch.layers) {
|
||||
const isConstructionLayer = layer.name === "_construction_";
|
||||
if (isConstructionLayer && !readConstructionSegments) continue;
|
||||
|
||||
for (let obj of layer.data) {
|
||||
if (isConstructionLayer && obj._class !== 'TCAD.TWO.Segment') continue;
|
||||
let isConstructionObject = isConstructionLayer || obj.role === 'construction';
|
||||
if (isConstructionObject && !readConstructionSegments) continue;
|
||||
// if (isConstructionObject && obj._class !== 'TCAD.TWO.Segment') continue;
|
||||
|
||||
if (obj.edge !== undefined) continue;
|
||||
if (!!obj.aux) continue;
|
||||
if (obj._class === 'TCAD.TWO.Segment') {
|
||||
const segA = ReadSketchPoint(obj.points[0]);
|
||||
const segB = ReadSketchPoint(obj.points[1]);
|
||||
const pushOn = isConstructionLayer ? out.constructionSegments : out.connections;
|
||||
const pushOn = isConstructionObject ? out.constructionSegments : out.connections;
|
||||
pushOn.push(new sm.Segment(getID(obj), segA, segB));
|
||||
} else if (obj._class === 'TCAD.TWO.Arc') {
|
||||
const arcA = ReadSketchPoint(obj.points[0]);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ import {state, stream} from 'lstream';
|
|||
import {InPlaceSketcher} from './inPlaceSketcher';
|
||||
import sketcherUIContrib from './sketcherUIContrib';
|
||||
import initReassignSketchMode from './reassignSketchMode';
|
||||
import sketcherStreams from '../../sketcher/sketcherStreams';
|
||||
|
||||
export function defineStreams(ctx) {
|
||||
ctx.streams.sketcher = {
|
||||
update: stream(),
|
||||
sketchingFace: state(null)
|
||||
};
|
||||
ctx.streams.sketcher.sketchingMode = ctx.streams.sketcher.sketchingFace.map(face => !!face);
|
||||
}
|
||||
|
||||
export function activate(ctx) {
|
||||
|
||||
|
|
@ -11,13 +20,6 @@ export function activate(ctx) {
|
|||
|
||||
sketcherUIContrib(ctx);
|
||||
|
||||
streams.sketcher = {
|
||||
update: stream(),
|
||||
sketchingFace: state(null)
|
||||
};
|
||||
|
||||
streams.sketcher.sketchingFace.attach(face => streams.ui.toolbars.sketcherToolbarsVisible.value = !!face);
|
||||
|
||||
const onSketchUpdate = evt => {
|
||||
let prefix = services.project.sketchStorageNamespace;
|
||||
if (evt.key.indexOf(prefix) < 0) return;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,14 @@ function initializeSketcherApplication() {
|
|||
app.viewer.parametricManager.listeners.push(function() {constrList.refresh()});
|
||||
constrList.refresh();
|
||||
|
||||
|
||||
var addingModeRadio = new toolkit.InlineRadio(['sketch', 'construction'], ['sketch', 'construction'], 0);
|
||||
app.dock.views['Properties'].node.append('<div>Adding Mode</div>').append(addingModeRadio.root);
|
||||
|
||||
addingModeRadio.root.find('input:radio').change(() => {
|
||||
app.viewer.addingRoleMode = addingModeRadio.getValue();
|
||||
});
|
||||
|
||||
var layerSelection = new toolkit.Combo('layerSelection', 'Layer');
|
||||
app.dock.views['Properties'].node.append(layerSelection.root);
|
||||
|
||||
|
|
|
|||
0
web/app/sketcher/components/Commands.jsx
Normal file
0
web/app/sketcher/components/Commands.jsx
Normal file
0
web/app/sketcher/components/ContraintExplorer.jsx
Normal file
0
web/app/sketcher/components/ContraintExplorer.jsx
Normal file
39
web/app/sketcher/components/SketchObjectExplorer.jsx
Normal file
39
web/app/sketcher/components/SketchObjectExplorer.jsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import ls from './SketchObjectExplorer.less'
|
||||
|
||||
import connect from 'ui/connect';
|
||||
|
||||
@connect(streams => streams.sketcherApp.objects.map(objects => ({objects})))
|
||||
export class SketchObjectExplorer extends React.Component {
|
||||
|
||||
render() {
|
||||
const {objects} = this.props;
|
||||
return <div>
|
||||
{objects.map(o => <div className={cx(ls.objectItem, getClassName(o))}>
|
||||
<span className={ls.objectIcon}><img width="15px" src='img/vec/pointOnArc.svg' /></span>
|
||||
{getObjectRole(o)}
|
||||
<span className={ls.objectTag}>{o.simpleClassName}</span>
|
||||
<span>{o.id}</span>
|
||||
<span className={ls.menuButton}></span>
|
||||
</div>)}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
function getObjectRole(o) {
|
||||
if (o.aux) {
|
||||
return <span title="object is a readonly 3D feature/boundary" className={cx(ls.objectRole, ls.aux)}>B</span>
|
||||
} else if (o.role) {
|
||||
return <span title="object is a readonly 3D feature/boundary" className={cx(ls.objectRole, ls.aux)}>B</span>
|
||||
}
|
||||
}
|
||||
|
||||
function ObjectIcon({object}) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getClassName() {
|
||||
return null;
|
||||
}
|
||||
25
web/app/sketcher/components/SketchObjectExplorer.less
Normal file
25
web/app/sketcher/components/SketchObjectExplorer.less
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
.objectItem {
|
||||
background-color: rgba(0,0,0, 0.6);
|
||||
border: 1px solid #000;
|
||||
border-radius: 5px;
|
||||
padding: 3px 5px;
|
||||
margin: 2px 5px;
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@alt-color: #9c9c9c;
|
||||
.objectIcon {
|
||||
background-color: @alt-color;
|
||||
}
|
||||
|
||||
.menuButton {
|
||||
background-color: @alt-color;
|
||||
}
|
||||
|
||||
.objectTag {
|
||||
display: inline-block;
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
0
web/app/sketcher/components/SketchSettings.jsx
Normal file
0
web/app/sketcher/components/SketchSettings.jsx
Normal file
|
|
@ -80,7 +80,7 @@ IO.prototype._loadSketch = function(sketch) {
|
|||
}
|
||||
}
|
||||
}
|
||||
var layer = new Layer(name, Styles.DEFAULT);
|
||||
var layer = viewer.createLayer(name, Styles.DEFAULT);
|
||||
viewer.layers.push(layer);
|
||||
return layer;
|
||||
}
|
||||
|
|
@ -103,6 +103,12 @@ IO.prototype._loadSketch = function(sketch) {
|
|||
var skobj = null;
|
||||
var _class = obj['_class'];
|
||||
var aux = !!obj['aux'];
|
||||
var role = obj['role'];
|
||||
|
||||
//support legacy format
|
||||
if (!role && layerName === '_construction_') {
|
||||
role = 'construction';
|
||||
}
|
||||
|
||||
if (boundaryProcessing) {
|
||||
if (_class === T.SEGMENT && boundary.lines.length == 0) continue;
|
||||
|
|
@ -158,6 +164,7 @@ IO.prototype._loadSketch = function(sketch) {
|
|||
skobj = new DiameterDimension(obj['obj']);
|
||||
}
|
||||
if (skobj != null) {
|
||||
skobj.role = role;
|
||||
if (!aux) skobj.stabilize(this.viewer);
|
||||
if (aux) skobj.accept(function(o){o.aux = true; return true;});
|
||||
if (obj['edge'] !== undefined) {
|
||||
|
|
@ -265,7 +272,7 @@ IO.prototype.addNewBoundaryObjects = function(boundary, maxEdge) {
|
|||
var boundaryLayer = this.viewer.findLayerByName(IO.BOUNDARY_LAYER_NAME);
|
||||
|
||||
if (boundaryLayer === null) {
|
||||
boundaryLayer = new Layer(IO.BOUNDARY_LAYER_NAME, Styles.BOUNDS);
|
||||
boundaryLayer = this.viewer.createLayer(IO.BOUNDARY_LAYER_NAME, Styles.BOUNDS);
|
||||
this.viewer.layers.splice(0, 0, boundaryLayer);
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +350,7 @@ IO.prototype._serializeSketch = function() {
|
|||
sketch['layers'].push(toLayer);
|
||||
for (var i = 0; i < layer.objects.length; ++i) {
|
||||
var obj = layer.objects[i];
|
||||
var to = {'id': obj.id, '_class': obj._class};
|
||||
var to = {'id': obj.id, '_class': obj._class, role: obj.role};
|
||||
if (obj.aux) to.aux = obj.aux;
|
||||
if (obj.edge !== undefined) to.edge = obj.edge;
|
||||
toLayer['data'].push(to);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class BezierCurve extends SketchObject {
|
|||
this.addChild(new Segment(a, cp1));
|
||||
this.addChild(new Segment(b, cp2));
|
||||
for (let c of this.children) {
|
||||
c.role = 'construction';
|
||||
c.role = 'objectConstruction';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ export class SketchObject extends Shape {
|
|||
this.visitParams(p => params.push(p));
|
||||
}
|
||||
|
||||
get simpleClassName() {
|
||||
return this._class.replace('TCAD.TWO.', '');
|
||||
}
|
||||
|
||||
get effectiveLayer() {
|
||||
let shape = this;
|
||||
while (shape) {
|
||||
|
|
|
|||
17
web/app/sketcher/sketcherStreams.js
Normal file
17
web/app/sketcher/sketcherStreams.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import {state, stream} from 'lstream';
|
||||
|
||||
export default function(viewer) {
|
||||
|
||||
const streams = {};
|
||||
|
||||
streams.objectsUpdate = stream();
|
||||
streams.objects = streams.objectsUpdate.throttle().map(() => {
|
||||
let objects = [];
|
||||
viewer.layers.forEach(l => l.objects.forEach(o => objects.push(o)));
|
||||
return objects;
|
||||
}).remember([]);
|
||||
|
||||
streams.addingRoleMode = state(null);
|
||||
|
||||
return streams;
|
||||
};
|
||||
|
|
@ -13,497 +13,532 @@ import Vector from 'math/vector';
|
|||
|
||||
import * as draw_utils from './shapes/draw-utils';
|
||||
import {Matrix3} from '../math/l3space';
|
||||
import sketcherStreams from './sketcherStreams';
|
||||
|
||||
/** @constructor */
|
||||
function Viewer(canvas, IO) {
|
||||
|
||||
// 1/1000'' aka 1 mil is a standard precision for the imperial system(for engeneering)
|
||||
// this precision also covers the metric system which is supposed to be ~0.01
|
||||
// this field is used only for displaying purposes now, although in future it could be
|
||||
// used to keep all internal data with such precision transforming the input from user
|
||||
this.presicion = 3;
|
||||
this.canvas = canvas;
|
||||
this.params = new Parameters();
|
||||
this.io = new IO(this);
|
||||
var viewer = this;
|
||||
this.retinaPxielRatio = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1;
|
||||
function updateCanvasSize() {
|
||||
var canvasWidth = canvas.parentNode.offsetWidth;
|
||||
var canvasHeight = canvas.parentNode.offsetHeight;
|
||||
class Viewer {
|
||||
|
||||
canvas.width = canvasWidth * viewer.retinaPxielRatio;
|
||||
canvas.height = canvasHeight * viewer.retinaPxielRatio;
|
||||
constructor(canvas, IO) {
|
||||
|
||||
canvas.style.width = canvasWidth + "px";
|
||||
canvas.style.height = canvasHeight + "px";
|
||||
}
|
||||
// 1/1000'' aka 1 mil is a standard precision for the imperial system(for engeneering)
|
||||
// this precision also covers the metric system which is supposed to be ~0.01
|
||||
// this field is used only for displaying purposes now, although in future it could be
|
||||
// used to keep all internal data with such precision transforming the input from user
|
||||
this.presicion = 3;
|
||||
this.canvas = canvas;
|
||||
this.params = new Parameters();
|
||||
this.io = new IO(this);
|
||||
this.streams = sketcherStreams(this);
|
||||
var viewer = this;
|
||||
this.retinaPxielRatio = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1;
|
||||
|
||||
this.onWindowResize = function() {
|
||||
function updateCanvasSize() {
|
||||
var canvasWidth = canvas.parentNode.offsetWidth;
|
||||
var canvasHeight = canvas.parentNode.offsetHeight;
|
||||
|
||||
canvas.width = canvasWidth * viewer.retinaPxielRatio;
|
||||
canvas.height = canvasHeight * viewer.retinaPxielRatio;
|
||||
|
||||
canvas.style.width = canvasWidth + "px";
|
||||
canvas.style.height = canvasHeight + "px";
|
||||
}
|
||||
|
||||
this.onWindowResize = function () {
|
||||
updateCanvasSize();
|
||||
viewer.refresh();
|
||||
};
|
||||
updateCanvasSize();
|
||||
viewer.refresh();
|
||||
};
|
||||
updateCanvasSize();
|
||||
window.addEventListener( 'resize', this.onWindowResize, false );
|
||||
window.addEventListener('resize', this.onWindowResize, false);
|
||||
|
||||
Object.defineProperty(this, "activeLayer", {
|
||||
get: viewer.getActiveLayer ,
|
||||
set: viewer.setActiveLayer
|
||||
});
|
||||
Object.defineProperty(this, "activeLayer", {
|
||||
get: viewer.getActiveLayer,
|
||||
set: viewer.setActiveLayer
|
||||
});
|
||||
|
||||
this.bus = new Bus();
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this._activeLayer = null;
|
||||
this.layers = [
|
||||
new Layer("sketch", Styles.DEFAULT),
|
||||
new Layer("_construction_", Styles.CONSTRUCTION)
|
||||
];
|
||||
this.dimLayer = new Layer("_dim", Styles.DIM);
|
||||
this.dimLayers = [this.dimLayer];
|
||||
this.bus.defineObservable(this, 'dimScale', 1);
|
||||
this.bus.subscribe('dimScale', function(){ viewer.refresh(); });
|
||||
this.bus = new Bus();
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this._activeLayer = null;
|
||||
this.layers = [
|
||||
this.createLayer("sketch", Styles.DEFAULT)
|
||||
// this.createLayer("_construction_", Styles.CONSTRUCTION)
|
||||
];
|
||||
this.dimLayer = this.createLayer("_dim", Styles.DIM);
|
||||
this.dimLayers = [this.dimLayer];
|
||||
this.bus.defineObservable(this, 'dimScale', 1);
|
||||
this.bus.subscribe('dimScale', function () {
|
||||
viewer.refresh();
|
||||
});
|
||||
|
||||
this._workspace = [this.layers, this.dimLayers];
|
||||
this._workspace = [this.layers, this.dimLayers];
|
||||
|
||||
this.referencePoint = new ReferencePoint();
|
||||
this._serviceWorkspace = [this._createServiceLayers()];
|
||||
this.referencePoint = new ReferencePoint();
|
||||
this._serviceWorkspace = [this._createServiceLayers()];
|
||||
|
||||
this.toolManager = new ToolManager(this, new PanTool(this));
|
||||
this.parametricManager = new ParametricManager(this);
|
||||
this.toolManager = new ToolManager(this, new PanTool(this));
|
||||
this.parametricManager = new ParametricManager(this);
|
||||
|
||||
this.translate = {x : 0.0, y : 0.0};
|
||||
this.scale = 1.0;
|
||||
this.translate = {x: 0.0, y: 0.0};
|
||||
this.scale = 1.0;
|
||||
|
||||
this.selected = [];
|
||||
this.snapped = null;
|
||||
|
||||
this.historyManager = new HistoryManager(this);
|
||||
this.transformation = null;
|
||||
this.screenToModelMatrix = null;
|
||||
this.validators = [];
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
Viewer.prototype.dispose = function() {
|
||||
window.removeEventListener( 'resize', this.onWindowResize, false );
|
||||
this.canvas = null;
|
||||
this.toolManager.dispose();
|
||||
};
|
||||
|
||||
Viewer.prototype.isDisposed = function() {
|
||||
return this.canvas === null;
|
||||
};
|
||||
|
||||
Viewer.prototype.setTransformation = function(a, b, c, d, e, f, zoom) {
|
||||
this.transformation = [a, b, c, d, e, f];
|
||||
this.scale = zoom;
|
||||
if (this.screenToModelMatrix === null) {
|
||||
this.screenToModelMatrix = new Matrix3();
|
||||
}
|
||||
this.screenToModelMatrix.set34(
|
||||
a, c, 0, e,
|
||||
b, d, 0, f,
|
||||
0, 0, 1, 0
|
||||
)._invert();
|
||||
};
|
||||
|
||||
Viewer.prototype.roundToPrecision = function(value) {
|
||||
return value.toFixed(this.presicion);
|
||||
};
|
||||
|
||||
Viewer.prototype.addSegment = function(x1, y1, x2, y2, layer) {
|
||||
var a = new EndPoint(x1, y1);
|
||||
var b = new EndPoint(x2, y2);
|
||||
var line = new Segment(a, b);
|
||||
layer.add(line);
|
||||
return line;
|
||||
};
|
||||
|
||||
Viewer.prototype.remove = function(obj) {
|
||||
this.removeAll([obj]);
|
||||
};
|
||||
|
||||
Viewer.prototype.removeAll = function(objects) {
|
||||
this.parametricManager.removeObjects(objects);
|
||||
};
|
||||
|
||||
Viewer.prototype.add = function(obj, layer) {
|
||||
layer.add(obj);
|
||||
};
|
||||
|
||||
function isEndPoint(o) {
|
||||
return o._class === 'TCAD.TWO.EndPoint'
|
||||
}
|
||||
|
||||
Viewer.prototype.search = function(x, y, buffer, deep, onlyPoints, filter) {
|
||||
|
||||
buffer *= 0.5;
|
||||
|
||||
var pickResult = [];
|
||||
var aim = new Vector(x, y);
|
||||
|
||||
var heroIdx = 0;
|
||||
var unreachable = buffer * 2;
|
||||
var heroLength = unreachable; // unreachable
|
||||
|
||||
function isFiltered(o) {
|
||||
for (var i = 0; i < filter.length; ++i) {
|
||||
if (filter[i] === o) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
var objs = this.layers[i].objects;
|
||||
for (var j = 0; j < objs.length; j++) {
|
||||
var l = unreachable + 1;
|
||||
var before = pickResult.length;
|
||||
objs[j].accept((o) => {
|
||||
if (!o.visible) return true;
|
||||
if (onlyPoints && !isEndPoint(o)) {
|
||||
return true;
|
||||
}
|
||||
l = o.normalDistance(aim, this.scale);
|
||||
if (l >= 0 && l <= buffer && !isFiltered(o)) {
|
||||
pickResult.push(o);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
var hit = before - pickResult.length != 0;
|
||||
if (hit) {
|
||||
if (!deep && pickResult.length != 0) return pickResult;
|
||||
if (l >= 0 && l < heroLength) {
|
||||
heroLength = l;
|
||||
heroIdx = pickResult.length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pickResult.length > 0) {
|
||||
var _f = pickResult[0];
|
||||
pickResult[0] = pickResult[heroIdx];
|
||||
pickResult[heroIdx] = _f;
|
||||
}
|
||||
return pickResult;
|
||||
};
|
||||
|
||||
Viewer.prototype._createServiceLayers = function() {
|
||||
let layer = new Layer("_service", Styles.SERVICE);
|
||||
// layer.objects.push(new CrossHair(0, 0, 20));
|
||||
layer.objects.push(new Point(0, 0, 2));
|
||||
layer.objects.push(this.referencePoint);
|
||||
layer.objects.push(new BasisOrigin(null, this));
|
||||
return [layer];
|
||||
|
||||
};
|
||||
|
||||
Viewer.prototype.refresh = function() {
|
||||
const viewer = this;
|
||||
window.requestAnimationFrame(function() {
|
||||
if (!viewer.isDisposed()) {
|
||||
viewer.repaint();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Viewer.prototype.repaint = function() {
|
||||
|
||||
const ctx = this.ctx;
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
|
||||
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
ctx.transform(1, 0, 0, -1, 0, this.canvas.height );
|
||||
|
||||
if (this.transformation) {
|
||||
let [a, b, c, d, e, f] = this.transformation;
|
||||
ctx.transform(a, b, c, d, e, f);
|
||||
} else {
|
||||
ctx.transform(1, 0, 0, 1, this.translate.x , this.translate.y );
|
||||
ctx.transform(this.scale, 0, 0, this.scale, 0, 0);
|
||||
}
|
||||
|
||||
this.__prevStyle = null;
|
||||
|
||||
this.__drawWorkspace(ctx, this._workspace, Viewer.__SKETCH_DRAW_PIPELINE);
|
||||
this.__drawWorkspace(ctx, this._serviceWorkspace, Viewer.__SIMPLE_DRAW_PIPELINE);
|
||||
};
|
||||
|
||||
Viewer.__SKETCH_DRAW_PIPELINE = [
|
||||
(obj) => !isEndPoint(obj) && obj.marked === null,
|
||||
(obj) => !isEndPoint(obj) && obj.marked !== null,
|
||||
(obj) => isEndPoint(obj) && obj.marked === null,
|
||||
(obj) => isEndPoint(obj) && obj.marked !== null
|
||||
];
|
||||
|
||||
Viewer.__SIMPLE_DRAW_PIPELINE = [
|
||||
(obj) => true
|
||||
];
|
||||
|
||||
Viewer.prototype.__drawWorkspace = function(ctx, workspace, pipeline) {
|
||||
for (let drawPredicate of pipeline) {
|
||||
for (let layers of workspace) {
|
||||
for (let layer of layers) {
|
||||
for (let obj of layer.objects) {
|
||||
obj.accept((obj) => {
|
||||
if (!obj.visible) return true;
|
||||
if (drawPredicate(obj)) {
|
||||
this.__draw(ctx, layer, obj);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.__draw = function(ctx, layer, obj) {
|
||||
const style = this.getStyleForObject(layer, obj);
|
||||
if (style !== this.__prevStyle) {
|
||||
this.setStyle(style, ctx);
|
||||
}
|
||||
this.__prevStyle = style;
|
||||
obj.draw(ctx, this.scale / this.retinaPxielRatio, this);
|
||||
};
|
||||
|
||||
Viewer.prototype.getStyleForObject = function(layer, obj) {
|
||||
if (obj.style != null) {
|
||||
return obj.style;
|
||||
} else if (obj.role != null) {
|
||||
const style = layer.stylesByRoles[obj.role];
|
||||
if (style) {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
return layer.style;
|
||||
};
|
||||
|
||||
Viewer.prototype.setStyle = function(style, ctx) {
|
||||
draw_utils.SetStyle(style, ctx, this.scale / this.retinaPxielRatio);
|
||||
};
|
||||
|
||||
Viewer.prototype.snap = function(x, y, excl) {
|
||||
this.cleanSnap();
|
||||
var snapTo = this.search(x, y, 20 / this.scale, true, true, excl);
|
||||
if (snapTo.length > 0) {
|
||||
this.snapped = snapTo[0];
|
||||
this.mark(this.snapped, Styles.SNAP);
|
||||
}
|
||||
return this.snapped;
|
||||
};
|
||||
|
||||
Viewer.prototype.cleanSnap = function() {
|
||||
if (this.snapped != null) {
|
||||
this.deselect(this.snapped);
|
||||
this.selected = [];
|
||||
this.snapped = null;
|
||||
|
||||
this.historyManager = new HistoryManager(this);
|
||||
this.transformation = null;
|
||||
this.screenToModelMatrix = null;
|
||||
this.validators = [];
|
||||
this.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.showBounds = function(x1, y1, x2, y2, offset) {
|
||||
var dx = Math.max(x2 - x1, 1);
|
||||
var dy = Math.max(y2 - y1, 1);
|
||||
if (this.canvas.width > this.canvas.height) {
|
||||
this.scale = this.canvas.height / dy;
|
||||
} else {
|
||||
this.scale = this.canvas.width / dx;
|
||||
}
|
||||
this.translate.x = -x1 * this.scale;
|
||||
this.translate.y = -y1 * this.scale;
|
||||
};
|
||||
dispose() {
|
||||
window.removeEventListener('resize', this.onWindowResize, false);
|
||||
this.canvas = null;
|
||||
this.toolManager.dispose();
|
||||
};
|
||||
|
||||
Viewer.prototype.screenToModel2 = function(x, y, out) {
|
||||
out.x = x * this.retinaPxielRatio;
|
||||
out.y = this.canvas.height - y * this.retinaPxielRatio;
|
||||
isDisposed() {
|
||||
return this.canvas === null;
|
||||
};
|
||||
|
||||
if (this.transformation) {
|
||||
out.z = 0;
|
||||
this.screenToModelMatrix._apply(out);
|
||||
} else {
|
||||
out.x -= this.translate.x;
|
||||
out.y -= this.translate.y;
|
||||
setTransformation(a, b, c, d, e, f, zoom) {
|
||||
this.transformation = [a, b, c, d, e, f];
|
||||
this.scale = zoom;
|
||||
if (this.screenToModelMatrix === null) {
|
||||
this.screenToModelMatrix = new Matrix3();
|
||||
}
|
||||
this.screenToModelMatrix.set34(
|
||||
a, c, 0, e,
|
||||
b, d, 0, f,
|
||||
0, 0, 1, 0
|
||||
)._invert();
|
||||
};
|
||||
|
||||
out.x /= this.scale;
|
||||
out.y /= this.scale;
|
||||
}
|
||||
};
|
||||
roundToPrecision(value) {
|
||||
return value.toFixed(this.presicion);
|
||||
};
|
||||
|
||||
Viewer.prototype.screenToModel = function(e) {
|
||||
return this._screenToModel(e.offsetX, e.offsetY);
|
||||
};
|
||||
addSegment(x1, y1, x2, y2, layer) {
|
||||
var a = new EndPoint(x1, y1);
|
||||
var b = new EndPoint(x2, y2);
|
||||
var line = new Segment(a, b);
|
||||
layer.add(line);
|
||||
return line;
|
||||
};
|
||||
|
||||
Viewer.prototype._screenToModel = function(x, y) {
|
||||
var out = {x: 0, y: 0};
|
||||
this.screenToModel2(x, y, out);
|
||||
return out;
|
||||
};
|
||||
remove(obj) {
|
||||
this.removeAll([obj]);
|
||||
};
|
||||
|
||||
Viewer.prototype.accept = function(visitor) {
|
||||
for (let layer of this.layers) {
|
||||
for (let object of layer.objects) {
|
||||
if (!object.accept(visitor)) {
|
||||
return false;
|
||||
removeAll(objects) {
|
||||
this.parametricManager.removeObjects(objects);
|
||||
};
|
||||
|
||||
add(obj, layer) {
|
||||
layer.add(obj);
|
||||
};
|
||||
|
||||
search(x, y, buffer, deep, onlyPoints, filter) {
|
||||
|
||||
buffer *= 0.5;
|
||||
|
||||
var pickResult = [];
|
||||
var aim = new Vector(x, y);
|
||||
|
||||
var heroIdx = 0;
|
||||
var unreachable = buffer * 2;
|
||||
var heroLength = unreachable; // unreachable
|
||||
|
||||
function isFiltered(o) {
|
||||
for (var i = 0; i < filter.length; ++i) {
|
||||
if (filter[i] === o) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.findLayerByName = function(name) {
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
if (this.layers[i].name == name) {
|
||||
return this.layers[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Viewer.prototype.findById = function(id) {
|
||||
var result = null;
|
||||
this.accept(function(o) {
|
||||
if (o.id === id) {
|
||||
result = o;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
Viewer.prototype.select = function(objs, exclusive) {
|
||||
if (exclusive) this.deselectAll();
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
this.mark(objs[i]);
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.pick = function(e) {
|
||||
var m = this.screenToModel(e);
|
||||
return this.search(m.x, m.y, 20 / this.scale, true, false, []);
|
||||
};
|
||||
|
||||
Viewer.prototype.mark = function(obj, style) {
|
||||
if (style === undefined) {
|
||||
style = Styles.MARK;
|
||||
}
|
||||
obj.marked = style;
|
||||
|
||||
if (this.selected.indexOf(obj) == -1) {
|
||||
this.selected.push(obj);
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.getActiveLayer = function() {
|
||||
var layer = this._activeLayer;
|
||||
if (layer == null || layer.readOnly) {
|
||||
layer = null;
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
var l = this.layers[i];
|
||||
if (!l.readOnly) {
|
||||
layer = l;
|
||||
var objs = this.layers[i].objects;
|
||||
for (var j = 0; j < objs.length; j++) {
|
||||
var l = unreachable + 1;
|
||||
var before = pickResult.length;
|
||||
objs[j].accept((o) => {
|
||||
if (!o.visible) return true;
|
||||
if (onlyPoints && !isEndPoint(o)) {
|
||||
return true;
|
||||
}
|
||||
l = o.normalDistance(aim, this.scale);
|
||||
if (l >= 0 && l <= buffer && !isFiltered(o)) {
|
||||
pickResult.push(o);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
var hit = before - pickResult.length != 0;
|
||||
if (hit) {
|
||||
if (!deep && pickResult.length != 0) return pickResult;
|
||||
if (l >= 0 && l < heroLength) {
|
||||
heroLength = l;
|
||||
heroIdx = pickResult.length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pickResult.length > 0) {
|
||||
var _f = pickResult[0];
|
||||
pickResult[0] = pickResult[heroIdx];
|
||||
pickResult[heroIdx] = _f;
|
||||
}
|
||||
return pickResult;
|
||||
};
|
||||
|
||||
_createServiceLayers() {
|
||||
let layer = this.createLayer("_service", Styles.SERVICE);
|
||||
// layer.objects.push(new CrossHair(0, 0, 20));
|
||||
layer.objects.push(new Point(0, 0, 2));
|
||||
layer.objects.push(this.referencePoint);
|
||||
layer.objects.push(new BasisOrigin(null, this));
|
||||
return [layer];
|
||||
|
||||
};
|
||||
|
||||
refresh() {
|
||||
const viewer = this;
|
||||
window.requestAnimationFrame(function () {
|
||||
if (!viewer.isDisposed()) {
|
||||
viewer.repaint();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
repaint() {
|
||||
|
||||
const ctx = this.ctx;
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
|
||||
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
ctx.transform(1, 0, 0, -1, 0, this.canvas.height);
|
||||
|
||||
if (this.transformation) {
|
||||
let [a, b, c, d, e, f] = this.transformation;
|
||||
ctx.transform(a, b, c, d, e, f);
|
||||
} else {
|
||||
ctx.transform(1, 0, 0, 1, this.translate.x, this.translate.y);
|
||||
ctx.transform(this.scale, 0, 0, this.scale, 0, 0);
|
||||
}
|
||||
|
||||
this.__prevStyle = null;
|
||||
|
||||
this.__drawWorkspace(ctx, this._workspace, Viewer.__SKETCH_DRAW_PIPELINE);
|
||||
this.__drawWorkspace(ctx, this._serviceWorkspace, Viewer.__SIMPLE_DRAW_PIPELINE);
|
||||
};
|
||||
|
||||
__drawWorkspace(ctx, workspace, pipeline) {
|
||||
for (let drawPredicate of pipeline) {
|
||||
for (let layers of workspace) {
|
||||
for (let layer of layers) {
|
||||
for (let obj of layer.objects) {
|
||||
obj.accept((obj) => {
|
||||
if (!obj.visible) return true;
|
||||
if (drawPredicate(obj)) {
|
||||
this.__draw(ctx, layer, obj);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
__draw(ctx, layer, obj) {
|
||||
const style = this.getStyleForObject(layer, obj);
|
||||
if (style !== this.__prevStyle) {
|
||||
this.setStyle(style, ctx);
|
||||
}
|
||||
this.__prevStyle = style;
|
||||
obj.draw(ctx, this.scale / this.retinaPxielRatio, this);
|
||||
};
|
||||
|
||||
getStyleForObject(layer, obj) {
|
||||
if (obj.style != null) {
|
||||
return obj.style;
|
||||
} else if (obj.role != null) {
|
||||
const style = layer.stylesByRoles[obj.role];
|
||||
if (style) {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
return layer.style;
|
||||
};
|
||||
|
||||
setStyle(style, ctx) {
|
||||
draw_utils.SetStyle(style, ctx, this.scale / this.retinaPxielRatio);
|
||||
};
|
||||
|
||||
snap(x, y, excl) {
|
||||
this.cleanSnap();
|
||||
var snapTo = this.search(x, y, 20 / this.scale, true, true, excl);
|
||||
if (snapTo.length > 0) {
|
||||
this.snapped = snapTo[0];
|
||||
this.mark(this.snapped, Styles.SNAP);
|
||||
}
|
||||
return this.snapped;
|
||||
};
|
||||
|
||||
cleanSnap() {
|
||||
if (this.snapped != null) {
|
||||
this.deselect(this.snapped);
|
||||
this.snapped = null;
|
||||
}
|
||||
};
|
||||
|
||||
showBounds(x1, y1, x2, y2, offset) {
|
||||
var dx = Math.max(x2 - x1, 1);
|
||||
var dy = Math.max(y2 - y1, 1);
|
||||
if (this.canvas.width > this.canvas.height) {
|
||||
this.scale = this.canvas.height / dy;
|
||||
} else {
|
||||
this.scale = this.canvas.width / dx;
|
||||
}
|
||||
this.translate.x = -x1 * this.scale;
|
||||
this.translate.y = -y1 * this.scale;
|
||||
};
|
||||
|
||||
screenToModel2(x, y, out) {
|
||||
out.x = x * this.retinaPxielRatio;
|
||||
out.y = this.canvas.height - y * this.retinaPxielRatio;
|
||||
|
||||
if (this.transformation) {
|
||||
out.z = 0;
|
||||
this.screenToModelMatrix._apply(out);
|
||||
} else {
|
||||
out.x -= this.translate.x;
|
||||
out.y -= this.translate.y;
|
||||
|
||||
out.x /= this.scale;
|
||||
out.y /= this.scale;
|
||||
}
|
||||
};
|
||||
|
||||
screenToModel(e) {
|
||||
return this._screenToModel(e.offsetX, e.offsetY);
|
||||
};
|
||||
|
||||
_screenToModel(x, y) {
|
||||
var out = {x: 0, y: 0};
|
||||
this.screenToModel2(x, y, out);
|
||||
return out;
|
||||
};
|
||||
|
||||
accept(visitor) {
|
||||
for (let layer of this.layers) {
|
||||
for (let object of layer.objects) {
|
||||
if (!object.accept(visitor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
findLayerByName(name) {
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
if (this.layers[i].name == name) {
|
||||
return this.layers[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
findById(id) {
|
||||
var result = null;
|
||||
this.accept(function (o) {
|
||||
if (o.id === id) {
|
||||
result = o;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
select(objs, exclusive) {
|
||||
if (exclusive) this.deselectAll();
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
this.mark(objs[i]);
|
||||
}
|
||||
};
|
||||
|
||||
pick(e) {
|
||||
var m = this.screenToModel(e);
|
||||
return this.search(m.x, m.y, 20 / this.scale, true, false, []);
|
||||
};
|
||||
|
||||
mark(obj, style) {
|
||||
if (style === undefined) {
|
||||
style = Styles.MARK;
|
||||
}
|
||||
obj.marked = style;
|
||||
|
||||
if (this.selected.indexOf(obj) == -1) {
|
||||
this.selected.push(obj);
|
||||
}
|
||||
};
|
||||
|
||||
getActiveLayer() {
|
||||
var layer = this._activeLayer;
|
||||
if (layer == null || layer.readOnly) {
|
||||
layer = null;
|
||||
for (var i = 0; i < this.layers.length; i++) {
|
||||
var l = this.layers[i];
|
||||
if (!l.readOnly) {
|
||||
layer = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer == null) {
|
||||
layer = this.createLayer("sketch", Styles.DEFAULT);
|
||||
this.layers.push(layer);
|
||||
}
|
||||
return layer;
|
||||
};
|
||||
|
||||
setActiveLayerName(layerName) {
|
||||
let layer = this.findLayerByName(layerName);
|
||||
if (layer) {
|
||||
this.activeLayer = layer;
|
||||
} else {
|
||||
console.warn("layer doesn't exist: " + layerName);
|
||||
}
|
||||
};
|
||||
|
||||
setActiveLayer(layer) {
|
||||
if (!layer.readOnly) {
|
||||
this._activeLayer = layer;
|
||||
this.bus.dispatch("activeLayer");
|
||||
}
|
||||
};
|
||||
|
||||
deselect(obj) {
|
||||
for (var i = 0; i < this.selected.length; i++) {
|
||||
if (obj === this.selected[i]) {
|
||||
this.selected.splice(i, 1)[0].marked = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer == null) {
|
||||
layer = new Layer("sketch", Styles.DEFAULT);
|
||||
this.layers.push(layer);
|
||||
}
|
||||
return layer;
|
||||
};
|
||||
};
|
||||
|
||||
Viewer.prototype.setActiveLayerName = function(layerName) {
|
||||
let layer = this.findLayerByName(layerName);
|
||||
if (layer) {
|
||||
this.activeLayer = layer;
|
||||
} else {
|
||||
console.warn("layer doesn't exist: " + layerName);
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.setActiveLayer = function(layer) {
|
||||
if (!layer.readOnly) {
|
||||
this._activeLayer = layer;
|
||||
this.bus.dispatch("activeLayer");
|
||||
}
|
||||
};
|
||||
|
||||
Viewer.prototype.deselect = function(obj) {
|
||||
for (var i = 0; i < this.selected.length; i++) {
|
||||
if (obj === this.selected[i]) {
|
||||
this.selected.splice(i, 1)[0].marked = null;
|
||||
break;
|
||||
deselectAll() {
|
||||
for (var i = 0; i < this.selected.length; i++) {
|
||||
this.selected[i].marked = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
while (this.selected.length > 0) this.selected.pop();
|
||||
};
|
||||
|
||||
Viewer.prototype.deselectAll = function() {
|
||||
for (var i = 0; i < this.selected.length; i++) {
|
||||
this.selected[i].marked = null;
|
||||
}
|
||||
while(this.selected.length > 0) this.selected.pop();
|
||||
};
|
||||
equalizeLinkedEndpoints() {
|
||||
const visited = new Set();
|
||||
|
||||
Viewer.prototype.equalizeLinkedEndpoints = function() {
|
||||
const visited = new Set();
|
||||
|
||||
function equalize(obj) {
|
||||
if (visited.has(obj.id)) return;
|
||||
visited.add(obj.id);
|
||||
for (let link of obj.linked) {
|
||||
if (isEndPoint(link)) {
|
||||
equalize(obj, link);
|
||||
link.setFromPoint(obj);
|
||||
equalize(link);
|
||||
function equalize(obj) {
|
||||
if (visited.has(obj.id)) return;
|
||||
visited.add(obj.id);
|
||||
for (let link of obj.linked) {
|
||||
if (isEndPoint(link)) {
|
||||
equalize(obj, link);
|
||||
link.setFromPoint(obj);
|
||||
equalize(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.accept((obj) => {
|
||||
if (isEndPoint(obj)) {
|
||||
equalize(obj);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/** @constructor */
|
||||
function Layer(name, style) {
|
||||
this.name = name;
|
||||
this.style = style;
|
||||
this.stylesByRoles = {
|
||||
'construction': Styles.CONSTRUCTION_OF_OBJECT,
|
||||
'virtual': Styles.VIRTUAL
|
||||
this.accept((obj) => {
|
||||
if (isEndPoint(obj)) {
|
||||
equalize(obj);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
this.objects = [];
|
||||
this.readOnly = false; // This is actually a mark for boundary layers coming from 3D
|
||||
|
||||
fullHeavyUIRefresh() {
|
||||
this.refresh();
|
||||
this.parametricManager.notify();
|
||||
};
|
||||
|
||||
createLayer(name, style, onUpdate) {
|
||||
return new Layer(name, style, this)
|
||||
};
|
||||
|
||||
objectsUpdate = () => this.streams.objectsUpdate.next();
|
||||
|
||||
get addingRoleMode() {
|
||||
return this.streams.addingRoleMode.value;
|
||||
}
|
||||
|
||||
set addingRoleMode(value) {
|
||||
this.streams.addingRoleMode.next(value);
|
||||
}
|
||||
|
||||
static __SKETCH_DRAW_PIPELINE = [
|
||||
(obj) => !isEndPoint(obj) && obj.marked === null && isConstruction(obj),
|
||||
(obj) => !isEndPoint(obj) && obj.marked === null && !isConstruction(obj),
|
||||
(obj) => !isEndPoint(obj) && obj.marked !== null,
|
||||
(obj) => isEndPoint(obj) && obj.marked === null,
|
||||
(obj) => isEndPoint(obj) && obj.marked !== null
|
||||
];
|
||||
|
||||
static __SIMPLE_DRAW_PIPELINE = [
|
||||
(obj) => true
|
||||
];
|
||||
}
|
||||
|
||||
Layer.prototype.remove = function(object) {
|
||||
const idx = this.objects.indexOf(object);
|
||||
if (idx != -1) {
|
||||
this.objects.splice(idx, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const isEndPoint = o => o._class === 'TCAD.TWO.EndPoint';
|
||||
const isConstruction = o => o.role === 'construction';
|
||||
|
||||
Layer.prototype.add = function(object) {
|
||||
if (object.layer !== undefined) {
|
||||
if (object.layer != null) {
|
||||
object.layer.remove(object);
|
||||
class Layer {
|
||||
|
||||
constructor(name, style, viewer) {
|
||||
this.name = name;
|
||||
this.style = style;
|
||||
this.stylesByRoles = {
|
||||
'objectConstruction': Styles.CONSTRUCTION_OF_OBJECT,
|
||||
'construction': Styles.CONSTRUCTION,
|
||||
'virtual': Styles.VIRTUAL
|
||||
};
|
||||
this.objects = [];
|
||||
this.readOnly = false; // This is actually a mark for boundary layers coming from 3D
|
||||
this.viewer = viewer;
|
||||
}
|
||||
|
||||
remove(object) {
|
||||
const idx = this.objects.indexOf(object);
|
||||
if (idx !== -1) {
|
||||
this.objects.splice(idx, 1);
|
||||
this.viewer.objectsUpdate();
|
||||
return true;
|
||||
}
|
||||
if (object.layer !== this) {
|
||||
this.objects.push(object);
|
||||
object.layer = this;
|
||||
return false;
|
||||
};
|
||||
|
||||
add(object) {
|
||||
if (object.layer !== undefined) {
|
||||
if (object.layer != null) {
|
||||
object.layer.remove(object);
|
||||
}
|
||||
if (object.layer !== this) {
|
||||
object.layer = this;
|
||||
this._addAndNotify(object);
|
||||
}
|
||||
} else {
|
||||
this._addAndNotify(object);
|
||||
}
|
||||
};
|
||||
|
||||
_addAndNotify(object) {
|
||||
if (this.viewer.addingRoleMode) {
|
||||
object.role = this.viewer.addingRoleMode;
|
||||
}
|
||||
} else {
|
||||
this.objects.push(object);
|
||||
this.viewer.objectsUpdate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Viewer.prototype.fullHeavyUIRefresh = function() {
|
||||
this.refresh();
|
||||
this.parametricManager.notify();
|
||||
};
|
||||
|
||||
export {Viewer, Layer, Styles}
|
||||
export {Viewer, Styles}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<head>
|
||||
<title>Web CAD / Part Designer</title>
|
||||
<link rel="stylesheet" href="lib/font-awesome/css/font-awesome.min.css?modeler">
|
||||
|
||||
<link rel="shortcut icon" href="img/cad/cube96.png" />
|
||||
<script src="lib/pnltri.js"></script>
|
||||
<script src="lib/verb.js"></script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -73,11 +73,11 @@ export function createSketcherSubject(sketcherApp) {
|
|||
}
|
||||
|
||||
function changeToConstructionLayer() {
|
||||
changeLayer('_construction_');
|
||||
viewer.addingRoleMode = 'construction';
|
||||
}
|
||||
|
||||
function changeToDefaultLayer() {
|
||||
changeLayer('sketch');
|
||||
viewer.addingRoleMode = null;
|
||||
}
|
||||
|
||||
function click(modelX, modelY, attrs) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue