diff --git a/packages/ketcher-react/src/script/chem/struct/simpleObject.ts b/packages/ketcher-react/src/script/chem/struct/simpleObject.ts index 8b5dd13b7e..614bd31e25 100644 --- a/packages/ketcher-react/src/script/chem/struct/simpleObject.ts +++ b/packages/ketcher-react/src/script/chem/struct/simpleObject.ts @@ -4,7 +4,7 @@ class SimpleObject { pos: Array mode: SimpleObjectMode - constructor(params) { + constructor(params: { mode: SimpleObjectMode, pos?: Array }) { params = params || {} this.pos = [] diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject.ts deleted file mode 100644 index 41ddb15b80..0000000000 --- a/packages/ketcher-react/src/script/editor/operations/simpleObject.ts +++ /dev/null @@ -1,291 +0,0 @@ -import Vec2 from '../../util/vec2' -import Base, { invalidateItem, OperationType } from './base' -import { ReSimpleObject } from '../../render/restruct' -import { SimpleObject, SimpleObjectMode } from 'src/script/chem/struct' -import scale from '../../util/scale' -import util from '../../render/util' - -const tfx = util.tfx - -class SimpleObjectAdd extends Base { - data: { - id: string | null | undefined - pos: Array - mode: SimpleObjectMode | undefined - toCircle: boolean - } - performed: boolean - - constructor( - pos: Array = [], - mode: SimpleObjectMode | undefined = undefined, - toCircle: boolean = false - ) { - super(OperationType.SIMPLE_OBJECT_ADD) - this.data = { id: null, pos, mode, toCircle } - this.performed = false - } - - execute(restruct: any): void { - const struct = restruct.molecule - if (!this.performed) { - this.data.id = struct.simpleObjects.add( - new SimpleObject({ mode: this.data.mode }) - ) - this.performed = true - } else { - struct.simpleObjects.set( - this.data.id, - new SimpleObject({ mode: this.data.mode }) - ) - } - - restruct.simpleObjects.set( - this.data.id, - new ReSimpleObject(struct.simpleObjects.get(this.data.id)) - ) - - const positions = [...this.data.pos] - if (this.data.toCircle) { - positions[1] = makeCircleFromEllipse(positions[0], positions[1]) - } - struct.simpleObjectSetPos( - this.data.id, - positions.map(p => new Vec2(p)) - ) - - invalidateItem(restruct, 'simpleObjects', this.data.id, 1) - } - - invert(): any { - const ret = new SimpleObjectDelete() - ret.data = this.data as any - return ret - } -} - -function makeCircleFromEllipse(position0: Vec2, position1: Vec2): Vec2 { - const diff = Vec2.diff(position1, position0) - const min = Math.abs(diff.x) < Math.abs(diff.y) ? diff.x : diff.y - return new Vec2( - position0.x + (diff.x > 0 ? 1 : -1) * Math.abs(min), - position0.y + (diff.y > 0 ? 1 : -1) * Math.abs(min), - 0 - ) -} - -class SimpleObjectDelete extends Base { - data: { - id: string | null | undefined - pos: Array - mode: SimpleObjectMode | undefined - toCircle: boolean - } - performed: boolean - - constructor(id?: string | null) { - super(OperationType.SIMPLE_OBJECT_DELETE) - this.data = { id: id, pos: [], mode: undefined, toCircle: false } - this.performed = false - } - - execute(restruct: any): void { - const struct = restruct.molecule - if (!this.performed) { - const item = struct.simpleObjects.get(this.data.id) - this.data.pos = item.pos - this.data.mode = item.mode - this.data.toCircle = item.toCircle - this.performed = true - } - - restruct.markItemRemoved() - restruct.clearVisel(restruct.simpleObjects.get(this.data.id).visel) - restruct.simpleObjects.delete(this.data.id) - - struct.simpleObjects.delete(this.data.id) - } - - invert(): Base { - const ret = new SimpleObjectAdd() - ret.data = this.data as any - return ret - } -} - -class SimpleObjectMove extends Base { - data: { - id: string - d: any - noinvalidate: boolean - } - constructor(id: string, d: any, noinvalidate: boolean) { - super(OperationType.SIMPLE_OBJECT_MOVE) - this.data = { id, d, noinvalidate } - } - execute(restruct: any): void { - const struct = restruct.molecule - const id = this.data.id - const d = this.data.d - const item = struct.simpleObjects.get(id) - item.pos.forEach(p => p.add_(d)) - restruct.simpleObjects - .get(id) - .visel.translate(scale.obj2scaled(d, restruct.render.options)) - this.data.d = d.negated() - if (!this.data.noinvalidate) - invalidateItem(restruct, 'simpleObjects', id, 1) - } - - invert(): Base { - return new SimpleObjectMove( - this.data.id, - this.data.d, - this.data.noinvalidate - ) - } -} - -class SimpleObjectResize extends Base { - data: { - id: string - d: any - current: Vec2 - anchor: any - noinvalidate: boolean - toCircle: boolean - } - - constructor( - id: string, - d: any, - current: Vec2, - anchor: any, - noinvalidate: boolean, - toCircle: boolean - ) { - super(OperationType.SIMPLE_OBJECT_RESIZE) - this.data = { id, d, current, anchor, noinvalidate, toCircle } - } - - execute(restruct: any): void { - const struct = restruct.molecule - const id = this.data.id - const d = this.data.d - const current = this.data.current - const item = struct.simpleObjects.get(id) - const anchor = this.data.anchor - if (item.mode === SimpleObjectMode.ellipse) { - if (anchor) { - const previousPos0 = item.pos[0].get_xy0() - const previousPos1 = item.pos[1].get_xy0() - - if (tfx(anchor.x) === tfx(item.pos[1].x)) { - item.pos[1].x = anchor.x = current.x - this.data.current.x = previousPos1.x - } - if (tfx(anchor.y) === tfx(item.pos[1].y)) { - item.pos[1].y = anchor.y = current.y - this.data.current.y = previousPos1.y - } - if (tfx(anchor.x) === tfx(item.pos[0].x)) { - item.pos[0].x = anchor.x = current.x - this.data.current.x = previousPos0.x - } - if (tfx(anchor.y) === tfx(item.pos[0].y)) { - item.pos[0].y = anchor.y = current.y - this.data.current.y = previousPos0.y - } - if ( - tfx(anchor.y) !== tfx(item.pos[0].y) && - tfx(anchor.x) !== tfx(item.pos[0].x) && - tfx(anchor.y) !== tfx(item.pos[1].y) && - tfx(anchor.x) !== tfx(item.pos[1].x) - ) { - const rad = Vec2.diff(item.pos[1], item.pos[0]) - const rx = Math.abs(rad.x / 2) - const ry = Math.abs(rad.y / 2) - const topLeftX = - item.pos[0].x <= item.pos[1].x ? item.pos[0] : item.pos[1] - const topLeftY = - item.pos[0].y <= item.pos[1].y ? item.pos[0] : item.pos[1] - const bottomRightX = - item.pos[0].x <= item.pos[1].x ? item.pos[1] : item.pos[0] - const bottomRightY = - item.pos[0].y <= item.pos[1].y ? item.pos[1] : item.pos[0] - if (anchor.x <= topLeftX.x + rx) { - topLeftX.x = current.x - } else { - bottomRightX.x = current.x - } - if (anchor.y <= topLeftY.y + ry) { - topLeftY.y = current.y - } else { - bottomRightY.y = current.y - } - } - } else if (this.data.toCircle) { - const previousPos1 = item.pos[1].get_xy0() - const circlePoint = makeCircleFromEllipse(item.pos[0], current) - item.pos[1].x = circlePoint.x - item.pos[1].y = circlePoint.y - this.data.current = previousPos1 - } else { - const previousPos1 = item.pos[1].get_xy0() - item.pos[1].x = current.x - item.pos[1].y = current.y - this.data.current = previousPos1 - } - } else if (item.mode === SimpleObjectMode.line && anchor) { - const previousPos1 = anchor.get_xy0() - anchor.x = current.x - anchor.y = current.y - this.data.current = previousPos1 - } else if (item.mode === SimpleObjectMode.rectangle && anchor) { - const previousPos0 = item.pos[0].get_xy0() - const previousPos1 = item.pos[1].get_xy0() - - if (tfx(anchor.x) === tfx(item.pos[1].x)) { - item.pos[1].x = anchor.x = current.x - this.data.current.x = previousPos1.x - } - if (tfx(anchor.y) === tfx(item.pos[1].y)) { - item.pos[1].y = anchor.y = current.y - this.data.current.y = previousPos1.y - } - if (tfx(anchor.x) === tfx(item.pos[0].x)) { - item.pos[0].x = anchor.x = current.x - this.data.current.x = previousPos0.x - } - if (tfx(anchor.y) === tfx(item.pos[0].y)) { - item.pos[0].y = anchor.y = current.y - this.data.current.y = previousPos0.y - } - } else item.pos[1].add_(d) - - restruct.simpleObjects - .get(id) - .visel.translate(scale.obj2scaled(d, restruct.render.options)) - this.data.d = d.negated() - if (!this.data.noinvalidate) - invalidateItem(restruct, 'simpleObjects', id, 1) - } - - invert(): Base { - return new SimpleObjectResize( - this.data.id, - this.data.d, - this.data.current, - this.data.anchor, - this.data.noinvalidate, - this.data.toCircle - ) - } -} - -export { - SimpleObjectAdd, - SimpleObjectDelete, - SimpleObjectMove, - SimpleObjectResize -} diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/index.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/index.ts new file mode 100644 index 0000000000..bde745e576 --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/index.ts @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import {SimpleObjectDelete} from "./simpleObjectDelete"; +import {SimpleObjectAdd} from "./simpleObjectAdd"; +import Base from "../base"; +import {SimpleObjectMove} from "./simpleObjectMove"; +import {SimpleObjectResize} from "./simpleObjectResize"; + + +class SimpleObjectAddImpl extends SimpleObjectAdd { + invert(): Base { + //@ts-ignore + return new SimpleObjectDelete(this.data.id) + } +} + +class SimpleObjectDeleteImpl extends SimpleObjectDelete { + invert(): Base { + return new SimpleObjectAdd(this.data.pos, this.data.mode, this.data.toCircle) + } +} + +class SimpleObjectMoveImpl extends SimpleObjectMove { + invert(): Base { + return new SimpleObjectMove(this.data.id, this.data.d, this.data.noinvalidate) + } +} + +class SimpleObjectResizeImpl extends SimpleObjectResize { + invert(): Base { + return new SimpleObjectResize(this.data.id, this.data.d, this.data.current, this.data.anchor, this.data.noinvalidate, this.data.toCircle) + } +} + +export { + SimpleObjectAddImpl as SimpleObjectAdd, + SimpleObjectDeleteImpl as SimpleObjectDelete, + SimpleObjectMoveImpl as SimpleObjectMove, + SimpleObjectResizeImpl as SimpleObjectResize +} \ No newline at end of file diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectAdd.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectAdd.ts new file mode 100644 index 0000000000..8d13fec271 --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectAdd.ts @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import Vec2 from '../../../util/vec2' +import Base, { invalidateItem, OperationType } from '../base' +import { ReSimpleObject } from '../../../render/restruct' +import { SimpleObject, SimpleObjectMode } from 'src/script/chem/struct' +import {makeCircleFromEllipse} from "./simpleObjectUtil"; + +class SimpleObjectAddData { + id: string|null + pos: Array + mode: SimpleObjectMode + toCircle: boolean + + constructor(id: string, pos: Array, mode:SimpleObjectMode, toCircle: boolean) { + this.id = id; + this.pos = pos; + this.mode = mode; + this.toCircle = toCircle; + } +} +export class SimpleObjectAdd extends Base { + data: SimpleObjectAddData + performed: boolean + + constructor( + pos: Array, + mode: SimpleObjectMode, + toCircle: boolean + ) { + super(OperationType.SIMPLE_OBJECT_ADD) + // here is "tempValue is used + this.data = new SimpleObjectAddData("tempValue", pos, mode, toCircle) + this.performed = false + } + + execute(restruct: any): void { + console.log("add") + const struct = restruct.molecule + if (!this.performed) { + this.data.id = struct.simpleObjects.add( + new SimpleObject({ mode: this.data.mode }) + ) + this.performed = true + } else { + struct.simpleObjects.set( + this.data.id, + new SimpleObject({ mode: this.data.mode }) + ) + } + + restruct.simpleObjects.set( + this.data.id, + new ReSimpleObject(struct.simpleObjects.get(this.data.id)) + ) + + const positions = [...this.data.pos] + if (this.data.toCircle) { + positions[1] = makeCircleFromEllipse(positions[0], positions[1]) + } + struct.simpleObjectSetPos( + this.data.id, + positions.map(p => new Vec2(p)) + ) + + invalidateItem(restruct, 'simpleObjects', this.data.id, 1) + } +} \ No newline at end of file diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectDelete.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectDelete.ts new file mode 100644 index 0000000000..9af6c157e6 --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectDelete.ts @@ -0,0 +1,58 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import Base, {OperationType} from "../base"; +import {SimpleObjectMode} from "../../../chem/struct"; +import Vec2 from "src/script/util/vec2"; + +class SimpleObjectDeleteData { + id: string + pos: Array = [] + mode: SimpleObjectMode = SimpleObjectMode.line + toCircle: boolean = false + + constructor(id: string) { + this.id = id; + } +} + +export class SimpleObjectDelete extends Base { + data: SimpleObjectDeleteData + performed: boolean + + constructor(id: string) { + super(OperationType.SIMPLE_OBJECT_DELETE) + this.data = new SimpleObjectDeleteData(id) + this.performed = false + } + + execute(restruct: any): void { + const struct = restruct.molecule + if (!this.performed) { + const item = struct.simpleObjects.get(this.data.id) as any + //save to data current values. In future they could be used in invert for restoring simple object + this.data.pos = item.pos + this.data.mode = item.mode + this.data.toCircle = item.toCircle + this.performed = true + } + + restruct.markItemRemoved() + restruct.clearVisel(restruct.simpleObjects.get(this.data.id).visel) + restruct.simpleObjects.delete(this.data.id) + + struct.simpleObjects.delete(this.data.id) + } +} \ No newline at end of file diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectMove.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectMove.ts new file mode 100644 index 0000000000..c6f5b5a24c --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectMove.ts @@ -0,0 +1,52 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import Base, {invalidateItem, OperationType} from "../base"; +import scale from "../../../util/scale"; + +class SimpleObjectMoveData { + id: string + d: any + noinvalidate: boolean + + constructor(id: string, d: any, noinvalidate: boolean) { + this.id = id; + this.d = d; + this.noinvalidate = noinvalidate; + } +} + +export class SimpleObjectMove extends Base { + data: SimpleObjectMoveData + + constructor(id: string, d: any, noinvalidate: boolean) { + super(OperationType.SIMPLE_OBJECT_MOVE) + this.data = new SimpleObjectMoveData(id, d, noinvalidate) + } + execute(restruct: any): void { + console.log("move") + const struct = restruct.molecule + const id = this.data.id + const d = this.data.d + const item = struct.simpleObjects.get(id) + item.pos.forEach(p => p.add_(d)) + restruct.simpleObjects + .get(id) + .visel.translate(scale.obj2scaled(d, restruct.render.options)) + this.data.d = d.negated() + if (!this.data.noinvalidate) + invalidateItem(restruct, 'simpleObjects', id, 1) + } +} diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectResize.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectResize.ts new file mode 100644 index 0000000000..00c18c6610 --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectResize.ts @@ -0,0 +1,174 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import Base, {invalidateItem, OperationType} from "../base"; +import {SimpleObjectMode} from "../../../chem/struct"; +import Vec2 from "src/script/util/vec2"; +import util from "../../../render/util"; +import {makeCircleFromEllipse} from "./simpleObjectUtil"; +import scale from "../../../util/scale"; + +const tfx = util.tfx + +class SimpleObjectResizeData { + id: string + d: any + current: Vec2 + anchor: Vec2 + noinvalidate: boolean + toCircle: boolean + + + constructor(id: string, d: any, current:Vec2, anchor:Vec2, noinvalidate: boolean, toCircle: boolean) { + this.id = id; + this.d = d; + this.current = current; + this.anchor = anchor; + this.noinvalidate = noinvalidate; + this.toCircle = toCircle; + } +} +export class SimpleObjectResize extends Base { + data: SimpleObjectResizeData + + constructor( + id: string, + d: any, + current: Vec2, + anchor: any, + noinvalidate: boolean, + toCircle: boolean + ) { + super(OperationType.SIMPLE_OBJECT_RESIZE) + this.data = new SimpleObjectResizeData(id, d, current, anchor, noinvalidate, toCircle) + } + + execute(restruct: any): void { + const struct = restruct.molecule + const id = this.data.id + const d = this.data.d + const current = this.data.current + const item = struct.simpleObjects.get(id) + const anchor = this.data.anchor + console.log(1) + if (item.mode === SimpleObjectMode.ellipse) { + console.log(2) + if (anchor) { + console.log(3) + const previousPos0 = item.pos[0].get_xy0() + const previousPos1 = item.pos[1].get_xy0() + + if (tfx(anchor.x) === tfx(item.pos[1].x) ) { + console.log(4) + item.pos[1].x = anchor.x = current.x + this.data.current.x = previousPos1.x + } + if (tfx(anchor.y) === tfx(item.pos[1].y)) { + console.log(5) + item.pos[1].y = anchor.y = current.y + this.data.current.y = previousPos1.y + } + if (tfx(anchor.x) === tfx(item.pos[0].x)) { + console.log(6) + item.pos[0].x = anchor.x = current.x + this.data.current.x = previousPos0.x + } + if (tfx(anchor.y) === tfx(item.pos[0].y)) { + console.log(7) + item.pos[0].y = anchor.y = current.y + this.data.current.y = previousPos0.y + } + if ( + tfx(anchor.y) !== tfx(item.pos[0].y) && + tfx(anchor.x) !== tfx(item.pos[0].x) && + tfx(anchor.y) !== tfx(item.pos[1].y) && + tfx(anchor.x) !== tfx(item.pos[1].x) + ) { + console.log(8) + const rad = Vec2.diff(item.pos[1], item.pos[0]) + const rx = Math.abs(rad.x / 2) + const ry = Math.abs(rad.y / 2) + const topLeftX = + item.pos[0].x <= item.pos[1].x ? item.pos[0] : item.pos[1] + const topLeftY = + item.pos[0].y <= item.pos[1].y ? item.pos[0] : item.pos[1] + const bottomRightX = + item.pos[0].x <= item.pos[1].x ? item.pos[1] : item.pos[0] + const bottomRightY = + item.pos[0].y <= item.pos[1].y ? item.pos[1] : item.pos[0] + if (anchor.x <= topLeftX.x + rx) { + console.log(81) + topLeftX.x = current.x + } else { + console.log(82) + bottomRightX.x = current.x + } + if (anchor.y <= topLeftY.y + ry) { + console.log(83) + topLeftY.y = current.y + } else { + console.log(84) + bottomRightY.y = current.y + } + } + } else if (this.data.toCircle) { + console.log(9) + const previousPos1 = item.pos[1].get_xy0() + const circlePoint = makeCircleFromEllipse(item.pos[0], current) + item.pos[1].x = circlePoint.x + item.pos[1].y = circlePoint.y + this.data.current = previousPos1 + } else { + console.log(10) + const previousPos1 = item.pos[1].get_xy0() + item.pos[1].x = current.x + item.pos[1].y = current.y + this.data.current = previousPos1 + } + } else if (item.mode === SimpleObjectMode.line && anchor) { + const previousPos1 = anchor.get_xy0() + anchor.x = current.x + anchor.y = current.y + this.data.current = previousPos1 + } else if (item.mode === SimpleObjectMode.rectangle && anchor) { + const previousPos0 = item.pos[0].get_xy0() + const previousPos1 = item.pos[1].get_xy0() + + if (tfx(anchor.x) === tfx(item.pos[1].x)) { + item.pos[1].x = anchor.x = current.x + this.data.current.x = previousPos1.x + } + if (tfx(anchor.y) === tfx(item.pos[1].y)) { + item.pos[1].y = anchor.y = current.y + this.data.current.y = previousPos1.y + } + if (tfx(anchor.x) === tfx(item.pos[0].x)) { + item.pos[0].x = anchor.x = current.x + this.data.current.x = previousPos0.x + } + if (tfx(anchor.y) === tfx(item.pos[0].y)) { + item.pos[0].y = anchor.y = current.y + this.data.current.y = previousPos0.y + } + } else item.pos[1].add_(d) + + restruct.simpleObjects + .get(id) + .visel.translate(scale.obj2scaled(d, restruct.render.options)) + this.data.d = d.negated() + if (!this.data.noinvalidate) + invalidateItem(restruct, 'simpleObjects', id, 1) + } +} \ No newline at end of file diff --git a/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectUtil.ts b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectUtil.ts new file mode 100644 index 0000000000..ff51c2bba0 --- /dev/null +++ b/packages/ketcher-react/src/script/editor/operations/simpleObject/simpleObjectUtil.ts @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +import Vec2 from '../../../util/vec2' + +export function makeCircleFromEllipse(position0: Vec2, position1: Vec2): Vec2 { + const diff = Vec2.diff(position1, position0) + const min = Math.abs(diff.x) < Math.abs(diff.y) ? diff.x : diff.y + return new Vec2( + position0.x + (diff.x > 0 ? 1 : -1) * Math.abs(min), + position0.y + (diff.y > 0 ? 1 : -1) * Math.abs(min), + 0 + ) +} + + diff --git a/packages/ketcher-react/src/script/render/restruct/resimpleobject.js b/packages/ketcher-react/src/script/render/restruct/resimpleobject.js index 09b5cf7ae5..b406a06ac7 100644 --- a/packages/ketcher-react/src/script/render/restruct/resimpleobject.js +++ b/packages/ketcher-react/src/script/render/restruct/resimpleobject.js @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright 2020 EPAM Systems + * Copyright 2021 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,11 +48,17 @@ ReSimpleObject.prototype.calcDistance = function (p, s) { const ry = rad.y / 2 const center = Vec2.sum(pos[0], { x: rx, y: ry }) const pointToCenter = Vec2.diff(point, center) - dist = Math.abs( - 1 - - (pointToCenter.x * pointToCenter.x) / (rx * rx) - - (pointToCenter.y * pointToCenter.y) / (ry * ry) - ) + if (rx !== 0 && ry !== 0 ) { + dist = Math.abs( + 1 - + (pointToCenter.x * pointToCenter.x) / (rx * rx) - + (pointToCenter.y * pointToCenter.y) / (ry * ry) + ) + } else { + // in case rx or ry is equal to 0 we have a line as a trivial case of ellipse + // in such case distance need to be calculated as a distance between line and current point + dist = calculateDistanceToLine(pos, point) + } break } case SimpleObjectMode.rectangle: { @@ -97,20 +103,7 @@ ReSimpleObject.prototype.calcDistance = function (p, s) { break } case SimpleObjectMode.line: { - if ( - (point.x < Math.min(pos[0].x, pos[1].x) || - point.x > Math.max(pos[0].x, pos[1].x)) && - (point.y < Math.min(pos[0].y, pos[1].y) || - point.y > Math.max(pos[0].y, pos[1].y)) - ) - dist = Math.min(Vec2.dist(pos[0], point), Vec2.dist(pos[1], point)) - else { - const a = Vec2.dist(pos[0], pos[1]) - const b = Vec2.dist(pos[0], point) - const c = Vec2.dist(pos[1], point) - const per = (a + b + c) / 2 - dist = (2 / a) * Math.sqrt(per * (per - a) * (per - b) * (per - c)) - } + dist = calculateDistanceToLine(pos, point) break } @@ -125,6 +118,25 @@ ReSimpleObject.prototype.calcDistance = function (p, s) { return { minDist: dist, refPoint: refPoint } } +function calculateDistanceToLine(pos, point) { + let dist; + if ( + (point.x < Math.min(pos[0].x, pos[1].x) || + point.x > Math.max(pos[0].x, pos[1].x)) && + (point.y < Math.min(pos[0].y, pos[1].y) || + point.y > Math.max(pos[0].y, pos[1].y)) + ) + dist = Math.min(Vec2.dist(pos[0], point), Vec2.dist(pos[1], point)) + else { + const a = Vec2.dist(pos[0], pos[1]) + const b = Vec2.dist(pos[0], point) + const c = Vec2.dist(pos[1], point) + const per = (a + b + c) / 2 + dist = (2 / a) * Math.sqrt(per * (per - a) * (per - b) * (per - c)) + } + return dist; +} + ReSimpleObject.prototype.getReferencePointDistance = function (p) { let dist = [] const refPoints = this.getReferencePoints() @@ -233,16 +245,18 @@ ReSimpleObject.prototype.highlightPath = function (render) { const ry = rad.y / 2 path.push( render.paper.ellipse( - point[0].x + rx, - point[0].y + ry, - Math.abs(rx) + s / 8, - Math.abs(ry) + s / 8 - ), + tfx(point[0].x + rx), + tfx(point[0].y + ry), + tfx(Math.abs(rx) + s / 8), + tfx(Math.abs(ry) + s / 8) + ) + ) + path.push( render.paper.ellipse( - point[0].x + rx, - point[0].y + ry, - Math.abs(rx) - s / 8, - Math.abs(ry) - s / 8 + tfx(point[0].x + rx), + tfx(point[0].y + ry), + tfx(Math.abs(rx) - s / 8), + tfx(Math.abs(ry) - s / 8) ) ) break diff --git a/packages/ketcher-react/src/script/ui/component/actionmenu.jsx b/packages/ketcher-react/src/script/ui/component/actionmenu.jsx index 63eb0bbec4..07118cccb9 100644 --- a/packages/ketcher-react/src/script/ui/component/actionmenu.jsx +++ b/packages/ketcher-react/src/script/ui/component/actionmenu.jsx @@ -183,6 +183,7 @@ function toolMargin(menuName, menu, visibleTools) { } function openHandle(event, onOpen) { + const hiddenEl = hiddenAncestor(event.currentTarget) const isSelected = event.currentTarget?.classList.contains('selected')