mirror of
https://github.com/Doodle3D/Doodle3D-Core.git
synced 2025-01-05 09:23:47 +01:00
fix imports
This commit is contained in:
parent
08e88805c4
commit
20995d0ac7
177
src/reducer/contextReducer.js
Normal file
177
src/reducer/contextReducer.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import update from 'react-addons-update';
|
||||||
|
import * as contextTools from 'src/js/constants/contextTools.js';
|
||||||
|
import { COLOR_STRING_TO_HEX, COLOR_HEX_TO_STRING } from 'src/js/constants/general.js';
|
||||||
|
import { ERASER_SIZES, BRUSH_SIZES } from 'src/js/constants/d2Constants.js';
|
||||||
|
import * as actions from 'src/js/actions/index.js';
|
||||||
|
import { select } from './menusReducer.js';
|
||||||
|
import { getSelectedObjectsSelector, getBoundingBox } from 'src/js/utils/selectionUtils.js';
|
||||||
|
import { Matrix } from 'cal';
|
||||||
|
|
||||||
|
export default function (state, action) {
|
||||||
|
switch (action.category) {
|
||||||
|
case actions.sketcher.CAT_SELECTION: {
|
||||||
|
let menus = state.menus;
|
||||||
|
|
||||||
|
const [firstSelected] = state.selection.objects;
|
||||||
|
const colorHex = firstSelected ? state.objectsById[firstSelected.id].color : state.context.color;
|
||||||
|
// pick current draw color when color is unknown
|
||||||
|
const color = COLOR_HEX_TO_STRING[colorHex] || COLOR_HEX_TO_STRING[state.context.color];
|
||||||
|
menus = select(menus, color);
|
||||||
|
|
||||||
|
const fillBool = firstSelected && state.objectsById[firstSelected.id].fill;
|
||||||
|
const fill = fillBool ? contextTools.FILL_TOGGLE_FILL : contextTools.FILL_TOGGLE_OUTLINE;
|
||||||
|
menus = select(menus, fill);
|
||||||
|
|
||||||
|
return update(state, { menus: { $set: menus } });
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
case actions.sketcher.D2_CHANGE_TOOL: {
|
||||||
|
const color = COLOR_HEX_TO_STRING[state.context.color];
|
||||||
|
return update(state, {
|
||||||
|
menus: { $set: select(state.menus, color) }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action.tool) {
|
||||||
|
case contextTools.LIGHT_BLUE:
|
||||||
|
case contextTools.LIGHT_GREEN:
|
||||||
|
case contextTools.LIGHT_PINK:
|
||||||
|
case contextTools.LIGHT_YELLOW:
|
||||||
|
case contextTools.BLUE:
|
||||||
|
case contextTools.GREEN:
|
||||||
|
case contextTools.PINK:
|
||||||
|
case contextTools.YELLOW:
|
||||||
|
case contextTools.DARK_BLUE:
|
||||||
|
case contextTools.DARK_GREEN:
|
||||||
|
case contextTools.DARK_PINK:
|
||||||
|
case contextTools.DARK_YELLOW: {
|
||||||
|
const color = COLOR_STRING_TO_HEX[action.tool];
|
||||||
|
return update(state, {
|
||||||
|
objectsById: state.selection.objects.reduce((updateObject, { id }) => {
|
||||||
|
updateObject[id] = { color: { $set: color } };
|
||||||
|
return updateObject;
|
||||||
|
}, {}),
|
||||||
|
context: {
|
||||||
|
color: { $set: color }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case contextTools.ERASER_SIZE_SMALL:
|
||||||
|
case contextTools.ERASER_SIZE_MEDIUM:
|
||||||
|
case contextTools.ERASER_SIZE_LARGE: {
|
||||||
|
const size = ERASER_SIZES[action.tool];
|
||||||
|
return update(state, {
|
||||||
|
d2: {
|
||||||
|
eraser: {
|
||||||
|
size: { $set: size }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case contextTools.BRUSH_SIZE_SMALL:
|
||||||
|
case contextTools.BRUSH_SIZE_MEDIUM:
|
||||||
|
case contextTools.BRUSH_SIZE_LARGE: {
|
||||||
|
const size = BRUSH_SIZES[action.tool];
|
||||||
|
return update(state, {
|
||||||
|
d2: {
|
||||||
|
brush: {
|
||||||
|
size: { $set: size }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case contextTools.FILL_TOGGLE_FILL:
|
||||||
|
case contextTools.FILL_TOGGLE_OUTLINE: {
|
||||||
|
const fill = action.tool === contextTools.FILL_TOGGLE_FILL;
|
||||||
|
|
||||||
|
return update(state, {
|
||||||
|
objectsById: state.selection.objects.reduce((updateObject, { id }) => {
|
||||||
|
updateObject[id] = { fill: { $set: fill } };
|
||||||
|
return updateObject;
|
||||||
|
}, {})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case contextTools.ALIGN_LEFT:
|
||||||
|
case contextTools.ALIGN_HORIZONTAL:
|
||||||
|
case contextTools.ALIGN_RIGHT:
|
||||||
|
case contextTools.ALIGN_TOP:
|
||||||
|
case contextTools.ALIGN_VERTICAL:
|
||||||
|
case contextTools.ALIGN_BOTTOM: {
|
||||||
|
if (state.selection.objects < 2) return state;
|
||||||
|
|
||||||
|
const selection = state.selection;
|
||||||
|
const selectedShapeDatas = getSelectedObjectsSelector(selection.objects, state.objectsById);
|
||||||
|
const totalBoundingBox = getBoundingBox(selectedShapeDatas);
|
||||||
|
|
||||||
|
for (const shapeData of selectedShapeDatas) {
|
||||||
|
const boundingBox = getBoundingBox([shapeData]);
|
||||||
|
|
||||||
|
let deltaX = 0;
|
||||||
|
let deltaY = 0;
|
||||||
|
switch (action.tool) {
|
||||||
|
case contextTools.ALIGN_LEFT:
|
||||||
|
deltaX = totalBoundingBox.min.x - boundingBox.min.x;
|
||||||
|
break;
|
||||||
|
case contextTools.ALIGN_HORIZONTAL:
|
||||||
|
deltaX = totalBoundingBox.center.x - boundingBox.center.x;
|
||||||
|
break;
|
||||||
|
case contextTools.ALIGN_RIGHT:
|
||||||
|
deltaX = totalBoundingBox.max.x - boundingBox.max.x;
|
||||||
|
break;
|
||||||
|
case contextTools.ALIGN_TOP:
|
||||||
|
deltaY = totalBoundingBox.min.z - boundingBox.min.z;
|
||||||
|
break;
|
||||||
|
case contextTools.ALIGN_VERTICAL:
|
||||||
|
deltaY = totalBoundingBox.center.y - boundingBox.center.y;
|
||||||
|
break;
|
||||||
|
case contextTools.ALIGN_BOTTOM:
|
||||||
|
deltaY = totalBoundingBox.max.z - boundingBox.max.z;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform = state.objectsById[shapeData.UID].transform.translate(deltaX, deltaY);
|
||||||
|
|
||||||
|
state = update(state, {
|
||||||
|
objectsById: {
|
||||||
|
[shapeData.UID]: {
|
||||||
|
transform: { $set: transform }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection: {
|
||||||
|
objects: {
|
||||||
|
[selection.objects.findIndex(({ id }) => id === shapeData.UID)]: {
|
||||||
|
initialTransform: { $set: transform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state = update(state, {
|
||||||
|
selection: {
|
||||||
|
transform: { $set: new Matrix() }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,14 @@
|
|||||||
|
import update from 'react-addons-update';
|
||||||
|
import fillPath from 'fill-path';
|
||||||
|
import ClipperShape from 'clipper-js';
|
||||||
import * as actions from '../../../actions/index.js';
|
import * as actions from '../../../actions/index.js';
|
||||||
import { SHAPE_TYPE_PROPERTIES } from '../../../constants/shapeTypeProperties.js';
|
import { SHAPE_TYPE_PROPERTIES } from '../../../constants/shapeTypeProperties.js';
|
||||||
import { LINE_WIDTH, CLIPPER_PRECISION } from '../../../constants/d2Constants.js';
|
import { LINE_WIDTH, CLIPPER_PRECISION } from '../../../constants/d2Constants.js';
|
||||||
import createDebug from 'debug';
|
import { shapeToPoints, applyMatrixOnShape, pathToVectorPath } from '../../../shape/shapeDataUtils.js';
|
||||||
import { shapeToPoints, applyMatrixOnShape, pathToVectorPath } from '../../../utils/shapeDataUtils.js';
|
|
||||||
import { addObject } from '../../../reducers/objectReducers.js';
|
import { addObject } from '../../../reducers/objectReducers.js';
|
||||||
import fillPath from 'fill-path';
|
|
||||||
import ClipperShape from 'clipper-js';
|
|
||||||
import subtractShapeFromState from '../../../utils/subtractShapeFromState.js';
|
import subtractShapeFromState from '../../../utils/subtractShapeFromState.js';
|
||||||
import update from 'react-addons-update';
|
|
||||||
import { get as getConfig } from '../../../services/config.js';
|
|
||||||
import { getColor, getFirst, filterType, getObjectsFromIds } from '../../../utils/objectSelectors.js';
|
import { getColor, getFirst, filterType, getObjectsFromIds } from '../../../utils/objectSelectors.js';
|
||||||
|
import createDebug from 'debug';
|
||||||
const debug = createDebug('d3d:reducer:bucket');
|
const debug = createDebug('d3d:reducer:bucket');
|
||||||
|
|
||||||
const MITER_LIMIT = 30.0;
|
const MITER_LIMIT = 30.0;
|
||||||
@ -20,22 +18,20 @@ export default function bucketReducer(state, action) {
|
|||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actions.D2_TAP:
|
case actions.D2_TAP:
|
||||||
const { experimentalColorPicker } = getConfig();
|
const color = state.context.color;
|
||||||
|
// if (experimentalColorPicker) {
|
||||||
let color = state.context.color;
|
// const imageColor = getColor(
|
||||||
if (experimentalColorPicker) {
|
// getFirst(
|
||||||
const imageColor = getColor(
|
// filterType(
|
||||||
getFirst(
|
// getObjectsFromIds(state, action.objects),
|
||||||
filterType(
|
// 'IMAGE_GUIDE'
|
||||||
getObjectsFromIds(state, action.objects),
|
// )
|
||||||
'IMAGE_GUIDE'
|
// ),
|
||||||
)
|
// action.position,
|
||||||
),
|
// action.screenMatrixZoom
|
||||||
action.position,
|
// );
|
||||||
action.screenMatrixZoom
|
// if (imageColor !== null) color = imageColor;
|
||||||
);
|
// }
|
||||||
if (imageColor !== null) color = imageColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if clicked on a filled shape change shape color
|
// if clicked on a filled shape change shape color
|
||||||
const filledPathIndex = action.objects.findIndex(id => (
|
const filledPathIndex = action.objects.findIndex(id => (
|
||||||
|
4
src/reducer/d3/tools/heightReducer.js
vendored
4
src/reducer/d3/tools/heightReducer.js
vendored
@ -1,8 +1,8 @@
|
|||||||
import update from 'react-addons-update';
|
import update from 'react-addons-update';
|
||||||
import { Utils } from 'cal';
|
import { Utils } from 'cal';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { SHAPE_TYPE_PROPERTIES } from '../../../constatants/shapeTypeProperties.js';
|
import { SHAPE_TYPE_PROPERTIES } from '../../../constants/shapeTypeProperties.js';
|
||||||
import * as d3Tools from '../../../constatants/d3Tools.js';
|
import * as d3Tools from '../../../constants/d3Tools.js';
|
||||||
import { getSelectedObjectsSelector, getBoundingBox } from '../../../utils/selectionUtils.js';
|
import { getSelectedObjectsSelector, getBoundingBox } from '../../../utils/selectionUtils.js';
|
||||||
import * as actions from '../../../actions/index.js';
|
import * as actions from '../../../actions/index.js';
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
|
6
src/reducer/d3/tools/stampReducer.js
vendored
6
src/reducer/d3/tools/stampReducer.js
vendored
@ -1,7 +1,7 @@
|
|||||||
import * as actions from '../../actions/index.js';
|
import * as actions from '../../../actions/index.js';
|
||||||
import { addObject, addSpaceActive } from '../../objectReducers.js';
|
import { addObject, addSpaceActive } from '../../objectReducers.js';
|
||||||
import { recursiveClone } from '../../utils/clone.js';
|
import { recursiveClone } from '../../../utils/clone.js';
|
||||||
import { getBoundingBox, getSelectedObjectsSelector } from '../../utils/selectionUtils.js';
|
import { getBoundingBox, getSelectedObjectsSelector } from '../../../utils/selectionUtils.js';
|
||||||
import { updateInitTransform } from '../../d2/tools/transformReducer.js';
|
import { updateInitTransform } from '../../d2/tools/transformReducer.js';
|
||||||
import update from 'react-addons-update';
|
import update from 'react-addons-update';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
|
97
src/reducer/menusReducer.js
Normal file
97
src/reducer/menusReducer.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import * as actions from 'src/js/actions/index.js';
|
||||||
|
import * as d2Tools from 'src/js/constants/d2Tools.js';
|
||||||
|
import initialMenuStructure from 'src/js/constants/menu.js';
|
||||||
|
// import createDebug from 'debug';
|
||||||
|
// const debug = createDebug('d3d:reducer:menu:index');
|
||||||
|
|
||||||
|
// flatten & add menu structure
|
||||||
|
const initialState = addChildren({}, initialMenuStructure);
|
||||||
|
|
||||||
|
// read children recursivly and add them flat/unnested to the state
|
||||||
|
function addChildren(state, childrenData) {
|
||||||
|
return childrenData.reduce((reducedState, childData) => {
|
||||||
|
reducedState = addItem(reducedState, childData);
|
||||||
|
if (childData.children) {
|
||||||
|
reducedState = addChildren(reducedState, childData.children);
|
||||||
|
}
|
||||||
|
return reducedState;
|
||||||
|
}, { ...state });
|
||||||
|
}
|
||||||
|
function addItem(state, data) {
|
||||||
|
state[data.value] = {
|
||||||
|
disabled: false,
|
||||||
|
selected: '',
|
||||||
|
open: false,
|
||||||
|
...data, // override defaults with given data
|
||||||
|
children: getChildrenValues(data.children)
|
||||||
|
};
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
function getChildrenValues(childrenData = []) {
|
||||||
|
return childrenData.map(child => child.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// item specific reducer
|
||||||
|
function item(state, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case actions.sketcher.MENU_OPEN:
|
||||||
|
case actions.sketcher.MENU_CLOSE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
open: (action.type === actions.sketcher.MENU_OPEN)
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMenu(state, targetValue) {
|
||||||
|
if (state[targetValue] === undefined) {
|
||||||
|
throw new Error(`Can't find menu item '${targetValue}'`);
|
||||||
|
}
|
||||||
|
for (const value in state) {
|
||||||
|
if (state[value].children.indexOf(targetValue) !== -1) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export const select = (state, value) => {
|
||||||
|
const menuValue = getMenu(state, value);
|
||||||
|
// debug(`selectItem: ${value} in ${menuValue}`);
|
||||||
|
if (menuValue === null) return state;
|
||||||
|
// select value in menu
|
||||||
|
state = {
|
||||||
|
...state,
|
||||||
|
[menuValue]: {
|
||||||
|
...state[menuValue],
|
||||||
|
selected: value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// try selecting menu in it's menu
|
||||||
|
state = select(state, menuValue);
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function menusReducer(state = initialState, action) {
|
||||||
|
if (action.category === actions.sketcher.CAT_SELECTION) {
|
||||||
|
state = select(state, d2Tools.TRANSFORM);
|
||||||
|
}
|
||||||
|
switch (action.type) {
|
||||||
|
case actions.sketcher.MENU_OPEN:
|
||||||
|
case actions.sketcher.MENU_CLOSE:
|
||||||
|
if (action.menuValue === undefined) return state;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
[action.menuValue]: item(state[action.menuValue], action)
|
||||||
|
};
|
||||||
|
case actions.sketcher.D2_CHANGE_TOOL:
|
||||||
|
case actions.sketcher.D3_CHANGE_TOOL:
|
||||||
|
case actions.sketcher.CONTEXT_CHANGE_TOOL:
|
||||||
|
// recursivly select items in menu's
|
||||||
|
return select(state, action.tool);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
136
src/reducer/pointsReducers.js
Normal file
136
src/reducer/pointsReducers.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import R from 'ramda';
|
||||||
|
// import createDebug from 'debug';
|
||||||
|
// const debug = createDebug('d3d:reducers:points');
|
||||||
|
|
||||||
|
export function mergePaths(pathA, pathB, matchIndexes) {
|
||||||
|
if (matchIndexes[0] !== -1) { // if first path's first point matches
|
||||||
|
// always reverse first path
|
||||||
|
const sortedA = R.reverse(pathA);
|
||||||
|
// if matches with second path's second point reverse
|
||||||
|
const sortedB = (matchIndexes[0] === 1) ? R.reverse(pathB) : pathB;
|
||||||
|
// add b behind a, removing overlapping point
|
||||||
|
return sortedA.concat(sortedB.slice(1));
|
||||||
|
} else if (matchIndexes[1] !== -1) { // if first path's second point matches
|
||||||
|
// no need to reorder first path
|
||||||
|
const sortedA = pathA;
|
||||||
|
// if matches with second path's second point reverse
|
||||||
|
const sortedB = (matchIndexes[1] === 1) ? R.reverse(pathB) : pathB;
|
||||||
|
// add b behind a, removing overlapping point
|
||||||
|
return sortedA.concat(sortedB.slice(1));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get just the end points of a path
|
||||||
|
export const getEndPoints = R.juxt([R.head, R.last]);
|
||||||
|
|
||||||
|
export const getEndPointPaths = R.map(getEndPoints);
|
||||||
|
|
||||||
|
const vectorEquals = R.curry(
|
||||||
|
(a, b) => a.equals(b)
|
||||||
|
);
|
||||||
|
|
||||||
|
// find the index of a point in an array of points
|
||||||
|
export const findPointIndex = R.curry(
|
||||||
|
(points, point) => R.findIndex(vectorEquals(point), points)
|
||||||
|
);
|
||||||
|
export const findEndPointIndex = R.curry(
|
||||||
|
(points, point) => findPointIndex(getEndPoints(points), point)
|
||||||
|
);
|
||||||
|
|
||||||
|
// find indexes of multiple points in array of points,
|
||||||
|
// returned as array of indexes
|
||||||
|
// Result examples:
|
||||||
|
// [0]: a's first point matches b's first point
|
||||||
|
// [1]: a's first point matches b's second point
|
||||||
|
// [-1]: a's first point matches none of b's points
|
||||||
|
// [1, 0]: a's first point matches and b's second point and a's second point matches b's first point
|
||||||
|
export const findPointsIndexes = R.curry(
|
||||||
|
(pointsA, pointsB) => R.map(findPointIndex(pointsB), pointsA)
|
||||||
|
);
|
||||||
|
export const findEndPointsIndexes = R.curry(
|
||||||
|
(pathA, pathB) => findPointsIndexes(
|
||||||
|
getEndPoints(pathA),
|
||||||
|
getEndPoints(pathB)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// find the index of a point in an array of paths
|
||||||
|
// (paths are arrays of points)
|
||||||
|
// returns first result
|
||||||
|
// returns array with
|
||||||
|
// - index of path with matching point
|
||||||
|
// - matching index (see findPointsIndexes)
|
||||||
|
export function findPointIndexInPaths(point, paths) {
|
||||||
|
// debug('findPointIndexInPaths: ', toString(point), toString(paths));
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
const path = paths[i];
|
||||||
|
// find matching endpoints
|
||||||
|
const index = findPointIndex(path, point);
|
||||||
|
// debug(` ${i}: index: `, index);
|
||||||
|
// if found stop searching
|
||||||
|
if (index > -1) return [i, index];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export const findEndPointIndexInPaths = R.curry(
|
||||||
|
(point, paths) => findPointIndexInPaths(point, getEndPointPaths(paths))
|
||||||
|
);
|
||||||
|
|
||||||
|
// find indexes of matching points of path inside other path
|
||||||
|
// returns first result
|
||||||
|
// returns array with
|
||||||
|
// - index of path with matching point
|
||||||
|
// - array of matching indexes (see findPointsIndexes)
|
||||||
|
export function findPointsIndexesOfPathInPaths(paths, path) {
|
||||||
|
// console.log('findPointsIndexesOfPathInPaths');
|
||||||
|
// console.log(' paths: ', toString(paths));
|
||||||
|
// console.log(' path: ', toString(path));
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
const otherPath = paths[i];
|
||||||
|
// skip current path
|
||||||
|
if (otherPath === path) continue;
|
||||||
|
// find matching endpoints
|
||||||
|
const indexes = findPointsIndexes(path, otherPath);
|
||||||
|
// console.log(` ${i}: indexes: `, indexes);
|
||||||
|
// found any matching indexes?
|
||||||
|
// indexes contains any item that's larget than -1
|
||||||
|
const foundMatch = R.any(R.lt(-1))(indexes);
|
||||||
|
// if found stop searching
|
||||||
|
// return index of matching path and indexes of machting end points
|
||||||
|
if (foundMatch) return [i, indexes];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find indexes of matching end points of path inside other path
|
||||||
|
// see: findPointsIndexesOfPathInPaths
|
||||||
|
export function findEndPointsIndexesOfPathInPaths(paths, path) {
|
||||||
|
return findPointsIndexesOfPathInPaths(
|
||||||
|
R.map(getEndPoints, paths),
|
||||||
|
getEndPoints(path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross-compare points of multiple paths
|
||||||
|
// returns first match
|
||||||
|
// array with
|
||||||
|
// - index of path A with matching point
|
||||||
|
// - index of path B with matching point
|
||||||
|
// - array of matching indexes (see findPointsIndexes)
|
||||||
|
export function findPointIndexesOfPaths(paths) {
|
||||||
|
// console.log('findPointIndexesOfPaths');
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
const path = paths[i];
|
||||||
|
const indexes = findPointsIndexesOfPathInPaths(paths, path);
|
||||||
|
// console.log(' indexes: ', toString(indexes));
|
||||||
|
if (indexes !== null) return [i, ...indexes];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross-compare endpoints of multiple paths
|
||||||
|
export function findEndPointIndexesOfPaths(paths) {
|
||||||
|
return findPointIndexesOfPaths(R.map(getEndPoints, paths));
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import update from 'react-addons-update';
|
import update from 'react-addons-update';
|
||||||
import * as actions from '../actions/index.js';
|
import * as actions from '../actions/index.js';
|
||||||
import { Vector } from 'cal';
|
import { Vector } from 'cal';
|
||||||
import { shapeToPoints } from '../utils/shapeDataUtils.js';
|
import { shapeToPoints } from '../shape/shapeDataUtils.js';
|
||||||
import createDebug from 'debug';
|
import createDebug from 'debug';
|
||||||
const debug = createDebug('d3d:reducer:selection');
|
const debug = createDebug('d3d:reducer:selection');
|
||||||
|
|
||||||
|
67
src/utils/objectSelectors.js
Normal file
67
src/utils/objectSelectors.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { SHAPE_TYPE_PROPERTIES } from 'src/js/constants/shapeTypeProperties.js';
|
||||||
|
import { calculatePointInImage } from 'src/js/utils/matrixUtils.js';
|
||||||
|
import R from 'ramda';
|
||||||
|
// import createDebug from 'debug';
|
||||||
|
// const debug = createDebug('d3d:utils:objectSelectors');
|
||||||
|
|
||||||
|
// returns true if object is a closed shape
|
||||||
|
export function closedShapesFilter({ points }) {
|
||||||
|
return points[0].equals(points[points.length - 1]);
|
||||||
|
}
|
||||||
|
// returns true if object is a open (not closed) shape
|
||||||
|
export function openShapesFilter(object) {
|
||||||
|
return !closedShapesFilter(object);
|
||||||
|
}
|
||||||
|
// returns true if object should snap
|
||||||
|
export function snappingFilter({ type }) {
|
||||||
|
return SHAPE_TYPE_PROPERTIES[type].snapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getObjectsById(state) {
|
||||||
|
return state.sketcher.present.objectsById;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function contains(state, testFn) {
|
||||||
|
const objects = R.values(getObjectsById(state));
|
||||||
|
const index = R.findIndex(testFn, objects);
|
||||||
|
return (index !== -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function containsType(state, type) {
|
||||||
|
return contains(state, R.propEq('type', type));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSnappingPoints(state, matrix) {
|
||||||
|
return Object.values(state.objectsById)
|
||||||
|
.filter(snappingFilter) // filter closed shapes
|
||||||
|
.filter(openShapesFilter)
|
||||||
|
.map(shapeData => {
|
||||||
|
const transform = matrix ? shapeData.transform.multiplyMatrix(matrix) : shapeData.transform;
|
||||||
|
const startPoint = shapeData.points[0].applyMatrix(transform);
|
||||||
|
const endPoint = shapeData.points[shapeData.points.length - 1].applyMatrix(transform);
|
||||||
|
|
||||||
|
return { shapeData, startPoint, endPoint };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function getObjectsFromIds(state, ids) {
|
||||||
|
return ids.map(id => state.objectsById[id]);
|
||||||
|
}
|
||||||
|
export function filterType(objects, type) {
|
||||||
|
return objects.filter(value => value.type === type);
|
||||||
|
}
|
||||||
|
export function getFirst(objects) {
|
||||||
|
return objects.length > 0 ? objects[0] : null;
|
||||||
|
}
|
||||||
|
export function getColor(shapeData, position, screenMatrixZoom) {
|
||||||
|
if (!shapeData) return null;
|
||||||
|
|
||||||
|
const canvas = shapeData.imageData;
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
const start = calculatePointInImage(position, shapeData, screenMatrixZoom);
|
||||||
|
|
||||||
|
const [r, g, b] = context.getImageData(start.x, start.y, 1, 1).data;
|
||||||
|
const color = (r << 16) + (g << 8) + b;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user