fix tests, working on the test infrastructure

This commit is contained in:
Val Erastov (xibyte) 2020-05-19 01:48:19 -07:00
parent 41ca9a51e8
commit 0c586935c7
45 changed files with 206 additions and 101 deletions

View file

@ -193,6 +193,10 @@ export function polynomial(coefs, vectors) {
return out;
}
export function fromXYZ({x, y, z}) {
return [x, y, z];
}
export const AXIS_X3 = [1,0,0];
export const AXIS_Y3 = [0,1,0];
export const AXIS_Z3 = [0,0,1];

View file

@ -1,4 +1,4 @@
import * as vec from '../../../web/app/math/vec';
import * as vec from 'math/vec';
import {perpendicularVector} from '../../../web/app/math/math';
import {Face3, Geometry, Vector3} from 'three';

View file

@ -1,6 +1,6 @@
import {Face3, FaceColors, Geometry, Mesh, MeshBasicMaterial, MeshPhongMaterial} from 'three';
import {advancePseudoFrenetFrame, frenetFrame, pseudoFrenetFrame} from '../../../web/app/brep/geom/curves/frenetFrame';
import * as vec from '../../../web/app/math/vec';
import * as vec from 'math/vec';
import {viewScaleFactor} from '../scaleHelper';
import {arrToThree} from 'math/vectorAdapters';
import {ORIGIN} from '../../../web/app/math/l3space';

View file

@ -173,8 +173,11 @@ export default class SceneSetUp {
return raycaster;
}
raycast(event, objects) {
let raycaster = this.createRaycaster(event.offsetX, event.offsetY);
raycast(event, objects, logInfoOut = null) {
const raycaster = this.createRaycaster(event.offsetX, event.offsetY);
if (logInfoOut !== null) {
logInfoOut.ray = raycaster.ray
}
return raycaster.intersectObjects( objects, true );
}

View file

@ -3,6 +3,6 @@ import React from 'react';
import ls from './Field.less'
import cx from 'classnames';
export default function Field({active, ...props}) {
return <div className={cx(ls.root, active&&ls.active)} {...props} />
export default function Field({active, name, ...props}) {
return <div className={cx(ls.root, active&&ls.active)} data-field-name={name} {...props} />
}

View file

@ -1,4 +1,4 @@
import * as vec from "../../web/app/math/vec";
import * as vec from "math/vec";
export class Node {

View file

@ -53,7 +53,7 @@ export default ctx => {
}
function select(from, to) {
ctx.services.pickControl.pickFromRay(from, to, ALL_EXCLUDING_SOLID_KINDS);
ctx.services.pickControl.simulatePickFromRay(from, to);
}
function selectFirst(type) {

View file

@ -1,26 +1,9 @@
import * as sketcher_utils from '../utils/sketcherUtils'
import {decapitalize} from '../../../modules/gems/capitalize';
import {genSerpinskiImpl} from '../../../web/app/utils/genSerpinski';
import {distance} from '../../../web/app/math/math';
export function createSubjectFromInPlaceSketcher(ctx) {
let actions = {};
for (const actionId of Object.keys(ctx.streams.action.state)) {
if (actionId.startsWith('sketch')) {
let oldId = decapitalize(actionId.substring(6));
actions[oldId] = {
action: () => ctx.services.action.run(actionId)
};
actions.addBezierCurve = actions.addCubicBezierSpline;
}
}
const oldStyleSketcherApp = {
viewer: ctx.services.sketcher.inPlaceEditor.viewer,
actions
};
return createSketcherTPI(oldStyleSketcherApp);
return createSketcherTPI(ctx.services.sketcher.inPlaceEditor.sketcherAppContext);
}
export function createSketcherTPI(context) {

View file

@ -73,7 +73,7 @@ export function addArc(ctx, cX, cY, aX, aY, bX, bY) {
[bX, bY] = modelToScreen(ctx.viewer, bX, bY);
[cX, cY] = modelToScreen(ctx.viewer, cX, cY);
ctx.actions['addArc'].action();
ctx.actions.ArcTool.invoke(ctx);
moveAndClickXY(ctx, cX, cY);
moveAndClickXY(ctx, aX, aY);
@ -166,12 +166,12 @@ export class TestSegment {
}
}
export function modelToScreen(x, y) {
if (this.screenToModelMatrix) {
let modelToScreenMx = this.screenToModelMatrix.invert();
export function modelToScreen(viewer, x, y) {
if (viewer.screenToModelMatrix) {
let modelToScreenMx = viewer.screenToModelMatrix.invert();
[x, y] = modelToScreenMx.apply3([x, y, 0]);
}
x /= this.retinaPxielRatio;
y = (this.canvas.height - y) / this.retinaPxielRatio;
x /= viewer.retinaPxielRatio;
y = (viewer.canvas.height - y) / viewer.retinaPxielRatio;
return [x, y];
}

View file

@ -16,13 +16,37 @@ import {defineCypressTests} from "../../../coreTests/defineCypress";
describe("Wizrds", () => {
afterEach(() => {
cy.screenshot();
beforeEach(() => {
cy.openModeller();
});
it("plane wizrd should open", () => {
createDatum();
// afterEach(() => {
// cy.screenshot();
// });
it("plane wizard should open", () => {
cy.getActionButton('PLANE').click();
cy.get('.wizard').should('have.attr', 'data-operation-id', 'PLANE');
cy.getActiveWizardField('depth').find('input').type('100');
cy.get('.wizard .dialog-ok').click();
cy.selectRaycasting([-119, 29, 167], [23, -15, 33])
});
it("extrube wizard should work", () => {
cy.getActionButton('PLANE').click();
cy.get('.wizard').should('have.attr', 'data-operation-id', 'PLANE');
cy.getActiveWizardField('depth').find('input').type('100');
cy.get('.wizard .dialog-ok').click();
cy.selectRaycasting([-119, 29, 167], [23, -15, 33]);
cy.openSketcher().then(sketcher => {
sketcher.addRectangle(0, 0, 80, 100);
cy.commitSketch();
});
cy.getActionButton('EXTRUDE').click();
cy.get('.wizard .dialog-ok').click();
cy.selectRaycasting([-18, 67, 219], [120, 25, 81]);
cy.get('.float-view-btn[data-view="selection"]').click();
cy.get('.selection-view [data-entity="face"] li').should('have.text', 'S:1/F:5');
});

View file

@ -1,25 +1,38 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
import modellerUISubject from "../../coreTests/subjects/modellerTPI";
Cypress.Commands.add("openModeller", () => {
return cy.visit("http://localhost:3000?test&LOG.PICK=true");;
});
Cypress.Commands.add("getActionButton", (actionId) => {
return cy.get(`[data-action-id='${actionId}']`);
});
Cypress.Commands.add("getActiveWizardField", (fieldName) => {
return cy.get(`.wizard [data-field-name='${fieldName}']`);
});
Cypress.Commands.add("selectRaycasting", (from, to) => {
return cy.window().then(win => {
win.__CAD_APP.services.pickControl.simulatePickFromRay(from, to);
win.__DEBUG__.AddSegment3(from, to);
});
});
Cypress.Commands.add("openSketcher", () => {
return cy.getModellerTPI().then(tpi => tpi.openSketcher());
});
Cypress.Commands.add("commitSketch", () => {
return cy.getModellerTPI().then(tpi => tpi.commitSketch());
});
Cypress.Commands.add("getModellerTPI", () => {
return cy.window().then(win => modellerUISubject(win.__CAD_APP));
});

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
export function cubicBezierPoint(p0, p1, p2, p3, t) {
const mt = 1 - t;

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import InvertedCurve from './invertedCurve';
export default class BoundedCurve {

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import newtonIterations, {newtonIterationsOnInterval} from './newtonIterations';
import {curveTessParams} from '../impl/curve/curve-tess';

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import {cubicBezierDer1, cubicBezierDer2, cubicBezierPoint} from './bezierCubic';
import {closestToCurveParam} from './closestPoint';
import InvertedCurve from './invertedCurve';

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import {perpendicularVector} from '../../../math/math';
export function frenetFrame(D1, D2) {

View file

@ -1,6 +1,6 @@
import {TOLERANCE, veq3} from '../tolerance';
import {surfaceClosestParam} from '../impl/nurbs-ext';
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import CubicHermiteInterpolation from './cubicHermiteIntepolation';
import InvertedCurve from './invertedCurve';
import {genericCurveSplit} from './boundedCurve';

View file

@ -1,4 +1,4 @@
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
export default class InvertedCurve {

View file

@ -1,4 +1,4 @@
import * as vec from "../../../../math/vec";
import * as vec from "math/vec";
export default function curveTess(curve, min, max, tessTol, scale) {
return curveTessParams(curve, min, max, tessTol, scale).map(u => curve.point(u));

View file

@ -1,4 +1,4 @@
import * as vec from "../../../../math/vec";
import * as vec from "math/vec";
import {TOLERANCE, TOLERANCE_SQ} from '../../tolerance';
import * as math from '../../../../math/math'
import {fmin_bfgs} from "../../../../math/optim";

View file

@ -1,4 +1,4 @@
import * as vec from "../../../math/vec";
import * as vec from "math/vec";
import * as math from '../../../math/math'
import {eqEps, TOLERANCE, TOLERANCE_01, TOLERANCE_SQ} from '../tolerance';
import {fmin_bfgs} from "../../../math/optim";

View file

@ -1,7 +1,7 @@
import {NUMERICAL_SOLVE_TOL, TOLERANCE, TOLERANCE_01, TOLERANCE_SQ} from '../tolerance';
import {curveDomain, curvePoint, meshesIntersect, surfaceMaxDegree} from '../impl/nurbs-ext';
import {IntersectionCurve} from '../curves/intersectionCurve';
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
export function surfaceIntersect(surfaceA, surfaceB) {
const tessA = verb.eval.Tess.rationalSurfaceAdaptive(surfaceA);

View file

@ -1,7 +1,7 @@
import BrepBuilder, {createBoundingSurfaceFrom2DPoints, createBoundingSurfaceFromBBox} from '../brep-builder';
import VertexFactory from '../vertexFactory';
import NurbsSurface from '../geom/surfaces/nurbsSurface';
import * as vec from '../../math/vec';
import * as vec from 'math/vec';
import {BrepSurface} from '../geom/surfaces/brepSurface';
import {Plane} from '../geom/impl/plane';
import Vector from '../../../../modules/math/vector';

View file

@ -18,6 +18,7 @@ export function ActionButtonBehavior({children, actionId}) {
const actionService = ctx.services.action;
return children({
'data-action-id': actionId,
onClick: e => actionService.run(actionId, e),
onMouseEnter: e => {
updateCoords(e);

View file

@ -60,6 +60,8 @@ export default class Wizard extends React.Component {
onClose={this.cancel}
onKeyDown={this.onKeyDown}
setFocus={this.focusFirstInput}
className='Wizard'
data-operation-id={operation.id}
controlButtons={<>
<WindowControlButton title='help' onClick={(e) => DocumentationTopic$.next({
topic: operation.id,
@ -74,8 +76,8 @@ export default class Wizard extends React.Component {
</FormContext.Provider>
<Stack>
<ButtonGroup>
<Button onClick={this.cancel}>Cancel</Button>
<Button type='accent' onClick={this.onOK}>OK</Button>
<Button className='dialog-cancel' onClick={this.cancel}>Cancel</Button>
<Button className='dialog-ok' type='accent' onClick={this.onOK}>OK</Button>
</ButtonGroup>
{this.state.hasError && <div className={ls.errorMessage}>
{this.state.algorithmError && <span>

View file

@ -24,7 +24,7 @@ export default class EntityList extends React.Component {
if (!Array.isArray(value)) {
value = value ? asArray(value) : EMPTY_ARRAY;
}
return <Field active={active} onClick={setActive}>
return <Field active={active} name={name} onClick={setActive}>
<Label>{label||camelCaseSplitToStr(name)}:</Label>
<div>{value.length === 0 ?
<span className={ls.emptySelection}>{placeholder || '<not selected>'}</span> :

View file

@ -14,7 +14,7 @@ export function Group({children}) {
export function formField(Control) {
return function FormPrimitive({label, name, active, setActive, ...props}) {
return <Field active={active} onFocus={setActive} onClick={setActive}>
return <Field active={active} name={name} onFocus={setActive} onClick={setActive}>
<Label>{label || camelCaseSplitToStr(name)}</Label>
<Control {...props} />
</Field>;

View file

@ -3,7 +3,7 @@ import {brepFaceToGeom, surfaceToThreeGeom} from './scene/wrappers/brepSceneObje
import {createSolidMaterial} from './scene/wrappers/sceneObject';
import DPR from 'dpr';
import Vector from 'math/vector';
import * as vec from '../math/vec';
import * as vec from 'math/vec';
import React from 'react';
import {readSketchFloat} from './sketch/sketchReader';
import {toLoops} from '../brep/io/brepLoopsFormat';

View file

@ -25,17 +25,25 @@ export default class FloatView extends React.Component {
render() {
let {views, getDescriptor} = this.props;
function renderedIcon(icon) {
if (typeof icon === 'string') {
return <Fa fw icon={icon}/>;
} else {
const I = icon;
return <I />;
}
}
function view(id) {
let {title, icon, Component} = getDescriptor(id);
return <Folder className={ls.folder} title={<span> <Fa fw icon={icon}/> {title}</span>}>
return <Folder className={ls.folder} title={<span> {renderedIcon(icon)} {title}</span>}>
<div className={ls.folderContent}><Component/></div>
</Folder>;
}
function icon(id) {
let {Icon} = getDescriptor(id);
return <Icon />
}
let selected = this.state.selected;
@ -43,8 +51,10 @@ export default class FloatView extends React.Component {
<div className={ls.tabs}>
{views.map(tabId => <ToolButton pressed={selected === tabId}
key={tabId}
className='float-view-btn'
data-view={tabId}
onClick={() => this.setState({selected: selected === tabId ? null : tabId})}>
{<Fa fw icon={getDescriptor(tabId).icon}/>}
{renderedIcon(getDescriptor(tabId).icon)}
</ToolButton>)}
</div>

View file

@ -2,6 +2,13 @@
.root {
display: flex;
svg {
path {
stroke: white;
}
width: 16px;
height: 16px;
}
}
.tabs {

View file

@ -0,0 +1,37 @@
import React from 'react';
import {useStream} from "ui/effects";
import {SELECTABLE_ENTITIES} from "../../scene/entityContextPlugin";
export function SelectionView() {
const selections = [];
SELECTABLE_ENTITIES.forEach(entity => {
selections.push(useStream(ctx => ctx.streams.selection[entity]));
});
return <div className='selection-view'>
{SELECTABLE_ENTITIES.map((entity, i) => {
const selection = selections[i];
if (selection.length === 0) {
return null;
}
return <div>
<b>{entity}</b>
<ul data-entity={entity} key={entity} style={{marginLeft: 10}}>
{selection.map(id => <li>{id}</li>)}
</ul>
</div>
})}
</div>
}

View file

@ -14,7 +14,7 @@ import BrepCurve from '../../brep/geom/curves/brepCurve';
import {Plane} from '../../brep/geom/impl/plane';
import pip from '../tess/pip';
import {readShellEntityFromJson} from '../scene/wrappers/entityIO';
import * as vec from '../../math/vec'
import * as vec from 'math/vec'
import NurbsSurface from '../../brep/geom/surfaces/nurbsSurface';

View file

@ -7,6 +7,8 @@ import ObjectExplorer from '../craft/ui/ObjectExplorer';
import React from 'react';
import OperationHistory from '../craft/ui/OperationHistory';
import Expressions from '../expressions/Expressions';
import {SelectionView} from "../dom/components/SelectionView";
import {GrSelect} from "react-icons/gr";
export const STANDARD_MODE_HEADS_UP_TOOLBAR = ['DATUM_CREATE', 'PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE', 'LOFT',
'-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION'];
@ -32,4 +34,5 @@ export function activate({services, streams}) {
services.ui.registerFloatView('project', ObjectExplorer, 'Model', 'cubes');
services.ui.registerFloatView('history', OperationHistory, 'Modifications', 'history');
services.ui.registerFloatView('expressions', Expressions, 'Expressions', 'percent');
services.ui.registerFloatView('selection', SelectionView, 'Selection', GrSelect);
}

View file

@ -1,5 +1,5 @@
import {AXIS, Matrix3, ORIGIN} from '../math/l3space'
import * as vec from '../math/vec'
import * as vec from 'math/vec'
import Vector from 'math/vector';
import BrepBuilder from '../brep/brep-builder'
import * as BREPPrimitives from '../brep/brep-primitives'

View file

@ -2,6 +2,7 @@ import * as mask from 'gems/mask'
import {getAttribute, setAttribute} from 'scene/objectData';
import {FACE, EDGE, SKETCH_OBJECT, DATUM, SHELL, DATUM_AXIS, LOOP} from '../entites';
import {LOG_FLAGS} from '../../logFlags';
import * as vec from 'math/vec';
export const PICK_KIND = {
FACE: mask.type(1),
@ -21,6 +22,8 @@ const DEFAULT_SELECTION_MODE = Object.freeze({
datum: true
});
let RayCastDebugInfo;
export const ALL_EXCLUDING_SOLID_KINDS = PICK_KIND.FACE | PICK_KIND.SKETCH | PICK_KIND.EDGE | PICK_KIND.DATUM_AXIS | PICK_KIND.LOOP;
export function activate(context) {
@ -98,7 +101,7 @@ export function activate(context) {
const deselectAll = () => services.marker.clear();
function handlePick(event) {
let pickResults = services.viewer.raycast(event, services.cadScene.workGroup.children);
let pickResults = services.viewer.raycast(event, services.cadScene.workGroup.children, RayCastDebugInfo);
traversePickResults(event, pickResults, ALL_EXCLUDING_SOLID_KINDS, pickHandler);
}
@ -107,6 +110,10 @@ export function activate(context) {
return traversePickResults(event, pickResults, kind, pickHandler);
}
function simulatePickFromRay(from3, to3, event = null) {
return pickFromRay(from3, to3, ALL_EXCLUDING_SOLID_KINDS, event);
}
function pick(obj, event = null) {
pickHandler(obj, event);
}
@ -136,8 +143,12 @@ export function activate(context) {
}
services.pickControl = {
setPickHandler, deselectAll, pick, pickFromRay
setPickHandler, deselectAll, pick, pickFromRay, simulatePickFromRay
};
if (LOG_FLAGS.PICK) {
RayCastDebugInfo = {};
}
}
export function traversePickResults(event, pickResults, kind, visitor) {
@ -210,5 +221,12 @@ function printPickInfo(model, rayCastData) {
console.dir(rayCastData);
let pt = rayCastData.point;
console.log('POINT: ' + pt.x + ', ' + pt.y + ',' + pt.z);
if (RayCastDebugInfo && RayCastDebugInfo.ray) {
//generating test data
const BUFFER = 100;
const r = vec.fromXYZ(pt).map(Math.round);
const dir = vec._mul(vec.fromXYZ(RayCastDebugInfo.ray.direction), BUFFER);
console.log('cy.selectRaycasting(['+ vec.sub(r, dir).map(Math.round).join(', ') + '], [' + vec.add(r, dir).map(Math.round).join(', ') + '])');
}
}
}

View file

@ -32,8 +32,8 @@ export default class Viewer {
this.sceneSetup.lookAtObject(obj);
}
raycast(event, objects) {
return this.sceneSetup.raycast(event, objects);
raycast(event, objects, logInfoOut) {
return this.sceneSetup.raycast(event, objects, logInfoOut);
}
customRaycast(from3, to3, objects) {

View file

@ -3,7 +3,7 @@ import {SceneEdge, SceneFace, SceneSolid} from './sceneObject';
import brepTess from '../../tess/brep-tess';
import tessellateSurface from '../../../brep/geom/surfaces/surfaceTess';
import {setAttribute} from '../../../../../modules/scene/objectData';
import * as vec from '../../../math/vec';
import * as vec from 'math/vec';
import {perpendicularVector} from '../../../math/math';
const SMOOTH_RENDERING = true;

View file

@ -1,5 +1,5 @@
import {areEqual, circleFromPoints, distanceAB, radiusOfCurvature, TOLERANCE} from '../../math/math';
import * as vec from '../../math/vec';
import * as vec from 'math/vec';
import {iteratePath} from '../cad-utils';
import NurbsCurve from '../../brep/geom/curves/nurbsCurve';
import {veqXYZ} from '../../brep/geom/tolerance';

View file

@ -1,7 +1,7 @@
import Vector from 'math/vector';
import BBox from './bbox'
import * as vec from './vec';
import {perp2d} from "./vec";
import * as vec from 'math/vec';
import {perp2d} from "math/vec";
import {eqTol} from "../brep/geom/tolerance";
export const TOLERANCE = 1E-6;

View file

@ -5,7 +5,7 @@ import {COS_FN, Polynomial, POW_1_FN, POW_2_FN, POW_3_FN, SIN_FN} from "./polyno
import {cubicBezierDer1, cubicBezierDer2, cubicBezierPoint} from "../../brep/geom/curves/bezierCubic";
import {greaterThanConstraint, lessThanConstraint} from "./barriers";
import {genericCurveStep} from "../../brep/geom/impl/nurbs-ext";
import {_normalize} from "../../math/vec";
import {_normalize} from "math/vec";
import {
AngleBetweenConstraintIcon,
AngleConstraintIcon,

View file

@ -4,7 +4,7 @@ import QR from '../../math/qr'
import LMOptimizer from '../../math/lm'
import {ConstantWrapper, EqualsTo} from './solverConstraints'
import {dog_leg} from '../../math/optim'
import {newVector} from '../../math/vec';
import {newVector} from 'math/vec';
/** @constructor */
function Param(value, objectParam) {

View file

@ -1,5 +1,5 @@
import * as math from '../../math/math'
import * as vec from '../../math/vec'
import * as vec from 'math/vec'
import {DEG_RAD, lineLineIntersection2d, makeAngle0_360, pointToLineSignedDistance} from '../../math/math'
import Vector from 'math/vector';
import {Styles} from "../styles";

View file

@ -1,5 +1,5 @@
import {SketchObject} from './sketch-object'
import * as vec from '../../math/vec';
import * as vec from 'math/vec';
import {curveTessellate} from '../../brep/geom/impl/nurbs-ext';
import {Ellipse} from "./ellipse";
import {EndPoint} from "./point";

View file

@ -1,5 +1,5 @@
import {_270, _90, makeAngle0_360, pointToLineSignedDistance} from "../../math/math";
import {_negate} from "../../math/vec";
import {_negate} from "math/vec";
export class TextHelper {

View file

@ -13,7 +13,7 @@ import {isInstanceOf} from "../actions/matchUtils";
import {Segment} from "../shapes/segment";
import {DEFAULT_SEARCH_BUFFER} from "../viewer2d";
import {distance} from "../../math/math";
import {_negate, cross2d} from "../../math/vec";
import {_negate, cross2d} from "math/vec";
export class AddDimTool extends Tool {