-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNodeRB.java
More file actions
306 lines (276 loc) · 8.36 KB
/
NodeRB.java
File metadata and controls
306 lines (276 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.lang.Math;
/**
* This class represents a node in a red black tree.
* <p>
* It holds information like key, color, refferences to children and parent and visual connector to parent.
*
* @author Roșca Paul-Teodor
* @version 1.0 (22/12/2020)
*/
public class NodeRB extends Actor
{
private int key;
private NodeRB parent,left,right;
/**
* The color of the node
* false - red
* true - black
*/
private boolean color;
/**
* The text with the key (for visualisation)
*/
private FloatingText text;
private Connector parentConnector;
/**
* The node pointer stuck to this node
* Used when we the node pointer is pointing to this node and we need to move this node
*/
private NodePointer stickyPointer;
/**
* Number of pixels this node has moved in the world
* Used when the world is focused on this node and the node is moving
*/
private int shiftedX;
private int shiftedY;
/**
* Constructor for the Node.
* <p>
* We set the node's key, color (default red), refference to children and parents (default null)
*
* @param k the desired key for the node
*/
public NodeRB(int k)
{
color = false;
parent=null;
left=null;
right=null;
key=k;
text=new FloatingText();
text.addChar(String.valueOf(key));
setImage("RedNode.png");
}
public void setKey(int k)
{
text.clear();
key=k;
text.addChar(String.valueOf(key));
}
public void setParentConnector(Connector c)
{
parentConnector = c;
}
/**
* Method for changing the color of the node directly, without any visualisation
* Used when the node is not actually in world
*/
private void setColorQuiet(boolean b)
{
color=b;
if(color==true)
setImage("BlackNode.png");
else
setImage("RedNode.png");
}
/**
* Method used for changing the color of the node.
* <p>
* It also adds a purple NodePointer and focuses the world on it.
*/
public void setColor(boolean b)
{
NodePointer np=new NodePointer((Background) getWorld());
getWorld().addObject(np,getX(),getY());
np.setImage("NodePointerPurple.png");
np.getImage().setTransparency(255);
np.focusOnThis();
Greenfoot.delay(50);
color=b;
if(color==true)
setImage("BlackNode.png");
else
setImage("RedNode.png");
getWorld().removeObject(np);
}
public void setLeft(NodeRB x)
{
left=x;
}
public void setRight(NodeRB x)
{
right=x;
}
public void setParent(NodeRB x)
{
parent=x;
}
public void setShiftedX(int dx)
{
shiftedX=dx;
}
public int getShiftedX()
{
return shiftedX;
}
public void setShiftedY(int dy)
{
shiftedY=dy;
}
public int getShiftedY()
{
return shiftedY;
}
public NodeRB getLeft()
{
return left;
}
public NodeRB getRight()
{
return right;
}
public NodeRB getParent()
{
return parent;
}
public boolean getColor()
{
return color;
}
public Connector getParentConnector()
{
return parentConnector;
}
public int getKey()
{
return key;
}
public FloatingText getText()
{
return text;
}
/**
* Method used for moving the node along with it's sticky NodePointer (if it has one)
*
* @param x the new X coordinate
* @param y the new Y coordinate
*/
public void setLocationWithPointer(int x,int y)
{
// We get the difference from the new coordinates to the old ones
int dx=x-getX();
int dy=y-getY();
setLocation(x,y);
if(stickyPointer!=null)// If the node has a stuck pointer
{
stickyPointer.setLocation(x,y);// We also move it
stickyPointer.focusOnThis();// We focuse the world on it
// Then we need to take into account shifting (because after focusing the coordinates don't actually change)
shiftedX+=dx;
shiftedY+=dy;
// We also acknowledge that all it's parents also shifted
NodeRB parent=this.getParent();
while(parent!=null)
{
parent.setShiftedX(shiftedX);
parent.setShiftedY(shiftedY);
parent=parent.getParent();
}
}
}
/**
* Method for moving the subtree rooted in this node, along with all it's visual components
*
* @param newX new X coordinate
* @param newY new Y coordinate
*/
public void setLocationWithComponents(int newX,int newY)
{
// We get the difference between the new coordinates and the old ones
int dx,dy;
dx=newX-this.getX();
dy=newY-this.getY();
// We move the node and it's sticky pointer
this.setLocationWithPointer(newX,newY);
text.setLocation(newX,newY);
if(parent!=null)//Unless we are moving the root itself
{
// We move the connect
parentConnector.setLocation((parent.getX()+this.getX())/2,(parent.getY()+this.getY())/2);
int dXc=Math.abs(parent.getX()-this.getX());
int dYc=Math.abs(parent.getY()-this.getY());
double hypotenuse=Math.sqrt(dXc*dXc+dYc*dYc);
double angle=Math.toDegrees(Math.asin(dYc/hypotenuse));//Recalculating the anlge of the connector
angle*=((parent.getLeft()==this)?-1:1);
parentConnector.setRotation(90+(int)angle);//Rotating the connector to match the calculated angle
parentConnector.setScale(5,(int)hypotenuse-45);//Seting the connector's size to match the distance between the connected nodes (for visualisation)
}
//We move the children too
if(left!=null)
left.setLocationWithComponents(left.getX()+dx,left.getY()+dy);
if(right!=null)
right.setLocationWithComponents(right.getX()+dx,right.getY()+dy);
}
/**
* Method for reseting {@link shiftedX} and {@link shiftedY} variables for a subtree
*
* @param node the root of the subtree
*/
public void clearShift(NodeRB node)
{
if(node==null)
return;
node.setShiftedX(0);
node.setShiftedY(0);
clearShift(node.getLeft());
clearShift(node.getRight());
}
/**
* Method for slowly moving the subtree rooted in this node, along with all it's visual components
*
* @param newX new X coordinate
* @param newY new Y coordinate
*
*/
public void setLocationWithComponentsTransition(int newX,int newY)
{
// We get the difference between the new coordinates and the old ones
int dX=newX-getX(),dY=newY-getY();
// The number of pixels we move on X and Y axis in one iteration
int speedX=dX/50,speedY=dY/50;
// Variable used to speed up (slow down the slow down) the transition
int timer = 0;
// We clear the shift of the subtree rooted in this node
clearShift(this);
while(getX()+shiftedX!=newX)// Until we've reached the desired new X coordinate
// If the node has a sticky pointer shiftedX will change while the actual coordinates will remain the same
// If the node doesn't have a sticky pointer shiftedX will stay 0 and actual coordinates will change
{
if(timer==1)
{
Greenfoot.delay(1);// We slow down the execution
timer=0;
}
setLocationWithComponents(getX()+speedX,getY()+speedY);// We move the subtree rooted in this node in the desired direction
timer++;
}
}
public void setStickyPointer(NodePointer np)
{
stickyPointer=np;
}
/**
* Method that clones the base information of this node (key and color)
*
* @return a clone of this node
*/
public NodeRB clone()
{
NodeRB node = new NodeRB(key);
node.setColorQuiet(color);
if(parentConnector!=null)
node.setParentConnector(new Connector());
return node;
}
}