revert md

This commit is contained in:
xibyte 2022-02-05 21:45:19 -08:00 committed by Val Erastov
parent 07db5af1db
commit 0cbd38d36c
41 changed files with 678 additions and 107 deletions

View file

@ -35,7 +35,7 @@ export default class CSys {
return new Matrix3x4().setBasisAxises(this.x, this.y, this.z); 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); const mx = new Matrix3x4().setBasisAxises(this.x, this.y, this.z);
mx.tx = this.origin.x; mx.tx = this.origin.x;
mx.ty = this.origin.y; mx.ty = this.origin.y;

View file

@ -33,7 +33,10 @@ export default class Folder extends React.Component{
} }
export function Title({children, isClosed, onClick}) { export function Title({children, isClosed, onClick}) {
return <div className={ls.title} onClick={onClick}> const titleCss = onClick ? {
cursor: 'pointer'
} : {};
return <div className={ls.title} onClick={onClick} style={titleCss}>
<span className={ls.handle}><Fa fw icon={isClosed ? 'chevron-right' : 'chevron-down'}/></span> <span className={ls.handle}><Fa fw icon={isClosed ? 'chevron-right' : 'chevron-down'}/></span>
{' '}{children} {' '}{children}
</div>; </div>;

View file

@ -4,10 +4,10 @@ import {Title} from '../Folder';
export class StackSection extends React.Component { export class StackSection extends React.Component {
render() { render() {
const {title, children} = this.props; const {title, children, isClosed, onTitleClick} = this.props;
return <React.Fragment> return <React.Fragment>
<Title>{title}</Title> <Title isClosed={isClosed} onClick={onTitleClick}>{title}</Title>
{children} {!isClosed && children}
</React.Fragment>; </React.Fragment>;
} }

View file

@ -3,10 +3,14 @@ import {MFace} from "cad/model/mface";
import {ApplicationContext} from "context"; import {ApplicationContext} from "context";
import {MDFCommand} from "cad/mdf/mdf"; import {MDFCommand} from "cad/mdf/mdf";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import Vector from "math/vector";
import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
interface ExtrudeParams { interface ExtrudeParams {
length: number; length: number;
face: MFace; face: MFace;
direction?: Vector,
boolean: BooleanDefinition
} }
const ExtrudeOperation: MDFCommand<ExtrudeParams> = { const ExtrudeOperation: MDFCommand<ExtrudeParams> = {
@ -28,17 +32,49 @@ const ExtrudeOperation: MDFCommand<ExtrudeParams> = {
const occFaces = occ.utils.sketchToFaces(sketch, face.csys); 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 { return {
consumed: [face.parent], created: tools.map(shapeName => occ.io.getShell(shapeName)),
created consumed: []
}; }
// return occ.utils.applyBooleanModifier(tools, params.boolean);
}, },
// useBoolean: {
// booleanField: 'boolean',
// impliedTargetField: 'face'
// },
form: [ form: [
{ {
type: 'number', type: 'number',
@ -57,6 +93,33 @@ const ExtrudeOperation: MDFCommand<ExtrudeParams> = {
preselectionIndex: 0 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'
}
], ],
} }

View file

@ -4,6 +4,10 @@ import {SketchGeom} from "cad/sketch/sketchReader";
import {OCCService} from "cad/craft/e0/occService"; import {OCCService} from "cad/craft/e0/occService";
import {CoreContext} from "context"; import {CoreContext} from "context";
import CSys from "math/csys"; 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 { export interface OCCUtils {
@ -11,8 +15,9 @@ export interface OCCUtils {
sketchToFaces(sketch: SketchGeom, csys: CSys): string[]; 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 { 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 { return {
wiresToFaces, sketchToFaces, prism 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, applyBooleanModifier
} }
} }

View file

@ -54,6 +54,11 @@ interface OCCCommands {
*/ */
BRepIntCS(...args: any[]); BRepIntCS(...args: any[]);
/*
Generic webcad engine command
*/
EngineCommand(...args: any[]);
/* /*
XProgress [+|-t] [+|-c] [+|-g] XProgress [+|-t] [+|-c] [+|-g]
The options are: The options are:

View file

@ -6,7 +6,7 @@ export const OCI: OCCCommandInterface = new Proxy({}, {
get: function (target, prop: string, receiver) { get: function (target, prop: string, receiver) {
return prop in target ? target[prop] : function() { return prop in target ? target[prop] : function() {
prop = prop.replace(/^_/, ''); 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); console.log("ARGUMENTS:", args);
const returnCode = CallCommand(prop, [prop, ...args]); const returnCode = CallCommand(prop, [prop, ...args]);
// if (returnCode !== 0) { // if (returnCode !== 0) {

View file

@ -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)
}
}
}

View file

@ -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 {MShell} from "cad/model/mshell";
import {MObject} from "cad/model/mobject"; import {MObject} from "cad/model/mobject";
import {Interrogate} from "cad/craft/e0/interact"; import {Interrogate} from "cad/craft/e0/interact";
import {readShellEntityFromJson} from "cad/scene/wrappers/entityIO"; import {readShellEntityFromJson} from "cad/scene/wrappers/entityIO";
import {createOCCSketchLoader, OCCSketchLoader} from "cad/craft/e0/occSketchLoader"; import {createOCCSketchLoader, OCCSketchLoader} from "cad/craft/e0/occSketchLoader";
import {CoreContext} from "context";
export interface OCCIO { export interface OCCIO {
@ -16,7 +17,7 @@ export interface OCCIO {
sketchLoader: OCCSketchLoader sketchLoader: OCCSketchLoader
} }
export function createOCCIO(oci: OCCCommandInterface): OCCIO { export function createOCCIO(ctx: CoreContext): OCCIO {
function getShell(shapeName: string, consumed: MShell[]): MShell { function getShell(shapeName: string, consumed: MShell[]): MShell {
const shapeJson = Interrogate(shapeName); const shapeJson = Interrogate(shapeName);
@ -24,11 +25,10 @@ export function createOCCIO(oci: OCCCommandInterface): OCCIO {
} }
function pushModel(model: MObject, name: string) { function pushModel(model: MObject, name: string) {
ctx.occService.engineInterface.pushModel({
} name,
operand: model.brepShell.data.externals.ptr
function anchorModel() { });
} }
function cleanupRegistry() { function cleanupRegistry() {
@ -38,7 +38,7 @@ export function createOCCIO(oci: OCCCommandInterface): OCCIO {
return { return {
getShell, pushModel, cleanupRegistry, getShell, pushModel, cleanupRegistry,
sketchLoader: createOCCSketchLoader(oci) sketchLoader: createOCCSketchLoader(OCI)
} }
} }

View file

@ -2,6 +2,7 @@ import {CoreContext} from "context";
import {OCCCommandInterface, OCI} from "cad/craft/e0/occCommandInterface"; import {OCCCommandInterface, OCI} from "cad/craft/e0/occCommandInterface";
import {createOCCIO, OCCIO} from "cad/craft/e0/occIO"; import {createOCCIO, OCCIO} from "cad/craft/e0/occIO";
import {createOCCUtils, OCCUtils} from "cad/craft/e0/OCCUtils"; import {createOCCUtils, OCCUtils} from "cad/craft/e0/OCCUtils";
import {createOCCEngineInterface} from "cad/craft/e0/occEngineInterface";
export interface OCCService { export interface OCCService {
@ -9,7 +10,9 @@ export interface OCCService {
commandInterface: OCCCommandInterface; commandInterface: OCCCommandInterface;
utils: OCCUtils utils: OCCUtils,
engineInterface: any
} }
export function createOCCService(ctx: CoreContext): OCCService { export function createOCCService(ctx: CoreContext): OCCService {
@ -18,10 +21,12 @@ export function createOCCService(ctx: CoreContext): OCCService {
return { return {
io: createOCCIO(oci), io: createOCCIO(ctx),
commandInterface: oci, commandInterface: oci,
engineInterface: createOCCEngineInterface(oci),
utils: createOCCUtils(ctx) utils: createOCCUtils(ctx)
} }

View file

@ -4,7 +4,7 @@ import {IconType} from "react-icons";
import {ActionAppearance} from "../actions/actionSystemPlugin"; import {ActionAppearance} from "../actions/actionSystemPlugin";
import {ApplicationContext, CoreContext} from "context"; import {ApplicationContext, CoreContext} from "context";
import {OperationResult} from "./craftPlugin"; 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"; import {FieldWidgetProps, UIDefinition} from "cad/mdf/ui/uiDefinition";
export function activate(ctx: ApplicationContext) { export function activate(ctx: ApplicationContext) {
@ -35,7 +35,9 @@ export function activate(ctx: ApplicationContext) {
}; };
actions.push(opAction); 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) run: (request, opContext) => runOperation(request, descriptor, opContext)
})); }));
} }
@ -86,6 +88,7 @@ export interface Operation<R> extends OperationDescriptor<R>{
icon96: string; icon96: string;
icon: string|IconType; icon: string|IconType;
}; };
workingSchema: OperationFlattenSchema;
} }
export interface OperationDescriptor<R> { export interface OperationDescriptor<R> {
@ -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' { declare module 'context' {
interface CoreContext { interface CoreContext {

View file

@ -1,7 +1,7 @@
export default { export default {
orientation: { orientation: {
type: 'enum', type: 'string',
values: ['XY', 'XZ', 'ZY'], enum: ['XY', 'XZ', 'ZY'],
defaultValue: 'XY' defaultValue: 'XY'
}, },
parallelTo: { parallelTo: {

View file

@ -0,0 +1,12 @@
import {MObject} from "cad/model/mobject";
export type BooleanKind = 'NONE' | 'UNION' | 'SUBTRACT' | 'INTERSECT';
export interface BooleanDefinition {
kind: BooleanKind;
targets: MObject[];
}

View file

@ -45,6 +45,12 @@ function materializeParamsImpl(ctx: CoreContext,
const typeDef = TypeRegistry[md.type]; const typeDef = TypeRegistry[md.type];
value = typeDef.resolve(ctx, value, md as any, reportError.dot(field), materializeParamsImpl); 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) { // if (md.type === Types.NUMBER) {
// try { // try {
// const valueType = typeof value; // const valueType = typeof value;

View file

@ -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;
}

View file

@ -1,16 +1,27 @@
import {Types} from "cad/craft/schema/types";
import {NumberTypeSchema} from "cad/craft/schema/types/numberType"; import {NumberTypeSchema} from "cad/craft/schema/types/numberType";
import {EntityTypeSchema} from "cad/craft/schema/types/entityType"; import {EntityTypeSchema} from "cad/craft/schema/types/entityType";
import {ArrayTypeSchema} from "cad/craft/schema/types/arrayType"; import {ArrayTypeSchema} from "cad/craft/schema/types/arrayType";
import {ObjectTypeSchema} from "cad/craft/schema/types/objectType"; 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 = { export type OperationSchema = {
[key: string]: SchemaField; [key: string]: SchemaField;
}; };
export type OperationFlattenSchema = {
[key: string]: FlatSchemaField;
};
export interface BaseSchemaField { export interface BaseSchemaField {
defaultValue: Coercable, defaultValue: Coercable,
optional: boolean, optional: boolean,
@ -31,3 +42,25 @@ export type OperationParamsError = {
export type OperationParamsErrorReporter = ((msg: string) => void) & { export type OperationParamsErrorReporter = ((msg: string) => void) & {
dot: (pathPart: string|number) => OperationParamsErrorReporter dot: (pathPart: string|number) => OperationParamsErrorReporter
}; };
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, []);
}

View file

@ -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<any, boolean, BooleanTypeSchema> = {
resolve(ctx: CoreContext,
value: any,
md: BooleanTypeSchema,
reportError: OperationParamsErrorReporter,
materializer: Materializer): boolean {
return !!value;
}
}

View file

@ -4,7 +4,8 @@ import {ArrayType} from "cad/craft/schema/types/arrayType";
import {EntityType} from "cad/craft/schema/types/entityType"; import {EntityType} from "cad/craft/schema/types/entityType";
import {NumberType} from "cad/craft/schema/types/numberType"; import {NumberType} from "cad/craft/schema/types/numberType";
import {ObjectType} from "cad/craft/schema/types/objectType"; 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, export type Materializer = (ctx: CoreContext,
params: OperationParams, params: OperationParams,
@ -22,16 +23,18 @@ export interface Type<IN, OUT, METADATA extends SchemaField> {
export enum Types { export enum Types {
array = 'array', array = 'array',
object = 'object',
entity = 'entity', entity = 'entity',
number = 'number', number = 'number',
object = 'object', boolean = 'boolean',
enum = 'enum', string = 'string'
} }
export const TypeRegistry = { export const TypeRegistry = {
[Types.array]: ArrayType, [Types.array]: ArrayType,
[Types.object]: ObjectType,
[Types.entity]: EntityType, [Types.entity]: EntityType,
[Types.number]: NumberType, [Types.number]: NumberType,
[Types.object]: ObjectType, [Types.boolean]: BooleanType,
[Types.enum]: EnumType, [Types.string]: StringType,
}; };

View file

@ -8,6 +8,8 @@ export interface ObjectTypeSchema extends BaseSchemaField {
schema: OperationSchema; schema: OperationSchema;
resolver: (input: any) => any;
} }
export const ObjectType: Type<any, any, ObjectTypeSchema> = { export const ObjectType: Type<any, any, ObjectTypeSchema> = {

View file

@ -2,25 +2,28 @@ import {Materializer, Type, TypeRegistry, Types} from "cad/craft/schema/types/in
import {CoreContext} from "context"; import {CoreContext} from "context";
import {BaseSchemaField, OperationParamsErrorReporter} from "cad/craft/schema/schema"; import {BaseSchemaField, OperationParamsErrorReporter} from "cad/craft/schema/schema";
export interface EnumTypeSchema extends BaseSchemaField { export interface StringTypeSchema extends BaseSchemaField {
type: Types.number, type: Types.number,
values: string[] enum?: string[]
} }
export const EnumType: Type<any, number, EnumTypeSchema> = { export const StringType: Type<any, string, StringTypeSchema> = {
resolve(ctx: CoreContext, resolve(ctx: CoreContext,
value: any, value: any,
md: EnumTypeSchema, md: StringTypeSchema,
reportError: OperationParamsErrorReporter, reportError: OperationParamsErrorReporter,
materializer: Materializer): number { materializer: Materializer): string {
if (md.values.indexOf(value) === -1) { value = value + '';
value = md.defaultValue || md.values[0];
if (md.enum && md.enum.indexOf(value) === -1) {
value = md.defaultValue || md.enum[0];
} }
return value; return value;
} }
} }

View file

@ -5,6 +5,7 @@ import materializeParams from '../schema/materializeParams';
import {createFunctionList} from 'gems/func'; import {createFunctionList} from 'gems/func';
import {onParamsUpdate} from '../cutExtrude/extrudeOperation'; import {onParamsUpdate} from '../cutExtrude/extrudeOperation';
import {propsChangeTracker} from 'lstream/utils'; import {propsChangeTracker} from 'lstream/utils';
import {OperationSchema, schemaIterator} from "cad/craft/schema/schema";
export function activate(ctx) { export function activate(ctx) {
@ -59,9 +60,9 @@ export function activate(ctx) {
let params; let params;
let {changingHistory, noWizardFocus} = opRequest; let {changingHistory, noWizardFocus} = opRequest;
if (changingHistory) { if (changingHistory) {
params = clone(opRequest.params) params = flattenParams(opRequest.params, operation.schema);
} else { } else {
params = initializeBySchema(operation.schema, ctx); params = initializeBySchema(operation.workingSchema, ctx);
if (opRequest.initialOverrides) { if (opRequest.initialOverrides) {
applyOverrides(params, opRequest.initialOverrides); applyOverrides(params, opRequest.initialOverrides);
} }
@ -75,7 +76,8 @@ export function activate(ctx) {
let materializedWorkingRequest$ = workingRequest$.map(req => { let materializedWorkingRequest$ = workingRequest$.map(req => {
let params = {}; let params = {};
let errors = []; 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) { if (errors.length !== 0) {
return INVALID_REQUEST; return INVALID_REQUEST;
} }
@ -83,7 +85,7 @@ export function activate(ctx) {
type: req.type, type: req.type,
params params
}; };
}).remember(INVALID_REQUEST).filter(r => r !== INVALID_REQUEST); }).remember(INVALID_REQUEST).filter(r => r !== INVALID_REQUEST).throttle(500);
const state$ = state({}); const state$ = state({});
const updateParams = mutator => workingRequest$.mutate(data => mutator(data.params)); const updateParams = mutator => workingRequest$.mutate(data => mutator(data.params));
const updateState = mutator => state$.mutate(state => mutator(state)); const updateState = mutator => state$.mutate(state => mutator(state));
@ -129,8 +131,12 @@ export function activate(ctx) {
}, },
applyWorkingRequest: () => { applyWorkingRequest: () => {
let {type, params} = streams.wizard.wizardContext.value.workingRequest$.value; let wizCtx = streams.wizard.wizardContext.value;
let request = clone({type, params}); 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)); const setError = error => streams.wizard.wizardContext.mutate(ctx => ctx.state$.mutate(state => state.error = error));
if (streams.wizard.insertOperation.value.type) { if (streams.wizard.insertOperation.value.type) {
ctx.services.craft.modify(request, () => streams.wizard.insertOperation.value = EMPTY_OBJECT, setError ); 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) { function applyOverrides(params, initialOverrides) {
Object.assign(params, initialOverrides); Object.assign(params, initialOverrides);
} }

View file

@ -10,7 +10,7 @@ export function activate(ctx) {
wizCtx.workingRequest$.attach(({type, params}) => { wizCtx.workingRequest$.attach(({type, params}) => {
const marker = ctx.services.marker; const marker = ctx.services.marker;
marker.startSession(); marker.startSession();
let {schema} = wizCtx.operation; let {workingSchema: schema} = wizCtx.operation;
Object.keys(schema).forEach(param => { Object.keys(schema).forEach(param => {
let md = schema[param]; let md = schema[param];
@ -65,7 +65,7 @@ function createPickHandlerFromSchema(wizCtx) {
const params = wizCtx.workingRequest$.value.params; const params = wizCtx.workingRequest$.value.params;
const state = wizCtx.state$.value; const state = wizCtx.state$.value;
let {schema} = wizCtx.operation; let {workingSchema: schema} = wizCtx.operation;
const activeMd = state.activeParam && schema[state.activeParam]; const activeMd = state.activeParam && schema[state.activeParam];
const activeCanTakeIt = kind => activeMd.allowedKinds && activeMd.allowedKinds.includes(kind); const activeCanTakeIt = kind => activeMd.allowedKinds && activeMd.allowedKinds.includes(kind);

View file

@ -3,7 +3,8 @@ import { ComboBoxOption } from 'ui/components/controls/ComboBoxControl';
import Entity from '../craft/wizard/components/form/Entity'; import Entity from '../craft/wizard/components/form/Entity';
import { CheckboxField, NumberField, ComboBoxField, TextField } from '../craft/wizard/components/form/Fields'; import { CheckboxField, NumberField, ComboBoxField, TextField } from '../craft/wizard/components/form/Fields';
import { Group } from '../craft/wizard/components/form/Form'; 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) { export function generateForm(schema: OperationSchema) {

View file

@ -32,8 +32,7 @@ export function loadMDFCommand<R>(mdfCommand: MDFCommand<R>): OperationDescripto
type: 'group', type: 'group',
content: mdfCommand.form content: mdfCommand.form
} }
const formFields = extractFormFields(uiDefinition); const {schema: derivedSchema, formFields} = deriveSchema(uiDefinition);
const derivedSchema = deriveSchema(formFields);
return { return {
id: mdfCommand.id, id: mdfCommand.id,
label: mdfCommand.label, label: mdfCommand.label,
@ -75,13 +74,20 @@ function extractFormFields(uiDefinition: UIDefinition): FieldWidgetProps[] {
return fields; return fields;
} }
export function deriveSchema(formFields: FieldWidgetProps[]): OperationSchema { export function deriveSchema(uiDefinition: UIDefinition): {
schema: OperationSchema,
formFields: FieldWidgetProps[]
} {
const formFields: FieldWidgetProps[] = extractFormFields(uiDefinition)
const schema = {}; const schema = {};
formFields.forEach(f => { formFields.forEach(f => {
let propsToSchema = DynamicComponents[f.type].propsToSchema; let propsToSchema = DynamicComponents[f.type].propsToSchema;
schema[f.name] = propsToSchema(schema, f as any); schema[f.name] = propsToSchema(schema, f as any);
}); });
return schema; return {
schema,
formFields
};
} }

View file

@ -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"
}

View file

@ -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 <DynamicComponentWidget {...vectorUIDefinition} />
}
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),
}
};

View file

@ -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 <CheckboxField name={props.name} defaultValue={props.defaultValue} label={props.label} />
}
CheckboxWidget.propsToSchema = (consumer: OperationSchema, props: CheckboxWidgetProps) => {
return {
type: Types.boolean,
...fieldToSchemaGeneric(props),
}
};

View file

@ -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 <ComboBoxField name={props.name} defaultValue={props.defaultValue} label={props.label} >
{props.values.map(value => <ComboBoxOption value={value}>{value}</ComboBoxOption>)}
</ComboBoxField>
} else {
throw 'implement me';
}
}
ChoiceWidget.propsToSchema = (consumer: OperationSchema, props: ChoiceWidgetProps) => {
return {
type: Types.string,
enum: props.values,
...fieldToSchemaGeneric(props),
}
};

View file

@ -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 <StackSection title={props.title} onTitleClick={onTitleClick} isClosed={!visible}>
{visible && <ContainerWidget content={props.content} />}
</StackSection>
}

View file

@ -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 <DynamicComponentWidget {...vectorUIDefinition} />
}
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),
}
};

View file

@ -2,6 +2,11 @@ import {NumberWidget} from "cad/mdf/ui/NumberWidget";
import {SelectionWidget} from "cad/mdf/ui/SelectionWidget"; import {SelectionWidget} from "cad/mdf/ui/SelectionWidget";
import {ContainerWidget} from "cad/mdf/ui/ContainerWidget"; import {ContainerWidget} from "cad/mdf/ui/ContainerWidget";
import {GroupWidget} from "cad/mdf/ui/GroupWidget"; 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 = { export const DynamicComponents = {
@ -12,4 +17,15 @@ export const DynamicComponents = {
'container': ContainerWidget, 'container': ContainerWidget,
'group': GroupWidget, 'group': GroupWidget,
'section': SectionWidget,
'vector': VectorWidget,
'checkbox': CheckboxWidget,
'boolean': BooleanWidget,
'choice': ChoiceWidget,
} }

View file

@ -1,12 +1,17 @@
import {NumberWidgetProps} from "cad/mdf/ui/NumberWidget"; import {NumberWidgetProps} from "cad/mdf/ui/NumberWidget";
import {SelectionWidgetProps} from "cad/mdf/ui/SelectionWidget"; 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 {DynamicComponents} from "cad/mdf/ui/componentRegistry";
import {ContainerWidgetProps} from "cad/mdf/ui/ContainerWidget"; 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; export type DynamicWidgetProps = FieldWidgetProps | BasicWidgetProps;

View file

@ -57,4 +57,8 @@ export class MDatumAxis extends MObject {
get parent() { get parent() {
return this.holder; return this.holder;
} }
toDirection(): Vector {
return this.dir;
};
} }

View file

@ -1,12 +1,14 @@
import {MObject} from './mobject'; import {MObject} from './mobject';
import {MBrepShell} from "./mshell"; import {MBrepShell} from "./mshell";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import {Edge} from "brep/topo/edge";
import Vector from "math/vector";
export class MEdge extends MObject { export class MEdge extends MObject {
static TYPE = EntityKind.EDGE; static TYPE = EntityKind.EDGE;
shell: MBrepShell; shell: MBrepShell;
brepEdge: any; brepEdge: Edge;
constructor(id, shell, brepEdge) { constructor(id, shell, brepEdge) {
super(MEdge.TYPE, id); super(MEdge.TYPE, id);
@ -34,4 +36,9 @@ export class MEdge extends MObject {
get parent() { get parent() {
return this.shell; return this.shell;
} }
toDirection(): Vector {
return this.brepEdge.halfEdge1.tangentAtStart();
};
} }

View file

@ -10,6 +10,7 @@ import BBox from "math/bbox";
import {Basis, BasisForPlane} from "math/basis"; import {Basis, BasisForPlane} from "math/basis";
import {Face} from "brep/topo/face"; import {Face} from "brep/topo/face";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import {Matrix3x4} from "math/matrix";
export class MFace extends MObject { export class MFace extends MObject {
@ -141,14 +142,14 @@ export class MFace extends MObject {
return EMPTY_ARRAY; return EMPTY_ARRAY;
} }
get sketchToWorldTransformation() { get sketchToWorldTransformation(): Matrix3x4 {
if (!this._sketchToWorldTransformation) { if (!this._sketchToWorldTransformation) {
this._sketchToWorldTransformation = this.csys.outTransformation; this._sketchToWorldTransformation = this.csys.outTransformation;
} }
return this._sketchToWorldTransformation; return this._sketchToWorldTransformation;
} }
get worldToSketchTransformation() { get worldToSketchTransformation(): Matrix3x4 {
if (!this._worldToSketchTransformation) { if (!this._worldToSketchTransformation) {
this._worldToSketchTransformation = this.csys.inTransformation; this._worldToSketchTransformation = this.csys.inTransformation;
} }
@ -223,4 +224,9 @@ export class MBrepFace extends MFace {
} }
return this.#favorablePoint; return this.#favorablePoint;
} }
toDirection(): Vector {
return this.normal();
};
} }

View file

@ -1,5 +1,6 @@
import {IDENTITY_MATRIX, Matrix3x4} from "math/matrix"; import {IDENTITY_MATRIX, Matrix3x4} from "math/matrix";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import Vector from "math/vector";
export abstract class MObject { export abstract class MObject {
@ -19,6 +20,10 @@ export abstract class MObject {
abstract get parent(); abstract get parent();
toDirection() {
return null;
};
get root(): MObject { get root(): MObject {
let obj = this; let obj = this;
while (obj.parent) { while (obj.parent) {

View file

@ -1,6 +1,8 @@
import {MObject} from './mobject'; import {MObject} from './mobject';
import {MFace} from "./mface"; import {MFace} from "./mface";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import Vector from "math/vector";
import {Segment} from "cad/sketch/sketchModel";
export class MSketchObject extends MObject { export class MSketchObject extends MObject {
@ -20,4 +22,9 @@ export class MSketchObject extends MObject {
return this.face; return this.face;
} }
toDirection(): Vector {
const tangent = (this.sketchPrimitive as Segment).tangentAtStart();
return this.face.sketchToWorldTransformation.apply(tangent);
};
} }

View file

@ -48,7 +48,7 @@ export class InPlaceSketcher {
this.ctx.streams.ui.toolbars.headsUpShowTitles.next(false); this.ctx.streams.ui.toolbars.headsUpShowTitles.next(false);
let sketchData = this.ctx.services.storage.get(this.sketchStorageKey); 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.viewer.io.loadSketch(sketchData);
this.ctx.streams.sketcher.sketchingFace.next(face); this.ctx.streams.sketcher.sketchingFace.next(face);
this.ctx.streams.sketcher.sketcherAppContext.next(this.sketcherAppContext); this.ctx.streams.sketcher.sketcherAppContext.next(this.sketcherAppContext);

View file

@ -70,7 +70,7 @@ class SketchPrimitive {
} }
} }
export class Segment<Segment> extends SketchPrimitive { export class Segment extends SketchPrimitive {
a: Vector; a: Vector;
b: Vector; b: Vector;
@ -105,7 +105,12 @@ export class Segment<Segment> extends SketchPrimitive {
const [A, B] = genForm; const [A, B] = genForm;
oci.point(underName + "_A", A.x, A.y, A.z); oci.point(underName + "_A", A.x, A.y, A.z);
oci.point(underName + "_B", B.x, B.y, B.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 { export class Arc extends SketchPrimitive {

View file

@ -106,7 +106,7 @@ export class GCCircle extends ContractibleObject {
static TYPE = 'GCCircle'; static TYPE = 'GCCircle';
static newInstance(x, y, r) { 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) { init(c, r) {

View file

@ -47,7 +47,7 @@ export class Project {
let sketchId = this.getSketchId(); let sketchId = this.getSketchId();
let sketchData = localStorage.getItem(sketchId); let sketchData = localStorage.getItem(sketchId);
if (sketchData != null) { if (sketchData != null) {
this.viewer.historyManager.init(sketchData, md); this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData); this.viewer.io.loadSketch(sketchData);
} }
this.viewer.repaint(); this.viewer.repaint();