diff --git a/modules/lstream/index.d.ts b/modules/lstream/index.d.ts new file mode 100644 index 00000000..f42cda90 --- /dev/null +++ b/modules/lstream/index.d.ts @@ -0,0 +1,57 @@ +interface StreamBase { + + attach(callback: (value: T) => any): () => void + + map(fn: (value: T) => V); + + filter(stream: Stream, predicate: (T) => boolean): Stream; + + pairwise(first: T): Stream<[T, T]>; + + scan(initAccumulator: any): Stream; + + remember(initialValue: T, usingStream: any): Stream + + distinct(): Stream; + + throttle(delay?: number, accumulator?: any): Stream; + + pipe(otherStream): () => void; +} + +interface Stream extends StreamBase { + + +} + +interface StateStream extends Stream { + + value: T; + + next(value?: T) : void; + +} + + +export function stream(): Stream; + +export function eventStream(): Stream; + +export function combine(...streams: Stream[]): Stream; + +export function merge(...streams: Stream[]): Stream; + +export function state(initialValue: T): StateStream; + +export function distinctState(initialValue: T): StateStream; + +export function externalState(get: any, set: any): StateStream; + +export function never(): Stream + +export function constant(value: T): Stream + +export function map(stream: Stream, fn: (T) => V): Stream; + +export function filter(stream: Stream, predicate: (T) => boolean): Stream; + diff --git a/test/coreTests/testCases/segment.js b/test/coreTests/testCases/segment.js index b1cb03db..88eba762 100644 --- a/test/coreTests/testCases/segment.js +++ b/test/coreTests/testCases/segment.js @@ -10,7 +10,7 @@ export function testSegmentWizard(env, tpi) { assertEquals(1, tpi.viewer.activeLayer.objects.length); const segment = tpi.viewer.activeLayer.objects[0]; - assertEquals('TCAD.TWO.Segment', segment._class); + assertEquals('Segment', segment.TYPE); const [asx, asy] = tpi.toScreen(10, 10); const [bsx, bsy] = tpi.toScreen(100, 100); assertPoint2DEquals(tpi.toModel(asx, asy), segment.a); diff --git a/tsconfig.json b/tsconfig.json index 8ff2e1e4..4675429d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "allowSyntheticDefaultImports": true, "target": "ES5", "baseUrl": ".", + "downlevelIteration": true, "paths": { "*": [ "modules/*", diff --git a/web/app/cad/cad-utils.js b/web/app/cad/cad-utils.js index f6a822d5..2ae6dc00 100644 --- a/web/app/cad/cad-utils.js +++ b/web/app/cad/cad-utils.js @@ -380,25 +380,12 @@ export function createShared() { return shared; } -export const CURVE_CLASSES = new Set(); -CURVE_CLASSES.add('TCAD.TWO.Arc'); -CURVE_CLASSES.add('TCAD.TWO.Circle'); -CURVE_CLASSES.add('TCAD.TWO.Ellipse'); -CURVE_CLASSES.add('TCAD.TWO.EllipticalArc'); -CURVE_CLASSES.add('TCAD.TWO.BezierCurve'); - export function isCurveClass(className) { - return CURVE_CLASSES.has(className); + return false; } -export function isSmoothPiece(shared) { - return shared.__tcad && - !!shared.__tcad.csgInfo && !!shared.__tcad.csgInfo.derivedFrom - && isCurveClass(shared.__tcad.csgInfo.derivedFrom._class); -} var POLYGON_COUNTER = 0; -/** @constructor */ export function Polygon(shell, holes, normal) { this.id = POLYGON_COUNTER ++; if (!holes) { diff --git a/web/app/cad/dom/components/View3d.jsx b/web/app/cad/dom/components/View3d.jsx index cc5dae01..2aa363ae 100644 --- a/web/app/cad/dom/components/View3d.jsx +++ b/web/app/cad/dom/components/View3d.jsx @@ -17,8 +17,8 @@ import {InplaceSketcher} from "../../sketch/components/InplaceSketcher"; import {ContextualControls} from "../../../sketcher/components/ContextualControls"; import {ConstraintEditor} from "../../../sketcher/components/ConstraintEditor"; import SketcherOperationWizard from "../../../sketcher/components/SketcherOperationWizard"; -import {StageControl} from "../../../sketcher/components/StageControl"; - +import {ToastContainer} from "react-toastify"; +import 'react-toastify/dist/ReactToastify.css'; export default class View3d extends React.Component { @@ -28,6 +28,7 @@ export default class View3d extends React.Component { render() { return +
diff --git a/web/app/cad/dom/components/WebApplication.jsx b/web/app/cad/dom/components/WebApplication.jsx index d82a780b..b3975438 100644 --- a/web/app/cad/dom/components/WebApplication.jsx +++ b/web/app/cad/dom/components/WebApplication.jsx @@ -1,4 +1,4 @@ -import React, {Fragment} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import 'ui/styles/init/index.less'; diff --git a/web/app/cad/legacy/mesh/revolve.js b/web/app/cad/legacy/mesh/revolve.js index a0069165..3feb4560 100644 --- a/web/app/cad/legacy/mesh/revolve.js +++ b/web/app/cad/legacy/mesh/revolve.js @@ -32,9 +32,9 @@ export default function revolve(polygons, axisSegment, angle, resolution) { let shared = createShared(); let sketchConnectionObject = pOrig[p].sketchConnectionObject; if (sketchConnectionObject) { - if (sketchConnectionObject._class == 'TCAD.TWO.Segment') { + if (sketchConnectionObject.TYPE === 'Segment') { sketchConnectionObject = Object.assign({}, sketchConnectionObject, { - _class: 'TCAD.TWO.Arc', + TYPE: 'Arc', id: sketchConnectionObject.id + ":REVOLVED" // just avoid having object with the same ID but different classes }); } diff --git a/web/app/cad/legacy/mesh/wizards/revolve.js b/web/app/cad/legacy/mesh/wizards/revolve.js index 3b114386..8ac52aff 100644 --- a/web/app/cad/legacy/mesh/wizards/revolve.js +++ b/web/app/cad/legacy/mesh/wizards/revolve.js @@ -150,7 +150,7 @@ RevolveWizard.prototype.dispose = function() { }; function isSketchSegment(line) { - return line.__TCAD_SketchObject && line.__TCAD_SketchObject._class === 'TCAD.TWO.Segment'; + return line.__TCAD_SketchObject && line.__TCAD_SketchObject.TYPE === 'Segment'; } function firstSegment(objects) { for (let line of objects) { diff --git a/web/app/cad/sample.js b/web/app/cad/sample.js deleted file mode 100644 index 66a0f557..00000000 --- a/web/app/cad/sample.js +++ /dev/null @@ -1,8 +0,0 @@ -export function init() { - localStorage.setItem("TCAD.projects.sample", '{"history":[{"type":"PLANE","solids":[],"params":{"basis":[[1,0,0],[0,0,1],[0,1,0]],"depth":"0"},"protoParams":["XZ","0"]},{"type":"EXTRUDE","solids":[0],"face":"0:0","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"EXTRUDE","solids":[1],"face":"1:1","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"CUT","solids":[2],"face":"2:0","params":{"target":[0,252,0],"expansionFactor":"1"},"protoParams":["252","1","0","0"]},{"type":"CUT","solids":[3],"face":"1:1$","params":{"target":[0,50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]}]}'); - localStorage.setItem("TCAD.projects.sample.sketch.0:0", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":6,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[0,[1,-400],[2,400]],[3,[4,-400],[5,-400]]]},{"id":13,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[7,[8,-400],[9,-400]],[10,[11,400],[12,-400]]]},{"id":20,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[14,[15,400],[16,-400]],[17,[18,400],[19,400]]]},{"id":27,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[21,[22,400],[23,400]],[24,[25,-400],[26,400]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":34,"_class":"TCAD.TWO.Segment","points":[[28,[29,-80.41502600578134],[30,240.48794311524324]],[31,[32,252.10163324769275],[33,71.15131239804411]]]},{"id":41,"_class":"TCAD.TWO.Segment","points":[[35,[36,255.946878629896],[37,-145.76094357167156]],[38,[39,-91.17342089039929],[40,-338.36716169336114]]]},{"id":48,"_class":"TCAD.TWO.Segment","points":[[42,[43,-172.00749593627577],[44,-240.71428346724593]],[45,[46,-88.51020843368133],[47,-140.46311545122035]]]},{"id":55,"_class":"TCAD.TWO.Segment","points":[[49,[50,-102.18982576106004],[51,18.31440664196805]],[52,[53,-182.7982464866314],[54,86.82364838151852]]]},{"id":72,"_class":"TCAD.TWO.Arc","points":[[63,[64,255.946878629896],[65,-145.76094357167156]],[66,[67,252.10163324769275],[68,71.15131239804411]],[69,[70,196.33682709088268],[71,-38.32745196977044]]]},{"id":83,"_class":"TCAD.TWO.Arc","points":[[74,[75,-80.41502600578134],[76,240.48794311524324]],[77,[78,-182.7982464866314],[79,86.82364838151852]],[80,[81,-122.59914075444685],[82,157.65429488839598]]]},{"id":94,"_class":"TCAD.TWO.Arc","points":[[85,[86,-88.51020843368133],[87,-140.46311545122035]],[88,[89,-102.18982576106004],[90,18.31440664196805]],[91,[92,-175.53398017227],[93,-67.98267439986091]]]},{"id":105,"_class":"TCAD.TWO.Arc","points":[[96,[97,-172.00749593627577],[98,-240.71428346724593]],[99,[100,-91.17342089039929],[101,-338.36716169336114]],[102,[103,-122.4591797419898],[104,-281.9821285194346]]]}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["Tangent",[72,41]],["Tangent",[72,34]],["coi",[63,35]],["coi",[66,31]],["Tangent",[83,34]],["Tangent",[83,55]],["coi",[74,28]],["coi",[77,52]],["Tangent",[94,48]],["Tangent",[94,55]],["coi",[85,45]],["coi",[88,49]],["Tangent",[105,48]],["Tangent",[105,41]],["coi",[96,42]],["coi",[99,38]]],"boundary":{"lines":[{"a":{"x":-400,"y":400},"b":{"x":-400,"y":-400}},{"a":{"x":-400,"y":-400},"b":{"x":400,"y":-400}},{"a":{"x":400,"y":-400},"b":{"x":400,"y":400}},{"a":{"x":400,"y":400},"b":{"x":-400,"y":400}}],"arcs":[],"circles":[]}}'); - localStorage.setItem("TCAD.projects.sample.sketch.1:0", '{"boundary":{"lines":[{"a":{"x":80.41502600578134,"y":240.48794311524324},"b":{"x":-252.10163324769275,"y":71.15131239804411}},{"a":{"x":-255.946878629896,"y":-145.76094357167156},"b":{"x":91.17342089039929,"y":-338.36716169336114}},{"a":{"x":172.00749593627577,"y":-240.71428346724593},"b":{"x":88.51020843368133,"y":-140.46311545122035}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":182.7982464866314,"y":86.82364838151852}}],"arcs":[{"a":{"x":-252.10163324769275,"y":71.15131239804411},"b":{"x":-255.946878629896,"y":-145.76094357167156},"c":{"x":-196.33682672526209,"y":-38.32745176660378}},{"a":{"x":91.17342089039929,"y":-338.36716169336114},"b":{"x":172.00749593627577,"y":-240.71428346724593},"c":{"x":122.45917974196499,"y":-281.98212851943595}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":88.51020843368133,"y":-140.46311545122035},"c":{"x":175.5339801724776,"y":-67.98267439979745}},{"a":{"x":182.7982464866314,"y":86.82364838151852},"b":{"x":80.41502600578134,"y":240.48794311524324},"c":{"x":122.59914075460381,"y":157.65429488902345}}],"circles":[]}}'); - localStorage.setItem("TCAD.projects.sample.sketch.1:1", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":6,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[0,[1,-91.17342089039929],[2,-338.36716169336114]],[3,[4,255.946878629896],[5,-145.76094357167156]]]},{"id":13,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[7,[8,252.10163324769275],[9,71.15131239804411]],[10,[11,-80.41502600578134],[12,240.48794311524324]]]},{"id":20,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[14,[15,-182.7982464866314],[16,86.82364838151852]],[17,[18,-102.18982576106004],[19,18.31440664196805]]]},{"id":27,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[21,[22,-88.51020843368133],[23,-140.46311545122035]],[24,[25,-172.00749593627577],[26,-240.71428346724593]]]},{"id":37,"_class":"TCAD.TWO.Arc","aux":true,"edge":8,"points":[[28,[29,255.946878629896],[30,-145.76094357167156]],[31,[32,252.10163324769275],[33,71.15131239804411]],[34,[35,196.33682672526209],[36,-38.32745176660376]]]},{"id":48,"_class":"TCAD.TWO.Arc","aux":true,"edge":10,"points":[[39,[40,-80.41502600578134],[41,240.48794311524324]],[42,[43,-182.7982464866314],[44,86.82364838151852]],[45,[46,-122.59914075460384],[47,157.65429488902345]]]},{"id":59,"_class":"TCAD.TWO.Arc","aux":true,"edge":12,"points":[[50,[51,-88.51020843368133],[52,-140.46311545122035]],[53,[54,-102.18982576106004],[55,18.31440664196805]],[56,[57,-175.5339801724776],[58,-67.98267439979745]]]},{"id":70,"_class":"TCAD.TWO.Arc","aux":true,"edge":14,"points":[[61,[62,-172.00749593627577],[63,-240.71428346724593]],[64,[65,-91.17342089039929],[66,-338.36716169336114]],[67,[68,-122.45917974196257],[69,-281.982128519434]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":75,"_class":"TCAD.TWO.Circle","c":[72,[73,-122.59914075460384],[74,157.65429488902345]],"r":92.9565103454672},{"id":77,"_class":"TCAD.TWO.EndPoint","location":[77,[78,30.202166630027865],[79,-54.24889318543422]]},{"id":83,"_class":"TCAD.TWO.Circle","c":[80,[81,-122.45917974196257],[82,-281.982128519434]],"r":64.48310377876552}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["RR",[48,75]],["coi",[72,45]],["coi",[80,67]],["RR",[83,70]]]}'); - localStorage.setItem("TCAD.projects.sample.sketch.1:1$", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":909,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[903,[904,-124.85084567322261],[905,-346.42086381904903]],[906,[907,-121.65017719515622],[908,-346.2848202888915]]]},{"id":916,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[910,[911,-121.65017719515622],[912,-346.2848202888915]],[913,[914,-126.76777558258588],[915,-346.1961840440328]]]},{"id":923,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[917,[918,-126.76777558258588],[919,-346.1961840440328]],[920,[921,-124.85084567322261],[922,-346.42086381904903]]]},{"id":930,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[924,[925,-116.53642857559844],[926,-346.06746181540075]],[927,[928,-114.6081175386342],[929,-345.98549948705966]]]},{"id":937,"_class":"TCAD.TWO.Segment","aux":true,"edge":8,"points":[[931,[932,-114.6081175386342],[933,-345.98549948705966]],[934,[935,-111.4694612123672],[936,-345.34392095429644]]]},{"id":944,"_class":"TCAD.TWO.Segment","aux":true,"edge":10,"points":[[938,[939,-111.4694612123672],[940,-345.34392095429644]],[941,[942,-116.53642857559844],[943,-346.06746181540075]]]},{"id":951,"_class":"TCAD.TWO.Segment","aux":true,"edge":12,"points":[[945,[946,-136.89021476237798],[947,-344.7017757862507]],[948,[949,-135.03311997329527],[950,-345.22741846263864]]]},{"id":958,"_class":"TCAD.TWO.Segment","aux":true,"edge":14,"points":[[952,[953,-135.03311997329527],[954,-345.22741846263864]],[955,[956,-131.85134223207632],[957,-345.6003486900595]]]},{"id":965,"_class":"TCAD.TWO.Segment","aux":true,"edge":16,"points":[[959,[960,-131.85134223207632],[961,-345.6003486900595]],[962,[963,-136.89021476237798],[964,-344.7017757862507]]]},{"id":972,"_class":"TCAD.TWO.Segment","aux":true,"edge":18,"points":[[966,[967,-106.45479019397476],[968,-344.31886279569994]],[969,[970,-104.5638397013956],[971,-343.9323301153285]]]},{"id":979,"_class":"TCAD.TWO.Segment","aux":true,"edge":20,"points":[[973,[974,-104.5638397013956],[975,-343.9323301153285]],[976,[977,-102.65803400883827],[978,-343.1402615618105]]]},{"id":986,"_class":"TCAD.TWO.Segment","aux":true,"edge":22,"points":[[980,[981,-102.65803400883827],[982,-343.1402615618105]],[983,[984,-106.45479019397476],[985,-344.31886279569994]]]},{"id":993,"_class":"TCAD.TWO.Segment","aux":true,"edge":24,"points":[[987,[988,-146.64788251166573],[989,-341.6220110088687]],[990,[991,-144.89756439084644],[992,-342.43532998379334]]]},{"id":1000,"_class":"TCAD.TWO.Segment","aux":true,"edge":26,"points":[[994,[995,-144.89756439084644],[996,-342.43532998379334]],[997,[998,-141.81510277637994],[999,-343.30780745905]]]},{"id":1007,"_class":"TCAD.TWO.Segment","aux":true,"edge":28,"points":[[1001,[1002,-141.81510277637994],[1003,-343.30780745905]],[1004,[1005,-146.64788251166573],[1006,-341.6220110088687]]]},{"id":1014,"_class":"TCAD.TWO.Segment","aux":true,"edge":30,"points":[[1008,[1009,-91.17342089039929],[1010,-338.36716169336114]],[1011,[1012,255.946878629896],[1013,-145.76094357167156]]]},{"id":1021,"_class":"TCAD.TWO.Segment","aux":true,"edge":32,"points":[[1015,[1016,252.10163324769275],[1017,71.15131239804411]],[1018,[1019,-80.41502600578134],[1020,240.48794311524324]]]},{"id":1028,"_class":"TCAD.TWO.Segment","aux":true,"edge":34,"points":[[1022,[1023,-80.41502600578134],[1024,240.48794311524324]],[1025,[1026,-81.03180870826053],[1027,240.74252296578175]]]},{"id":1035,"_class":"TCAD.TWO.Segment","aux":true,"edge":36,"points":[[1029,[1030,-81.03180870826053],[1031,240.74252296578175]],[1032,[1033,-68.90130878449338],[1034,233.53219455234265]]]},{"id":1042,"_class":"TCAD.TWO.Segment","aux":true,"edge":38,"points":[[1036,[1037,-68.90130878449338],[1038,233.53219455234265]],[1039,[1040,-57.55454096229795],[1041,224.06297544710796]]]},{"id":1049,"_class":"TCAD.TWO.Segment","aux":true,"edge":40,"points":[[1043,[1044,-183.60296592346776],[1045,87.66174623159009]],[1046,[1047,-182.7982464866314],[1048,86.82364838151852]]]},{"id":1056,"_class":"TCAD.TWO.Segment","aux":true,"edge":42,"points":[[1050,[1051,-182.7982464866314],[1052,86.82364838151852]],[1053,[1054,-102.18982576106004],[1055,18.31440664196805]]]},{"id":1063,"_class":"TCAD.TWO.Segment","aux":true,"edge":44,"points":[[1057,[1058,-88.51020843368133],[1059,-140.46311545122035]],[1060,[1061,-172.00749593627577],[1062,-240.71428346724593]]]},{"id":1070,"_class":"TCAD.TWO.Segment","aux":true,"edge":46,"points":[[1064,[1065,-172.00749593627577],[1066,-240.71428346724593]],[1067,[1068,-173.85553817260416],[1069,-243.3310613415531]]]},{"id":1077,"_class":"TCAD.TWO.Segment","aux":true,"edge":48,"points":[[1071,[1072,-173.85553817260416],[1073,-243.3310613415531]],[1074,[1075,-169.45270100330094],[1076,-237.82695178551998]]]},{"id":1084,"_class":"TCAD.TWO.Segment","aux":true,"edge":50,"points":[[1078,[1079,-169.45270100330094],[1080,-237.82695178551998]],[1081,[1082,-161.86089236160166],[1083,-230.93728827497424]]]},{"id":1091,"_class":"TCAD.TWO.Segment","aux":true,"edge":52,"points":[[1085,[1086,-93.05073865718533],[1087,-339.1473904301305]],[1088,[1089,-91.17342089039929],[1090,-338.36716169336114]]]},{"id":1098,"_class":"TCAD.TWO.Segment","aux":true,"edge":54,"points":[[1092,[1093,-155.79413550803565],[1094,-337.03473653312227]],[1095,[1096,-154.194836623249],[1097,-338.11517364666224]]]},{"id":1105,"_class":"TCAD.TWO.Segment","aux":true,"edge":56,"points":[[1099,[1100,-154.194836623249],[1101,-338.11517364666224]],[1102,[1103,-151.28960612438567],[1104,-339.465144867979]]]},{"id":1112,"_class":"TCAD.TWO.Segment","aux":true,"edge":58,"points":[[1106,[1107,-151.28960612438567],[1108,-339.465144867979]],[1109,[1110,-155.79413550803565],[1111,-337.03473653312227]]]},{"id":1119,"_class":"TCAD.TWO.Segment","aux":true,"edge":60,"points":[[1113,[1114,-164.09778508175484],[1115,-331.0559043105029]],[1116,[1117,-162.68993070681643],[1118,-332.3761494916342]]]},{"id":1126,"_class":"TCAD.TWO.Segment","aux":true,"edge":62,"points":[[1120,[1121,-162.68993070681643],[1122,-332.3761494916342]],[1123,[1124,-160.03536646411845],[1125,-334.1694914087516]]]},{"id":1133,"_class":"TCAD.TWO.Segment","aux":true,"edge":64,"points":[[1127,[1128,-160.03536646411845],[1129,-334.1694914087516]],[1130,[1131,-164.09778508175484],[1132,-331.0559043105029]]]},{"id":1140,"_class":"TCAD.TWO.Segment","aux":true,"edge":66,"points":[[1134,[1135,-171.34894094227198],[1136,-323.8366405200772]],[1137,[1138,-170.1681172325551],[1139,-325.3633220998529]]]},{"id":1147,"_class":"TCAD.TWO.Segment","aux":true,"edge":68,"points":[[1141,[1142,-170.1681172325551],[1143,-325.3633220998529]],[1144,[1145,-167.83131832762314],[1146,-327.5547046380108]]]},{"id":1154,"_class":"TCAD.TWO.Segment","aux":true,"edge":70,"points":[[1148,[1149,-167.83131832762314],[1150,-327.5547046380108]],[1151,[1152,-171.34894094227198],[1153,-323.8366405200772]]]},{"id":1161,"_class":"TCAD.TWO.Segment","aux":true,"edge":72,"points":[[1155,[1156,-177.36431654830434],[1157,-315.5594255713455]],[1158,[1159,-176.44037103403136],[1160,-317.2539538143128]]]},{"id":1168,"_class":"TCAD.TWO.Segment","aux":true,"edge":74,"points":[[1162,[1163,-176.44037103403136],[1164,-317.2539538143128]],[1165,[1166,-174.48040443457532],[1167,-319.787985676768]]]},{"id":1175,"_class":"TCAD.TWO.Segment","aux":true,"edge":76,"points":[[1169,[1170,-174.48040443457532],[1171,-319.787985676768]],[1172,[1173,-177.36431654830434],[1174,-315.5594255713455]]]},{"id":1182,"_class":"TCAD.TWO.Segment","aux":true,"edge":78,"points":[[1176,[1177,-181.9918620183506],[1178,-306.43348157021944]],[1179,[1180,-181.34814915237982],[1181,-308.25302410223765]]]},{"id":1189,"_class":"TCAD.TWO.Segment","aux":true,"edge":80,"points":[[1183,[1184,-181.34814915237982],[1185,-308.25302410223765]],[1186,[1187,-179.81455668401662],[1188,-311.0656528889991]]]},{"id":1196,"_class":"TCAD.TWO.Segment","aux":true,"edge":82,"points":[[1190,[1191,-179.81455668401662],[1192,-311.0656528889991]],[1193,[1194,-181.9918620183506],[1195,-306.43348157021944]]]},{"id":1203,"_class":"TCAD.TWO.Segment","aux":true,"edge":84,"points":[[1197,[1198,-185.11460747614086],[1199,-296.6894838385504]],[1200,[1201,-184.76739830644107],[1202,-298.5880483152473]]]},{"id":1210,"_class":"TCAD.TWO.Segment","aux":true,"edge":86,"points":[[1204,[1205,-184.76739830644107],[1206,-298.5880483152473]],[1207,[1208,-183.69894439028664],[1209,-301.6081795674206]]]},{"id":1217,"_class":"TCAD.TWO.Segment","aux":true,"edge":88,"points":[[1211,[1212,-183.69894439028664],[1213,-301.6081795674206]],[1214,[1215,-185.11460747614086],[1216,-296.6894838385504]]]},{"id":1224,"_class":"TCAD.TWO.Segment","aux":true,"edge":90,"points":[[1218,[1219,-186.65361968327025],[1220,-286.5737301634624]],[1221,[1222,-186.61169057171756],[1223,-288.5033268128508]]]},{"id":1231,"_class":"TCAD.TWO.Segment","aux":true,"edge":92,"points":[[1225,[1226,-186.61169057171756],[1227,-288.5033268128508]],[1228,[1229,-186.03538238106256],[1230,-291.6546210581988]]]},{"id":1238,"_class":"TCAD.TWO.Segment","aux":true,"edge":94,"points":[[1232,[1233,-186.03538238106256],[1234,-291.6546210581988]],[1235,[1236,-186.65361968327025],[1237,-286.5737301634624]]]},{"id":1245,"_class":"TCAD.TWO.Segment","aux":true,"edge":96,"points":[[1239,[1240,-186.56999722459386],[1241,-276.3419151596114]],[1242,[1243,-186.83440800799133],[1244,-278.25376981343675]]]},{"id":1252,"_class":"TCAD.TWO.Segment","aux":true,"edge":98,"points":[[1246,[1247,-186.83440800799133],[1248,-278.25376981343675]],[1249,[1250,-186.76481281142574],[1251,-281.4565721894818]]]},{"id":1259,"_class":"TCAD.TWO.Segment","aux":true,"edge":100,"points":[[1253,[1254,-186.76481281142574],[1255,-281.4565721894818]],[1256,[1257,-186.56999722459386],[1258,-276.3419151596114]]]},{"id":1266,"_class":"TCAD.TWO.Segment","aux":true,"edge":102,"points":[[1260,[1261,-184.86585381433073],[1262,-266.252667109051]],[1263,[1264,-185.42992101504922],[1265,-268.0984540612155]]]},{"id":1273,"_class":"TCAD.TWO.Segment","aux":true,"edge":104,"points":[[1267,[1268,-185.42992101504922],[1269,-268.0984540612155]],[1270,[1271,-185.86879796147372],[1272,-271.2718077410349]]]},{"id":1280,"_class":"TCAD.TWO.Segment","aux":true,"edge":106,"points":[[1274,[1275,-185.86879796147372],[1276,-271.2718077410349]],[1277,[1278,-184.86585381433073],[1279,-266.252667109051]]]},{"id":1287,"_class":"TCAD.TWO.Segment","aux":true,"edge":108,"points":[[1281,[1282,-181.58426486797975],[1283,-256.5610106471486]],[1284,[1285,-182.43373063136903],[1286,-258.2940741764191]]]},{"id":1294,"_class":"TCAD.TWO.Segment","aux":true,"edge":110,"points":[[1288,[1289,-182.43373063136903],[1290,-258.2940741764191]],[1291,[1292,-183.3699862842126],[1293,-261.35776670402527]]]},{"id":1301,"_class":"TCAD.TWO.Segment","aux":true,"edge":112,"points":[[1295,[1296,-183.3699862842126],[1297,-261.35776670402527]],[1298,[1299,-181.58426486797975],[1300,-256.5610106471486]]]},{"id":1308,"_class":"TCAD.TWO.Segment","aux":true,"edge":114,"points":[[1302,[1303,-176.80817869053936],[1304,-247.5119205374264]],[1305,[1306,-177.92157117890073],[1307,-249.08845421814587]]]},{"id":1315,"_class":"TCAD.TWO.Segment","aux":true,"edge":116,"points":[[1309,[1310,-177.92157117890073],[1311,-249.08845421814587]],[1312,[1313,-179.3315399235013],[1314,-251.96504502850303]]]},{"id":1322,"_class":"TCAD.TWO.Segment","aux":true,"edge":118,"points":[[1316,[1317,-179.3315399235013],[1318,-251.96504502850303]],[1319,[1320,-176.80817869053936],[1321,-247.5119205374264]]]},{"id":1329,"_class":"TCAD.TWO.Segment","aux":true,"edge":120,"points":[[1323,[1324,-199.52633139024357],[1325,105.99235078457345]],[1326,[1327,-195.81654775637261],[1328,100.38192696448344]]]},{"id":1336,"_class":"TCAD.TWO.Segment","aux":true,"edge":122,"points":[[1330,[1331,-195.81654775637261],[1332,100.38192696448344]],[1333,[1334,-195.41416831449038],[1335,99.96285749788738]]]},{"id":1343,"_class":"TCAD.TWO.Segment","aux":true,"edge":124,"points":[[1337,[1338,-195.41416831449038],[1339,99.96285749788738]],[1340,[1341,-199.52633139024357],[1342,105.99235078457345]]]},{"id":1350,"_class":"TCAD.TWO.Segment","aux":true,"edge":126,"points":[[1344,[1345,-206.74167768777465],[1346,118.83699711877475]],[1347,[1348,-203.9679416929228],[1349,112.70953935972136]]]},{"id":1357,"_class":"TCAD.TWO.Segment","aux":true,"edge":128,"points":[[1351,[1352,-203.9679416929228],[1353,112.70953935972136]],[1354,[1355,-203.59991146204723],[1356,112.1529555323074]]]},{"id":1364,"_class":"TCAD.TWO.Segment","aux":true,"edge":130,"points":[[1358,[1359,-203.59991146204723],[1360,112.1529555323074]],[1361,[1362,-206.74167768777465],[1363,118.83699711877475]]]},{"id":1371,"_class":"TCAD.TWO.Segment","aux":true,"edge":132,"points":[[1365,[1366,-211.83016381958026],[1367,132.6628233336642]],[1368,[1369,-210.06258683256036],[1370,126.17321460454002]]]},{"id":1378,"_class":"TCAD.TWO.Segment","aux":true,"edge":134,"points":[[1372,[1373,-210.06258683256036],[1374,126.17321460454002]],[1375,[1376,-209.7874174967478],[1377,125.56533826558501]]]},{"id":1385,"_class":"TCAD.TWO.Segment","aux":true,"edge":136,"points":[[1379,[1380,-209.7874174967478],[1381,125.56533826558501]],[1382,[1383,-211.83016381958026],[1384,132.6628233336642]]]},{"id":1392,"_class":"TCAD.TWO.Segment","aux":true,"edge":138,"points":[[1386,[1387,-214.66316877134335],[1388,147.1203557849574]],[1389,[1390,-213.94642960789847],[1391,140.43263309803072]]]},{"id":1399,"_class":"TCAD.TWO.Segment","aux":true,"edge":140,"points":[[1393,[1394,-213.94642960789847],[1395,140.43263309803072]],[1396,[1397,-213.77107658712956],[1398,139.78882946027298]]]},{"id":1406,"_class":"TCAD.TWO.Segment","aux":true,"edge":142,"points":[[1400,[1401,-213.77107658712956],[1402,139.78882946027298]],[1403,[1404,-214.66316877134335],[1405,147.1203557849574]]]},{"id":1413,"_class":"TCAD.TWO.Segment","aux":true,"edge":144,"points":[[1407,[1408,-215.16908303852756],[1409,161.84415327050888]],[1410,[1411,-215.5212986207668],[1412,155.127361338742]]]},{"id":1420,"_class":"TCAD.TWO.Segment","aux":true,"edge":146,"points":[[1414,[1415,-215.5212986207668],[1416,155.127361338742]],[1417,[1418,-215.4501942907495],[1419,154.46390374461535]]]},{"id":1427,"_class":"TCAD.TWO.Segment","aux":true,"edge":148,"points":[[1421,[1422,-215.4501942907495],[1423,154.46390374461535]],[1424,[1425,-215.16908303852756],[1426,161.84415327050888]]]},{"id":1434,"_class":"TCAD.TWO.Segment","aux":true,"edge":150,"points":[[1428,[1429,-213.33511869067203],[1430,176.46204424088245]],[1431,[1432,-214.74738610811426],[1433,169.88596255629682]]]},{"id":1441,"_class":"TCAD.TWO.Segment","aux":true,"edge":152,"points":[[1435,[1436,-214.74738610811426],[1437,169.88596255629682]],[1438,[1439,-214.7823277637057],[1440,169.21962113872806]]]},{"id":1448,"_class":"TCAD.TWO.Segment","aux":true,"edge":154,"points":[[1442,[1443,-214.7823277637057],[1444,169.21962113872806]],[1445,[1446,-213.33511869067203],[1447,176.46204424088245]]]},{"id":1455,"_class":"TCAD.TWO.Segment","aux":true,"edge":156,"points":[[1449,[1450,-209.20763261028907],[1451,190.60453413204746]],[1452,[1453,-211.6442541577552],[1454,184.335385471234]]]},{"id":1462,"_class":"TCAD.TWO.Segment","aux":true,"edge":158,"points":[[1456,[1457,-211.6442541577552],[1458,184.335385471234]],[1459,[1460,-211.78435858298565],[1461,183.68300325713744]]]},{"id":1469,"_class":"TCAD.TWO.Segment","aux":true,"edge":160,"points":[[1463,[1464,-211.78435858298565],[1465,183.68300325713744]],[1466,[1467,-209.20763261028907],[1468,190.60453413204746]]]},{"id":1476,"_class":"TCAD.TWO.Segment","aux":true,"edge":162,"points":[[1470,[1471,-202.89095473588415],[1472,203.91414503228458]],[1473,[1474,-206.29034023997258],[1475,198.11039386458984]]]},{"id":1483,"_class":"TCAD.TWO.Segment","aux":true,"edge":164,"points":[[1477,[1478,-206.29034023997258],[1479,198.11039386458984]],[1480,[1481,-206.5320660329977],[1482,197.48846103583213]]]},{"id":1490,"_class":"TCAD.TWO.Segment","aux":true,"edge":166,"points":[[1484,[1485,-206.5320660329977],[1486,197.48846103583213]],[1487,[1488,-202.89095473588415],[1489,203.91414503228458]]]},{"id":1497,"_class":"TCAD.TWO.Segment","aux":true,"edge":168,"points":[[1491,[1492,-194.54475092745736],[1493,216.05445160568848]],[1494,[1495,-198.82097455359153],[1496,210.86279860719284]]]},{"id":1504,"_class":"TCAD.TWO.Segment","aux":true,"edge":170,"points":[[1498,[1499,-198.82097455359153],[1500,210.86279860719284]],[1501,[1502,-199.1582116422664],[1503,210.28703568038364]]]},{"id":1511,"_class":"TCAD.TWO.Segment","aux":true,"edge":172,"points":[[1505,[1506,-199.1582116422664],[1507,210.28703568038364]],[1508,[1509,-194.54475092745736],[1510,216.05445160568848]]]},{"id":1518,"_class":"TCAD.TWO.Segment","aux":true,"edge":174,"points":[[1512,[1513,-184.379987112991],[1514,226.7185848724264]],[1515,[1516,-189.42495930181502],[1517,222.27025879184544]]]},{"id":1525,"_class":"TCAD.TWO.Segment","aux":true,"edge":176,"points":[[1519,[1520,-189.42495930181502],[1521,222.27025879184544]],[1522,[1523,-189.84918338721522],[1524,221.7552192528602]]]},{"id":1532,"_class":"TCAD.TWO.Segment","aux":true,"edge":178,"points":[[1526,[1527,-189.84918338721522],[1528,221.7552192528602]],[1529,[1530,-184.379987112991],[1531,226.7185848724264]]]},{"id":1539,"_class":"TCAD.TWO.Segment","aux":true,"edge":180,"points":[[1533,[1534,-172.65359672964632],[1535,235.63698889679065]],[1536,[1537,-178.3397963630285],[1538,232.04442950329735]]]},{"id":1546,"_class":"TCAD.TWO.Segment","aux":true,"edge":182,"points":[[1540,[1541,-178.3397963630285],[1542,232.04442950329735]],[1543,[1544,-178.8402843870677],[1545,231.6031319406896]]]},{"id":1553,"_class":"TCAD.TWO.Segment","aux":true,"edge":184,"points":[[1547,[1548,-178.8402843870677],[1549,231.6031319406896]],[1550,[1551,-172.65359672964632],[1552,235.63698889679065]]]},{"id":1560,"_class":"TCAD.TWO.Segment","aux":true,"edge":186,"points":[[1554,[1555,-159.66198625012984],[1556,242.58423431817306]],[1557,[1558,-165.84568398613052],[1559,239.93825027586973]]]},{"id":1567,"_class":"TCAD.TWO.Segment","aux":true,"edge":188,"points":[[1561,[1562,-165.84568398613052],[1563,239.93825027586973]],[1564,[1565,-166.40978517692938],[1566,239.58184931168483]]]},{"id":1574,"_class":"TCAD.TWO.Segment","aux":true,"edge":190,"points":[[1568,[1569,-166.40978517692938],[1570,239.58184931168483]],[1571,[1572,-159.66198625012984],[1573,242.58423431817306]]]},{"id":1581,"_class":"TCAD.TWO.Segment","aux":true,"edge":192,"points":[[1575,[1576,-87.85873092574069],[1577,243.56036599344466]],[1578,[1579,-94.0759657597847],[1580,246.1265577956006]]]},{"id":1588,"_class":"TCAD.TWO.Segment","aux":true,"edge":194,"points":[[1582,[1583,-94.0759657597847],[1584,246.1265577956006]],[1585,[1586,-94.72530009714954],[1587,246.28017003496572]]]},{"id":1595,"_class":"TCAD.TWO.Segment","aux":true,"edge":196,"points":[[1589,[1590,-94.72530009714954],[1591,246.28017003496572]],[1592,[1593,-87.85873092574069],[1594,243.56036599344466]]]},{"id":1602,"_class":"TCAD.TWO.Segment","aux":true,"edge":198,"points":[[1596,[1597,-145.73354295417178],[1598,247.38471650027034]],[1599,[1600,-152.25843425515438],[1601,245.75219000931554]]]},{"id":1609,"_class":"TCAD.TWO.Segment","aux":true,"edge":200,"points":[[1603,[1604,-152.25843425515438],[1605,245.75219000931554]],[1606,[1607,-152.8718898989769],[1608,245.48969434514922]]]},{"id":1616,"_class":"TCAD.TWO.Segment","aux":true,"edge":202,"points":[[1610,[1611,-152.8718898989769],[1612,245.48969434514922]],[1613,[1614,-145.73354295417178],[1615,247.38471650027034]]]},{"id":1623,"_class":"TCAD.TWO.Segment","aux":true,"edge":204,"points":[[1617,[1618,-101.91252341270427],[1619,247.98044276780786]],[1620,[1621,-108.45788216795745],[1622,249.5288703774163]]]},{"id":1630,"_class":"TCAD.TWO.Segment","aux":true,"edge":206,"points":[[1624,[1625,-108.45788216795745],[1626,249.5288703774163]],[1627,[1628,-109.12335499908941],[1629,249.57763216878644]]]},{"id":1637,"_class":"TCAD.TWO.Segment","aux":true,"edge":208,"points":[[1631,[1632,-109.12335499908941],[1633,249.57763216878644]],[1634,[1635,-101.91252341270427],[1636,247.98044276780786]]]},{"id":1644,"_class":"TCAD.TWO.Segment","aux":true,"edge":210,"points":[[1638,[1639,-131.22033432517946],[1640,249.91709426712018]],[1641,[1642,-137.9214903475247],[1643,249.33929049097623]]]},{"id":1651,"_class":"TCAD.TWO.Segment","aux":true,"edge":212,"points":[[1645,[1646,-137.9214903475247],[1647,249.33929049097623]],[1648,[1649,-138.56879420445267],[1650,249.17733519618488]]]},{"id":1658,"_class":"TCAD.TWO.Segment","aux":true,"edge":214,"points":[[1652,[1653,-138.56879420445267],[1654,249.17733519618488]],[1655,[1656,-131.22033432517946],[1657,249.91709426712018]]]},{"id":1665,"_class":"TCAD.TWO.Segment","aux":true,"edge":216,"points":[[1659,[1660,-116.48920888540648],[1661,250.11735702856262]],[1662,[1663,-123.19724536469215],[1664,250.60888103976808]]]},{"id":1672,"_class":"TCAD.TWO.Segment","aux":true,"edge":218,"points":[[1666,[1667,-123.19724536469215],[1668,250.60888103976808]],[1669,[1670,-123.86203561786023],[1671,250.5515598376735]]]},{"id":1679,"_class":"TCAD.TWO.Segment","aux":true,"edge":220,"points":[[1673,[1674,-123.86203561786023],[1675,250.5515598376735]],[1676,[1677,-116.48920888540648],[1678,250.11735702856262]]]},{"id":1689,"_class":"TCAD.TWO.Arc","aux":true,"edge":222,"points":[[1680,[1681,255.946878629896],[1682,-145.76094357167156]],[1683,[1684,252.10163324769275],[1685,71.15131239804411]],[1686,[1687,196.3368270908827],[1688,-38.32745196977044]]]},{"id":1700,"_class":"TCAD.TWO.Arc","aux":true,"edge":224,"points":[[1691,[1692,-183.60296592346776],[1693,87.66174623159009]],[1694,[1695,-57.55454096229795],[1696,224.06297544710796]],[1697,[1698,-122.51437135823936],[1699,157.65106605088206]]]},{"id":1711,"_class":"TCAD.TWO.Arc","aux":true,"edge":226,"points":[[1702,[1703,-88.51020843368133],[1704,-140.46311545122035]],[1705,[1706,-102.18982576106004],[1707,18.31440664196805]],[1708,[1709,-175.53398017227008],[1710,-67.98267439986091]]]},{"id":1722,"_class":"TCAD.TWO.Arc","aux":true,"edge":228,"points":[[1713,[1714,-93.05073865718533],[1715,-339.1473904301305]],[1716,[1717,-161.86089236160166],[1718,-230.93728827497424]],[1719,[1720,-122.42898493097368],[1721,-281.845807994961]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":824,"_class":"TCAD.TWO.Circle","c":[821,[822,196.3368270908827],[823,-38.32745196977044]],"r":60.35462341678487},{"id":839,"_class":"TCAD.TWO.Circle","c":[836,[837,132.69721678409343],[838,-101.96706227655973]],"r":19.800361524305362},{"id":844,"_class":"TCAD.TWO.Circle","c":[841,[842,132.69721678409343],[843,25.31215833701884]],"r":19.800361524305362},{"id":1728,"_class":"TCAD.TWO.Circle","c":[1725,[1726,286.3368270908827],[1727,-38.32745196977044]],"r":19.800361524305362}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[{"id":849,"_class":"TCAD.TWO.Circle","c":[846,[847,196.3368270908827],[848,-38.32745196977044]],"r":90},{"id":857,"_class":"TCAD.TWO.Segment","points":[[851,[852,196.33682709088274],[853,132.78406845227903]],[854,[855,196.33682709088274],[856,-220.71977128010505]]]},{"id":864,"_class":"TCAD.TWO.Segment","points":[[858,[859,51.75067758157451],[860,-38.32745196977045]],[861,[862,338.80027616827897],[863,-38.32745196977045]]]},{"id":865,"_class":"TCAD.TWO.EndPoint","location":[865,[866,106.33682709088271],[867,-38.32745196977044]]},{"id":868,"_class":"TCAD.TWO.EndPoint","location":[868,[869,196.3368270908827],[870,51.67254803022956]]},{"id":871,"_class":"TCAD.TWO.EndPoint","location":[871,[872,286.3368270908827],[873,-38.32745196977044]]},{"id":874,"_class":"TCAD.TWO.EndPoint","location":[874,[875,196.33682709088274],[876,-128.32745196977044]]},{"id":877,"_class":"TCAD.TWO.EndPoint","location":[877,[878,259.976437397672],[879,-101.96706227655972]]},{"id":880,"_class":"TCAD.TWO.EndPoint","location":[880,[881,132.69721678409343],[882,-101.96706227655973]]},{"id":883,"_class":"TCAD.TWO.EndPoint","location":[883,[884,259.976437397672],[885,25.31215833701884]]},{"id":886,"_class":"TCAD.TWO.EndPoint","location":[886,[887,132.69721678409343],[888,25.31215833701884]]},{"id":895,"_class":"TCAD.TWO.Segment","points":[[889,[890,304.81959818306],[891,-146.8102230619477]],[892,[893,96.47030360363001],[894,61.539071517482256]]]},{"id":902,"_class":"TCAD.TWO.Segment","points":[[896,[897,78.91914321714893],[898,-155.74513584350424]],[899,[900,306.6329904254398],[901,71.96871136478666]]]}]}],"constraints":[["Vertical",[857]],["perpendicular",[864,857]],["PointOnLine",[846,857]],["PointOnLine",[865,864]],["PointOnArc",[865,849]],["Radius",[849,90]],["PointOnArc",[868,849]],["PointOnLine",[868,857]],["PointOnArc",[871,849]],["PointOnLine",[871,864]],["PointOnArc",[874,849]],["PointOnLine",[874,857]],["Angle",[851,854,892,889,45]],["perpendicular",[902,895]],["PointOnArc",[880,849]],["PointOnLine",[880,902]],["PointOnLine",[886,895]],["PointOnArc",[886,849]],["PointOnArc",[883,849]],["PointOnLine",[883,902]],["PointOnLine",[877,895]],["PointOnArc",[877,849]],["coi",[836,880]],["coi",[841,886]],["coi",[1725,871]],["RR",[839,844]],["RR",[844,1728]]]}'); - localStorage.setItem("TCAD.projects.sample.sketch.2:0", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":3,"_class":"TCAD.TWO.Circle","aux":true,"edge":0,"c":[0,[1,-122.59914075460358],[2,157.65429488902262]],"r":92.95651034546636},{"id":8,"_class":"TCAD.TWO.Circle","aux":true,"edge":2,"c":[5,[6,-122.45917974196298],[7,-281.9821285194316]],"r":64.48310377876794}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":13,"_class":"TCAD.TWO.Circle","c":[10,[11,-122.59914075460358],[12,157.65429488902262]],"r":42.51842590924937},{"id":18,"_class":"TCAD.TWO.Circle","c":[15,[16,-122.45917974196298],[17,-281.9821285194316]],"r":34.86217749713944}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["coi",[10,0]],["coi",[15,5]]]}'); -} \ No newline at end of file diff --git a/web/app/cad/sketch/sketchReader.js b/web/app/cad/sketch/sketchReader.js index 4d090537..4682f8da 100644 --- a/web/app/cad/sketch/sketchReader.js +++ b/web/app/cad/sketch/sketchReader.js @@ -62,58 +62,47 @@ export function ReadSketch(sketch, sketchId, readConstructionSegments) { } let vectorFactory = new VectorFactory(); let pointsById = new Map(); - function ReadSketchPoint(arr) { - let pointId = arr[0]; - pointId = coiJoints.master(pointId); - let point = pointsById.get(pointId); - if (!point) { - point = vectorFactory.create(readSketchFloat(arr[1][1]), readSketchFloat(arr[2][1]), 0); - pointsById.set(pointId, point); - } - return point; + function ReadSketchPoint(pt) { + return vectorFactory.create(pt.x, pt.y, 0); } - if (sketch.layers !== undefined) { - for (let layer of sketch.layers) { - const isConstructionLayer = layer.name === "_construction_"; - - for (let obj of layer.data) { - 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 && obj.role !== 'virtual') continue; - if (obj._class === 'TCAD.TWO.Segment') { - const segA = ReadSketchPoint(obj.points[0]); - const segB = ReadSketchPoint(obj.points[1]); - 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]); - const arcB = ReadSketchPoint(obj.points[1]); - const arcCenter = ReadSketchPoint(obj.points[2]); - out.connections.push(new sm.Arc(getID(obj), arcA, arcB, arcCenter)); - } else if (obj._class === 'TCAD.TWO.EllipticalArc') { - const ep1 = ReadSketchPoint(obj.ep1); - const ep2 = ReadSketchPoint(obj.ep2); - const a = ReadSketchPoint(obj.a); - const b = ReadSketchPoint(obj.b); - out.connections.push(new sm.EllipticalArc(getID(obj), ep1, ep2, a, b, readSketchFloat(obj.r))); - } else if (obj._class === 'TCAD.TWO.BezierCurve') { - const a = ReadSketchPoint(obj.a); - const b = ReadSketchPoint(obj.b); - const cp1 = ReadSketchPoint(obj.cp1); - const cp2 = ReadSketchPoint(obj.cp2); - out.connections.push(new sm.BezierCurve(getID(obj), a, b, cp1, cp2)); - } else if (obj._class === 'TCAD.TWO.Circle') { - const circleCenter = ReadSketchPoint(obj.c); - out.loops.push(new sm.Circle(getID(obj), circleCenter, readSketchFloat(obj.r))); - } else if (obj._class === 'TCAD.TWO.Ellipse') { - const ep1 = ReadSketchPoint(obj.ep1); - const ep2 = ReadSketchPoint(obj.ep2); - out.loops.push(new sm.Ellipse(getID(obj), ep1, ep2, readSketchFloat(obj.r))); - } - } + if (sketch.version !== 3) { + return out; + } + for (let obj of sketch.objects) { + let isConstructionObject = obj.role === 'construction'; + if (isConstructionObject && !readConstructionSegments) continue; + // if (isConstructionObject && obj._class !== 'TCAD.TWO.Segment') continue; + + const data = obj.data; + if (obj.type === 'Segment') { + const segA = ReadSketchPoint(data.a); + const segB = ReadSketchPoint(data.b); + const pushOn = isConstructionObject ? out.constructionSegments : out.connections; + pushOn.push(new sm.Segment(getID(obj), segA, segB)); + } else if (obj.type === 'Arc') { + const arcA = ReadSketchPoint(data.a); + const arcB = ReadSketchPoint(data.b); + const arcCenter = ReadSketchPoint(data.c); + out.connections.push(new sm.Arc(getID(obj), arcA, arcB, arcCenter)); + } else if (obj.type === 'EllipticalArc') { + const ep1 = ReadSketchPoint(data.ep1); + const ep2 = ReadSketchPoint(data.ep2); + const a = ReadSketchPoint(data.a); + const b = ReadSketchPoint(data.b); + out.connections.push(new sm.EllipticalArc(getID(obj), ep1, ep2, a, b, readSketchFloat(data.r))); + } else if (obj.type === 'BezierCurve') { + const a = ReadSketchPoint(data.cp1); + const b = ReadSketchPoint(data.cp4); + const cp1 = ReadSketchPoint(data.cp2); + const cp2 = ReadSketchPoint(data.cp3); + out.connections.push(new sm.BezierCurve(getID(obj), a, b, cp1, cp2)); + } else if (obj.type === 'Circle') { + const circleCenter = ReadSketchPoint(data.c); + out.loops.push(new sm.Circle(getID(obj), circleCenter, readSketchFloat(data.r))); + } else if (obj.type === 'Ellipse') { + const ep1 = ReadSketchPoint(data.ep1); + const ep2 = ReadSketchPoint(data.ep2); + out.loops.push(new sm.Ellipse(getID(obj), ep1, ep2, readSketchFloat(data.r))); } } return out; diff --git a/web/app/sketcher/components/SketchObjectExplorer.jsx b/web/app/sketcher/components/SketchObjectExplorer.jsx index f39e2576..e206a298 100644 --- a/web/app/sketcher/components/SketchObjectExplorer.jsx +++ b/web/app/sketcher/components/SketchObjectExplorer.jsx @@ -68,7 +68,7 @@ export function SketchObjectExplorer() {
Objects
{objects.map(o =>
- + {getObjectRole(o)} tweakSelection(o, e.shiftKey)} className={cx(ls.objectTag, o.marked && ls.selected)}>{o.simpleClassName} {o.id} @@ -79,8 +79,8 @@ export function SketchObjectExplorer() { } function ObjectIcon({object}) { - - return null; + const Icon = object.icon; + return ; } function getClassName() { diff --git a/web/app/sketcher/components/SketchObjectExplorer.less b/web/app/sketcher/components/SketchObjectExplorer.less index 259b99e0..64e690a0 100644 --- a/web/app/sketcher/components/SketchObjectExplorer.less +++ b/web/app/sketcher/components/SketchObjectExplorer.less @@ -15,6 +15,10 @@ border-radius: @itemRadius 0 0 @itemRadius; padding: 3px 3px; background-color: @alt-color; + & svg { + width: 16px; + height: 16px; + } } .menuButton { diff --git a/web/app/sketcher/constr/AlgNumSystem.js b/web/app/sketcher/constr/AlgNumSystem.js index a2f42983..d3361cd1 100644 --- a/web/app/sketcher/constr/AlgNumSystem.js +++ b/web/app/sketcher/constr/AlgNumSystem.js @@ -319,7 +319,7 @@ export class AlgNumSubSystem { }); console.log('with respect to:'); - this.substitutionOrder.forEach(x => console.log('X' + x.id + ' = ' + this.substitutedParams.get(x).toString())); + this.substitutionOrder.forEach(x => console.log(x.toString() + ' = ' + this.substitutedParams.get(x).toString())); } } diff --git a/web/app/sketcher/generators/boundaryGenerator.js b/web/app/sketcher/generators/boundaryGenerator.js new file mode 100644 index 00000000..290e9756 --- /dev/null +++ b/web/app/sketcher/generators/boundaryGenerator.js @@ -0,0 +1,84 @@ +import {NoIcon} from "../icons/NoIcon"; +import {NOOP} from "../../../../modules/gems/func"; +import {Arc} from "../shapes/arc"; +import {EndPoint} from "../shapes/point"; +import {Circle} from "../shapes/circle"; +import {NurbsObject} from "../shapes/nurbsObject"; +import NurbsCurve from "../../brep/geom/curves/nurbsCurve"; +import {Segment} from "../shapes/segment"; + +export const BoundaryGeneratorSchema = { + + id: 'Boundary', + title: 'Boundary', + description: 'Generates object comming as a boundary data from the part editor', + internal: true, + icon: NoIcon, + persistGeneratedObjects: false, + + params: [ + { + name: 'boundaryData', + label: 'Boundary Data', + type: 'object' + }, + ], + + sourceObjects: () => { + }, + + removeObject(params, generatedObjects, object, destroy, fullDestroy) { + }, + + initiateState: state => { + }, + + generate: (params, state) => { + + const {boundaryData: boundary} = params; + + const out = []; + + let i, obj; + function process(obj) { + obj.visitParams(param => { + param.set = NOOP; + }); + out.push(obj); + } + + for (i = 0; i < boundary.lines.length; ++i) { + let edge = boundary.lines[i]; + let seg = new Segment(edge.a.x, edge.a.y, edge.b.x, edge.b.y,'boundary/' + edge.id); + process(seg); + } + for (i = 0; i < boundary.arcs.length; ++i) { + const a = boundary.arcs[i]; + const arc = new Arc( + a.a.x, a.a.y, + a.b.x, a.b.y, + a.c.x, a.c.y, + 'boundary/' + a.id + ); + process(arc); + } + for (i = 0; i < boundary.circles.length; ++i) { + obj = boundary.circles[i]; + const circle = new Circle(obj.c.x, obj.c.y, 'boundary/' + obj.id); + circle.r.set(obj.r); + process(circle); + } + for (i = 0; i < boundary.nurbses.length; ++i) { + let nurbsData = boundary.nurbses[i]; + let nurbs = new NurbsObject(NurbsCurve.deserialize(nurbsData), 'boundary/' + nurbsData.id); + process(nurbs); + } + + return out; + }, + + regenerate: (params, generatedObjects, viewer, state) => { + } + +}; + diff --git a/web/app/sketcher/generators/mirrorGenerator.js b/web/app/sketcher/generators/mirrorGenerator.js index a2eada18..cca03aff 100644 --- a/web/app/sketcher/generators/mirrorGenerator.js +++ b/web/app/sketcher/generators/mirrorGenerator.js @@ -8,6 +8,7 @@ export const MirrorGeneratorSchema = { title: 'Mirror', description: 'Reflects objects off of a given line', icon: MirrorGeneratorIcon, + persistGeneratedObjects: true, params: [ { @@ -56,7 +57,7 @@ export const MirrorGeneratorSchema = { state.dir = new Vector(); }, - generate: (params, viewer, state, onCreate) => { + generate: (params, state) => { const {reflectionLine: [reflectionLine], objects} = params; @@ -64,15 +65,12 @@ export const MirrorGeneratorSchema = { return objects.map(o => { const copy = o.copy(); - - onCreate(copy); - o.layer.add(copy); reflect(state.dir, reflectionLine, o, copy); return copy; }); }, - regenerate: (params, generatedObjects, viewer, state) => { + regenerate: (params, generatedObjects, state) => { const {reflectionLine: [reflectionLine], objects} = params; diff --git a/web/app/sketcher/generators/sketchGenerator.js b/web/app/sketcher/generators/sketchGenerator.js index aeba7a39..9e46d2ec 100644 --- a/web/app/sketcher/generators/sketchGenerator.js +++ b/web/app/sketcher/generators/sketchGenerator.js @@ -2,6 +2,7 @@ import {NOOP} from "gems/func"; import {MirrorGeneratorSchema} from "./mirrorGenerator"; import {memoize} from "lodash/function"; import {indexArray} from "gems/iterables"; +import {PREDEFINED_LAYERS} from "../viewer2d"; const SCHEMAS = [ MirrorGeneratorSchema, @@ -34,12 +35,18 @@ export class SketchGenerator { generate(viewer) { this.init(); - this.generatedObjects = this.schema.generate(this.params, viewer, this.internalState, obj => obj.generator = this); - this.generatedObjects.forEach(obj => obj.syncGeometry()); + let layer = viewer.findLayerByName(PREDEFINED_LAYERS.SKETCH); + this.generatedObjects = this.schema.generate(this.params, this.internalState); + this.generatedObjects.forEach(obj => { + obj.generator = this; + this.stage.assignObject(obj); + layer.objects.push(obj); + obj.syncGeometry() + }); } regenerate(viewer) { - this.schema.regenerate(this.params, this.generatedObjects, viewer, this.internalState); + this.schema.regenerate(this.params, this.generatedObjects, this.internalState); this.generatedObjects.forEach(obj => obj.syncGeometry()); } @@ -102,7 +109,7 @@ export class SketchGenerator { typeId: schema.id, params, stage: this.stage&&this.stage.index, - generatedObjects: this.generatedObjects.map(obj => obj.id) + generatedObjects: this.schema.persistGeneratedObjects ? this.generatedObjects.map(obj => obj.id) : undefined }; } } \ No newline at end of file diff --git a/web/app/sketcher/io.js b/web/app/sketcher/io.js deleted file mode 100644 index 43eb3f43..00000000 --- a/web/app/sketcher/io.js +++ /dev/null @@ -1,803 +0,0 @@ -import {Generator} from './id-generator' -import {Layer} from './viewer2d' -import {Styles} from './styles' -import {Arc} from './shapes/arc' -import {EndPoint} from './shapes/point' -import {Segment} from './shapes/segment' -import {Circle} from './shapes/circle' -import {Ellipse} from './shapes/ellipse' -import {EllipticalArc} from './shapes/elliptical-arc' -import {BezierCurve} from './shapes/bezier-curve' -import {AngleBetweenDimension, DiameterDimension, Dimension, HDimension, VDimension} from './shapes/dim' -import {Constraints} from './parametric' -import Vector from 'math/vector'; -import exportTextData from 'gems/exportTextData'; -import NurbsCurve from '../brep/geom/curves/nurbsCurve'; -import {NurbsObject} from './shapes/nurbsObject'; -import {AlgNumConstraint} from "./constr/ANConstraints"; -import {SketchGenerator} from "./generators/sketchGenerator"; -import {SketchTypes} from "./shapes/sketch-types"; -import {NOOP} from "../../../modules/gems/func"; - -const Types = SketchTypes; - -IO.BOUNDARY_LAYER_NAME = "__bounds__"; - -/** @constructor */ -function IO(viewer) { - this.viewer = viewer; -} - -IO.prototype.loadSketch = function(sketchData) { - return this._loadSketch(JSON.parse(sketchData)); -}; - -IO.prototype.serializeSketch = function(metadata) { - return JSON.stringify(this._serializeSketch(metadata)); -}; - -IO.prototype._loadSketch = function(sketch) { - - this.cleanUpData(); - - this.viewer.parametricManager.startTransaction(); - - const index = {}; - - function endPoint(p) { - const [id, [xref, x], [yref, y]] = p; - let ep = index[id]; - if (ep !== undefined) { - return ep; - } - ep = new EndPoint(x, y); - index[xref] = ep.params.x; - index[yref] = ep.params.y; - index[id] = ep; - return ep; - } - - const getStage = pointer => { - if (pointer === undefined) { - return this.viewer.parametricManager.stage; - } - this.viewer.parametricManager.accommodateStages(pointer); - return this.viewer.parametricManager.getStage(pointer); - }; - - let layerIdGen = 0; - function getLayer(viewer, name) { - if (name === undefined) { - name = "layer_" + layerIdGen++; - } else { - if (name === viewer.dimLayer.name) { - return viewer.dimLayer; - } - for (let i = 0; i < viewer.layers.length; ++i) { - if (name === viewer.layers[i].name) { - return viewer.layers[i]; - } - } - } - let layer = viewer.createLayer(name, Styles.DEFAULT); - viewer.layers.push(layer); - return layer; - } - const version = sketch.version || 1; - let T = Types; - let sketchLayers = sketch.layers; - let boundary = sketch.boundary; - - const dimensions = []; - if (sketchLayers !== undefined) { - for (let l = 0; l < sketchLayers.length; ++l) { - let ioLayer = sketchLayers[l]; - let layerName = ioLayer.name; - if (layerName === IO.BOUNDARY_LAYER_NAME && boundary) { - continue; - } - let layer = getLayer(this.viewer, layerName); - // if (!!ioLayer.style) layer.style = ioLayer.style; - layer.readOnly = !!ioLayer.readOnly; - let layerData = ioLayer.data; - for (let i = 0; i < layerData.length; ++i) { - let obj = layerData[i]; - let skobj = null; - let _class = obj._class; - let aux = !!obj.aux; - let role = obj.role; - - //support legacy format - if (!role) { - role = layerName === '_construction_' ? 'construction' : null; - } - - if (_class === T.SEGMENT) { - const [aRef, bRef] = obj.points; - const a = endPoint(aRef); - const b = endPoint(bRef); - skobj = new Segment(a, b); - } else if (_class === T.POINT) { - skobj = endPoint(obj.location); - } else if (_class === T.ARC) { - const points = obj.points; - const a = endPoint(points[0]); - const b = endPoint(points[1]); - const c = endPoint(points[2]); - skobj = new Arc(a, b, c); - } else if (_class === T.CIRCLE) { - const c = endPoint(obj.c); - skobj = new Circle(c); - skobj.r.set(obj.r); - } else if (_class === T.ELLIPSE) { - const ep1 = endPoint(obj.ep1); - const ep2 = endPoint(obj.ep2); - skobj = new Ellipse(ep1, ep2); - skobj.r.set(obj.r); - } else if (_class === T.ELL_ARC) { - const ep1 = endPoint(obj.ep1); - const ep2 = endPoint(obj.ep2); - const a = endPoint(obj.a); - const b = endPoint(obj.b); - skobj = new EllipticalArc(ep1, ep2, a, b); - skobj.r.set(obj.r); - } else if (_class === T.BEZIER) { - const a = endPoint(obj.a); - const b = endPoint(obj.b); - const cp1 = endPoint(obj.cp1); - const cp2 = endPoint(obj.cp2); - skobj = new BezierCurve(a, b, cp1, cp2); - } else { - dimensions.push(obj); - } - if (skobj != null) { - skobj.role = role; - getStage(obj.stage).assignObject(skobj); - if (!aux) skobj.stabilize(this.viewer); - if (aux) skobj.accept(function(o){o.aux = true; return true;}); - layer.add(skobj); - index[obj.id] = skobj; - - //reindex non point children to recover constraints - const childrenIds = obj.children; - if (childrenIds) { - const children = nonPointChildren(skobj); - for (let childIdx = 0; childIdx < childrenIds.length; childIdx++) { - index[childrenIds[childIdx]] = children[childIdx]; - } - } - } - } - } - } - - for (let obj of dimensions) { - let _class = obj._class; - let skobj = null; - if (_class === T.HDIM) { - skobj = new HDimension(index[obj.a], index[obj.b]); - obj.offset !== undefined && (skobj.offset = obj.offset); - } else if (_class === T.VDIM) { - skobj = new VDimension(index[obj.a], index[obj.b]); - obj.offset !== undefined && (skobj.offset = obj.offset); - } else if (_class === T.DIM) { - skobj = new Dimension(index[obj.a], index[obj.b]); - obj.offset !== undefined && (skobj.offset = obj.offset); - } else if (_class === T.DDIM) { - skobj = new DiameterDimension(index[obj.obj]); - skobj.angle = obj.angle; - } else if (_class === T.ANGLE_BW) { - skobj = new AngleBetweenDimension(index[obj.a], index[obj.b]); - skobj.offset = obj.offset; - if (obj.configuration) { - skobj.configuration = obj.configuration.map(o => index[o]); - } - } - if (skobj !== null) { - this.viewer.dimLayer.add(skobj); - index[obj.id] = skobj; - } - } - - if (boundary) { - this.createBoundaryObjects(boundary); - } - - if (sketch.constraints && !sketch.stages) { - sketch.stages = [ - { - constraints: sketch.constraints, - generators: [] - } - ] - } - - if (sketch.stages) { - for (let stage of sketch.stages) { - - for (let constr of stage.constraints) { - try { - const constraint = AlgNumConstraint.read(constr, index); - const stage = getStage(constr.stage||0); - stage.addConstraint(constraint); - } catch (e) { - console.error(e); - console.error("skipping errant constraint: " + constr&&constr.typeId); - } - } - for (let gen of stage.generators) { - try { - const generator = SketchGenerator.read(gen, index); - const stage = getStage(gen.stage||0); - stage.addGenerator(generator); - } catch (e) { - console.error(e); - console.error("skipping errant generator: " + gen&&gen.typeId); - } - } - - } - - } - let constants = sketch.constants; - if (constants !== undefined) { - this.viewer.parametricManager.$constantDefinition.next(constants); - } - - this.viewer.parametricManager.finishTransaction(); - this.viewer.parametricManager.notify(); -}; - - -IO.prototype.synchLine = function(skobj, edgeObj) { - skobj.a.x = edgeObj.a.x; - skobj.a.y = edgeObj.a.y; - skobj.b.x = edgeObj.b.x; - skobj.b.y = edgeObj.b.y; -}; - -IO.prototype.synchArc = function(skobj, edgeObj) { - skobj.a.x = edgeObj.a.x; - skobj.a.y = edgeObj.a.y; - skobj.b.x = edgeObj.b.x; - skobj.b.y = edgeObj.b.y; - skobj.c.x = edgeObj.c.x; - skobj.c.y = edgeObj.c.y; -}; - -IO.prototype.synchCircle = function(skobj, edgeObj) { - skobj.c.x = edgeObj.c.x; - skobj.c.y = edgeObj.c.y; - skobj.r.set(edgeObj.r); -}; - -IO.prototype.createBoundaryObjects = function(boundary) { - const groundStage = this.viewer.parametricManager.groundStage; - let boundaryLayer = this.viewer.findLayerByName(IO.BOUNDARY_LAYER_NAME); - - if (boundaryLayer === null) { - boundaryLayer = this.viewer.createLayer(IO.BOUNDARY_LAYER_NAME, Styles.BOUNDS); - this.viewer.layers.splice(0, 0, boundaryLayer); - } - - boundaryLayer.readOnly = true; - boundaryLayer.style = Styles.BOUNDS; - - let i, obj; - function setId(obj, id) { - obj.id = id; - let counter = 0; - obj.accept(child => { - if (child !== obj) { - child.id = id + '/' + (++counter); - } - }); - obj.visitParams(param => { - param.set = NOOP; - }); - obj.stage = groundStage; - } - - for (i = 0; i < boundary.lines.length; ++i) { - let edge = boundary.lines[i]; - let seg = this.viewer.addSegment(edge.a.x, edge.a.y, edge.b.x, edge.b.y, boundaryLayer); - setId(seg, edge.id); - } - for (i = 0; i < boundary.arcs.length; ++i) { - const a = boundary.arcs[i]; - const arc = new Arc( - new EndPoint(a.a.x, a.a.y), - new EndPoint(a.b.x, a.b.y), - new EndPoint(a.c.x, a.c.y) - ); - boundaryLayer.objects.push(arc); - setId(arc, a.id); - } - for (i = 0; i < boundary.circles.length; ++i) { - obj = boundary.circles[i]; - const circle = new Circle(new EndPoint(obj.c.x, obj.c.y)); - circle.r.set(obj.r); - boundaryLayer.objects.push(circle); - setId(circle, obj.id); - } - for (i = 0; i < boundary.nurbses.length; ++i) { - let nurbsData = boundary.nurbses[i]; - let nurbs = new NurbsObject(NurbsCurve.deserialize(nurbsData), new EndPoint(), new EndPoint()); - boundaryLayer.objects.push(nurbs); - setId(nurbs, nurbsData.id); - } -}; - -IO.prototype.cleanUpData = function() { - for (var l = 0; l < this.viewer.layers.length; ++l) { - var layer = this.viewer.layers[l]; - if (layer.objects.length !== 0) { - layer.objects = []; - } - } - this.viewer.deselectAll(); - Generator.resetIDGenerator(0); - - this.viewer.parametricManager.reset(); - this.viewer.parametricManager.notify(); - -}; - -IO.prototype._serializeSketch = function(metadata) { - var sketch = {}; - //sketch.boundary = boundary; - sketch.layers = []; - function point(p) { - return [ p.id, [p.params.x.id, p.x], [p.params.y.id, p.y] ]; - } - var T = Types; - var toSave = [this.viewer.dimLayers, this.viewer.layers]; - for (var t = 0; t < toSave.length; ++t) { - var layers = toSave[t]; - for (var l = 0; l < layers.length; ++l) { - var layer = layers[l]; - if (layer.name === IO.BOUNDARY_LAYER_NAME) { - continue; - } - var toLayer = {name : layer.name, readOnly: layer.readOnly, data : []}; - sketch.layers.push(toLayer); - for (var i = 0; i < layer.objects.length; ++i) { - const obj = layer.objects[i]; - if (obj.isAnnotation) { - continue; - } - try { - const 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; - to.stage = this.viewer.parametricManager.getStageIndex(obj.stage); - if (obj._class === T.SEGMENT) { - to.points = [point(obj.a), point(obj.b)]; - } else if (obj._class === T.POINT) { - to.location = point(obj); - } else if (obj._class === T.ARC) { - to.points = [point(obj.a), point(obj.b), point(obj.c)]; - } else if (obj._class === T.CIRCLE) { - to.c = point(obj.c); - to.r = obj.r.get(); - } else if (obj._class === T.ELLIPSE) { - to.ep1 = point(obj.ep1); - to.ep2 = point(obj.ep2); - to.r = obj.r.get(); - } else if (obj._class === T.ELL_ARC) { - to.ep1 = point(obj.ep1); - to.ep2 = point(obj.ep2); - to.a = point(obj.a); - to.b = point(obj.b); - to.r = obj.r.get(); - } else if (obj._class === T.BEZIER) { - to.a = point(obj.a); - to.b = point(obj.b); - to.cp1 = point(obj.cp1); - to.cp2 = point(obj.cp2); - } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { - to.a = obj.a.id; - to.b = obj.b.id; - to.offset = obj.offset; - } else if (obj._class === T.DDIM) { - to.obj = obj.obj.id; - to.angle = obj.angle; - } else if (obj._class === T.ANGLE_BW) { - to.a = obj.a.id; - to.b = obj.b.id; - to.offset = obj.offset; - to.configuration = obj.configuration.map(o => o.id); - } - const children = nonPointChildren(obj).map(c => c.id); - if (children.length !== 0) { - to.children = children; - } - toLayer.data.push(to); - } catch (e) { - console.error(e); - } - } - } - } - - sketch.stages = []; - - for (let stage of this.viewer.parametricManager.stages) { - const stageOut = { - constraints: [], - generators: [], - }; - const systemConstraints = stage.algNumSystem.allConstraints; - for (let sc of systemConstraints) { - if (!sc.internal) { - stageOut.constraints.push(sc.write()); - } - } - - for (let gen of stage.generators) { - stageOut.generators.push(gen.write()); - } - - sketch.stages.push(stageOut); - } - - const constantDefinition = this.viewer.parametricManager.constantDefinition; - if (constantDefinition !== undefined && constantDefinition != null && !/^\s*$/.test(constantDefinition)) { - sketch.constants = constantDefinition; - } - sketch.scene = { - dx: this.viewer.translate.x, - dy: this.viewer.translate.y, - scale: this.viewer.scale, - }; - sketch.metadata = metadata; - sketch.version = 2; - return sketch; -}; - -function nonPointChildren(obj){ - const children = []; - obj.accept((o) => { - if (o._class !== Types.POINT) { - children.push(o); - } - return true; - }); - return children; -} - -IO.prototype.parseConstr = function (c, index) { - var name = c[0]; - var ps = c[1]; - function find(id) { - var p = index[id]; - if (!p) { - throw "Constraint " + name + " refers to nonexistent object."; - } - return p; - } - var constrCreate = Constraints.Factory[name]; - if (constrCreate === undefined) { - throw "Constraint " + name + " doesn't exist."; - } - return constrCreate(find, ps); -}; - - -function _format(str, args) { - if (args.length == 0) return str; - var i = 0; - return str.replace(/\$/g, function() { - if (args === undefined || args[i] === undefined) throw "format arguments mismatch"; - var val = args[i]; - if (typeof val === 'number') val = val.toPrecision(); - i ++; - return val; - }); -} - -/** @constructor */ -function PrettyColors() { - var colors = ["#000000", "#00008B", "#006400", "#8B0000", "#FF8C00", "#E9967A"]; - var colIdx = 0; - this.next = function () { - return colors[colIdx++ % colors.length]; - } -} - -/** @constructor */ -function TextBuilder() { - this.data = ""; - this.fline = function (chunk, args) { - this.data += _format(chunk, args) + "\n" - }; - this.line = function (chunk) { - this.data += chunk + "\n" - }; - this.number = function (n) { - this.data += n.toPrecision() - }; - this.numberln = function (n) { - this.number(n) - this.data += "\n" - } -} - -/** @constructor */ -function BBox() { - var bbox = [Number.MAX_VALUE, Number.MAX_VALUE, - Number.MAX_VALUE, - Number.MAX_VALUE]; - - var T = Types; - - this.checkLayers = function(layers) { - for (var l = 0; l < layers.length; ++l) - for (var i = 0; i < layers[l].objects.length; ++i) - this.check(layers[l].objects[i]); - }; - - this.check = function(obj) { - if (obj._class === T.SEGMENT) { - this.checkBounds(obj.a.x, obj.a.y); - this.checkBounds(obj.b.x, obj.b.y); - } else if (obj._class === T.POINT) { - this.checkBounds(obj.x, obj.y); - } else if (obj._class === T.ARC) { - this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get()); - } else if (obj._class === T.CIRCLE) { - this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get()); - } else if (obj._class === T.ELLIPSE || obj._class === T.ELL_ARC) { - this.checkCircBounds(obj.centerX, obj.centerY, Math.max(obj.radiusX, obj.radiusY)); - } else if (obj) { - obj.accept((o) => { - if (o._class == T.POINT) { - this.checkBounds(o.x, o.y); - } - return true; - }); -// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { - } - }; - - this.isValid = function() { - return bbox[0] != Number.MAX_VALUE; - }; - - this.checkBounds = function(x, y) { - bbox[0] = Math.min(bbox[0], x); - bbox[1] = Math.min(bbox[1], y); - bbox[2] = Math.max(bbox[2], x); - bbox[3] = Math.max(bbox[3], y); - }; - - this.checkCircBounds = function(x, y, r) { - this.checkBounds(x + r, y + r); - this.checkBounds(x - r, y + r); - this.checkBounds(x - r, y - r); - this.checkBounds(x - r, y + r); - }; - - this.inc = function(by) { - bbox[0] -= by; - bbox[1] -= by; - bbox[2] += by; - bbox[3] += by; - }; - - this.width = function() { - return bbox[2] - bbox[0]; - }; - - this.height = function() { - return bbox[3] - bbox[1]; - }; - - this.bbox = bbox; -} - -IO.prototype.getWorkspaceToExport = function() { - return [this.viewer.layers]; -}; - -IO.prototype.getLayersToExport = function() { - var ws = this.getWorkspaceToExport(); - var toExport = []; - for (var t = 0; t < ws.length; ++t) { - var layers = ws[t]; - for (var l = 0; l < layers.length; ++l) { - var layer = layers[l]; - toExport.push(layer) - } - } - return toExport; -}; - -IO.prototype.svgExport = function () { - - var T = Types; - var out = new TextBuilder(); - - var bbox = new BBox(); - - var a = new Vector(); - var b = new Vector(); - - var prettyColors = new PrettyColors(); - var toExport = this.getLayersToExport(); - for (var l = 0; l < toExport.length; ++l) { - var layer = toExport[l]; - var color = prettyColors.next(); - out.fline('', [layer.name, "none", color, '2']); - for (var i = 0; i < layer.objects.length; ++i) { - var obj = layer.objects[i]; - if (obj._class !== T.POINT) bbox.check(obj); - if (obj._class === T.SEGMENT) { - out.fline('', [obj.a.x, obj.a.y, obj.b.x, obj.b.y]); - } else if (obj._class === T.ARC) { - a.set(obj.a.x - obj.c.x, obj.a.y - obj.c.y, 0); - b.set(obj.b.x - obj.c.x, obj.b.y - obj.c.y, 0); - var dir = a.cross(b).z > 0 ? 0 : 1; - var r = obj.r.get(); - out.fline('', [obj.a.x, obj.a.y, r, r, dir, 1, obj.b.x, obj.b.y]); - } else if (obj._class === T.CIRCLE) { - out.fline('', [obj.c.x, obj.c.y, obj.r.get()]); -// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { - } - } - out.line(''); - } - bbox.inc(20); - return _format("\n", bbox.bbox) + out.data + "" -}; - -IO.prototype.dxfExport = function () { - var T = Types; - var out = new TextBuilder(); - var bbox = new BBox(); - var toExport = this.getLayersToExport(); - var i; - bbox.checkLayers(toExport); - out.line("999"); - out.line("js.parametric.sketcher"); - out.line("0"); - out.line("SECTION"); - out.line("2"); - out.line("HEADER"); - out.line("9"); - out.line("$ACADVER"); - out.line("1"); - out.line("AC1006"); - out.line("9"); - out.line("$INSBASE"); - out.line("10"); - out.line("0"); - out.line("20"); - out.line("0"); - out.line("30"); - out.line("0"); - out.line("9"); - out.line("$EXTMIN"); - out.line("10"); - out.numberln(bbox.bbox[0]); - out.line("20"); - out.numberln(bbox.bbox[1]); - out.line("9"); - out.line("$EXTMAX"); - out.line("10"); - out.numberln(bbox.bbox[2]); - out.line("20"); - out.numberln(bbox.bbox[3]); - out.line("0"); - out.line("ENDSEC"); - - out.line("0"); - out.line("SECTION"); - out.line("2"); - out.line("TABLES"); - - for (i = 0; i < toExport.length; i++) { - out.line("0"); - out.line("LAYER"); - out.line("2"); - out.line("" + (i + 1)); - out.line("70"); - out.line("64"); - out.line("62"); - out.line("7"); - out.line("6"); - out.line("CONTINUOUS"); - } - out.line("0"); - out.line("ENDTAB"); - out.line("0"); - out.line("ENDSEC"); - out.line("0"); - out.line("SECTION"); - out.line("2"); - out.line("BLOCKS"); - out.line("0"); - out.line("ENDSEC"); - out.line("0"); - out.line("SECTION"); - out.line("2"); - out.line("ENTITIES"); - - for (var l = 0; l < toExport.length; l++) { - var lid = l + 1; - var layer = toExport[l]; - for (i = 0; i < layer.objects.length; ++i) { - var obj = layer.objects[i]; - if (obj._class === T.POINT) { - out.line("0"); - out.line("POINT"); - out.line("8"); - out.line(lid); - out.line("10"); - out.numberln(obj.x); - out.line("20"); - out.numberln(obj.y); - out.line("30"); - out.line("0"); - } else if (obj._class === T.SEGMENT) { - out.line("0"); - out.line("LINE"); - out.line("8"); - out.line(lid); - //out.line("62"); color - //out.line("4"); - out.line("10"); - out.numberln(obj.a.x); - out.line("20"); - out.numberln(obj.a.y); - out.line("30"); - out.line("0"); - out.line("11"); - out.numberln(obj.b.x); - out.line("21"); - out.numberln(obj.b.y); - out.line("31"); - out.line("0"); - } else if (obj._class === T.ARC) { - out.line("0"); - out.line("ARC"); - out.line("8"); - out.line(lid); - out.line("10"); - out.numberln(obj.c.x); - out.line("20"); - out.numberln(obj.c.y); - out.line("30"); - out.line("0"); - out.line("40"); - out.numberln(obj.r.get()); - out.line("50"); - out.numberln(obj.getStartAngle() * (180 / Math.PI)); - out.line("51"); - out.numberln(obj.getEndAngle() * (180 / Math.PI)); - } else if (obj._class === T.CIRCLE) { - out.line("0"); - out.line("CIRCLE"); - out.line("8"); - out.line(lid); - out.line("10"); - out.numberln(obj.c.x); - out.line("20"); - out.numberln(obj.c.y); - out.line("30"); - out.line("0"); - out.line("40"); - out.numberln(obj.r.get()); -// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { - } - } - } - - out.line("0"); - out.line("ENDSEC"); - out.line("0"); - out.line("EOF"); - return out.data; -}; - -IO.exportTextData = exportTextData; - -export {IO, BBox}; \ No newline at end of file diff --git a/web/app/sketcher/io.ts b/web/app/sketcher/io.ts new file mode 100644 index 00000000..918c8087 --- /dev/null +++ b/web/app/sketcher/io.ts @@ -0,0 +1,613 @@ +import {Generator} from './id-generator' +import {Viewer} from './viewer2d' +import {Styles} from './styles' +import {Arc} from './shapes/arc' +import {EndPoint} from './shapes/point' +import {Segment} from './shapes/segment' +import {Circle} from './shapes/circle' +import {Ellipse} from './shapes/ellipse' +import {EllipticalArc} from './shapes/elliptical-arc' +import {BezierCurve} from './shapes/bezier-curve' +import {LinearDimension, AngleBetweenDimension, DiameterDimension, Dimension, HDimension, VDimension} from './shapes/dim' +import Vector from 'math/vector'; +import exportTextData from 'gems/exportTextData'; +import {AlgNumConstraint} from "./constr/ANConstraints"; +import {SketchGenerator} from "./generators/sketchGenerator"; +import {BoundaryGeneratorSchema} from "./generators/boundaryGenerator"; +import {SketchTypes} from "./shapes/sketch-types"; +import {SketchObject} from "./shapes/sketch-object"; + +export interface SketchFormat_V3 { + + version: number; + + objects: { + id: string, + type: string, + role: string, + stage: number, + data: any + }[]; + + dimensions: { + id: string, + type: string, + data: any + }[]; + + stages: { + + generators: { + typeId: string + }[]; + + constraints: { + typeId: string + }[]; + + }[]; + + constants: { + [key: string]: string; + }; + + metadata: any; + + boundary?: ExternalBoundary + +} + +class ExternalBoundary { + +} + + +export class IO { + + static exportTextData = exportTextData + + viewer: Viewer; + + constructor(viewer) { + this.viewer = viewer; + } + + + loadSketch(sketchData) { + return this._loadSketch(JSON.parse(sketchData)); + } + + serializeSketch(metadata) { + return JSON.stringify(this._serializeSketch(metadata)); + } + + _loadSketch(sketch: SketchFormat_V3) { + + this.cleanUpData(); + + this.viewer.parametricManager.startTransaction(); + try { + const getStage = pointer => { + if (pointer === undefined) { + return this.viewer.parametricManager.stage; + } + this.viewer.parametricManager.accommodateStages(pointer); + return this.viewer.parametricManager.getStage(pointer); + }; + + if (sketch.boundary) { + this.createBoundaryObjects(sketch.boundary); + } + + if (sketch.version !== 3) { + return; + } + + const sketchLayer = this.viewer.findLayerByName('sketch'); + for (let obj of sketch.objects) { + try { + let skobj: SketchObject = null; + let type = obj.type; + + if (type === Segment.prototype.TYPE) { + skobj = Segment.read(obj.id, obj.data); + } else if (type === EndPoint.prototype.TYPE) { + skobj = EndPoint.read(obj.id, obj.data); + } else if (type === Arc.prototype.TYPE) { + skobj = Arc.read(obj.id, obj.data); + } else if (type === Circle.prototype.TYPE) { + skobj = Circle.read(obj.id, obj.data); + } else if (type === Ellipse.prototype.TYPE) { + skobj = Ellipse.read(obj.id, obj.data); + } else if (type === EllipticalArc.prototype.TYPE) { + skobj = EllipticalArc.read(obj.id, obj.data); + } else if (type === EllipticalArc.prototype.TYPE) { + skobj = BezierCurve.read(obj.id, obj.data); + } + if (skobj != null) { + skobj.role = obj.role; + getStage(obj.stage).assignObject(skobj); + sketchLayer.add(skobj); + skobj.stabilize(this.viewer); + } + + } catch (e) { + console.error(e); + console.error("Failed loading " + obj.type + " " + obj.id); + } + } + + for (let obj of sketch.dimensions) { + try { + let type = obj.type; + let skobj = null; + if (type === HDimension.prototype.TYPE) { + skobj = LinearDimension.load(HDimension, obj.id, obj.data); + } else if (type === VDimension.prototype.TYPE) { + skobj = LinearDimension.load(VDimension, obj.id, obj.data); + } else if (type === LinearDimension.prototype.TYPE) { + skobj = LinearDimension.load(LinearDimension, obj.id, obj.data); + } else if (type === DiameterDimension.prototype.TYPE) { + skobj = DiameterDimension.load(obj.id, obj.data); + } else if (type === AngleBetweenDimension.prototype.TYPE) { + skobj = AngleBetweenDimension.load(obj.id, obj.data); + } + if (skobj !== null) { + this.viewer.dimLayer.add(skobj); + } + + } catch (e) { + console.error(e); + console.error("Failed loading " + obj.type + " " + obj.id); + } + } + + + const index = this.viewer.createIndex(); + + for (let i = 0; i < sketch.stages.length; i++) { + let dataStage = sketch.stages[i]; + let stage = getStage(i); + for (let constr of dataStage.constraints) { + try { + const constraint = AlgNumConstraint.read(constr, index); + stage.addConstraint(constraint) + } catch (e) { + console.error(e); + console.error("skipping errant constraint: " + constr&&constr.typeId); + } + } + for (let gen of dataStage.generators) { + try { + const generator = SketchGenerator.read(gen, index); + stage.addGenerator(generator) + } catch (e) { + console.error(e); + console.error("skipping errant generator: " + gen&&gen.typeId); + } + } + } + + let constants = sketch.constants; + if (constants !== undefined) { + this.viewer.parametricManager.$constantDefinition.next(constants); + } + + } finally { + this.viewer.parametricManager.finishTransaction(); + this.viewer.parametricManager.notify(); + } + + }; + + + createBoundaryObjects(boundary) { + + const boundaryGenerator = new SketchGenerator({ + boundaryData: boundary + }, BoundaryGeneratorSchema); + + this.viewer.parametricManager.addGeneratorToStage(boundaryGenerator, this.viewer.parametricManager.groundStage); + } + + cleanUpData() { + for (var l = 0; l < this.viewer.layers.length; ++l) { + var layer = this.viewer.layers[l]; + if (layer.objects.length !== 0) { + layer.objects = []; + } + } + this.viewer.deselectAll(); + Generator.resetIDGenerator(0); + + this.viewer.parametricManager.reset(); + this.viewer.parametricManager.notify(); + + }; + + _serializeSketch(metadata) { + + const sketch: SketchFormat_V3 = { + version: 3, + objects: [], + dimensions: [], + stages: [], + constants: this.viewer.parametricManager.constantDefinition, + metadata + }; + + for (let layer of this.viewer.layers) { + for (let obj of layer.objects) { + if (obj instanceof Dimension) { + continue; + } + if (obj.isGenerated && !obj.generator.schema.persistGeneratedObjects) { + continue; + } + try { + sketch.objects.push({ + id: obj.id, + type: obj.TYPE, + role: obj.role, + stage: this.viewer.parametricManager.getStageIndex(obj.stage), + data: obj.write() + }); + } catch (e) { + console.error(e); + } + } + } + + for (let obj of this.viewer.dimLayer.objects) { + try { + sketch.dimensions.push({ + id: obj.id, + type: obj.TYPE, + data: obj.write() + }); + } catch (e) { + console.error(e); + } + } + + for (let stage of this.viewer.parametricManager.stages) { + const stageOut = { + constraints: [], + generators: [], + }; + const systemConstraints = stage.algNumSystem.allConstraints; + for (let sc of systemConstraints) { + if (!sc.internal) { + stageOut.constraints.push(sc.write()); + } + } + + for (let gen of stage.generators) { + if (gen.internal) { + continue; + } + stageOut.generators.push(gen.write()); + } + + sketch.stages.push(stageOut); + } + + return sketch; + }; + + getWorkspaceToExport() { + return [this.viewer.layers]; + }; + + getLayersToExport() { + var ws = this.getWorkspaceToExport(); + var toExport = []; + for (var t = 0; t < ws.length; ++t) { + var layers = ws[t]; + for (var l = 0; l < layers.length; ++l) { + var layer = layers[l]; + toExport.push(layer) + } + } + return toExport; + } + + svgExport() { + + var T = SketchTypes; + var out = new TextBuilder(); + + var bbox = new BBox(); + + var a = new Vector(); + var b = new Vector(); + + var prettyColors = new PrettyColors(); + var toExport = this.getLayersToExport(); + for (var l = 0; l < toExport.length; ++l) { + var layer = toExport[l]; + var color = prettyColors.next(); + out.fline('', [layer.name, "none", color, '2']); + for (var i = 0; i < layer.objects.length; ++i) { + var obj = layer.objects[i]; + if (obj._class !== T.POINT) bbox.check(obj); + if (obj._class === T.SEGMENT) { + out.fline('', [obj.a.x, obj.a.y, obj.b.x, obj.b.y]); + } else if (obj._class === T.ARC) { + a.set(obj.a.x - obj.c.x, obj.a.y - obj.c.y, 0); + b.set(obj.b.x - obj.c.x, obj.b.y - obj.c.y, 0); + var dir = a.cross(b).z > 0 ? 0 : 1; + var r = obj.r.get(); + out.fline('', [obj.a.x, obj.a.y, r, r, dir, 1, obj.b.x, obj.b.y]); + } else if (obj._class === T.CIRCLE) { + out.fline('', [obj.c.x, obj.c.y, obj.r.get()]); +// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { + } + } + out.line(''); + } + bbox.inc(20); + return _format("\n", bbox.bbox) + out.data + "" + }; + + dxfExport() { + var T = SketchTypes; + var out = new TextBuilder(); + var bbox = new BBox(); + var toExport = this.getLayersToExport(); + var i; + bbox.checkLayers(toExport); + out.line("999"); + out.line("js.parametric.sketcher"); + out.line("0"); + out.line("SECTION"); + out.line("2"); + out.line("HEADER"); + out.line("9"); + out.line("$ACADVER"); + out.line("1"); + out.line("AC1006"); + out.line("9"); + out.line("$INSBASE"); + out.line("10"); + out.line("0"); + out.line("20"); + out.line("0"); + out.line("30"); + out.line("0"); + out.line("9"); + out.line("$EXTMIN"); + out.line("10"); + out.numberln(bbox.bbox[0]); + out.line("20"); + out.numberln(bbox.bbox[1]); + out.line("9"); + out.line("$EXTMAX"); + out.line("10"); + out.numberln(bbox.bbox[2]); + out.line("20"); + out.numberln(bbox.bbox[3]); + out.line("0"); + out.line("ENDSEC"); + + out.line("0"); + out.line("SECTION"); + out.line("2"); + out.line("TABLES"); + + for (i = 0; i < toExport.length; i++) { + out.line("0"); + out.line("LAYER"); + out.line("2"); + out.line("" + (i + 1)); + out.line("70"); + out.line("64"); + out.line("62"); + out.line("7"); + out.line("6"); + out.line("CONTINUOUS"); + } + out.line("0"); + out.line("ENDTAB"); + out.line("0"); + out.line("ENDSEC"); + out.line("0"); + out.line("SECTION"); + out.line("2"); + out.line("BLOCKS"); + out.line("0"); + out.line("ENDSEC"); + out.line("0"); + out.line("SECTION"); + out.line("2"); + out.line("ENTITIES"); + + for (var l = 0; l < toExport.length; l++) { + var lid = l + 1; + var layer = toExport[l]; + for (i = 0; i < layer.objects.length; ++i) { + var obj = layer.objects[i]; + if (obj._class === T.POINT) { + out.line("0"); + out.line("POINT"); + out.line("8"); + out.line(lid); + out.line("10"); + out.numberln(obj.x); + out.line("20"); + out.numberln(obj.y); + out.line("30"); + out.line("0"); + } else if (obj._class === T.SEGMENT) { + out.line("0"); + out.line("LINE"); + out.line("8"); + out.line(lid); + //out.line("62"); color + //out.line("4"); + out.line("10"); + out.numberln(obj.a.x); + out.line("20"); + out.numberln(obj.a.y); + out.line("30"); + out.line("0"); + out.line("11"); + out.numberln(obj.b.x); + out.line("21"); + out.numberln(obj.b.y); + out.line("31"); + out.line("0"); + } else if (obj._class === T.ARC) { + out.line("0"); + out.line("ARC"); + out.line("8"); + out.line(lid); + out.line("10"); + out.numberln(obj.c.x); + out.line("20"); + out.numberln(obj.c.y); + out.line("30"); + out.line("0"); + out.line("40"); + out.numberln(obj.r.get()); + out.line("50"); + out.numberln(obj.getStartAngle() * (180 / Math.PI)); + out.line("51"); + out.numberln(obj.getEndAngle() * (180 / Math.PI)); + } else if (obj._class === T.CIRCLE) { + out.line("0"); + out.line("CIRCLE"); + out.line("8"); + out.line(lid); + out.line("10"); + out.numberln(obj.c.x); + out.line("20"); + out.numberln(obj.c.y); + out.line("30"); + out.line("0"); + out.line("40"); + out.numberln(obj.r.get()); +// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { + } + } + } + + out.line("0"); + out.line("ENDSEC"); + out.line("0"); + out.line("EOF"); + return out.data; + }; +} + +function _format(str, args) { + if (args.length == 0) return str; + var i = 0; + return str.replace(/\$/g, function() { + if (args === undefined || args[i] === undefined) throw "format arguments mismatch"; + var val = args[i]; + if (typeof val === 'number') val = val.toPrecision(); + i ++; + return val; + }); +} + +/** @constructor */ +function PrettyColors() { + var colors = ["#000000", "#00008B", "#006400", "#8B0000", "#FF8C00", "#E9967A"]; + var colIdx = 0; + this.next = function () { + return colors[colIdx++ % colors.length]; + } +} + +/** @constructor */ +function TextBuilder() { + this.data = ""; + this.fline = function (chunk, args) { + this.data += _format(chunk, args) + "\n" + }; + this.line = function (chunk) { + this.data += chunk + "\n" + }; + this.number = function (n) { + this.data += n.toPrecision() + }; + this.numberln = function (n) { + this.number(n) + this.data += "\n" + } +} + +/** @constructor */ +function BBox() { + var bbox = [Number.MAX_VALUE, Number.MAX_VALUE, - Number.MAX_VALUE, - Number.MAX_VALUE]; + + var T = SketchTypes; + + this.checkLayers = function(layers) { + for (var l = 0; l < layers.length; ++l) + for (var i = 0; i < layers[l].objects.length; ++i) + this.check(layers[l].objects[i]); + }; + + this.check = function(obj) { + if (obj._class === T.SEGMENT) { + this.checkBounds(obj.a.x, obj.a.y); + this.checkBounds(obj.b.x, obj.b.y); + } else if (obj._class === T.POINT) { + this.checkBounds(obj.x, obj.y); + } else if (obj._class === T.ARC) { + this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get()); + } else if (obj._class === T.CIRCLE) { + this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get()); + } else if (obj._class === T.ELLIPSE || obj._class === T.ELL_ARC) { + this.checkCircBounds(obj.centerX, obj.centerY, Math.max(obj.radiusX, obj.radiusY)); + } else if (obj) { + obj.accept((o) => { + if (o._class == T.POINT) { + this.checkBounds(o.x, o.y); + } + return true; + }); +// } else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) { + } + }; + + this.isValid = function() { + return bbox[0] != Number.MAX_VALUE; + }; + + this.checkBounds = function(x, y) { + bbox[0] = Math.min(bbox[0], x); + bbox[1] = Math.min(bbox[1], y); + bbox[2] = Math.max(bbox[2], x); + bbox[3] = Math.max(bbox[3], y); + }; + + this.checkCircBounds = function(x, y, r) { + this.checkBounds(x + r, y + r); + this.checkBounds(x - r, y + r); + this.checkBounds(x - r, y - r); + this.checkBounds(x - r, y + r); + }; + + this.inc = function(by) { + bbox[0] -= by; + bbox[1] -= by; + bbox[2] += by; + bbox[3] += by; + }; + + this.width = function() { + return bbox[2] - bbox[0]; + }; + + this.height = function() { + return bbox[3] - bbox[1]; + }; + + this.bbox = bbox; +} + +export {BBox}; \ No newline at end of file diff --git a/web/app/sketcher/parametric.js b/web/app/sketcher/parametric.js index c9478e28..f07b4f74 100644 --- a/web/app/sketcher/parametric.js +++ b/web/app/sketcher/parametric.js @@ -261,7 +261,7 @@ class ParametricManager { obj.constraints.clear(); obj.generators.clear(); - this.viewer.dimLayer.traverse(dim => { + this.viewer.dimLayer.traverseSketchObjects(dim => { obj.accept(o => { if (dim.dependsOn && dim.dependsOn(o)) { this._removeObject(dim); @@ -284,22 +284,20 @@ class ParametricManager { } prepare(interactiveObjects) { + this.groundStage.prepare(interactiveObjects); for (let stage of this.stages) { - stage.algNumSystem.prepare(interactiveObjects); + stage.prepare(interactiveObjects); } } solve(rough) { + this.groundStage.solve(rough); for (let stage of this.stages) { - stage.algNumSystem.solve(rough); - stage.generators.forEach(gen => { - gen.regenerate(this.viewer); - }) + stage.solve(rough); } } addGenerator(generator) { - generator.generate(this.viewer); let highestStage = this.stages[0]; @@ -309,9 +307,20 @@ class ParametricManager { } }); + this.addGeneratorToStage(generator, highestStage); + + if (highestStage !== this.stage && !this.inTransaction) { + toast("Generator's been added to stage " + highestStage.index + "!") + } + + this.refresh(); + } + + addGeneratorToStage(generator, stage) { + let fail = false; generator.sourceObjects(obj => { - if (obj.isGenerated && obj.stage === highestStage) { + if (obj.isGenerated && obj.stage === stage) { toast("Cannot refer to a generated object from the same stage is being added to."); } }); @@ -320,13 +329,8 @@ class ParametricManager { return; } - highestStage.addGenerator(generator); - - if (highestStage !== this.stage && !this.inTransaction) { - toast("Generator's been added to stage " + highestStage.index + "!") - } - - this.refresh(); + stage.addGenerator(generator); + generator.generate(this.viewer); } coincidePoints(pt1, pt2) { @@ -449,6 +453,17 @@ class SolveStage { return new AlgNumSubSystem(calcVisualLimit, this.parametricManager.constantResolver, this); } + prepare(interactiveObjects) { + this.algNumSystem.prepare(interactiveObjects); + } + + solve(rough) { + this.algNumSystem.solve(rough); + this.generators.forEach(gen => { + gen.regenerate(this.viewer); + }) + } + get index() { return this.viewer.parametricManager.getStageIndex(this); } diff --git a/web/app/sketcher/selectionMatcher.js b/web/app/sketcher/selectionMatcher.js index 2f5597b8..f26ea139 100644 --- a/web/app/sketcher/selectionMatcher.js +++ b/web/app/sketcher/selectionMatcher.js @@ -70,7 +70,7 @@ export function getDescription(definition) { } function stringifyTypes(types, minQuantity) { - return types.map(t => t.prototype._class.replace('TCAD.TWO.', '') + (minQuantity > 1 ? 's' : '')).join(' or '); + return types.map(t => t.prototype.TYPE + (minQuantity > 1 ? 's' : '')).join(' or '); } export class MatchIndex { diff --git a/web/app/sketcher/shapes/annotations/angleAnnotation.js b/web/app/sketcher/shapes/annotations/angleAnnotation.js index ca9aeb08..33c34f8f 100644 --- a/web/app/sketcher/shapes/annotations/angleAnnotation.js +++ b/web/app/sketcher/shapes/annotations/angleAnnotation.js @@ -1,4 +1,4 @@ -import {AngleBetweenDimension, DiameterDimension, Dimension} from "../dim"; +import {AngleBetweenDimension, DiameterDimension, LinearDimension} from "../dim"; import {Styles} from "../../styles"; export class AngleBetweenAnnotation extends AngleBetweenDimension { @@ -23,6 +23,8 @@ export class AngleBetweenAnnotation extends AngleBetweenDimension { } } +AngleBetweenAnnotation.prototype.TYPE = 'AngleBetweenAnnotation'; + AngleBetweenAnnotation.prototype._class = 'TCAD.TWO.AngleBetweenAnnotation'; export class AngleAbsoluteAnnotation extends AngleBetweenDimension { @@ -85,10 +87,10 @@ export class AngleAbsoluteAnnotation extends AngleBetweenDimension { } } -AngleAbsoluteAnnotation.prototype._class = 'TCAD.TWO.AngleAbsoluteAnnotation'; +AngleAbsoluteAnnotation.prototype._class = 'AngleAbsoluteAnnotation'; -export class LengthAnnotation extends Dimension { +export class LengthAnnotation extends LinearDimension { constructor(segment, constraint) { super(segment.a, segment.b); @@ -110,6 +112,8 @@ export class LengthAnnotation extends Dimension { } } +LengthAnnotation.prototype.TYPE = 'LengthAnnotation'; + LengthAnnotation.prototype._class = 'TCAD.TWO.LengthAnnotation'; export class RadiusLengthAnnotation extends DiameterDimension { @@ -134,4 +138,6 @@ export class RadiusLengthAnnotation extends DiameterDimension { } } +RadiusLengthAnnotation.prototype.TYPE = 'RadiusLengthAnnotation'; + RadiusLengthAnnotation.prototype._class = 'TCAD.TWO.RadiusLengthAnnotation'; diff --git a/web/app/sketcher/shapes/arc.js b/web/app/sketcher/shapes/arc.ts similarity index 75% rename from web/app/sketcher/shapes/arc.js rename to web/app/sketcher/shapes/arc.ts index f0a5e200..af018cb0 100644 --- a/web/app/sketcher/shapes/arc.js +++ b/web/app/sketcher/shapes/arc.ts @@ -1,21 +1,30 @@ import * as math from '../../math/math'; import Vector from 'math/vector'; -import {SketchObject} from './sketch-object'; +import {SketchObject, SketchObjectSerializationData} from './sketch-object'; import {Param} from "./param"; import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints"; import {makeAngle0_360} from "../../math/math"; +import {EndPoint, SketchPointSerializationData} from "./point"; export class Arc extends SketchObject { + + a: EndPoint; + b: EndPoint; + c: EndPoint; + r: Param; + ang1: Param; + ang2: Param; - constructor(a, b, c) { - super(); - this.a = a; - this.b = b; - this.c = c; - a.parent = this; - b.parent = this; - c.parent = this; - this.children.push(a, b, c); + constructor(ax, ay, bx, by, cx, cy, id?: string) { + super(id); + this.a = new EndPoint(ax, ay, this.id + ':A'); + this.b = new EndPoint(bx, by, this.id + ':B'); + this.c = new EndPoint(cx, cy, this.id + ':C'); + + this.a.parent = this; + this.b.parent = this; + this.c.parent = this; + this.children.push(this.a, this.b, this.c); this.r = new Param(0, 'R'); this.r.enforceVisualLimit = true; @@ -153,7 +162,7 @@ export class Arc extends SketchObject { } copy() { - return new Arc(this.a.copy(), this.b.copy(), this.c.copy()); + return new Arc(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y); } mirror(dest, mirroringFunc) { @@ -161,6 +170,34 @@ export class Arc extends SketchObject { this.b.mirror(dest.a, mirroringFunc); this.c.mirror(dest.c, mirroringFunc); } + + write(): SketchArcSerializationData { + return { + a: this.a.write(), + b: this.b.write(), + c: this.c.write() + }; + } + + static read(id: string, data: SketchArcSerializationData): Arc { + return new Arc( + data.a.x, + data.a.y, + data.b.x, + data.b.y, + data.c.x, + data.c.y, + id + ) + } } +export interface SketchArcSerializationData extends SketchObjectSerializationData { + a: SketchPointSerializationData; + b: SketchPointSerializationData; + c: SketchPointSerializationData; +} + +Arc.prototype.TYPE = 'Arc'; + Arc.prototype._class = 'TCAD.TWO.Arc'; diff --git a/web/app/sketcher/shapes/bezier-curve.js b/web/app/sketcher/shapes/bezier-curve.js index f3d5ceea..c7a60701 100644 --- a/web/app/sketcher/shapes/bezier-curve.js +++ b/web/app/sketcher/shapes/bezier-curve.js @@ -5,19 +5,23 @@ import {ConvexHull2D} from '../../math/convex-hull' import * as draw_utils from '../shapes/draw-utils' import * as math from '../../math/math'; +import {EndPoint} from "./point"; export class BezierCurve extends SketchObject { - constructor(a, b, cp1, cp2) { - super(); - this.a = a; - this.b = b; - this.cp1 = cp1; - this.cp2 = cp2; + constructor(ax, ay, bx, by, cp1x, cp1y, cp2x, cp2y, id) { + super(id); + const s1 = new Segment(ax, ay, cp1x, cp1y, this.id + ':1'); + const s2 = new Segment(bx, by, cp2x, cp2y, this.id + ':2'); + this.addChild(s1); + this.addChild(s2); + + this.a = this.s1.a; + this.b = this.s2.b; + this.cp1 = this.s1.b; + this.cp2 = this.s2.a; - this.addChild(new Segment(a, cp1)); - this.addChild(new Segment(b, cp2)); for (let c of this.children) { c.role = 'objectConstruction'; } @@ -61,8 +65,8 @@ export class BezierCurve extends SketchObject { let hero = -1; for (let p = segments.length - 1, q = 0; q < segments.length; p = q ++) { const dist = Math.min(Segment.calcNormalDistance(aim, segments[p], segments[q])); - if (dist != -1) { - hero = hero == -1 ? dist : Math.min(dist, hero); + if (dist !== -1) { + hero = hero === -1 ? dist : Math.min(dist, hero); } } return hero; @@ -91,7 +95,33 @@ export class BezierCurve extends SketchObject { ctx.stroke(); } } + + write() { + return { + cp1: this.a.write(), + cp2: this.cp1.write(), + cp3: this.cp2.write(), + cp4: this.b.write() + }; + } + + static read(id, data) { + return new BezierCurve( + data.cp1.x, + data.cp1.y, + data.cp2.x, + data.cp2.y, + data.cp3.x, + data.cp3.y, + data.cp4.x, + data.cp4.y, + id + ) + } } + +BezierCurve.prototype.TYPE = 'BezierCurve'; + BezierCurve.prototype._class = 'TCAD.TWO.BezierCurve'; const RECOVER_LENGTH = 100; \ No newline at end of file diff --git a/web/app/sketcher/shapes/circle.js b/web/app/sketcher/shapes/circle.js index b0742cb9..afd82c10 100644 --- a/web/app/sketcher/shapes/circle.js +++ b/web/app/sketcher/shapes/circle.js @@ -1,17 +1,18 @@ import * as math from '../../math/math'; import {SketchObject} from './sketch-object' import {Param} from "./param"; +import {EndPoint} from "./point"; export const MIN_RADIUS = 100; export class Circle extends SketchObject { - constructor(c) { - super(); - this.c = c; - c.parent = this; - this.children.push(c); - this.r = new Param(0, 'R'); + constructor(cx, cy, r = 0, id) { + super(id); + this.c = new EndPoint(cx, cy, this.id + ':C'); + this.c.parent = this; + this.children.push(this.c); + this.r = new Param(r, 'R'); this.r.enforceVisualLimit = true; } @@ -46,6 +47,24 @@ export class Circle extends SketchObject { circle.r.set(this.r.get()); return circle; } + + write() { + return { + c: this.c.write(), + r: this.r.get() + } + } + + static read(id, data) { + return new Circle( + data.c.x, + data.c.y, + data.r, + id + ) + } + } Circle.prototype._class = 'TCAD.TWO.Circle'; +Circle.prototype.TYPE = 'Circle'; \ No newline at end of file diff --git a/web/app/sketcher/shapes/dim.d.ts b/web/app/sketcher/shapes/dim.d.ts new file mode 100644 index 00000000..00b679af --- /dev/null +++ b/web/app/sketcher/shapes/dim.d.ts @@ -0,0 +1,5 @@ +import {SketchObject} from "./sketch-object"; + +export interface Dimension extends SketchObject { + +} diff --git a/web/app/sketcher/shapes/dim.js b/web/app/sketcher/shapes/dim.js index 92c33c64..954a9981 100644 --- a/web/app/sketcher/shapes/dim.js +++ b/web/app/sketcher/shapes/dim.js @@ -2,11 +2,11 @@ import * as math from '../../math/math' import * as vec from '../../math/vec' import {DEG_RAD, lineLineIntersection2d, makeAngle0_360, pointToLineSignedDistance} from '../../math/math' import Vector from 'math/vector'; -import {SketchObject} from './sketch-object' import {Styles} from "../styles"; import {TextHelper} from "./textHelper"; import {isInstanceOf} from "../actions/matchUtils"; import {Arc} from "./arc"; +import {SketchObject} from "./sketch-object"; const ARROW_W_PX = 15; const ARROW_H_PX = 4; @@ -44,10 +44,17 @@ function drawExtensionLine(ctx, x, y, nx, ny, width, tip, arrowW) { ctx.stroke(); } -class LinearDimension extends SketchObject { +export class Dimension extends SketchObject { + + constructor(id) { + super(id); + } +} + +export class LinearDimension extends Dimension { - constructor(a, b) { - super(); + constructor(a, b, id) { + super(id); this.a = a; this.b = b; this.offset = 20; @@ -210,23 +217,32 @@ class LinearDimension extends SketchObject { return Math.abs(sdist); } -} + write() { + return { + a: this.a.id, + b: this.b.id, + offset: this.offset + } + } - - - -export class Dimension extends LinearDimension { - constructor(a, b) { - super(a, b); + static load(constr, id, data, index) { + const dim = new constr( + index[data.a], + index[data.b], + id + ); + dim.offset = data.offset; + return dim; } } -Dimension.prototype._class = 'TCAD.TWO.Dimension'; +LinearDimension.prototype._class = 'TCAD.TWO.LinearDimension'; +LinearDimension.prototype.TYPE = 'LinearDimension'; export class HDimension extends LinearDimension { - constructor(a, b) { - super(a, b); + constructor(a, b, id) { + super(a, b, id); } getA() { @@ -238,11 +254,12 @@ export class HDimension extends LinearDimension { } } HDimension.prototype._class = 'TCAD.TWO.HDimension'; +HDimension.prototype.TYPE = 'HDimension'; export class VDimension extends LinearDimension { - constructor(a, b) { - super(a, b); + constructor(a, b, id) { + super(a, b, id); } getA() { @@ -254,12 +271,13 @@ export class VDimension extends LinearDimension { } } VDimension.prototype._class = 'TCAD.TWO.VDimension'; +VDimension.prototype.TYPE = 'VDimension'; -export class DiameterDimension extends SketchObject { +export class DiameterDimension extends Dimension { - constructor(obj) { - super(); + constructor(obj, id) { + super(id); this.obj = obj; this.angle = Math.PI / 4; this.textHelper = new TextHelper(); @@ -387,13 +405,29 @@ export class DiameterDimension extends SketchObject { } + write() { + return { + obj: this.obj.id, + angle: this.angle + } + } + + static load(constr, id, data, index) { + const dim = new DiameterDimension( + index[data.obj], + id + ); + dim.angle = data.angle; + return dim; + } } DiameterDimension.prototype._class = 'TCAD.TWO.DiameterDimension'; +DiameterDimension.prototype.TYPE = 'DiameterDimension'; -export class AngleBetweenDimension extends SketchObject { +export class AngleBetweenDimension extends Dimension { - constructor(a, b) { - super(); + constructor(a, b, id) { + super(id); this.a = a; this.b = b; this.offset = 20; @@ -669,6 +703,26 @@ export class AngleBetweenDimension extends SketchObject { ); } } + + write() { + return { + a: this.a.id, + b: this.b.id, + offset: this.offset, + configuration: this.configuration.map(o => o.id) + } + } + + static load(constr, id, data, index) { + const dim = new AngleBetweenDimension( + index[data.a], + index[data.b], + id + ); + dim.offset = data.offset; + dim.configuration = data.configuration.map(id => index[id]); + return dim; + } } export function findCenter(aa, ab, ba, bb, avx, avy, bvx, bvy) { @@ -698,5 +752,6 @@ export function findCenter(aa, ab, ba, bb, avx, avy, bvx, bvy) { } AngleBetweenDimension.prototype._class = 'TCAD.TWO.AngleBetweenDimension'; +AngleBetweenDimension.prototype.TYPE = 'AngleBetweenDimension'; diff --git a/web/app/sketcher/shapes/ellipse.js b/web/app/sketcher/shapes/ellipse.js index 1a166013..b67f3497 100644 --- a/web/app/sketcher/shapes/ellipse.js +++ b/web/app/sketcher/shapes/ellipse.js @@ -2,18 +2,19 @@ import {SketchObject} from './sketch-object' import * as math from '../../math/math'; import {Param} from "./param"; +import {SketchSegmentSerializationData} from "./segment"; +import {EndPoint} from "./point"; export class Ellipse extends SketchObject { - constructor(ep1, ep2) { - super(); - this.ep1 = ep1; - this.ep2 = ep2; + constructor(x1, y1, x2, y2, r, id) { + super(id); + this.ep1 = new EndPoint(x1, y1, this.id + ':1'); + this.ep2 = new EndPoint(x2, y2, this.id + ':2'); this.addChild(this.ep1); this.addChild(this.ep2); - this.r = new Param(0, 'R'); + this.r = new Param(r === undefined ? 0 : this.radiusX * 0.5, 'R'); this.r.enforceVisualLimit = true; - this.r.set(this.radiusX * 0.5); } recoverIfNecessary() { @@ -88,8 +89,29 @@ export class Ellipse extends SketchObject { static findMinorRadius(majorRadius, pntRadius, pntAngle) { return Math.abs( Math.sin(pntAngle) / Math.sqrt(1 / sq(pntRadius) - sq(Math.cos(pntAngle) / majorRadius)) ); } + + write() { + return { + ep1: this.ep1.write(), + ep2: this.ep2.write(), + r: this.r.get() + }; + } + + static read(id, data) { + return new Ellipse( + data.ep1.x, + data.ep1.y, + data.ep2.x, + data.ep2.y, + data.r, + id + ) + } + } Ellipse.prototype._class = 'TCAD.TWO.Ellipse'; +Ellipse.prototype.TYPE = 'Ellipse'; const sq = (a) => a * a; const RECOVER_LENGTH = 100; \ No newline at end of file diff --git a/web/app/sketcher/shapes/elliptical-arc.js b/web/app/sketcher/shapes/elliptical-arc.js index bc1275a6..1f3fc363 100644 --- a/web/app/sketcher/shapes/elliptical-arc.js +++ b/web/app/sketcher/shapes/elliptical-arc.js @@ -3,15 +3,16 @@ import {Constraints} from '../parametric' import * as math from '../../math/math'; import {swap} from '../../utils/utils' +import {EndPoint} from "./point"; export class EllipticalArc extends Ellipse { - constructor(ep1, ep2, a, b) { - super(ep1, ep2); - this.a = a; - this.b = b; - this.addChild(a); - this.addChild(b); + constructor(x1, y1, x2, y2, ax, ay, bx, by, r, id) { + super(x1, y1, x2, y2, r, id); + this.a = new EndPoint(ax, ay, this.id + ':A'); + this.b = new EndPoint(bx, by, this.id + ':B'); + this.addChild(this.a); + this.addChild(this.b); //we'd like to have angles points have higher selection order swap(this.children, 0, this.children.length - 2); @@ -49,7 +50,32 @@ export class EllipticalArc extends Ellipse { xx *= deformScale; return Math.atan2(yy, xx); } + + write() { + return { + ep1: this.ep1.write(), + ep2: this.ep2.write(), + a: this.a.write(), + b: this.b.write(), + r: this.r.get() + } + } + + static read(id, data) { + return new EllipticalArc( + data.ep1.x, + data.ep1.y, + data.ep2.x, + data.ep2.y, + data.a.x, + data.a.y, + data.b.x, + data.b.y, + data.r, + id + ); + } } EllipticalArc.prototype._class = 'TCAD.TWO.EllipticalArc'; -EllipticalArc.prototype.TYPE = 'ELLIPTICAL_ARC'; +EllipticalArc.prototype.TYPE = 'EllipticalArc'; diff --git a/web/app/sketcher/shapes/nurbsObject.js b/web/app/sketcher/shapes/nurbsObject.js index eac465bc..3e9448e1 100644 --- a/web/app/sketcher/shapes/nurbsObject.js +++ b/web/app/sketcher/shapes/nurbsObject.js @@ -2,21 +2,18 @@ import {SketchObject} from './sketch-object' import * as vec from '../../math/vec'; import {curveTessellate} from '../../brep/geom/impl/nurbs-ext'; import {Ellipse} from "./ellipse"; +import {EndPoint} from "./point"; const __v = [0, 0, 0]; export class NurbsObject extends SketchObject { - constructor(curve, a, b) { - super(); + constructor(curve, id) { + super(id); this.curve = curve; - this.a = a; - this.b = b; let cp = curve.data.controlPoints; - this.a.x = cp[0].x; - this.a.y = cp[0].y; - this.b.x = cp[cp.length - 1].x; - this.b.y = cp[cp.length - 1].y; + this.a = new EndPoint(cp[0].x, cp[0].y, this.id + ":A"); + this.b = new EndPoint(cp[cp.length - 1].x, cp[cp.length - 1].y, this.id + ":B"); this.bezierPieces = this.calcBezierPiecewise(); } @@ -90,3 +87,4 @@ export class NurbsObject extends SketchObject { } NurbsObject.prototype._class = 'TCAD.TWO.NurbsObject'; +NurbsObject.prototype.TYPE = 'NurbsObject'; diff --git a/web/app/sketcher/shapes/param.js b/web/app/sketcher/shapes/param.ts similarity index 75% rename from web/app/sketcher/shapes/param.js rename to web/app/sketcher/shapes/param.ts index 27f32b94..2cc164dd 100644 --- a/web/app/sketcher/shapes/param.js +++ b/web/app/sketcher/shapes/param.ts @@ -3,6 +3,13 @@ import {Param as SolverParam} from '../constr/solver'; export class Param { + id: number; + value: number; + solverParam: any; + private readonly debugSymbol: string; + normalizer: (number) => any; + enforceVisualLimit: boolean = false; + constructor(value, debugSymbol) { this.id = Generator.genID(); this.value = value; diff --git a/web/app/sketcher/shapes/point.js b/web/app/sketcher/shapes/point.ts similarity index 69% rename from web/app/sketcher/shapes/point.js rename to web/app/sketcher/shapes/point.ts index 3bcb5f93..faf90757 100644 --- a/web/app/sketcher/shapes/point.js +++ b/web/app/sketcher/shapes/point.ts @@ -1,16 +1,20 @@ -import {SketchObject} from './sketch-object' +import {SketchObject, SketchObjectSerializationData} from './sketch-object' import {DrawPoint} from './draw-utils' import Vector from 'math/vector'; import {Param} from "./param"; import {ConstraintDefinitions} from "../constr/ANConstraints"; import {dfs} from "../../../../modules/gems/traverse"; - +import {SketchSegmentSerializationData} from "./segment"; export class EndPoint extends SketchObject { - constructor(x, y) { - super(); - this.parent = null; + params : { + x: Param, + y: Param + }; + + constructor(x, y, id?) { + super(id); this.params = { x: new Param(x, 'X'), y: new Param(y, 'Y') @@ -22,7 +26,7 @@ export class EndPoint extends SketchObject { } set x(val) { - return this.params.x.set(val); + this.params.x.set(val); } get y() { @@ -30,7 +34,7 @@ export class EndPoint extends SketchObject { } set y(val) { - return this.params.y.set(val); + this.params.y.set(val); } visitParams(callback) { @@ -93,7 +97,29 @@ export class EndPoint extends SketchObject { dest.x = x; dest.y = y; } + + write(): SketchPointSerializationData { + return { + x: this.x, + y: this.y + } + } + + static read(id: string, data: SketchPointSerializationData): EndPoint { + return new EndPoint( + data.x, + data.y, + id + ) + } +} + +export interface SketchPointSerializationData extends SketchObjectSerializationData { + x: number; + y: number; } EndPoint.prototype._class = 'TCAD.TWO.EndPoint'; +EndPoint.prototype.TYPE = 'Point'; + diff --git a/web/app/sketcher/shapes/segment.js b/web/app/sketcher/shapes/segment.ts similarity index 75% rename from web/app/sketcher/shapes/segment.js rename to web/app/sketcher/shapes/segment.ts index 87d34513..33daf410 100644 --- a/web/app/sketcher/shapes/segment.js +++ b/web/app/sketcher/shapes/segment.ts @@ -1,23 +1,28 @@ -import {SketchObject} from './sketch-object' +import {SketchObject, SketchObjectSerializationData} from './sketch-object' import Vector from 'math/vector'; import * as math from '../../math/math' import {DEG_RAD, makeAngle0_360} from '../../math/math' import {Param} from "./param"; import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints"; +import {EndPoint, SketchPointSerializationData} from "./point"; export class Segment extends SketchObject { - constructor(a, b) { - super(); - this.a = a; - this.b = b; - a.parent = this; - b.parent = this; - this.children.push(a, b); - this.params = { - ang: new Param(undefined, 'A'), - t: new Param(undefined, 'T') - }; + a: EndPoint; + b: EndPoint; + + params = { + ang: new Param(undefined, 'A'), + t: new Param(undefined, 'T') + }; + + constructor(x1:number, y1:number, x2:number, y2:number, id?: string) { + super(id); + this.a = new EndPoint(x1, y1, this.id + ':A'); + this.b = new EndPoint(x2, y2, this.id + ':B'); + this.a.parent = this; + this.b.parent = this; + this.children.push(this.a, this.b); this.params.ang.normalizer = makeAngle0_360; this.params.t.enforceVisualLimit = true; this.syncGeometry(); @@ -159,8 +164,31 @@ export class Segment extends SketchObject { } copy() { - return new Segment(this.a.copy(), this.b.copy()); + return new Segment(this.a.x, this.a.y, this.b.x, this.b.y); + } + + write(): SketchSegmentSerializationData { + return { + a: this.a.write(), + b: this.b.write() + } + } + + static read(id: string, data: SketchSegmentSerializationData): Segment { + return new Segment( + data.a.x, + data.a.y, + data.b.x, + data.b.y, + id + ) } } +export interface SketchSegmentSerializationData extends SketchObjectSerializationData { + a: SketchPointSerializationData; + b: SketchPointSerializationData; +} + Segment.prototype._class = 'TCAD.TWO.Segment'; +Segment.prototype.TYPE = 'Segment'; diff --git a/web/app/sketcher/shapes/shape.js b/web/app/sketcher/shapes/shape.js deleted file mode 100644 index 2b85b370..00000000 --- a/web/app/sketcher/shapes/shape.js +++ /dev/null @@ -1,16 +0,0 @@ - -export class Shape { - - constructor() { - this.visible = true; - this.style = null; - this.role = null; - } - - accept(visitor) { - return visitor(this); - } - - draw(ctx, scale) { - } -} diff --git a/web/app/sketcher/shapes/shape.ts b/web/app/sketcher/shapes/shape.ts new file mode 100644 index 00000000..d8bc5d3a --- /dev/null +++ b/web/app/sketcher/shapes/shape.ts @@ -0,0 +1,15 @@ +import {Viewer} from "../viewer2d"; + +export class Shape { + + visible: boolean = true; + style: any = null; + role: string = null; + + accept(visitor) { + return visitor(this); + } + + draw(ctx: any, scale: number, viewer: Viewer) { + } +} diff --git a/web/app/sketcher/shapes/sketch-object.js b/web/app/sketcher/shapes/sketch-object.ts similarity index 78% rename from web/app/sketcher/shapes/sketch-object.js rename to web/app/sketcher/shapes/sketch-object.ts index a7394d23..49f6d51e 100644 --- a/web/app/sketcher/shapes/sketch-object.js +++ b/web/app/sketcher/shapes/sketch-object.ts @@ -1,27 +1,32 @@ import {Generator} from '../id-generator' import {Shape} from './shape' import {Styles} from "../styles"; -import {SketchTypes} from "./sketch-types"; +import {NoIcon} from "../icons/NoIcon"; +import {Layer, Viewer} from "../viewer2d"; -export class SketchObject extends Shape { +export abstract class SketchObject extends Shape { - constructor() { + ref: string; + id: string; + parent: SketchObject = null; + markers: any[] = []; + children: SketchObject[] =[]; + layer: Layer = null; + constraints: Set = new Set(); + readOnly: boolean = false; + fullyConstrained: boolean = false; + generator: any = null; + generators: Set = new Set(); + _stage: any = null; + + constructor(id: string) { super(); - this.id = Generator.genID(); - this.parent = null; - this.markers = []; - this.children = []; - this.layer = null; - this.constraints = new Set(); - this.readOnly = false; - this.fullyConstrained = false; - this.generator = null; - this.generators = new Set(); - this._stage = null; + this.ref= Generator.genID(); + this.id = id || this.ref; } get isGenerated() { - let obj = this; + let obj: SketchObject = this; while (obj) { if (obj.generator) { return true; @@ -97,7 +102,7 @@ export class SketchObject extends Shape { translateImpl(dx, dy) { this.accept(function (obj) { - if (obj._class === 'TCAD.TWO.EndPoint') { + if (obj.TYPE === 'Point') { obj.translate(dx, dy); } return true; @@ -120,7 +125,9 @@ export class SketchObject extends Shape { return this.markers.length !== 0; } - draw(ctx, scale, viewer) { + abstract drawImpl(ctx: CanvasRenderingContext2D, scale: number, viewer: Viewer); + + draw(ctx: CanvasRenderingContext2D, scale: number, viewer: Viewer) { if (!this.visible) return; const customStyle = this.getCustomStyle(); if (customStyle !== null) { @@ -191,11 +198,11 @@ export class SketchObject extends Shape { } get simpleClassName() { - return this._class.replace('TCAD.TWO.', ''); + return this.TYPE; } get effectiveLayer() { - let shape = this; + let shape: SketchObject = this; while (shape) { if (shape.layer) { return shape.layer; @@ -215,7 +222,7 @@ export class SketchObject extends Shape { } ancestry(cb) { - let obj = this; + let obj: SketchObject = this; while (obj) { cb(obj); obj = obj.parent; @@ -223,7 +230,7 @@ export class SketchObject extends Shape { } root() { - let obj = this; + let obj: SketchObject = this; while (obj.parent) { obj = obj.parent; } @@ -233,11 +240,21 @@ export class SketchObject extends Shape { get isRoot() { return this.parent === null; } + + get icon() { + return NoIcon; + } + + abstract write(): SketchObjectSerializationData; +} + +export interface SketchObjectSerializationData { + } export function pointIterator(shape, func) { shape.accept(o => { - if (o._class === SketchTypes.POINT) { + if (o.TYPE === 'Point') { func(o); } return true; diff --git a/web/app/sketcher/sketcherContext.js b/web/app/sketcher/sketcherContext.js index f3d340d5..ff9897f0 100644 --- a/web/app/sketcher/sketcherContext.js +++ b/web/app/sketcher/sketcherContext.js @@ -1,4 +1,4 @@ -import {Viewer} from './viewer2d.js' +import {Viewer} from './viewer2d' import {IO} from './io' import React from "react"; import {state, stream} from "lstream"; diff --git a/web/app/sketcher/sketcherStreams.js b/web/app/sketcher/sketcherStreams.js deleted file mode 100644 index 8caa2049..00000000 --- a/web/app/sketcher/sketcherStreams.js +++ /dev/null @@ -1,25 +0,0 @@ -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); - streams.selection = state([]); - streams.objectUpdate = stream(); - streams.dimScale = state(1); - streams.tool = { - $change: stream(), - $message: stream(), - $hint: stream() - }; - - return streams; -}; \ No newline at end of file diff --git a/web/app/sketcher/sketcherStreams.ts b/web/app/sketcher/sketcherStreams.ts new file mode 100644 index 00000000..d0b4d239 --- /dev/null +++ b/web/app/sketcher/sketcherStreams.ts @@ -0,0 +1,37 @@ +import {state, StateStream, Stream, stream} from 'lstream'; + +export interface SketcherStreams { + selection: StateStream; + addingRoleMode: StateStream; + objectsUpdate: StateStream; + objects: StateStream; + objectUpdate: Stream; + dimScale: StateStream; + tool: { $change: Stream; $message: Stream; $hint: Stream }; + +} + +export default function(viewer): SketcherStreams { + + const streams: any = { + }; + + 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); + streams.selection = state([]); + streams.objectUpdate = stream(); + streams.dimScale = state(1); + streams.tool = { + $change: stream(), + $message: stream(), + $hint: stream() + }; + + return streams as SketcherStreams; +}; \ No newline at end of file diff --git a/web/app/sketcher/tools/arc.js b/web/app/sketcher/tools/arc.js index 76c5ed3c..f0fc03da 100644 --- a/web/app/sketcher/tools/arc.js +++ b/web/app/sketcher/tools/arc.js @@ -60,9 +60,9 @@ export class AddArcTool extends Tool { createArcStep(p) { this.viewer.historyManager.checkpoint(); this.arc = new Arc( - new EndPoint(p.x, p.y), - new EndPoint(p.x, p.y), - new EndPoint(p.x, p.y) + p.x, p.y, + p.x, p.y, + p.x, p.y ); this.point = this.arc.a; this.viewer.activeLayer.add(this.arc); diff --git a/web/app/sketcher/tools/bezier-curve.js b/web/app/sketcher/tools/bezier-curve.js index 1d67899b..78f62441 100644 --- a/web/app/sketcher/tools/bezier-curve.js +++ b/web/app/sketcher/tools/bezier-curve.js @@ -31,8 +31,14 @@ export class BezierCurveTool extends Tool { mouseup(e) { if (this.curve == null) { this.checkIfConnectedToOtherCurve(); - const p = this.endpoint(e); - this.curve = new BezierCurve(p, p.copy(), p.copy(), p.copy()); + + const p = this.viewer.screenToModel(e); + + this.curve = new BezierCurve(p.x, p.y, p.x, p.y, p.x, p.y, p.x, p.y); + if (this.viewer.snapped != null) { + this.snapIfNeed(this.curve.a); + } + this.viewer.activeLayer.add(this.curve); this.viewer.refresh(); } else { diff --git a/web/app/sketcher/tools/circle.js b/web/app/sketcher/tools/circle.js index dfb39915..3b5936e4 100644 --- a/web/app/sketcher/tools/circle.js +++ b/web/app/sketcher/tools/circle.js @@ -47,9 +47,7 @@ export class EditCircleTool extends Tool { this.viewer.historyManager.checkpoint(); const needSnap = tryToSnap && this.viewer.snapped != null; const p = needSnap ? this.viewer.snapped : center; - this.circle = new Circle( - new EndPoint(p.x, p.y) - ); + this.circle = new Circle(p.x, p.y); this.pointPicked(this.circle.c.x, this.circle.c.y); this.sendHint('specify radius'); this.viewer.activeLayer.add(this.circle); diff --git a/web/app/sketcher/tools/dim.js b/web/app/sketcher/tools/dim.js index 96d53169..a731efa5 100644 --- a/web/app/sketcher/tools/dim.js +++ b/web/app/sketcher/tools/dim.js @@ -1,4 +1,10 @@ -import {AngleBetweenDimension, DiameterDimension, Dimension, findCenter, HDimension, VDimension,} from '../shapes/dim' +import { + AngleBetweenDimension, + DiameterDimension, + findCenter, + HDimension, LinearDimension, + VDimension, +} from '../shapes/dim' import Vector from 'math/vector'; import {EndPoint} from '../shapes/point' import {Tool} from './tool' @@ -69,7 +75,7 @@ export class AddDimTool extends Tool { export class AddFreeDimTool extends AddDimTool { constructor(viewer, layer) { - super('free dimension', viewer, layer, (a, b) => new Dimension(a, b)); + super('free dimension', viewer, layer, (a, b) => new LinearDimension(a, b)); } } @@ -96,7 +102,7 @@ export class AddCircleDimTool extends Tool { mousemove(e) { var p = this.viewer.screenToModel(e); var objects = this.viewer.search(p.x, p.y, DEFAULT_SEARCH_BUFFER, true, false, []).filter(function (o) { - return o._class === 'TCAD.TWO.Circle' || o._class === 'TCAD.TWO.Arc'; + return o.TYPE === 'Circle' || o.TYPE === 'Arc'; }); if (objects.length !== 0) { @@ -137,7 +143,7 @@ export class AddAngleTool extends Tool { mousemove(e) { const p = this.viewer.screenToModel(e); - const result = this.viewer.search(p.x, p.y, DEFAULT_SEARCH_BUFFER, true, false, []).filter(o => o._class === 'TCAD.TWO.Segment'); + const result = this.viewer.search(p.x, p.y, DEFAULT_SEARCH_BUFFER, true, false, []).filter(o => o.TYPE === 'Segment'); const [segment] = result; if (this.dim) { diff --git a/web/app/sketcher/tools/ellipse.js b/web/app/sketcher/tools/ellipse.js index 9133e90d..eb885337 100644 --- a/web/app/sketcher/tools/ellipse.js +++ b/web/app/sketcher/tools/ellipse.js @@ -32,8 +32,8 @@ export class EllipseTool extends Tool { } newEllipse(p) { - const ep = () => new EndPoint(p.x, p.y); - return this.arc ? new EllipticalArc(ep(), ep(), ep(), ep()) : new Ellipse(ep(), ep()); + + return this.arc ? new EllipticalArc(p.x, p.y, p.x, p.y, p.x, p.y, p.x, p.y) : new Ellipse(p.x, p.y, p.x, p.y); } demoBPoint() { diff --git a/web/app/sketcher/tools/fillet.js b/web/app/sketcher/tools/fillet.js index ecfb82d6..64137b88 100644 --- a/web/app/sketcher/tools/fillet.js +++ b/web/app/sketcher/tools/fillet.js @@ -60,9 +60,9 @@ export class FilletTool extends Tool { vec._plus(point1); const arc = new Arc( - new EndPoint(point1.x, point1.y), - new EndPoint(point2.x, point2.y), - new EndPoint(vec.x, vec.y)); + point1.x, point1.y, + point2.x, point2.y, + vec.x, vec.y); point1.parent.layer.add(arc); const pm = this.viewer.parametricManager; @@ -127,7 +127,7 @@ export class FilletTool extends Tool { } static isLine(line) { - return line != null && line._class === 'TCAD.TWO.Segment'; + return line != null && line.TYPE === 'Segment'; } getCandidate(e) { diff --git a/web/app/sketcher/tools/loop-pick.js b/web/app/sketcher/tools/loop-pick.js index 1feb527c..7f475ebc 100644 --- a/web/app/sketcher/tools/loop-pick.js +++ b/web/app/sketcher/tools/loop-pick.js @@ -34,7 +34,7 @@ export class LoopPickTool extends Tool { } otherEnd(point) { - if (point.parent.a.id == point.id) { + if (point.parent.a.id === point.id) { return point.parent.b; } else { return point.parent.a; @@ -45,8 +45,8 @@ export class LoopPickTool extends Tool { this.loops.clear(); const points = []; this.viewer.accept((obj) => { - if (obj._class == 'TCAD.TWO.EndPoint' && obj.parent && - obj.parent.a && obj.parent.b && (obj.parent.a == obj || obj.parent.b == obj)) { + if (obj.TYPE === 'Point' && obj.parent && + obj.parent.a && obj.parent.b && (obj.parent.a === obj || obj.parent.b === obj)) { points.push(obj); } return true; @@ -68,7 +68,7 @@ export class LoopPickTool extends Tool { return points.length; } }; - const loopPoints = Graph.findAllLoops(graph, (p) => p.id, (a, b) => a.id == b.id); + const loopPoints = Graph.findAllLoops(graph, (p) => p.id, (a, b) => a.id === b.id); const loops = loopPoints.map(l => this.cleanLoop(l)); for (let loop of loops) { for (let point of loop.points) { diff --git a/web/app/sketcher/tools/offset.js b/web/app/sketcher/tools/offset.js index b396df67..8179b4b3 100644 --- a/web/app/sketcher/tools/offset.js +++ b/web/app/sketcher/tools/offset.js @@ -18,7 +18,7 @@ export class OffsetTool extends LoopPickTool { const length = loopEdges.length; for (let obj of loopEdges) { - if (!SUPPORTED_OBJECTS.has(obj._class)) { + if (!SUPPORTED_OBJECTS.has(obj.TYPE)) { alert(obj._class + " isn't supported for offsets"); return; } @@ -43,14 +43,14 @@ export class OffsetTool extends LoopPickTool { for (let i = 0; i < length; ++i) { const edge = edges[i]; const origEdge = loopEdges[i]; - const edgeInverse = loopPoints[i] != origEdge.a; - const inverse = mainInverse != edgeInverse; + const edgeInverse = loopPoints[i] !== origEdge.a; + const inverse = mainInverse !== edgeInverse; this.viewer.activeLayer.add(edge); - if (edge._class == 'TCAD.TWO.Segment') { + if (edge.TYPE === 'Segment') { pm._add(new Constraints.Parallel(origEdge, edge)); pm._add(new Constraints.P2LDistanceSigned(origEdge.a, inverse?edge.b:edge.a, inverse?edge.a:edge.b, offsetConstant)); - } else if (edge._class == 'TCAD.TWO.Arc') { + } else if (edge.TYPE === 'Arc') { edge.stabilize(this.viewer); pm._linkObjects([edge.c, origEdge.c]); pm._add(new Constraints.RadiusOffset(inverse?origEdge:edge, inverse?edge:origEdge, offsetConstant)); @@ -59,13 +59,13 @@ export class OffsetTool extends LoopPickTool { for (let i = 0; i < edges.length; i++) { const next = ((i + 1) % edges.length); - if (loopEdges[i].a.linked.indexOf(loopEdges[next].a) != -1) { + if (loopEdges[i].a.linked.indexOf(loopEdges[next].a) !== -1) { pm._linkObjects([edges[i].a, edges[next].a]); - } else if (loopEdges[i].a.linked.indexOf(loopEdges[next].b) != -1) { + } else if (loopEdges[i].a.linked.indexOf(loopEdges[next].b) !== -1) { pm._linkObjects([edges[i].a, edges[next].b]); - } else if (loopEdges[i].b.linked.indexOf(loopEdges[next].a) != -1) { + } else if (loopEdges[i].b.linked.indexOf(loopEdges[next].a) !== -1) { pm._linkObjects([edges[i].b, edges[next].a]); - } else if (loopEdges[i].b.linked.indexOf(loopEdges[next].b) != -1) { + } else if (loopEdges[i].b.linked.indexOf(loopEdges[next].b) !== -1) { pm._linkObjects([edges[i].b, edges[next].b]); } } @@ -76,10 +76,10 @@ export class OffsetTool extends LoopPickTool { twoConnectedArcs() { function isArc(edge) { - return edge._class == 'TCAD.TWO.Arc'; + return edge._class === 'Arc'; } const edges = this.pickedLoop.edges; - return edges.length == 2 && isArc(edges[0]) && isArc(edges[1]); + return edges.length === 2 && isArc(edges[0]) && isArc(edges[1]); } } @@ -89,8 +89,8 @@ function segmentToVector(segment) { } const SUPPORTED_OBJECTS = new Set(); -SUPPORTED_OBJECTS.add('TCAD.TWO.Segment'); -SUPPORTED_OBJECTS.add('TCAD.TWO.Arc'); +SUPPORTED_OBJECTS.add('Segment'); +SUPPORTED_OBJECTS.add('Arc'); function SimpleEdge(a, b) { this.a = a; diff --git a/web/app/sketcher/tools/rectangle.js b/web/app/sketcher/tools/rectangle.js index aecf9037..e8dd4d1e 100644 --- a/web/app/sketcher/tools/rectangle.js +++ b/web/app/sketcher/tools/rectangle.js @@ -64,19 +64,18 @@ export class RectangleTool extends Tool { } createRectangle(v) { - const p = new EndPoint(v.x, v.y); //from top, clockwise this.rectangle = [ - new Segment(p, p.copy()), - new Segment(p.copy(), p.copy()), - new Segment(p.copy(), p.copy()), - new Segment(p.copy(), p.copy()) + new Segment(v.x, v.y, v.x, v.y), + new Segment(v.x, v.y, v.x, v.y), + new Segment(v.x, v.y, v.x, v.y), + new Segment(v.x, v.y, v.x, v.y) ]; for (let s of this.rectangle) { this.viewer.activeLayer.add(s); this.snapExclude.push(s.a, s.b); } - this.pointPicked(p.x, p.y); + this.pointPicked(v.x, v.y); this.viewer.refresh(); } diff --git a/web/app/sketcher/tools/tool.js b/web/app/sketcher/tools/tool.js index cf231f0f..12db5354 100644 --- a/web/app/sketcher/tools/tool.js +++ b/web/app/sketcher/tools/tool.js @@ -53,16 +53,6 @@ export class Tool { } } - endpoint(e) { - const ep = new EndPoint(0, 0); - if (this.viewer.snapped != null) { - this.snapIfNeed(ep); - } else { - ep.setFromPoint(this.viewer.screenToModel(e)) - } - return ep; - } - static dumbMode(e) { return e.ctrlKey || e.metaKey || e.altKey; } diff --git a/web/app/sketcher/viewer2d.js b/web/app/sketcher/viewer2d.ts similarity index 83% rename from web/app/sketcher/viewer2d.js rename to web/app/sketcher/viewer2d.ts index 3c5d99da..f26ff439 100644 --- a/web/app/sketcher/viewer2d.js +++ b/web/app/sketcher/viewer2d.ts @@ -1,21 +1,57 @@ -import {Styles} from './styles'; import {ParametricManager} from './parametric'; import {HistoryManager} from './history'; import {ToolManager} from './tools/manager'; import {PanTool} from './tools/pan'; import {Segment} from './shapes/segment'; import {EndPoint} from './shapes/point'; -import {Point} from './shapes/primitives'; import {ReferencePoint} from './shapes/reference-point'; import {BasisOrigin} from './shapes/basis-origin'; import Vector from 'math/vector'; import * as draw_utils from './shapes/draw-utils'; import {Matrix3} from '../math/l3space'; -import sketcherStreams from './sketcherStreams'; -import {BBox} from "./io"; +import sketcherStreams, {SketcherStreams} from './sketcherStreams'; +import {BBox, IO} from "./io"; +import {NOOP} from "../../../modules/gems/func"; +import {Shape} from "./shapes/shape"; +import {SketchObject} from "./shapes/sketch-object"; +import {Styles} from './styles'; +import {Dimension} from "./shapes/dim"; -class Viewer { +export class Viewer { + + presicion: number; + canvas: any; + io: IO; + streams: SketcherStreams; + retinaPxielRatio: number; + ctx: CanvasRenderingContext2D; + onWindowResize: () => void; + private _activeLayer: Layer; + layers: Layer[]; + dimLayer: Layer; + annotationLayer: Layer; + dimLayers: Layer[]; + private readonly _workspace: Layer[][]; + referencePoint: Shape; + toolManager: any; + parametricManager: any; + translate: { x: number; y: number }; + scale: number; + captured: { + highlight2: any[], + tool: any[], + highlight: any[], + selection: any[] + }; + historyManager: any; + transformation: any; + screenToModelMatrix: any; + private readonly _serviceWorkspace: Layer[][]; + private __prevStyle: null; + interactiveScale: number; + unscale: number; + customSelectionHandler: any; constructor(canvas, IO) { @@ -44,19 +80,15 @@ class Viewer { updateCanvasSize(); window.addEventListener('resize', this.onWindowResize, false); - Object.defineProperty(this, "activeLayer", { - get: viewer.getActiveLayer, - set: viewer.setActiveLayer - }); - this.ctx = this.canvas.getContext("2d"); this._activeLayer = null; this.layers = [ - this.createLayer("sketch", Styles.DEFAULT) + this.createLayer(PREDEFINED_LAYERS.GROUND, Styles.DEFAULT), + this.createLayer(PREDEFINED_LAYERS.SKETCH, Styles.DEFAULT) // this.createLayer("_construction_", Styles.CONSTRUCTION) ]; this.dimLayer = this.createLayer("_dim", Styles.DIM); - this.annotationLayer = this.createLayer("_annotations", Styles.ANNOTATIONS); + this.annotationLayer = this.createLayer("_annotations", Styles.ANNOTATIONS); this.dimLayers = [this.dimLayer, this.annotationLayer]; this.streams.dimScale.attach(() => this.refresh()); @@ -64,7 +96,6 @@ class Viewer { this.referencePoint = new ReferencePoint(); this.referencePoint.visible = false; - this._serviceWorkspace = [this._createServiceLayers()]; this.toolManager = new ToolManager(this, new PanTool(this)); this.parametricManager = new ParametricManager(this); @@ -72,14 +103,17 @@ class Viewer { this.translate = {x: 0.0, y: 0.0}; this.scale = 1.0; + // @ts-ignore this.captured = { }; Object.keys(CAPTURES).forEach(key => this.captured[key] = []); - this.historyManager = new HistoryManager(this); this.transformation = null; this.screenToModelMatrix = null; + + this._serviceWorkspace = [this._createServiceLayers()]; + this.refresh(); } @@ -123,9 +157,7 @@ class Viewer { }; addSegment(x1, y1, x2, y2, layer) { - var a = new EndPoint(x1, y1); - var b = new EndPoint(x2, y2); - var line = new Segment(a, b); + var line = new Segment(x1, y1, x2, y2); layer.add(line); return line; }; @@ -199,14 +231,21 @@ class Viewer { return pickResult; }; - _createServiceLayers() { - let layer = this.createLayer("_service", Styles.SERVICE); + _createServiceLayers(): Layer[] { + 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(new Point(0, 0, 2)); layer.objects.push(this.referencePoint); layer.objects.push(new BasisOrigin(null, this)); - return [layer]; + const origin = new EndPoint(0, 0); + origin.id = 'ORIGIN'; + layer.objects.push(origin); + origin.stage = this.parametricManager.groundStage; + origin.visitParams(param => { + param.set = NOOP; + }); + return [layer]; }; refresh() { @@ -304,7 +343,7 @@ class Viewer { this.withdrawAll('tool') }; - showBounds(x1, y1, x2, y2, offset) { + showBounds(x1, y1, x2, y2) { const dx = Math.max(x2 - x1, 1); const dy = Math.max(y2 - y1, 1); const cRatio = this.canvas.width / this.canvas.height; @@ -383,9 +422,7 @@ class Viewer { //same as accept but without controlling when to break the flow traverse(visitor) { for (let layer of this.layers) { - for (let object of layer.objects) { - object.traverse(visitor); - } + layer.traverseSketchObjects(visitor) } } @@ -410,6 +447,12 @@ class Viewer { return result; }; + createIndex() { + const index = {}; + this.traverse(o => index[o.id] = o); + return index; + } + select(objs, exclusive) { if (this.customSelectionHandler) { this.customSelectionHandler(objs, exclusive); @@ -474,7 +517,7 @@ class Viewer { } unHighlight(objs) { - this.withdrawAll('highlight', objs); + this.withdraw('highlight', objs); } pick(e) { @@ -482,29 +525,25 @@ class Viewer { return this.search(m.x, m.y, DEFAULT_SEARCH_BUFFER, true, false, []); }; - getActiveLayer() { - var layer = this._activeLayer; + get activeLayer() { + let layer = this._activeLayer; if (layer == null || layer.readOnly) { layer = null; - for (var i = 0; i < this.layers.length; i++) { - var l = this.layers[i]; + for (let i = 0; i < this.layers.length; i++) { + let 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; + return this.findLayerByName(PREDEFINED_LAYERS.SKETCH); }; - setActiveLayerName(layerName) { + set activeLayerName(layerName) { let layer = this.findLayerByName(layerName); if (layer) { - this.activeLayer = layer; + this._activeLayer = layer; } else { console.warn("layer doesn't exist: " + layerName); } @@ -516,36 +555,13 @@ class Viewer { } }; - equalizeLinkedEndpoints() { - 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); - } - } - } - - this.accept((obj) => { - if (isEndPoint(obj)) { - equalize(obj); - } - return true; - }); - }; - fullHeavyUIRefresh() { this.refresh(); this.parametricManager.notify(); }; - createLayer(name, style, onUpdate) { - return new Layer(name, style, this) + createLayer(name, style) { + return new Layer(name, style, this) }; objectsUpdate = () => this.streams.objectsUpdate.next(); @@ -574,7 +590,14 @@ class Viewer { const isEndPoint = o => o._class === 'TCAD.TWO.EndPoint'; const isConstruction = o => o.role === 'construction'; -class Layer { +export class Layer { + + name: any; + style: any; + stylesByRoles: { virtual: any; objectConstruction: any; construction: any }; + objects: T[]; + readOnly: boolean; + viewer: Viewer; constructor(name, style, viewer) { this.name = name; @@ -614,8 +637,12 @@ class Layer { } }; - traverse(callback) { - this.objects.forEach(o => o.traverse(callback)); + traverseSketchObjects(callback) { + this.objects.forEach(o => { + if (o instanceof SketchObject) { + o.traverse(callback) + } + }); } _addAndNotify(object) { @@ -653,4 +680,9 @@ const measurer = {x: 0, y: 0, z: 0}; export const DEFAULT_SEARCH_BUFFER = 20; -export {Viewer, Styles} \ No newline at end of file +export const PREDEFINED_LAYERS = { + SKETCH: "sketch", + GROUND: "ground", +}; + +export {Styles}; \ No newline at end of file