Skip to content

Commit a8c567b

Browse files
author
Ryan Reilly
authored
Merge branch 'master' into dependabot/npm_and_yarn/types/node-20.10.0
2 parents 8f63acd + 71583a7 commit a8c567b

18 files changed

+965
-207
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"Anusha",
44
"atomnode",
55
"buttonface",
6+
"Deiterate",
67
"Deiteration",
78
"hasmousedown",
89
"Huda",

src/DrawModes/DeleteMultiTool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,5 @@ export function deleteMultiMouseUp(event: MouseEvent) {
8484
export function deleteMultiMouseOut() {
8585
currentNode = null;
8686
legalNode = false;
87+
redrawTree(treeContext.tree);
8788
}

src/DrawModes/DrawUtils.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,41 @@ export function highlightNode(child: AtomNode | CutNode, color: string) {
173173
}
174174
}
175175
}
176+
177+
/**
178+
* Determines which widest points the current point is closest to so that the resize
179+
* can move in that direction.
180+
* widestPoints[0] = leftmost widest point of the ellipse
181+
* widestPoints[1] = topmost widest point of the ellipse
182+
* widestPoints[2] = rightmost widest point of the ellipse
183+
* widestPoints[3] = bottommost widest point of the ellipse
184+
* @returns The new direction for x and y
185+
*/
186+
export function determineDirection(currentNode: CutNode, startingPoint: Point): Point {
187+
const newDirection = new Point(1, 1);
188+
if (currentNode instanceof CutNode && (currentNode as CutNode).ellipse !== null) {
189+
const currentEllipse: Ellipse = currentNode.ellipse as Ellipse;
190+
const widestPoints: Point[] = [
191+
new Point(currentEllipse.center.x - currentEllipse.radiusX, currentEllipse.center.y),
192+
new Point(currentEllipse.center.x, currentEllipse.center.y - currentEllipse.radiusY),
193+
new Point(currentEllipse.center.x + currentEllipse.radiusX, currentEllipse.center.y),
194+
new Point(currentEllipse.center.x, currentEllipse.center.y + currentEllipse.radiusY),
195+
];
196+
197+
//If the current point is closer to the top or equal the direction is positive and going down
198+
if (widestPoints[0].distance(startingPoint) >= widestPoints[2].distance(startingPoint)) {
199+
newDirection.x = 1;
200+
} else {
201+
newDirection.x = -1;
202+
}
203+
204+
//If the current point is closer to the left or equal the direction is positive and going right
205+
if (widestPoints[1].distance(startingPoint) >= widestPoints[3].distance(startingPoint)) {
206+
newDirection.y = 1;
207+
} else {
208+
newDirection.y = -1;
209+
}
210+
}
211+
212+
return newDirection;
213+
}

src/DrawModes/EditModeUtils.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,43 @@ export function alterCut(originalCut: CutNode, difference: Point): CutNode {
136136
}
137137
}
138138

139+
/**
140+
* Takes a cut and makes a copy of it with the center changed by the given difference.
141+
* Creates a new array of children and alters those by the same distance acting recursively if needed.
142+
* @param originalCut The cut we want to change the center of
143+
* @param difference The distance the cut will be shifted
144+
* @returns The new cut node with all of it's children altered
145+
*/
146+
export function alterCutChildren(originalCut: CutNode, difference: Point): CutNode {
147+
if (originalCut.ellipse !== null) {
148+
const alteredChildren: (CutNode | AtomNode)[] = [];
149+
150+
for (let i = 0; i < originalCut.children.length; i++) {
151+
if (originalCut.children[i] instanceof CutNode) {
152+
alteredChildren.push(
153+
alterCutChildren(originalCut.children[i] as CutNode, difference)
154+
);
155+
} else if (originalCut.children[i] instanceof AtomNode) {
156+
alteredChildren.push(alterAtom(originalCut.children[i] as AtomNode, difference));
157+
}
158+
}
159+
160+
return new CutNode(
161+
new Ellipse(
162+
new Point(
163+
originalCut.ellipse.center.x + difference.x - offset.x,
164+
originalCut.ellipse.center.y + difference.y - offset.y
165+
),
166+
originalCut.ellipse.radiusX,
167+
originalCut.ellipse.radiusY
168+
),
169+
alteredChildren
170+
);
171+
} else {
172+
throw new Error("Cannot alter the position of a cut without an ellipse.");
173+
}
174+
}
175+
139176
/**
140177
* Takes an atom object and changes the origin point by the difference.
141178
* @param originalAtom The Atom to be altered
@@ -169,3 +206,28 @@ export function highlightChildren(child: AtomNode | CutNode, color: string) {
169206
}
170207
}
171208
}
209+
210+
/**
211+
* Makes a copy of original cut and changes the center and radii by the difference given.
212+
* Alters the change to the center based on the direction that is being moved to.
213+
* @param originalCut The original cut that will be copied and altered
214+
* @param difference The change for the new cut
215+
* @param direction the direction the radius will be expanding towards
216+
* @returns The new altered cut
217+
*/
218+
export function resizeCut(originalCut: CutNode, difference: Point, direction: Point) {
219+
if (originalCut.ellipse !== null) {
220+
return new CutNode(
221+
new Ellipse(
222+
new Point(
223+
originalCut.ellipse.center.x + difference.x,
224+
originalCut.ellipse.center.y + difference.y
225+
),
226+
originalCut.ellipse.radiusX + difference.x * direction.x,
227+
originalCut.ellipse.radiusY + difference.y * direction.y
228+
)
229+
);
230+
} else {
231+
throw new Error("Cannot alter the position of a cut without an ellipse.");
232+
}
233+
}

src/DrawModes/ResizeTool.ts

Lines changed: 7 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
*/
44

55
import {Point} from "../AEG/Point";
6-
import {Ellipse} from "../AEG/Ellipse";
6+
import {determineDirection} from "./DrawUtils";
7+
import {resizeCut} from "./EditModeUtils";
78
import {AtomNode} from "../AEG/AtomNode";
89
import {CutNode} from "../AEG/CutNode";
910
import {treeContext} from "../treeContext";
@@ -23,7 +24,7 @@ let legalNode: boolean;
2324

2425
//The direction the cut will move in. For x 1 means going to the right and -1 means left.
2526
//For y 1 means going down and -1 means going up.
26-
const direction: Point = new Point(1, 1);
27+
let direction: Point = new Point(1, 1);
2728

2829
/**
2930
* Takes the point the user clicked and stores that for later use. If the lowest node containing
@@ -34,7 +35,7 @@ const direction: Point = new Point(1, 1);
3435
export function resizeMouseDown(event: MouseEvent) {
3536
startingPoint = new Point(event.x - offset.x, event.y - offset.y);
3637
currentNode = treeContext.tree.getLowestNode(startingPoint);
37-
if (currentNode !== treeContext.tree.sheet && currentNode instanceof CutNode) {
38+
if (currentNode instanceof CutNode && currentNode.ellipse !== null) {
3839
legalNode = true;
3940
const currentParent = treeContext.tree.getLowestParent(startingPoint);
4041
if (currentParent !== null) {
@@ -44,7 +45,7 @@ export function resizeMouseDown(event: MouseEvent) {
4445
for (let i = 0; i < currentNode.children.length; i++) {
4546
treeContext.tree.insert(currentNode.children[i]);
4647
}
47-
determineDirection();
48+
direction = determineDirection(currentNode, startingPoint);
4849
currentNode.children = [];
4950
}
5051
}
@@ -62,7 +63,7 @@ export function resizeMouseMove(event: MouseEvent) {
6263
);
6364

6465
if (currentNode instanceof CutNode) {
65-
const tempCut: CutNode = resizeCut(currentNode, moveDifference);
66+
const tempCut: CutNode = resizeCut(currentNode, moveDifference, direction);
6667
//This is just to make the lint stop yelling
6768
if (tempCut.ellipse !== null) {
6869
redrawTree(treeContext.tree);
@@ -88,7 +89,7 @@ export function resizeMouseUp(event: MouseEvent) {
8889
);
8990

9091
if (currentNode instanceof CutNode) {
91-
const tempCut: CutNode = resizeCut(currentNode, moveDifference);
92+
const tempCut: CutNode = resizeCut(currentNode, moveDifference, direction);
9293
//This is just to make the lint stop yelling
9394
if (tempCut.ellipse !== null) {
9495
if (treeContext.tree.canInsert(tempCut) && ellipseLargeEnough(tempCut.ellipse)) {
@@ -113,61 +114,3 @@ export function resizeMouseOut() {
113114
legalNode = false;
114115
redrawTree(treeContext.tree);
115116
}
116-
117-
/**
118-
* Makes a copy of original cut and changes the center and radii by the difference given.
119-
* Alters the change to the center based on the direction that is being moved to.
120-
* @param originalCut The original cut that will be copied and altered
121-
* @param difference The change for the new cut
122-
* @returns The new altered cut
123-
*/
124-
function resizeCut(originalCut: CutNode, difference: Point) {
125-
if (originalCut.ellipse !== null) {
126-
return new CutNode(
127-
new Ellipse(
128-
new Point(
129-
originalCut.ellipse.center.x + difference.x,
130-
originalCut.ellipse.center.y + difference.y
131-
),
132-
originalCut.ellipse.radiusX + difference.x * direction.x,
133-
originalCut.ellipse.radiusY + difference.y * direction.y
134-
)
135-
);
136-
} else {
137-
throw new Error("Cannot alter the position of a cut without an ellipse.");
138-
}
139-
}
140-
141-
/**
142-
* Determines which widest points the current point is closest to so that the resize
143-
* can move in that direction.
144-
* widestPoints[0] = leftmost widest point of the ellipse
145-
* widestPoints[1] = topmost widest point of the ellipse
146-
* widestPoints[2] = rightmost widest point of the ellipse
147-
* widestPoints[3] = bottommost widest point of the ellipse
148-
*/
149-
function determineDirection() {
150-
if (currentNode instanceof CutNode && (currentNode as CutNode).ellipse !== null) {
151-
const currentEllipse: Ellipse = currentNode.ellipse as Ellipse;
152-
const widestPoints: Point[] = [
153-
new Point(currentEllipse.center.x - currentEllipse.radiusX, currentEllipse.center.y),
154-
new Point(currentEllipse.center.x, currentEllipse.center.y - currentEllipse.radiusY),
155-
new Point(currentEllipse.center.x + currentEllipse.radiusX, currentEllipse.center.y),
156-
new Point(currentEllipse.center.x, currentEllipse.center.y + currentEllipse.radiusY),
157-
];
158-
159-
//If the current point is closer to the top or equal the direction is positive and going down
160-
if (widestPoints[0].distance(startingPoint) >= widestPoints[2].distance(startingPoint)) {
161-
direction.x = 1;
162-
} else {
163-
direction.x = -1;
164-
}
165-
166-
//If the current point is closer to the left or equal the direction is positive and going right
167-
if (widestPoints[1].distance(startingPoint) >= widestPoints[3].distance(startingPoint)) {
168-
direction.y = 1;
169-
} else {
170-
direction.y = -1;
171-
}
172-
}
173-
}

src/ProofTools/DeiterationTool.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/**
2+
* Tool to be used during proof mode to perform deiteration on subgraphs on an AEG
3+
* @author Dawn Moore
4+
*/
5+
6+
import {Point} from "../AEG/Point";
7+
import {AtomNode} from "../AEG/AtomNode";
8+
import {CutNode} from "../AEG/CutNode";
9+
import {redrawProof} from "../DrawModes/DrawUtils";
10+
import {treeContext} from "../treeContext";
11+
import {illegalColor} from "../Themes";
12+
import {offset} from "../DrawModes/DragTool";
13+
import {ProofNode} from "../AEG/ProofNode";
14+
import {AEGTree} from "../AEG/AEGTree";
15+
import {highlightChildren} from "../DrawModes/EditModeUtils";
16+
17+
//The node selected with the user mouse down.
18+
let currentNode: CutNode | AtomNode | null = null;
19+
20+
//Whether or not the node is allowed to be moved (not the sheet).
21+
let legalNode: boolean;
22+
23+
//The current tree in the proof chain
24+
let currentProofTree: AEGTree;
25+
26+
/**
27+
* Determines the lowest node containing the current point and if that is not the sheet is is
28+
* considered a legal node. If it can also deiterate highlight it and all of it's children.
29+
* @param event A Mouse up event while using the deiteration tool
30+
*/
31+
export function deiterationMouseDown(event: MouseEvent) {
32+
const currentPoint: Point = new Point(event.x - offset.x, event.y - offset.y);
33+
currentProofTree = new AEGTree(treeContext.getLastProofStep().tree.sheet);
34+
currentNode = currentProofTree.getLowestNode(currentPoint);
35+
36+
setLegal();
37+
}
38+
39+
/**
40+
* Determines the lowest node containing the current point and if that is not the sheet it is
41+
* considered a legal node and will be highlighted.
42+
* @param event A mouse move event while using deiteration tool
43+
*/
44+
export function deiterationMouseMove(event: MouseEvent) {
45+
const currentPoint: Point = new Point(event.x - offset.x, event.y - offset.y);
46+
currentNode = currentProofTree.getLowestNode(currentPoint);
47+
redrawProof();
48+
49+
setLegal();
50+
}
51+
52+
/**
53+
* If the node we currently have is legal, find it's parent and remove the current node from it.
54+
* Push the new version of the tree onto the proof history array.
55+
* @param event A mouse up event while using deiteration tool
56+
*/
57+
export function deiterationMouseUp(event: MouseEvent) {
58+
if (legalNode) {
59+
const currentPoint: Point = new Point(event.x - offset.x, event.y - offset.y);
60+
if (
61+
currentNode !== null &&
62+
canDeiterate(currentProofTree.sheet, currentProofTree.getLevel(currentNode))
63+
) {
64+
const currentParent: CutNode | null = currentProofTree.getLowestParent(currentPoint);
65+
if (currentParent instanceof CutNode) {
66+
currentParent.remove(currentPoint);
67+
}
68+
treeContext.proofHistory.push(new ProofNode(currentProofTree, "Deiteration"));
69+
}
70+
}
71+
72+
legalNode = false;
73+
redrawProof();
74+
}
75+
76+
/**
77+
* Helper function to determine if the currently selected node is a legal node and highlight it.
78+
*/
79+
function setLegal() {
80+
if (
81+
currentNode !== null &&
82+
!(currentNode instanceof CutNode && currentNode.ellipse === null) &&
83+
canDeiterate(currentProofTree.sheet, currentProofTree.getLevel(currentNode))
84+
) {
85+
highlightChildren(currentNode, illegalColor());
86+
legalNode = true;
87+
} else {
88+
legalNode = false;
89+
}
90+
}
91+
92+
/**
93+
* Reset the current null and make this node illegal until it's selected again, redraws the screen.
94+
*/
95+
export function deiterationMouseOut() {
96+
legalNode = false;
97+
currentNode = null;
98+
redrawProof();
99+
}
100+
101+
/**
102+
* Searches the tree for an equal match to the node we're attempting to delete/deiterate that is
103+
* not itself. It cannot go to a level lower than itself and it cannot search any cuts it is not
104+
* contained by. The Node we search for is the currently selected no currentNode.
105+
* @param currentParent The current node we are searching the children of
106+
* @param level The level the node we're searching for is located
107+
* @returns Whether or not this is a valid deiteration
108+
*/
109+
function canDeiterate(currentParent: CutNode, level: number): boolean {
110+
let potentialParent: CutNode | null = null;
111+
for (let i = 0; i < currentParent.children.length; i++) {
112+
//If both nodes are cuts, and they are equal then we have found a copy higher on the tree
113+
if (
114+
currentParent.children[i] instanceof CutNode &&
115+
currentNode instanceof CutNode &&
116+
currentNode.isEqualTo(currentParent.children[i] as CutNode) &&
117+
currentNode.ellipse !== (currentParent.children[i] as CutNode).ellipse
118+
) {
119+
return true;
120+
} //If both nodes are atoms, and they both have the same identifier then they are equal
121+
else if (
122+
currentParent.children[i] instanceof AtomNode &&
123+
currentNode instanceof AtomNode &&
124+
(currentParent.children[i] as AtomNode).identifier === currentNode.identifier &&
125+
currentParent.children[i].toString() !== currentNode.toString()
126+
) {
127+
return true;
128+
} //If this cut has the node we're looking for we want to recurse towards it, however
129+
//We want to still check the rest of this level so we do it afterwards.
130+
else if (
131+
currentParent.children[i] instanceof CutNode &&
132+
(currentParent.children[i] as CutNode).containsNode(currentNode!) &&
133+
currentProofTree.getLevel(currentParent.children[i]) < level
134+
) {
135+
potentialParent = currentParent.children[i] as CutNode;
136+
}
137+
}
138+
139+
//If we did find the parent of the node we're trying to find an equal of, we look at the next
140+
//closest node.
141+
if (potentialParent !== null) {
142+
return canDeiterate(potentialParent, level);
143+
}
144+
145+
//If there was no equal found then we cannot deiterate.
146+
return false;
147+
}

0 commit comments

Comments
 (0)