diff --git a/modules/math/csys.ts b/modules/math/csys.ts
index 808dbdb1..8f58eda2 100644
--- a/modules/math/csys.ts
+++ b/modules/math/csys.ts
@@ -35,7 +35,7 @@ export default class CSys {
return new Matrix3x4().setBasisAxises(this.x, this.y, this.z);
}
- get outTransformation() {
+ get outTransformation(): Matrix3x4 {
const mx = new Matrix3x4().setBasisAxises(this.x, this.y, this.z);
mx.tx = this.origin.x;
mx.ty = this.origin.y;
diff --git a/modules/ui/components/Folder.jsx b/modules/ui/components/Folder.jsx
index 2b595bf0..feb7fe11 100644
--- a/modules/ui/components/Folder.jsx
+++ b/modules/ui/components/Folder.jsx
@@ -33,7 +33,10 @@ export default class Folder extends React.Component{
}
export function Title({children, isClosed, onClick}) {
- return
+ const titleCss = onClick ? {
+ cursor: 'pointer'
+ } : {};
+ return
{' '}{children}
;
diff --git a/modules/ui/components/controls/FormSection.jsx b/modules/ui/components/controls/FormSection.jsx
index c4ac8b4e..37bc5739 100644
--- a/modules/ui/components/controls/FormSection.jsx
+++ b/modules/ui/components/controls/FormSection.jsx
@@ -4,10 +4,10 @@ import {Title} from '../Folder';
export class StackSection extends React.Component {
render() {
- const {title, children} = this.props;
+ const {title, children, isClosed, onTitleClick} = this.props;
return
- {title}
- {children}
+ {title}
+ {!isClosed && children}
;
}
diff --git a/modules/workbenches/modeler/features/extrude/extrude.operation.ts b/modules/workbenches/modeler/features/extrude/extrude.operation.ts
index d9035fea..e0d0cde0 100644
--- a/modules/workbenches/modeler/features/extrude/extrude.operation.ts
+++ b/modules/workbenches/modeler/features/extrude/extrude.operation.ts
@@ -3,10 +3,14 @@ import {MFace} from "cad/model/mface";
import {ApplicationContext} from "context";
import {MDFCommand} from "cad/mdf/mdf";
import {EntityKind} from "cad/model/entities";
+import Vector from "math/vector";
+import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
interface ExtrudeParams {
length: number;
face: MFace;
+ direction?: Vector,
+ boolean: BooleanDefinition
}
const ExtrudeOperation: MDFCommand
= {
@@ -28,17 +32,49 @@ const ExtrudeOperation: MDFCommand = {
const occFaces = occ.utils.sketchToFaces(sketch, face.csys);
- const shapeNames = occ.utils.prism(occFaces, [0, 0, params.length]);
+ const dir = (params.direction && params.direction) || face.normal();
- const created = shapeNames.map(shapeName => occ.io.getShell(shapeName));
+ const extrusionVector = dir.normalize()._multiply(params.length).data();
+
+ const tools = occFaces.map((faceName, i) => {
+ const shapeName = "Tool" + i;
+ oci.prism(shapeName, faceName, ...extrusionVector)
+
+ // occIterateFaces(oc, shape, face => {
+ // let role;
+ // if (face.IsSame(prismAPI.FirstShape())) {
+ // role = "bottom";
+ // } else if (face.IsSame(prismAPI.LastShape())) {
+ // role = "top";
+ // } else {
+ // role = "sweep";
+ // }
+ // getProductionInfo(face).role = role;
+ // });
+ //
+ // occIterateEdges(oc, wire, edge => {
+ // const generatedList = prismAPI.Generated(edge);
+ // occIterateListOfShape(oc, generatedList, face => {
+ // console.log(face);
+ // })
+ // })
+
+ return shapeName;
+ });
return {
- consumed: [face.parent],
- created
- };
+ created: tools.map(shapeName => occ.io.getShell(shapeName)),
+ consumed: []
+ }
+ // return occ.utils.applyBooleanModifier(tools, params.boolean);
},
+ // useBoolean: {
+ // booleanField: 'boolean',
+ // impliedTargetField: 'face'
+ // },
+
form: [
{
type: 'number',
@@ -57,6 +93,33 @@ const ExtrudeOperation: MDFCommand = {
preselectionIndex: 0
},
},
+ // {
+ // type: 'vector',
+ // name: 'direction',
+ // label: 'direction'
+ // },
+ // {
+ // type: 'boolean',
+ // name: 'boolean',
+ // label: 'boolean',
+ // defaultValue: {
+ // implyItFromField: 'face'
+ // }
+ // },
+ {
+ type: 'vector',
+ name: 'direction',
+ label: 'direction',
+ optional: true
+ },
+ {
+ type: 'boolean',
+ name: 'boolean',
+ label: 'boolean',
+ optional: true,
+ defaultValue: 'NONE'
+ }
+
],
}
diff --git a/web/app/cad/craft/e0/OCCUtils.ts b/web/app/cad/craft/e0/OCCUtils.ts
index 5367e6c7..d46b5aed 100644
--- a/web/app/cad/craft/e0/OCCUtils.ts
+++ b/web/app/cad/craft/e0/OCCUtils.ts
@@ -4,6 +4,10 @@ import {SketchGeom} from "cad/sketch/sketchReader";
import {OCCService} from "cad/craft/e0/occService";
import {CoreContext} from "context";
import CSys from "math/csys";
+import {OperationResult} from "cad/craft/craftPlugin";
+import {MShell} from "cad/model/mshell";
+import {BooleanDefinition, BooleanKind} from "cad/craft/schema/common/BooleanDefinition";
+import {bool} from "prop-types";
export interface OCCUtils {
@@ -11,8 +15,9 @@ export interface OCCUtils {
sketchToFaces(sketch: SketchGeom, csys: CSys): string[];
- prism(faces: string[], dir: Vec3): string[];
+ // applyBoolean(tools: string[], kind: BooleanKind): string[];
+ applyBooleanModifier(tools: string[], booleanDef?: BooleanDefinition): OperationResult;
}
export function createOCCUtils(ctx: CoreContext): OCCUtils {
@@ -32,39 +37,67 @@ export function createOCCUtils(ctx: CoreContext): OCCUtils {
});
}
- function prism(faces: string[], dir: Vec3): string[] {
- const oci = ctx.occService.commandInterface;
- return faces.map((faceName, i) => {
- const shapeName = "Shape:" + i;
+ function applyBoolean(tools: string[], target: string[], kind: BooleanKind): string[] {
- oci.prism(shapeName, faceName, ...dir)
- // occIterateFaces(oc, shape, face => {
- // let role;
- // if (face.IsSame(prismAPI.FirstShape())) {
- // role = "bottom";
- // } else if (face.IsSame(prismAPI.LastShape())) {
- // role = "top";
- // } else {
- // role = "sweep";
- // }
- // getProductionInfo(face).role = role;
- // });
- //
- // occIterateEdges(oc, wire, edge => {
- // const generatedList = prismAPI.Generated(edge);
- // occIterateListOfShape(oc, generatedList, face => {
- // console.log(face);
- // })
- // })
- return shapeName;
- });
}
+ function applyBooleanModifier(tools: string[], booleanDef?: BooleanDefinition): OperationResult {
+ const occ = ctx.occService;
+ const oci = ctx.occService.commandInterface;
+
+ if (!booleanDef || booleanDef.kind === 'NONE') {
+
+ return {
+ created: tools.map(shapeName => occ.io.getShell(shapeName)),
+ consumed: []
+ }
+
+ } else {
+ const kind = booleanDef.kind;
+
+ let targets = booleanDef.targets;
+ if (targets.length === 0) {
+ targets = ctx.cadRegistry.shells;
+ }
+
+ let targetNames = targets.map((target, i) => {
+ const targetName = 'Target:' + i;
+ ctx.occService.io.pushModel(target, targetName)
+ return targetName;
+ });
+
+ oci.bfuzzyvalue(0.0001);
+ oci.bclearobjects();
+ oci.bcleartools();
+
+ targetNames.forEach(targetName => oci.baddobjects(targetName));
+ tools.forEach(toolName => oci.baddtools(toolName));
+
+ oci.bfillds();
+ oci.bcbuild("BooleanResult");
+
+ // oci.bopcommon("result");
+//oci.bopfuse("result");
+//oci.bopcut("result");
+
+ return {
+ consumed: targets,
+ created: tools.map(shapeName => occ.io.getShell(shapeName), targets)
+ }
+
+
+ }
+
+
+
+ }
+
+
return {
- wiresToFaces, sketchToFaces, prism
+ wiresToFaces, sketchToFaces, applyBooleanModifier
}
}
\ No newline at end of file
diff --git a/web/app/cad/craft/e0/OCI.d.ts b/web/app/cad/craft/e0/OCI.d.ts
index f98b8efc..57cac4cf 100644
--- a/web/app/cad/craft/e0/OCI.d.ts
+++ b/web/app/cad/craft/e0/OCI.d.ts
@@ -54,6 +54,11 @@ interface OCCCommands {
*/
BRepIntCS(...args: any[]);
+ /*
+ Generic webcad engine command
+ */
+ EngineCommand(...args: any[]);
+
/*
XProgress [+|-t] [+|-c] [+|-g]
The options are:
diff --git a/web/app/cad/craft/e0/occCommandInterface.ts b/web/app/cad/craft/e0/occCommandInterface.ts
index cf801351..c90d0683 100644
--- a/web/app/cad/craft/e0/occCommandInterface.ts
+++ b/web/app/cad/craft/e0/occCommandInterface.ts
@@ -6,7 +6,7 @@ export const OCI: OCCCommandInterface = new Proxy({}, {
get: function (target, prop: string, receiver) {
return prop in target ? target[prop] : function() {
prop = prop.replace(/^_/, '');
- const args = Array.from(arguments).map(a => a + "");
+ const args = Array.from(arguments).map(a => JSON.stringify(a));
console.log("ARGUMENTS:", args);
const returnCode = CallCommand(prop, [prop, ...args]);
// if (returnCode !== 0) {
diff --git a/web/app/cad/craft/e0/occEngineInterface.ts b/web/app/cad/craft/e0/occEngineInterface.ts
new file mode 100644
index 00000000..6c59e870
--- /dev/null
+++ b/web/app/cad/craft/e0/occEngineInterface.ts
@@ -0,0 +1,18 @@
+import {OCCCommandInterface} from "cad/craft/e0/occCommandInterface";
+import {MShell} from "cad/model/mshell";
+import {MObject} from "cad/model/mobject";
+import {Interrogate} from "cad/craft/e0/interact";
+import {readShellEntityFromJson} from "cad/scene/wrappers/entityIO";
+import {createOCCSketchLoader, OCCSketchLoader} from "cad/craft/e0/occSketchLoader";
+
+export function createOCCEngineInterface(oci: OCCCommandInterface) {
+
+ return {
+ io: {
+ pushModel: (params: {
+ name: string, operand: number,
+ }) => oci.EngineCommand(params)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/web/app/cad/craft/e0/occIO.ts b/web/app/cad/craft/e0/occIO.ts
index 82cff5e5..5b6e3cc1 100644
--- a/web/app/cad/craft/e0/occIO.ts
+++ b/web/app/cad/craft/e0/occIO.ts
@@ -1,9 +1,10 @@
-import {OCCCommandInterface} from "cad/craft/e0/occCommandInterface";
+import {OCI} from "cad/craft/e0/occCommandInterface";
import {MShell} from "cad/model/mshell";
import {MObject} from "cad/model/mobject";
import {Interrogate} from "cad/craft/e0/interact";
import {readShellEntityFromJson} from "cad/scene/wrappers/entityIO";
import {createOCCSketchLoader, OCCSketchLoader} from "cad/craft/e0/occSketchLoader";
+import {CoreContext} from "context";
export interface OCCIO {
@@ -16,7 +17,7 @@ export interface OCCIO {
sketchLoader: OCCSketchLoader
}
-export function createOCCIO(oci: OCCCommandInterface): OCCIO {
+export function createOCCIO(ctx: CoreContext): OCCIO {
function getShell(shapeName: string, consumed: MShell[]): MShell {
const shapeJson = Interrogate(shapeName);
@@ -24,11 +25,10 @@ export function createOCCIO(oci: OCCCommandInterface): OCCIO {
}
function pushModel(model: MObject, name: string) {
-
- }
-
- function anchorModel() {
-
+ ctx.occService.engineInterface.pushModel({
+ name,
+ operand: model.brepShell.data.externals.ptr
+ });
}
function cleanupRegistry() {
@@ -38,7 +38,7 @@ export function createOCCIO(oci: OCCCommandInterface): OCCIO {
return {
getShell, pushModel, cleanupRegistry,
- sketchLoader: createOCCSketchLoader(oci)
+ sketchLoader: createOCCSketchLoader(OCI)
}
}
\ No newline at end of file
diff --git a/web/app/cad/craft/e0/occService.ts b/web/app/cad/craft/e0/occService.ts
index b5808fc9..9505a8f1 100644
--- a/web/app/cad/craft/e0/occService.ts
+++ b/web/app/cad/craft/e0/occService.ts
@@ -2,6 +2,7 @@ import {CoreContext} from "context";
import {OCCCommandInterface, OCI} from "cad/craft/e0/occCommandInterface";
import {createOCCIO, OCCIO} from "cad/craft/e0/occIO";
import {createOCCUtils, OCCUtils} from "cad/craft/e0/OCCUtils";
+import {createOCCEngineInterface} from "cad/craft/e0/occEngineInterface";
export interface OCCService {
@@ -9,7 +10,9 @@ export interface OCCService {
commandInterface: OCCCommandInterface;
- utils: OCCUtils
+ utils: OCCUtils,
+
+ engineInterface: any
}
export function createOCCService(ctx: CoreContext): OCCService {
@@ -18,10 +21,12 @@ export function createOCCService(ctx: CoreContext): OCCService {
return {
- io: createOCCIO(oci),
+ io: createOCCIO(ctx),
commandInterface: oci,
+ engineInterface: createOCCEngineInterface(oci),
+
utils: createOCCUtils(ctx)
}
diff --git a/web/app/cad/craft/operationPlugin.ts b/web/app/cad/craft/operationPlugin.ts
index 1242a8a7..1ac19012 100644
--- a/web/app/cad/craft/operationPlugin.ts
+++ b/web/app/cad/craft/operationPlugin.ts
@@ -4,7 +4,7 @@ import {IconType} from "react-icons";
import {ActionAppearance} from "../actions/actionSystemPlugin";
import {ApplicationContext, CoreContext} from "context";
import {OperationResult} from "./craftPlugin";
-import {OperationSchema} from "cad/craft/schema/schema";
+import {OperationFlattenSchema, OperationSchema, schemaIterator} from "cad/craft/schema/schema";
import {FieldWidgetProps, UIDefinition} from "cad/mdf/ui/uiDefinition";
export function activate(ctx: ApplicationContext) {
@@ -35,7 +35,9 @@ export function activate(ctx: ApplicationContext) {
};
actions.push(opAction);
- registry$.mutate(registry => registry[id] = Object.assign({appearance}, descriptor, {
+ const workingSchema = flattenSchema(descriptor.schema);
+
+ registry$.mutate(registry => registry[id] = Object.assign({appearance, workingSchema}, descriptor, {
run: (request, opContext) => runOperation(request, descriptor, opContext)
}));
}
@@ -86,6 +88,7 @@ export interface Operation extends OperationDescriptor{
icon96: string;
icon: string|IconType;
};
+ workingSchema: OperationFlattenSchema;
}
export interface OperationDescriptor {
@@ -117,6 +120,14 @@ export interface OperationGeometryProvider {
}
+function flattenSchema(schema: OperationSchema): OperationFlattenSchema {
+ const flatSchema = {} as OperationFlattenSchema;
+ schemaIterator(schema, (path, flattenedPath, schemaField) => {
+ flatSchema[flattenedPath] = schemaField;
+ });
+ return flatSchema;
+}
+
declare module 'context' {
interface CoreContext {
diff --git a/web/app/cad/craft/primitives/simplePlane/simplePlaneOpSchema.js b/web/app/cad/craft/primitives/simplePlane/simplePlaneOpSchema.js
index a7c1b4f2..cc1befa2 100644
--- a/web/app/cad/craft/primitives/simplePlane/simplePlaneOpSchema.js
+++ b/web/app/cad/craft/primitives/simplePlane/simplePlaneOpSchema.js
@@ -1,7 +1,7 @@
export default {
orientation: {
- type: 'enum',
- values: ['XY', 'XZ', 'ZY'],
+ type: 'string',
+ enum: ['XY', 'XZ', 'ZY'],
defaultValue: 'XY'
},
parallelTo: {
diff --git a/web/app/cad/craft/schema/common/BooleanDefinition.ts b/web/app/cad/craft/schema/common/BooleanDefinition.ts
new file mode 100644
index 00000000..d7e2bbda
--- /dev/null
+++ b/web/app/cad/craft/schema/common/BooleanDefinition.ts
@@ -0,0 +1,12 @@
+import {MObject} from "cad/model/mobject";
+
+export type BooleanKind = 'NONE' | 'UNION' | 'SUBTRACT' | 'INTERSECT';
+
+export interface BooleanDefinition {
+
+ kind: BooleanKind;
+
+ targets: MObject[];
+
+}
+
diff --git a/web/app/cad/craft/schema/materializeParams.ts b/web/app/cad/craft/schema/materializeParams.ts
index ceb553ce..0a1ee08b 100644
--- a/web/app/cad/craft/schema/materializeParams.ts
+++ b/web/app/cad/craft/schema/materializeParams.ts
@@ -45,6 +45,12 @@ function materializeParamsImpl(ctx: CoreContext,
const typeDef = TypeRegistry[md.type];
value = typeDef.resolve(ctx, value, md as any, reportError.dot(field), materializeParamsImpl);
+ if (md.resolve !== undefined) {
+ value = md.resolve(
+ ctx, value, md as any, reportError.dot(field), materializeParamsImpl
+ )
+ }
+
// if (md.type === Types.NUMBER) {
// try {
// const valueType = typeof value;
diff --git a/web/app/cad/craft/schema/resolvers/vectorResolver.ts b/web/app/cad/craft/schema/resolvers/vectorResolver.ts
new file mode 100644
index 00000000..eaa00be0
--- /dev/null
+++ b/web/app/cad/craft/schema/resolvers/vectorResolver.ts
@@ -0,0 +1,31 @@
+import {Materializer} from "cad/craft/schema/types/index";
+import {CoreContext} from "context";
+import {OperationParamsErrorReporter} from "cad/craft/schema/schema";
+import Vector from "math/vector";
+import {MObject} from "cad/model/mobject";
+import {ObjectTypeSchema} from "cad/craft/schema/types/objectType";
+
+type VectorInput = {
+ vectorEntity: MObject,
+ flip: boolean
+}
+
+export function VectorResolver(ctx: CoreContext,
+ value: VectorInput,
+ md: ObjectTypeSchema,
+ reportError: OperationParamsErrorReporter,
+ materializer: Materializer): Vector {
+
+ if (!value.vectorEntity) {
+ return null;
+ }
+
+ let vector = value.vectorEntity.toDirection();
+ if (!vector) {
+ throw 'unsupported entity type: ' + value.vectorEntity.TYPE;
+ }
+ if (value.flip) {
+ vector = vector.negate();
+ }
+ return vector;
+}
diff --git a/web/app/cad/craft/schema/schema.ts b/web/app/cad/craft/schema/schema.ts
index 5d350371..a5779c54 100644
--- a/web/app/cad/craft/schema/schema.ts
+++ b/web/app/cad/craft/schema/schema.ts
@@ -1,16 +1,27 @@
-import {Types} from "cad/craft/schema/types";
import {NumberTypeSchema} from "cad/craft/schema/types/numberType";
import {EntityTypeSchema} from "cad/craft/schema/types/entityType";
import {ArrayTypeSchema} from "cad/craft/schema/types/arrayType";
import {ObjectTypeSchema} from "cad/craft/schema/types/objectType";
-import {EnumTypeSchema} from "cad/craft/schema/types/enumType";
+import {StringTypeSchema} from "cad/craft/schema/types/stringType";
+import {BooleanTypeSchema} from "cad/craft/schema/types/booleanType";
-export type SchemaField = NumberTypeSchema | EntityTypeSchema | ArrayTypeSchema | ObjectTypeSchema | EnumTypeSchema;
+export type FlatSchemaField =
+ | ArrayTypeSchema
+ | EntityTypeSchema
+ | NumberTypeSchema
+ | StringTypeSchema
+ | BooleanTypeSchema;
+
+export type SchemaField = FlatSchemaField | ObjectTypeSchema;
export type OperationSchema = {
[key: string]: SchemaField;
};
+export type OperationFlattenSchema = {
+ [key: string]: FlatSchemaField;
+};
+
export interface BaseSchemaField {
defaultValue: Coercable,
optional: boolean,
@@ -30,4 +41,26 @@ export type OperationParamsError = {
export type OperationParamsErrorReporter = ((msg: string) => void) & {
dot: (pathPart: string|number) => OperationParamsErrorReporter
-};
\ No newline at end of file
+};
+
+export function schemaIterator(schema: OperationSchema,
+ callback: (path: string[], flattenedPath: string, field: FlatSchemaField) => void) {
+
+ function inorder(schema: OperationSchema, parentPath: string[]) {
+
+ Object.keys(schema).forEach(key => {
+ const path = [...parentPath, key]
+ const flattenedPath = path.join('/');
+ const schemaField = schema[key];
+
+
+ if (schemaField.type === 'object') {
+ inorder(schemaField.schema, path);
+ } else {
+ callback(path, flattenedPath, schemaField as FlatSchemaField);
+ }
+ })
+
+ }
+ inorder(schema, []);
+}
\ No newline at end of file
diff --git a/web/app/cad/craft/schema/types/booleanType.ts b/web/app/cad/craft/schema/types/booleanType.ts
new file mode 100644
index 00000000..9b1369fe
--- /dev/null
+++ b/web/app/cad/craft/schema/types/booleanType.ts
@@ -0,0 +1,20 @@
+import {Materializer, Type, Types} from "cad/craft/schema/types/index";
+import {CoreContext} from "context";
+import {BaseSchemaField, OperationParamsErrorReporter} from "cad/craft/schema/schema";
+
+export interface BooleanTypeSchema extends BaseSchemaField {
+
+ type: Types.boolean,
+
+}
+
+export const BooleanType: Type = {
+
+ resolve(ctx: CoreContext,
+ value: any,
+ md: BooleanTypeSchema,
+ reportError: OperationParamsErrorReporter,
+ materializer: Materializer): boolean {
+ return !!value;
+ }
+}
diff --git a/web/app/cad/craft/schema/types/index.ts b/web/app/cad/craft/schema/types/index.ts
index 30d9fdaf..27e28c0b 100644
--- a/web/app/cad/craft/schema/types/index.ts
+++ b/web/app/cad/craft/schema/types/index.ts
@@ -4,7 +4,8 @@ import {ArrayType} from "cad/craft/schema/types/arrayType";
import {EntityType} from "cad/craft/schema/types/entityType";
import {NumberType} from "cad/craft/schema/types/numberType";
import {ObjectType} from "cad/craft/schema/types/objectType";
-import {EnumType} from "cad/craft/schema/types/enumType";
+import {StringType} from "cad/craft/schema/types/stringType";
+import {BooleanType} from "cad/craft/schema/types/booleanType";
export type Materializer = (ctx: CoreContext,
params: OperationParams,
@@ -22,16 +23,18 @@ export interface Type {
export enum Types {
array = 'array',
+ object = 'object',
entity = 'entity',
number = 'number',
- object = 'object',
- enum = 'enum',
+ boolean = 'boolean',
+ string = 'string'
}
export const TypeRegistry = {
[Types.array]: ArrayType,
+ [Types.object]: ObjectType,
[Types.entity]: EntityType,
[Types.number]: NumberType,
- [Types.object]: ObjectType,
- [Types.enum]: EnumType,
+ [Types.boolean]: BooleanType,
+ [Types.string]: StringType,
};
diff --git a/web/app/cad/craft/schema/types/objectType.ts b/web/app/cad/craft/schema/types/objectType.ts
index d0a661af..695c4044 100644
--- a/web/app/cad/craft/schema/types/objectType.ts
+++ b/web/app/cad/craft/schema/types/objectType.ts
@@ -8,6 +8,8 @@ export interface ObjectTypeSchema extends BaseSchemaField {
schema: OperationSchema;
+ resolver: (input: any) => any;
+
}
export const ObjectType: Type = {
diff --git a/web/app/cad/craft/schema/types/enumType.ts b/web/app/cad/craft/schema/types/stringType.ts
similarity index 51%
rename from web/app/cad/craft/schema/types/enumType.ts
rename to web/app/cad/craft/schema/types/stringType.ts
index b5ce89d2..663c8a53 100644
--- a/web/app/cad/craft/schema/types/enumType.ts
+++ b/web/app/cad/craft/schema/types/stringType.ts
@@ -2,25 +2,28 @@ import {Materializer, Type, TypeRegistry, Types} from "cad/craft/schema/types/in
import {CoreContext} from "context";
import {BaseSchemaField, OperationParamsErrorReporter} from "cad/craft/schema/schema";
-export interface EnumTypeSchema extends BaseSchemaField {
+export interface StringTypeSchema extends BaseSchemaField {
type: Types.number,
- values: string[]
+ enum?: string[]
}
-export const EnumType: Type = {
+export const StringType: Type = {
resolve(ctx: CoreContext,
value: any,
- md: EnumTypeSchema,
+ md: StringTypeSchema,
reportError: OperationParamsErrorReporter,
- materializer: Materializer): number {
+ materializer: Materializer): string {
- if (md.values.indexOf(value) === -1) {
- value = md.defaultValue || md.values[0];
+ value = value + '';
+
+ if (md.enum && md.enum.indexOf(value) === -1) {
+ value = md.defaultValue || md.enum[0];
}
+
return value;
}
}
diff --git a/web/app/cad/craft/wizard/wizardPlugin.js b/web/app/cad/craft/wizard/wizardPlugin.js
index 52559e55..bab05b8a 100644
--- a/web/app/cad/craft/wizard/wizardPlugin.js
+++ b/web/app/cad/craft/wizard/wizardPlugin.js
@@ -5,6 +5,7 @@ import materializeParams from '../schema/materializeParams';
import {createFunctionList} from 'gems/func';
import {onParamsUpdate} from '../cutExtrude/extrudeOperation';
import {propsChangeTracker} from 'lstream/utils';
+import {OperationSchema, schemaIterator} from "cad/craft/schema/schema";
export function activate(ctx) {
@@ -59,9 +60,9 @@ export function activate(ctx) {
let params;
let {changingHistory, noWizardFocus} = opRequest;
if (changingHistory) {
- params = clone(opRequest.params)
+ params = flattenParams(opRequest.params, operation.schema);
} else {
- params = initializeBySchema(operation.schema, ctx);
+ params = initializeBySchema(operation.workingSchema, ctx);
if (opRequest.initialOverrides) {
applyOverrides(params, opRequest.initialOverrides);
}
@@ -75,7 +76,8 @@ export function activate(ctx) {
let materializedWorkingRequest$ = workingRequest$.map(req => {
let params = {};
let errors = [];
- materializeParams(ctx, req.params, operation.schema, params, errors, []);
+ let unflatten = unflattenParams(req.params, operation.schema);
+ materializeParams(ctx, unflatten, operation.schema, params, errors);
if (errors.length !== 0) {
return INVALID_REQUEST;
}
@@ -83,7 +85,7 @@ export function activate(ctx) {
type: req.type,
params
};
- }).remember(INVALID_REQUEST).filter(r => r !== INVALID_REQUEST);
+ }).remember(INVALID_REQUEST).filter(r => r !== INVALID_REQUEST).throttle(500);
const state$ = state({});
const updateParams = mutator => workingRequest$.mutate(data => mutator(data.params));
const updateState = mutator => state$.mutate(state => mutator(state));
@@ -129,8 +131,12 @@ export function activate(ctx) {
},
applyWorkingRequest: () => {
- let {type, params} = streams.wizard.wizardContext.value.workingRequest$.value;
- let request = clone({type, params});
+ let wizCtx = streams.wizard.wizardContext.value;
+ let {type, params} = wizCtx.workingRequest$.value;
+ let request = {
+ type,
+ params: unflattenParams(params, wizCtx.operation.schema)
+ };
const setError = error => streams.wizard.wizardContext.mutate(ctx => ctx.state$.mutate(state => state.error = error));
if (streams.wizard.insertOperation.value.type) {
ctx.services.craft.modify(request, () => streams.wizard.insertOperation.value = EMPTY_OBJECT, setError );
@@ -143,6 +149,23 @@ export function activate(ctx) {
};
}
+function flattenParams(params, originalSchema) {
+ const flatParams = {};
+ schemaIterator(originalSchema, (path, flattenedPath, schemaField) => {
+ flatParams[flattenedPath] = _.get(params, path);
+ });
+ return flatParams;
+}
+
+function unflattenParams(params, originalSchema) {
+ const unflatParams = {};
+ schemaIterator(originalSchema, (path, flattenedPath, schemaField) => {
+ _.set(unflatParams, path, params[flattenedPath]);
+ });
+ return unflatParams;
+}
+
+
function applyOverrides(params, initialOverrides) {
Object.assign(params, initialOverrides);
}
diff --git a/web/app/cad/craft/wizard/wizardSelectionPlugin.js b/web/app/cad/craft/wizard/wizardSelectionPlugin.js
index 0d40e7d9..60a95700 100644
--- a/web/app/cad/craft/wizard/wizardSelectionPlugin.js
+++ b/web/app/cad/craft/wizard/wizardSelectionPlugin.js
@@ -10,7 +10,7 @@ export function activate(ctx) {
wizCtx.workingRequest$.attach(({type, params}) => {
const marker = ctx.services.marker;
marker.startSession();
- let {schema} = wizCtx.operation;
+ let {workingSchema: schema} = wizCtx.operation;
Object.keys(schema).forEach(param => {
let md = schema[param];
@@ -65,7 +65,7 @@ function createPickHandlerFromSchema(wizCtx) {
const params = wizCtx.workingRequest$.value.params;
const state = wizCtx.state$.value;
- let {schema} = wizCtx.operation;
+ let {workingSchema: schema} = wizCtx.operation;
const activeMd = state.activeParam && schema[state.activeParam];
const activeCanTakeIt = kind => activeMd.allowedKinds && activeMd.allowedKinds.includes(kind);
diff --git a/web/app/cad/mdf/generateForm.tsx b/web/app/cad/mdf/generateForm.tsx
index 8a7d9e9f..fab219f6 100644
--- a/web/app/cad/mdf/generateForm.tsx
+++ b/web/app/cad/mdf/generateForm.tsx
@@ -3,7 +3,8 @@ import { ComboBoxOption } from 'ui/components/controls/ComboBoxControl';
import Entity from '../craft/wizard/components/form/Entity';
import { CheckboxField, NumberField, ComboBoxField, TextField } from '../craft/wizard/components/form/Fields';
import { Group } from '../craft/wizard/components/form/Form';
-import { OperationSchema, SchemaField } from './mdf';
+import {OperationSchema, SchemaField} from "cad/craft/schema/schema";
+
export function generateForm(schema: OperationSchema) {
diff --git a/web/app/cad/mdf/mdf.ts b/web/app/cad/mdf/mdf.ts
index bc98885d..2faa1ae0 100644
--- a/web/app/cad/mdf/mdf.ts
+++ b/web/app/cad/mdf/mdf.ts
@@ -32,8 +32,7 @@ export function loadMDFCommand(mdfCommand: MDFCommand): OperationDescripto
type: 'group',
content: mdfCommand.form
}
- const formFields = extractFormFields(uiDefinition);
- const derivedSchema = deriveSchema(formFields);
+ const {schema: derivedSchema, formFields} = deriveSchema(uiDefinition);
return {
id: mdfCommand.id,
label: mdfCommand.label,
@@ -75,13 +74,20 @@ function extractFormFields(uiDefinition: UIDefinition): FieldWidgetProps[] {
return fields;
}
-export function deriveSchema(formFields: FieldWidgetProps[]): OperationSchema {
+export function deriveSchema(uiDefinition: UIDefinition): {
+ schema: OperationSchema,
+ formFields: FieldWidgetProps[]
+} {
+ const formFields: FieldWidgetProps[] = extractFormFields(uiDefinition)
const schema = {};
formFields.forEach(f => {
let propsToSchema = DynamicComponents[f.type].propsToSchema;
schema[f.name] = propsToSchema(schema, f as any);
});
- return schema;
+ return {
+ schema,
+ formFields
+ };
}
diff --git a/web/app/cad/mdf/ui/AccordionWidget.tsx b/web/app/cad/mdf/ui/AccordionWidget.tsx
deleted file mode 100644
index 2b32d705..00000000
--- a/web/app/cad/mdf/ui/AccordionWidget.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from "react";
-import {ContainerBasicProps, ContainerWidgetProps} from "cad/mdf/ui/ContainerWidget";
-
-export interface AccordionWidgetProps extends ContainerBasicProps {
-
- type: 'accordion';
-
-}
-
-export function AccordionWidget(props: AccordionWidgetProps) {
- return "TBD"
-}
-
-
-
diff --git a/web/app/cad/mdf/ui/BooleanWidget.tsx b/web/app/cad/mdf/ui/BooleanWidget.tsx
new file mode 100644
index 00000000..5ef15991
--- /dev/null
+++ b/web/app/cad/mdf/ui/BooleanWidget.tsx
@@ -0,0 +1,84 @@
+import React from "react";
+import {OperationSchema} from "cad/craft/schema/schema";
+import {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field";
+import {Types} from "cad/craft/schema/types";
+import {EntityKind} from "cad/model/entities";
+import {SectionWidgetProps} from "cad/mdf/ui/SectionWidget";
+import {DynamicComponentWidget} from "cad/mdf/ui/DynamicComponentWidget";
+import {VectorResolver} from "cad/craft/schema/resolvers/vectorResolver";
+
+export interface BooleanWidgetProps extends FieldBasicProps {
+
+ type: 'boolean';
+
+}
+
+const ENTITY_CAPTURE = [EntityKind.SHELL];
+
+const BOOLEAN_OPTIONS = ['NONE', 'UNION', 'SUBTRACT', 'INTERSECT'];
+
+const BooleanUIDefinition = (fieldName: string, label: string) => ({
+
+ type: 'section',
+
+ title: label,
+
+ collapsible: true,
+
+ initialCollapse: false,
+
+ content: [
+ {
+ name: fieldName+"/kind",
+ label: 'kind',
+ type: "choice",
+ optional: true,
+ values: BOOLEAN_OPTIONS
+ },
+ {
+ name: fieldName+"/targets",
+ label: 'target',
+ type: "selection",
+ capture: ENTITY_CAPTURE,
+ multi: true,
+ optional: true,
+ }
+ ]
+} as SectionWidgetProps);
+
+
+export function BooleanWidget(props: BooleanWidgetProps) {
+
+ let vectorUIDefinition = BooleanUIDefinition(props.name, props.label);
+
+ return
+}
+
+BooleanWidget.propsToSchema = (consumer: OperationSchema, props: BooleanWidgetProps) => {
+ return {
+ type: Types.object,
+ schema: {
+ kind: {
+ label: 'kind',
+ type: Types.string,
+ enum: BOOLEAN_OPTIONS,
+ defaultValue: props.defaultValue || 'NONE',
+ optional: false
+ },
+
+ targets: {
+ label: 'targets',
+ type: Types.array,
+ item: {
+ type: Types.boolean,
+ allowedKinds: ENTITY_CAPTURE,
+ },
+ optional: true,
+ applicable: 'kind !== "NONE"'
+ }
+ },
+ ...fieldToSchemaGeneric(props),
+ }
+};
+
+
diff --git a/web/app/cad/mdf/ui/CheckboxWidget.tsx b/web/app/cad/mdf/ui/CheckboxWidget.tsx
new file mode 100644
index 00000000..23624d4c
--- /dev/null
+++ b/web/app/cad/mdf/ui/CheckboxWidget.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import {OperationSchema} from "cad/craft/schema/schema";
+import {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field";
+import {Types} from "cad/craft/schema/types";
+import {CheckboxField} from "cad/craft/wizard/components/form/Fields";
+
+export interface CheckboxWidgetProps extends FieldBasicProps {
+
+ type: 'checkbox';
+
+ min?: number;
+
+ max?: number;
+}
+
+export function CheckboxWidget(props: CheckboxWidgetProps) {
+ return
+}
+
+CheckboxWidget.propsToSchema = (consumer: OperationSchema, props: CheckboxWidgetProps) => {
+ return {
+ type: Types.boolean,
+ ...fieldToSchemaGeneric(props),
+ }
+};
+
+
diff --git a/web/app/cad/mdf/ui/ChoiceWidget.tsx b/web/app/cad/mdf/ui/ChoiceWidget.tsx
new file mode 100644
index 00000000..85723ae5
--- /dev/null
+++ b/web/app/cad/mdf/ui/ChoiceWidget.tsx
@@ -0,0 +1,36 @@
+import {ComboBoxField, NumberField} from "cad/craft/wizard/components/form/Fields";
+import React from "react";
+import {OperationSchema} from "cad/craft/schema/schema";
+import {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field";
+import {Types} from "cad/craft/schema/types";
+import {ComboBoxOption} from "ui/components/controls/ComboBoxControl";
+
+export interface ChoiceWidgetProps extends FieldBasicProps {
+
+ type: 'choice';
+
+ style?: 'dropdown' | 'radio';
+
+ values: string[];
+
+}
+
+export function ChoiceWidget(props: ChoiceWidgetProps) {
+ if (!props.style || props.style === 'dropdown') {
+ return
+ {props.values.map(value => {value})}
+
+ } else {
+ throw 'implement me';
+ }
+}
+
+ChoiceWidget.propsToSchema = (consumer: OperationSchema, props: ChoiceWidgetProps) => {
+ return {
+ type: Types.string,
+ enum: props.values,
+ ...fieldToSchemaGeneric(props),
+ }
+};
+
+
diff --git a/web/app/cad/mdf/ui/SectionWidget.tsx b/web/app/cad/mdf/ui/SectionWidget.tsx
new file mode 100644
index 00000000..b42a5801
--- /dev/null
+++ b/web/app/cad/mdf/ui/SectionWidget.tsx
@@ -0,0 +1,31 @@
+import React, {useState} from "react";
+import {ContainerBasicProps, ContainerWidget, ContainerWidgetProps} from "cad/mdf/ui/ContainerWidget";
+import {Group} from "cad/craft/wizard/components/form/Form";
+import {StackSection} from "ui/components/controls/FormSection";
+import Entity from "cad/craft/wizard/components/form/EntityList";
+import {CheckboxField} from "cad/craft/wizard/components/form/Fields";
+
+export interface SectionWidgetProps extends ContainerBasicProps {
+
+ type: 'section';
+
+ title: string;
+
+ collapsible: boolean;
+
+ initialCollapse: boolean;
+
+}
+
+export function SectionWidget(props: SectionWidgetProps) {
+ const [visible, setVisible] = useState(!props.initialCollapse);
+
+ const onTitleClick = props.collapsible ? () => setVisible(visible => !visible) : undefined;
+
+ return
+ {visible && }
+
+}
+
+
+
diff --git a/web/app/cad/mdf/ui/VectorWidget.tsx b/web/app/cad/mdf/ui/VectorWidget.tsx
new file mode 100644
index 00000000..e8462bb3
--- /dev/null
+++ b/web/app/cad/mdf/ui/VectorWidget.tsx
@@ -0,0 +1,75 @@
+import React from "react";
+import {OperationSchema} from "cad/craft/schema/schema";
+import {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field";
+import {Types} from "cad/craft/schema/types";
+import {EntityKind} from "cad/model/entities";
+import {SectionWidgetProps} from "cad/mdf/ui/SectionWidget";
+import {DynamicComponentWidget} from "cad/mdf/ui/DynamicComponentWidget";
+import {VectorResolver} from "cad/craft/schema/resolvers/vectorResolver";
+
+export interface VectorWidgetProps extends FieldBasicProps {
+
+ type: 'vector';
+
+}
+
+const ENTITY_CAPTURE = [EntityKind.EDGE, EntityKind.SKETCH_OBJECT, EntityKind.DATUM_AXIS, EntityKind.FACE];
+
+const VectorUIDefinition = (fieldName: string, label: string) => ({
+
+ type: 'section',
+
+ title: label,
+
+ collapsible: true,
+
+ initialCollapse: false,
+
+ content: [
+ {
+ name: fieldName+"/vectorEntity",
+ label: 'vector',
+ type: "selection",
+ capture: ENTITY_CAPTURE,
+ multi: false,
+ },
+ {
+ name: fieldName+"/flip",
+ label: 'flip',
+ type: "checkbox",
+ defaultValue: false
+ }
+ ]
+} as SectionWidgetProps);
+
+
+export function VectorWidget(props: VectorWidgetProps) {
+
+ let vectorUIDefinition = VectorUIDefinition(props.name, props.label);
+
+ return
+}
+
+VectorWidget.propsToSchema = (consumer: OperationSchema, props: VectorWidgetProps) => {
+ return {
+ type: Types.object,
+ schema: {
+ vectorEntity: {
+ label: 'vector',
+ type: Types.entity,
+ allowedKinds: ENTITY_CAPTURE,
+ optional: true
+ },
+ flip: {
+ label: 'flip',
+ type: Types.boolean,
+ defaultValue: false,
+ optional: false
+ }
+ },
+ resolve: VectorResolver,
+ ...fieldToSchemaGeneric(props),
+ }
+};
+
+
diff --git a/web/app/cad/mdf/ui/componentRegistry.ts b/web/app/cad/mdf/ui/componentRegistry.ts
index ed15175a..3f224bf5 100644
--- a/web/app/cad/mdf/ui/componentRegistry.ts
+++ b/web/app/cad/mdf/ui/componentRegistry.ts
@@ -2,6 +2,11 @@ import {NumberWidget} from "cad/mdf/ui/NumberWidget";
import {SelectionWidget} from "cad/mdf/ui/SelectionWidget";
import {ContainerWidget} from "cad/mdf/ui/ContainerWidget";
import {GroupWidget} from "cad/mdf/ui/GroupWidget";
+import {SectionWidget} from "cad/mdf/ui/SectionWidget";
+import {VectorWidget} from "cad/mdf/ui/VectorWidget";
+import {CheckboxWidget} from "cad/mdf/ui/CheckboxWidget";
+import {BooleanWidget} from "cad/mdf/ui/BooleanWidget";
+import {ChoiceWidget} from "cad/mdf/ui/ChoiceWidget";
export const DynamicComponents = {
@@ -12,4 +17,15 @@ export const DynamicComponents = {
'container': ContainerWidget,
'group': GroupWidget,
+
+ 'section': SectionWidget,
+
+ 'vector': VectorWidget,
+
+ 'checkbox': CheckboxWidget,
+
+ 'boolean': BooleanWidget,
+
+ 'choice': ChoiceWidget,
+
}
\ No newline at end of file
diff --git a/web/app/cad/mdf/ui/uiDefinition.ts b/web/app/cad/mdf/ui/uiDefinition.ts
index f5ee11d7..fb89b4ca 100644
--- a/web/app/cad/mdf/ui/uiDefinition.ts
+++ b/web/app/cad/mdf/ui/uiDefinition.ts
@@ -1,12 +1,17 @@
import {NumberWidgetProps} from "cad/mdf/ui/NumberWidget";
import {SelectionWidgetProps} from "cad/mdf/ui/SelectionWidget";
-import {AccordionWidgetProps} from "cad/mdf/ui/AccordionWidget";
+import {SectionWidgetProps} from "cad/mdf/ui/SectionWidget";
import {DynamicComponents} from "cad/mdf/ui/componentRegistry";
import {ContainerWidgetProps} from "cad/mdf/ui/ContainerWidget";
+import {GroupWidgetProps} from "cad/mdf/ui/GroupWidget";
+import {CheckboxWidgetProps} from "cad/mdf/ui/CheckboxWidget";
+import {VectorWidgetProps} from "cad/mdf/ui/VectorWidget";
+import {BooleanWidgetProps} from "cad/mdf/ui/BooleanWidget";
+import {ChoiceWidgetProps} from "cad/mdf/ui/ChoiceWidget";
-export type FieldWidgetProps = NumberWidgetProps | SelectionWidgetProps;
+export type FieldWidgetProps = NumberWidgetProps | CheckboxWidgetProps | ChoiceWidgetProps | SelectionWidgetProps | VectorWidgetProps | BooleanWidgetProps;
-export type BasicWidgetProps = ContainerWidgetProps | AccordionWidgetProps;
+export type BasicWidgetProps = ContainerWidgetProps | SectionWidgetProps | GroupWidgetProps;
export type DynamicWidgetProps = FieldWidgetProps | BasicWidgetProps;
diff --git a/web/app/cad/model/mdatum.ts b/web/app/cad/model/mdatum.ts
index d36721c2..9bb5496b 100644
--- a/web/app/cad/model/mdatum.ts
+++ b/web/app/cad/model/mdatum.ts
@@ -57,4 +57,8 @@ export class MDatumAxis extends MObject {
get parent() {
return this.holder;
}
+
+ toDirection(): Vector {
+ return this.dir;
+ };
}
\ No newline at end of file
diff --git a/web/app/cad/model/medge.ts b/web/app/cad/model/medge.ts
index 7e0b134b..e27c2891 100644
--- a/web/app/cad/model/medge.ts
+++ b/web/app/cad/model/medge.ts
@@ -1,12 +1,14 @@
import {MObject} from './mobject';
import {MBrepShell} from "./mshell";
import {EntityKind} from "cad/model/entities";
+import {Edge} from "brep/topo/edge";
+import Vector from "math/vector";
export class MEdge extends MObject {
static TYPE = EntityKind.EDGE;
shell: MBrepShell;
- brepEdge: any;
+ brepEdge: Edge;
constructor(id, shell, brepEdge) {
super(MEdge.TYPE, id);
@@ -34,4 +36,9 @@ export class MEdge extends MObject {
get parent() {
return this.shell;
}
+
+ toDirection(): Vector {
+ return this.brepEdge.halfEdge1.tangentAtStart();
+ };
+
}
\ No newline at end of file
diff --git a/web/app/cad/model/mface.ts b/web/app/cad/model/mface.ts
index 2a882fd8..3b5d85c0 100644
--- a/web/app/cad/model/mface.ts
+++ b/web/app/cad/model/mface.ts
@@ -10,6 +10,7 @@ import BBox from "math/bbox";
import {Basis, BasisForPlane} from "math/basis";
import {Face} from "brep/topo/face";
import {EntityKind} from "cad/model/entities";
+import {Matrix3x4} from "math/matrix";
export class MFace extends MObject {
@@ -141,14 +142,14 @@ export class MFace extends MObject {
return EMPTY_ARRAY;
}
- get sketchToWorldTransformation() {
+ get sketchToWorldTransformation(): Matrix3x4 {
if (!this._sketchToWorldTransformation) {
this._sketchToWorldTransformation = this.csys.outTransformation;
}
return this._sketchToWorldTransformation;
}
- get worldToSketchTransformation() {
+ get worldToSketchTransformation(): Matrix3x4 {
if (!this._worldToSketchTransformation) {
this._worldToSketchTransformation = this.csys.inTransformation;
}
@@ -223,4 +224,9 @@ export class MBrepFace extends MFace {
}
return this.#favorablePoint;
}
+
+ toDirection(): Vector {
+ return this.normal();
+ };
+
}
diff --git a/web/app/cad/model/mobject.ts b/web/app/cad/model/mobject.ts
index eddfb2c5..ee115ce8 100644
--- a/web/app/cad/model/mobject.ts
+++ b/web/app/cad/model/mobject.ts
@@ -1,5 +1,6 @@
import {IDENTITY_MATRIX, Matrix3x4} from "math/matrix";
import {EntityKind} from "cad/model/entities";
+import Vector from "math/vector";
export abstract class MObject {
@@ -19,6 +20,10 @@ export abstract class MObject {
abstract get parent();
+ toDirection() {
+ return null;
+ };
+
get root(): MObject {
let obj = this;
while (obj.parent) {
diff --git a/web/app/cad/model/msketchObject.ts b/web/app/cad/model/msketchObject.ts
index 654ebda0..5d6f0c39 100644
--- a/web/app/cad/model/msketchObject.ts
+++ b/web/app/cad/model/msketchObject.ts
@@ -1,6 +1,8 @@
import {MObject} from './mobject';
import {MFace} from "./mface";
import {EntityKind} from "cad/model/entities";
+import Vector from "math/vector";
+import {Segment} from "cad/sketch/sketchModel";
export class MSketchObject extends MObject {
@@ -20,4 +22,9 @@ export class MSketchObject extends MObject {
return this.face;
}
+ toDirection(): Vector {
+ const tangent = (this.sketchPrimitive as Segment).tangentAtStart();
+ return this.face.sketchToWorldTransformation.apply(tangent);
+ };
+
}
\ No newline at end of file
diff --git a/web/app/cad/sketch/inPlaceSketcher.js b/web/app/cad/sketch/inPlaceSketcher.js
index 11d779c4..33bd2342 100644
--- a/web/app/cad/sketch/inPlaceSketcher.js
+++ b/web/app/cad/sketch/inPlaceSketcher.js
@@ -48,7 +48,7 @@ export class InPlaceSketcher {
this.ctx.streams.ui.toolbars.headsUpShowTitles.next(false);
let sketchData = this.ctx.services.storage.get(this.sketchStorageKey);
- this.viewer.historyManager.init(sketchData, md);
+ this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData);
this.ctx.streams.sketcher.sketchingFace.next(face);
this.ctx.streams.sketcher.sketcherAppContext.next(this.sketcherAppContext);
diff --git a/web/app/cad/sketch/sketchModel.ts b/web/app/cad/sketch/sketchModel.ts
index f9b0e130..d54aa4e9 100644
--- a/web/app/cad/sketch/sketchModel.ts
+++ b/web/app/cad/sketch/sketchModel.ts
@@ -70,7 +70,7 @@ class SketchPrimitive {
}
}
-export class Segment extends SketchPrimitive {
+export class Segment extends SketchPrimitive {
a: Vector;
b: Vector;
@@ -105,7 +105,12 @@ export class Segment extends SketchPrimitive {
const [A, B] = genForm;
oci.point(underName + "_A", A.x, A.y, A.z);
oci.point(underName + "_B", B.x, B.y, B.z);
- oci.gcarc(underName, "seg", underName + "_A", underName + "_B")}
+ oci.gcarc(underName, "seg", underName + "_A", underName + "_B")
+ }
+
+ tangentAtStart(): Vector {
+ return this.b.minus(this.a);
+ }
}
export class Arc extends SketchPrimitive {
diff --git a/web/app/sketcher/constr/constractibles.js b/web/app/sketcher/constr/constractibles.js
index 988dc780..d47d199d 100644
--- a/web/app/sketcher/constr/constractibles.js
+++ b/web/app/sketcher/constr/constractibles.js
@@ -106,7 +106,7 @@ export class GCCircle extends ContractibleObject {
static TYPE = 'GCCircle';
static newInstance(x, y, r) {
- return GCCircle().init(new GCPoint(x, y), md)
+ return GCCircle().init(new GCPoint(x, y), new GCParam(r))
}
init(c, r) {
diff --git a/web/app/sketcher/project.js b/web/app/sketcher/project.js
index 9509e765..d085b445 100644
--- a/web/app/sketcher/project.js
+++ b/web/app/sketcher/project.js
@@ -47,7 +47,7 @@ export class Project {
let sketchId = this.getSketchId();
let sketchData = localStorage.getItem(sketchId);
if (sketchData != null) {
- this.viewer.historyManager.init(sketchData, md);
+ this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData);
}
this.viewer.repaint();