diff --git a/src/DrawModes/DrawUtils.ts b/src/DrawModes/DrawUtils.ts index 9c0e7a38..020d0d7b 100644 --- a/src/DrawModes/DrawUtils.ts +++ b/src/DrawModes/DrawUtils.ts @@ -173,3 +173,41 @@ export function highlightNode(child: AtomNode | CutNode, color: string) { } } } + +/** + * Determines which widest points the current point is closest to so that the resize + * can move in that direction. + * widestPoints[0] = leftmost widest point of the ellipse + * widestPoints[1] = topmost widest point of the ellipse + * widestPoints[2] = rightmost widest point of the ellipse + * widestPoints[3] = bottommost widest point of the ellipse + * @returns The new direction for x and y + */ +export function determineDirection(currentNode: CutNode, startingPoint: Point): Point { + const newDirection = new Point(1, 1); + if (currentNode instanceof CutNode && (currentNode as CutNode).ellipse !== null) { + const currentEllipse: Ellipse = currentNode.ellipse as Ellipse; + const widestPoints: Point[] = [ + new Point(currentEllipse.center.x - currentEllipse.radiusX, currentEllipse.center.y), + new Point(currentEllipse.center.x, currentEllipse.center.y - currentEllipse.radiusY), + new Point(currentEllipse.center.x + currentEllipse.radiusX, currentEllipse.center.y), + new Point(currentEllipse.center.x, currentEllipse.center.y + currentEllipse.radiusY), + ]; + + //If the current point is closer to the top or equal the direction is positive and going down + if (widestPoints[0].distance(startingPoint) >= widestPoints[2].distance(startingPoint)) { + newDirection.x = 1; + } else { + newDirection.x = -1; + } + + //If the current point is closer to the left or equal the direction is positive and going right + if (widestPoints[1].distance(startingPoint) >= widestPoints[3].distance(startingPoint)) { + newDirection.y = 1; + } else { + newDirection.y = -1; + } + } + + return newDirection; +} diff --git a/src/DrawModes/EditModeUtils.ts b/src/DrawModes/EditModeUtils.ts index 09441291..53d5f5e8 100644 --- a/src/DrawModes/EditModeUtils.ts +++ b/src/DrawModes/EditModeUtils.ts @@ -206,3 +206,28 @@ export function highlightChildren(child: AtomNode | CutNode, color: string) { } } } + +/** + * Makes a copy of original cut and changes the center and radii by the difference given. + * Alters the change to the center based on the direction that is being moved to. + * @param originalCut The original cut that will be copied and altered + * @param difference The change for the new cut + * @param direction the direction the radius will be expanding towards + * @returns The new altered cut + */ +export function resizeCut(originalCut: CutNode, difference: Point, direction: Point) { + if (originalCut.ellipse !== null) { + return new CutNode( + new Ellipse( + new Point( + originalCut.ellipse.center.x + difference.x, + originalCut.ellipse.center.y + difference.y + ), + originalCut.ellipse.radiusX + difference.x * direction.x, + originalCut.ellipse.radiusY + difference.y * direction.y + ) + ); + } else { + throw new Error("Cannot alter the position of a cut without an ellipse."); + } +} diff --git a/src/DrawModes/ResizeTool.ts b/src/DrawModes/ResizeTool.ts index 92bc124f..0b336e1b 100644 --- a/src/DrawModes/ResizeTool.ts +++ b/src/DrawModes/ResizeTool.ts @@ -3,7 +3,8 @@ */ import {Point} from "../AEG/Point"; -import {Ellipse} from "../AEG/Ellipse"; +import {determineDirection} from "./DrawUtils"; +import {resizeCut} from "./EditModeUtils"; import {AtomNode} from "../AEG/AtomNode"; import {CutNode} from "../AEG/CutNode"; import {treeContext} from "../treeContext"; @@ -113,66 +114,3 @@ export function resizeMouseOut() { legalNode = false; redrawTree(treeContext.tree); } - -/** - * Makes a copy of original cut and changes the center and radii by the difference given. - * Alters the change to the center based on the direction that is being moved to. - * @param originalCut The original cut that will be copied and altered - * @param difference The change for the new cut - * @param direction the direction the radius will be expanding towards - * @returns The new altered cut - */ -export function resizeCut(originalCut: CutNode, difference: Point, direction: Point) { - if (originalCut.ellipse !== null) { - return new CutNode( - new Ellipse( - new Point( - originalCut.ellipse.center.x + difference.x, - originalCut.ellipse.center.y + difference.y - ), - originalCut.ellipse.radiusX + difference.x * direction.x, - originalCut.ellipse.radiusY + difference.y * direction.y - ) - ); - } else { - throw new Error("Cannot alter the position of a cut without an ellipse."); - } -} - -/** - * Determines which widest points the current point is closest to so that the resize - * can move in that direction. - * widestPoints[0] = leftmost widest point of the ellipse - * widestPoints[1] = topmost widest point of the ellipse - * widestPoints[2] = rightmost widest point of the ellipse - * widestPoints[3] = bottommost widest point of the ellipse - * @returns The new direction for x and y - */ -export function determineDirection(currentNode: CutNode, startingPoint: Point): Point { - const newDirection = new Point(1, 1); - if (currentNode instanceof CutNode && (currentNode as CutNode).ellipse !== null) { - const currentEllipse: Ellipse = currentNode.ellipse as Ellipse; - const widestPoints: Point[] = [ - new Point(currentEllipse.center.x - currentEllipse.radiusX, currentEllipse.center.y), - new Point(currentEllipse.center.x, currentEllipse.center.y - currentEllipse.radiusY), - new Point(currentEllipse.center.x + currentEllipse.radiusX, currentEllipse.center.y), - new Point(currentEllipse.center.x, currentEllipse.center.y + currentEllipse.radiusY), - ]; - - //If the current point is closer to the top or equal the direction is positive and going down - if (widestPoints[0].distance(startingPoint) >= widestPoints[2].distance(startingPoint)) { - newDirection.x = 1; - } else { - newDirection.x = -1; - } - - //If the current point is closer to the left or equal the direction is positive and going right - if (widestPoints[1].distance(startingPoint) >= widestPoints[3].distance(startingPoint)) { - newDirection.y = 1; - } else { - newDirection.y = -1; - } - } - - return newDirection; -} diff --git a/src/ProofTools/ProofMoveMultiTool.ts b/src/ProofTools/ProofMoveMultiTool.ts index a9379b14..a9026823 100644 --- a/src/ProofTools/ProofMoveMultiTool.ts +++ b/src/ProofTools/ProofMoveMultiTool.ts @@ -14,7 +14,7 @@ import {offset} from "../DrawModes/DragTool"; import {drawAtom, redrawTree} from "../DrawModes/DrawUtils"; import {legalColor, illegalColor} from "../Themes"; import {drawAltered, alterAtom, alterCutChildren} from "../DrawModes/EditModeUtils"; -import {proofCanInsert} from "./ProofMoveSingleTool"; +import {isMoveLegal} from "./ProofMoveUtils"; //The initial point the user pressed down. let startingPoint: Point; @@ -68,11 +68,11 @@ export function proofMoveMultiMouseMove(event: MouseEvent) { redrawTree(currentProofTree); if (currentNode instanceof CutNode) { const tempCut: CutNode = alterCutChildren(currentNode, moveDifference); - const color = isLegal(tempCut) ? legalColor() : illegalColor(); + const color = isMoveLegal(currentProofTree, tempCut) ? legalColor() : illegalColor(); drawAltered(currentNode, color, moveDifference); } else if (currentNode instanceof AtomNode) { const tempAtom: AtomNode = alterAtom(currentNode, moveDifference); - const color = isLegal(tempAtom) ? legalColor() : illegalColor(); + const color = isMoveLegal(currentProofTree, tempAtom) ? legalColor() : illegalColor(); drawAtom(tempAtom, color, true); } } @@ -96,7 +96,7 @@ export function proofMoveMultiMouseUp(event: MouseEvent) { if (currentNode instanceof CutNode) { const tempCut: CutNode = alterCutChildren(currentNode, moveDifference); - if (isLegal(tempCut)) { + if (isMoveLegal(currentProofTree, tempCut)) { nextStep.tree.insert(tempCut); } else { nextStep.tree.insert(currentNode); @@ -104,7 +104,7 @@ export function proofMoveMultiMouseUp(event: MouseEvent) { } else if (currentNode instanceof AtomNode) { const tempAtom: AtomNode = alterAtom(currentNode, moveDifference); - if (isLegal(tempAtom)) { + if (isMoveLegal(currentProofTree, tempAtom)) { nextStep.tree.insert(tempAtom); } else { nextStep.tree.insert(currentNode); @@ -127,10 +127,3 @@ export function proofMoveMultiMouseOut() { legalNode = false; redrawTree(treeContext.getLastProofStep().tree); } - -function isLegal(currentNode: CutNode | AtomNode): boolean { - return ( - currentProofTree.canInsert(currentNode) && - proofCanInsert(new AEGTree(currentProofTree.sheet), currentNode) - ); -} diff --git a/src/ProofTools/ProofMoveSingleTool.ts b/src/ProofTools/ProofMoveSingleTool.ts index ee5de9fa..9965b61a 100644 --- a/src/ProofTools/ProofMoveSingleTool.ts +++ b/src/ProofTools/ProofMoveSingleTool.ts @@ -13,6 +13,7 @@ import {drawCut, drawAtom, redrawTree} from "../DrawModes/DrawUtils"; import {legalColor, illegalColor} from "../Themes"; import {alterAtom, alterCut} from "../DrawModes/EditModeUtils"; import {ProofNode} from "../AEG/ProofNode"; +import {isMoveLegal} from "./ProofMoveUtils"; //The initial point the user pressed down. let startingPoint: Point; @@ -74,12 +75,12 @@ export function proofMoveSingleMouseMove(event: MouseEvent) { if (currentNode instanceof CutNode) { const tempCut: CutNode = alterCut(currentNode, moveDifference); - const color = isLegal(tempCut) ? legalColor() : illegalColor(); + const color = isMoveLegal(currentProofTree, tempCut) ? legalColor() : illegalColor(); drawCut(tempCut, color); } //If the node is an atom, make a temporary atom and check legality, drawing that. else if (currentNode instanceof AtomNode) { const tempAtom: AtomNode = alterAtom(currentNode, moveDifference); - const color = isLegal(tempAtom) ? legalColor() : illegalColor(); + const color = isMoveLegal(currentProofTree, tempAtom) ? legalColor() : illegalColor(); drawAtom(tempAtom, color, true); } } @@ -104,7 +105,7 @@ export function proofMoveSingleMouseUp(event: MouseEvent) { const tempCut: CutNode = alterCut(currentNode, moveDifference); //If the new location is legal, insert the cut otherwise reinsert the cut we removed. - if (isLegal(tempCut)) { + if (isMoveLegal(currentProofTree, tempCut)) { nextStep.tree.insert(tempCut); } else { nextStep.tree.insert(currentNode); @@ -113,7 +114,7 @@ export function proofMoveSingleMouseUp(event: MouseEvent) { const tempAtom: AtomNode = alterAtom(currentNode, moveDifference); //If the new location is legal, insert the atom, if not reinsert the atom we removed. - if (isLegal(tempAtom)) { + if (isMoveLegal(currentProofTree, tempAtom)) { nextStep.tree.insert(tempAtom); } else { nextStep.tree.insert(currentNode); @@ -136,28 +137,3 @@ export function proofMoveSingleMouseOut() { legalNode = false; redrawTree(treeContext.getLastProofStep().tree); } - -/** - * Determines if the current node can be inserted in a position that is not overlapping with anything - * and it being inserted would result in a graph that would equal one another. - * @param currentNode The node that will be checked for legality - * @returns Whether or no the node is in a legal position - */ -function isLegal(currentNode: CutNode | AtomNode): boolean { - return ( - currentProofTree.canInsert(currentNode) && - proofCanInsert(new AEGTree(currentProofTree.sheet), currentNode) - ); -} - -/** - * Inserts a copy of our current node into a copy of our current tree and compares this to a copy - * of the original tree. - * @param tree A copy of the current tree without the current node - * @param currentNode The node that will be checked for legality - * @returns Whether or not the two graphs are equal - */ -export function proofCanInsert(tree: AEGTree, currentNode: CutNode | AtomNode): boolean { - tree.insert(currentNode.copy()); - return tree.isEqualTo(new AEGTree(treeContext.getLastProofStep().tree.sheet)); -} diff --git a/src/ProofTools/ProofMoveUtils.ts b/src/ProofTools/ProofMoveUtils.ts new file mode 100644 index 00000000..b6b487d9 --- /dev/null +++ b/src/ProofTools/ProofMoveUtils.ts @@ -0,0 +1,26 @@ +import {AEGTree} from "../AEG/AEGTree"; +import {CutNode} from "../AEG/CutNode"; +import {AtomNode} from "../AEG/AtomNode"; +import {treeContext} from "../treeContext"; + +/** + * Determines if the current node can be inserted in a position that is not overlapping with anything + * and it being inserted would result in a graph that would equal one another. + * @param currentNode The node that will be checked for legality + * @returns Whether or no the node is in a legal position + */ +export function isMoveLegal(tree: AEGTree, currentNode: CutNode | AtomNode): boolean { + return tree.canInsert(currentNode) && proofCanInsert(new AEGTree(tree.sheet), currentNode); +} + +/** + * Inserts a copy of our current node into a copy of our current tree and compares this to a copy + * of the original tree. + * @param tree A copy of the current tree without the current node + * @param currentNode The node that will be checked for legality + * @returns Whether or not the two graphs are equal + */ +export function proofCanInsert(tree: AEGTree, currentNode: CutNode | AtomNode): boolean { + tree.insert(currentNode.copy()); + return tree.isEqualTo(new AEGTree(treeContext.getLastProofStep().tree.sheet)); +} diff --git a/src/ProofTools/ProofResizeTool.ts b/src/ProofTools/ProofResizeTool.ts index fc958daf..35318261 100644 --- a/src/ProofTools/ProofResizeTool.ts +++ b/src/ProofTools/ProofResizeTool.ts @@ -12,9 +12,10 @@ import {offset} from "../DrawModes/DragTool"; import {drawCut, redrawTree} from "../DrawModes/DrawUtils"; import {legalColor, illegalColor} from "../Themes"; import {ProofNode} from "../AEG/ProofNode"; -import {resizeCut, determineDirection} from "../DrawModes/ResizeTool"; +import {resizeCut} from "../DrawModes/EditModeUtils"; +import {determineDirection} from "../DrawModes/DrawUtils"; import {ellipseLargeEnough} from "../DrawModes/CutTool"; -import {proofCanInsert} from "./ProofMoveSingleTool"; +import {proofCanInsert} from "./ProofMoveUtils"; //The initial point the user pressed down. let startingPoint: Point; @@ -32,6 +33,12 @@ let direction: Point = new Point(1, 1); //The tree of the current proof step let currentProofTree: AEGTree; +/** + * Takes the point the user clicked and stores that for later use. If the lowest node containing + * that point is not the sheet, then store that as currentNode and find that node's parent. + * Removes the node from the parent and reinsert its children if it has any. Cannot be an Atom. + * @param event The mouse down even while using resize tool in proof mode + */ export function proofResizeMouseDown(event: MouseEvent) { currentProofTree = new AEGTree(treeContext.getLastProofStep().tree.sheet); startingPoint = new Point(event.x - offset.x, event.y - offset.y); @@ -52,6 +59,11 @@ export function proofResizeMouseDown(event: MouseEvent) { } } +/** + * If the node is legal alters the center and both of the radii. Creates a copy of the current cut + * So that the original is not altered in any way. + * @param event The mouse move event while the resize tool is being used in proof mode + */ export function proofResizeMouseMove(event: MouseEvent) { if (legalNode) { const moveDifference: Point = new Point( @@ -71,6 +83,11 @@ export function proofResizeMouseMove(event: MouseEvent) { } } +/** + * If the node is legal creates a new temporary cut and alters the ellipse center and radii. + * If this new cut can be inserted inserts that into the tree, otherwise reinserts the original. + * @param event The mouse up event while using resize tool in proof mode + */ export function proofResizeMouseUp(event: MouseEvent) { if (legalNode) { const moveDifference: Point = new Point( @@ -96,6 +113,9 @@ export function proofResizeMouseUp(event: MouseEvent) { } } +/** + * If the mouse leaves the canvas then it is no longer a legal node and reinserts the original. + */ export function proofResizeMouseOut() { if (legalNode && currentNode !== null) { currentProofTree.insert(currentNode); @@ -104,6 +124,12 @@ export function proofResizeMouseOut() { redrawTree(treeContext.getLastProofStep().tree); } +/** + * Determines if a node in a given position is legal if it can be inserted, is bigger than our + * minimum ellipse radii size, and can be inserted into the tree without changing the structure. + * @param currentCut The cut to be checked to see if it is legal + * @returns Whether or not the cut in this position is legal + */ function isLegal(currentCut: CutNode): boolean { return ( currentProofTree.canInsert(currentCut) &&