Skip to content

Commit 4a1e8ba

Browse files
CopilotbedaHovorkaclaude
authored
Remove java.awt dependency from non-GUI packages (#7)
* Replace java.awt.Point with custom Point class in non-GUI packages * Fix GUI classes to use custom Point when interacting with domain model * Add missing distance() method to custom Point class The custom Point class was missing the distance() method that java.awt.Point provides, causing compilation errors in DefaultContext.kt that uses this method to calculate distances between points. * Make Point class immutable and add comprehensive tests - Changed Point class properties from var to val for immutability - Added comprehensive test suite with 21 test cases covering: - Constructor variations (default and parameterized) - Immutability verification - Clone and copy operations - Equals and hashCode contracts - Distance calculations (horizontal, vertical, diagonal) - Edge cases (negative coordinates, large values) - Data class features (component access, copy with modifications) This improves code quality and test coverage for SonarQube. * Fix immutable Point class compilation errors Made Point class properties truly immutable by changing them from var to val. Fixed code that was trying to mutate Point objects: 1. DefaultContext.swapXY() - Now returns a new Point with swapped coordinates 2. DefaultContext.bresenham() - Uses local var copies (p1Mut, p2Mut) instead of mutating parameters 3. Cell.Segment.transform() - Creates new Point instead of cloning and mutating These changes maintain the original algorithm logic while respecting immutability. Added BresenhamJoinTest.kt with 9 test cases covering: - Horizontal line generation (straight line along x-axis) - Vertical line generation (straight line along y-axis) - Diagonal line at 45 degrees - Shallow slope lines (more x than y movement) - Steep slope lines (more y than x movement) - Short distance handling (≤ √2 skips Bresenham) - Negative coordinate handling - Bidirectional line generation (forward/reverse) - Point immutability preservation during join operations Tests verify the Bresenham algorithm through the public joinCells API, ensuring correct intermediate cell placement when connecting distant cells. Addresses request in comment 2672984094. * Remove clone() method from immutable Point class Since Point is now an immutable data class, cloning is unnecessary. Updated all usages to use Point instances directly: - DefaultContext: Removed clone() calls in bresenhamJoin - PointTest: Removed clone() test - Array2DMapTest: Simplified point creation - BresenhamJoinTest: Fixed tests to avoid negative coordinates and grid boundaries - RailwayNetGridCanvas: Minor formatting cleanup --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Bedřich Hovorka <bedrich.hovorka@gmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent be077d9 commit 4a1e8ba

23 files changed

Lines changed: 654 additions & 63 deletions

src/main/kotlin/cz/vutbr/fit/interlockSim/context/AbstractRailwayNetGrid.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ package cz.vutbr.fit.interlockSim.context
1111

1212
import cz.vutbr.fit.interlockSim.objects.cells.Cell
1313
import cz.vutbr.fit.interlockSim.util.Array2DMap
14-
import java.awt.Point
14+
import cz.vutbr.fit.interlockSim.util.Point
1515
import java.util.Iterator
1616
import java.util.Map.Entry
1717
import java.util.Set

src/main/kotlin/cz/vutbr/fit/interlockSim/context/Context.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ package cz.vutbr.fit.interlockSim.context
1212
import cz.vutbr.fit.interlockSim.objects.cells.Cell.Segment
1313
import cz.vutbr.fit.interlockSim.objects.tracks.TrackBlock
1414
import cz.vutbr.fit.interlockSim.util.ExtendedUnorientedGraph
15-
import java.awt.Point
15+
import cz.vutbr.fit.interlockSim.util.Point
1616
import java.beans.PropertyChangeListener
1717

1818
/**

src/main/kotlin/cz/vutbr/fit/interlockSim/context/DefaultContext.kt

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ import cz.vutbr.fit.interlockSim.sim.ShuntingLoop
3131
import cz.vutbr.fit.interlockSim.sim.SimulationException
3232
import cz.vutbr.fit.interlockSim.util.ExtendedUnorientedGraph
3333
import cz.vutbr.fit.interlockSim.util.HashMapGraph
34+
import cz.vutbr.fit.interlockSim.util.Point
3435
import cz.vutbr.fit.interlockSim.util.TreeMultiMap
3536
import cz.vutbr.fit.interlockSim.util.Util
3637
import jDisco.DiscoException
3738
import jDisco.Process
3839
import jDisco.Random
3940
import org.slf4j.Logger
4041
import org.slf4j.LoggerFactory
41-
import java.awt.Point
4242
import java.beans.PropertyChangeSupport
4343
import java.util.ArrayList
4444
import java.util.Collection
@@ -168,10 +168,8 @@ abstract class DefaultContext :
168168
/**
169169
* Swap X and Y coordinates of a point (used in Bresenham algorithm)
170170
*/
171-
private fun swapXY(p: Point) {
172-
val temp = p.x
173-
p.x = p.y
174-
p.y = temp
171+
private fun swapXY(p: Point): Point {
172+
return Point(p.y, p.x)
175173
}
176174

177175
/**
@@ -286,8 +284,8 @@ abstract class DefaultContext :
286284
trackBlock: TrackBlock
287285
): Map<Point, TrackBlockPart>? {
288286
if (pi1 == null || pi2 == null) throw IllegalArgumentException()
289-
val p1 = pi1.clone() as Point
290-
val p2 = pi2.clone() as Point
287+
val p1 = pi1
288+
val p2 = pi2
291289

292290
val keys: MutableList<Point> = ArrayList()
293291
val b = bresenham(key1, key2, p1, p2, keys)
@@ -389,42 +387,44 @@ abstract class DefaultContext :
389387
): Boolean {
390388
assert(key1 != null && key2 != null && p1 != null && p2 != null)
391389
assert(!key1.equals(p1) && !key2.equals(p2) && !key1.equals(p2) && !key2.equals(p1))
390+
391+
// Make mutable copies since we need to modify them for the algorithm
392+
var p1Mut = p1
393+
var p2Mut = p2
392394

393-
if (p1.equals(p2)) {
394-
points.add(p1) // snad je naklonovany
395+
if (p1Mut.equals(p2Mut)) {
396+
points.add(p1Mut) // snad je naklonovany
395397
return false
396398
}
397399

398-
var dx = Math.abs(p2.x - p1.x)
399-
var dy = Math.abs(p2.y - p1.y)
400+
var dx = Math.abs(p2Mut.x - p1Mut.x)
401+
var dy = Math.abs(p2Mut.y - p1Mut.y)
400402
val swapped = dy > dx
401403

402404
if (swapped) {
403-
swapXY(p1)
404-
swapXY(p2)
405+
p1Mut = swapXY(p1Mut)
406+
p2Mut = swapXY(p2Mut)
405407
val temp = dx
406408
dx = dy
407409
dy = temp
408410
}
409411

410-
val b = p1.x > p2.x
412+
val b = p1Mut.x > p2Mut.x
411413
if (b) {
412-
val temp = p1
413-
// assign to parameters is part of algorithm
414-
p1.x = p2.x
415-
p1.y = p2.y
416-
p2.x = temp.x
417-
p2.y = temp.y
414+
val temp = p1Mut
415+
// swap p1 and p2
416+
p1Mut = Point(p2Mut.x, p2Mut.y)
417+
p2Mut = Point(temp.x, temp.y)
418418
}
419419

420420
var P = 2 * dy - dx // prediktor
421421
val P1 = 2 * dy
422422
val P2 = P1 - 2 * dx
423-
var y = p1.y
423+
var y = p1Mut.y
424424

425-
val step_y = if (p1.y > p2.y) -1 else 1 // smer kresleni
425+
val step_y = if (p1Mut.y > p2Mut.y) -1 else 1 // smer kresleni
426426

427-
for (x in p1.x..p2.x) {
427+
for (x in p1Mut.x..p2Mut.x) {
428428
val newPoint = if (!swapped) Point(x, y) else Point(y, x)
429429

430430
if (newPoint.equals(key1) || newPoint.equals(key2) || used(newPoint)) {

src/main/kotlin/cz/vutbr/fit/interlockSim/context/DefaultRailWayNetGrid.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ package cz.vutbr.fit.interlockSim.context
1111

1212
import cz.vutbr.fit.interlockSim.objects.cells.Cell
1313
import cz.vutbr.fit.interlockSim.objects.cells.TrackBlockPart
14-
import java.awt.Point
14+
import cz.vutbr.fit.interlockSim.util.Point
1515
import java.util.AbstractSet
1616
import java.util.Iterator
1717
import java.util.Map

src/main/kotlin/cz/vutbr/fit/interlockSim/context/EditingContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ package cz.vutbr.fit.interlockSim.context
1111

1212
import cz.vutbr.fit.interlockSim.objects.cells.NodeCell
1313
import cz.vutbr.fit.interlockSim.objects.tracks.TrackBlock
14-
import java.awt.Point
14+
import cz.vutbr.fit.interlockSim.util.Point
1515

1616
/**
1717
* Interface to shared functions of inner data model, which is allowed by editing

src/main/kotlin/cz/vutbr/fit/interlockSim/context/RailwayNetGrid.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
package cz.vutbr.fit.interlockSim.context
1111

1212
import cz.vutbr.fit.interlockSim.objects.cells.Cell
13-
import java.awt.Point
13+
import cz.vutbr.fit.interlockSim.util.Point
1414
import java.util.Iterator
1515
import java.util.Map.Entry
1616

src/main/kotlin/cz/vutbr/fit/interlockSim/gui/RailwayNetGridCanvas.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class RailwayNetGridCanvas :
183183
private var state = State.EDITING
184184
private var toolbarCellClass: Class<out NodeCell>? = null
185185
private var toolbarArgs: Array<Any?>? = null
186-
private var selectedKey: Point? = null
186+
private var selectedKey: cz.vutbr.fit.interlockSim.util.Point? = null
187187

188188
init {
189189
background = Color.BLACK
@@ -316,7 +316,8 @@ class RailwayNetGridCanvas :
316316
}
317317

318318
// Mouse coordinate to grid coordinate conversion
319-
private fun currentKey(e: MouseEvent): Point = Point(e.x / CELL_WIDTH, e.y / CELL_HEIGHT)
319+
private fun currentKey(e: MouseEvent): cz.vutbr.fit.interlockSim.util.Point =
320+
cz.vutbr.fit.interlockSim.util.Point(e.x / CELL_WIDTH, e.y / CELL_HEIGHT)
320321

321322
private fun cellOn(
322323
x: Int,

src/main/kotlin/cz/vutbr/fit/interlockSim/gui/gridcanvas/GridCanvasEditingPopupMenu.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ package cz.vutbr.fit.interlockSim.gui.gridcanvas
1111

1212
import cz.vutbr.fit.interlockSim.objects.cells.NodeCell
1313
import cz.vutbr.fit.interlockSim.objects.tracks.TrackBlock
14-
import java.awt.Point
1514
import java.awt.event.ActionEvent
1615

1716
/**
@@ -31,7 +30,7 @@ class GridCanvasEditingPopupMenu : GridCanvasPopupMenu() {
3130
}
3231
}
3332

34-
private var key: Point? = null
33+
private var key: cz.vutbr.fit.interlockSim.util.Point? = null
3534
private var nodeCell: NodeCell? = null
3635
private var trackBlock: TrackBlock? = null
3736

@@ -44,7 +43,7 @@ class GridCanvasEditingPopupMenu : GridCanvasPopupMenu() {
4443
}
4544

4645
override fun reorganizeMenu(
47-
key: Point,
46+
key: cz.vutbr.fit.interlockSim.util.Point,
4847
cell: NodeCell
4948
) {
5049
this.key = key

src/main/kotlin/cz/vutbr/fit/interlockSim/gui/gridcanvas/GridCanvasPopupMenu.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import cz.vutbr.fit.interlockSim.objects.cells.Cell
1414
import cz.vutbr.fit.interlockSim.objects.cells.NodeCell
1515
import cz.vutbr.fit.interlockSim.objects.cells.TrackBlockPart
1616
import cz.vutbr.fit.interlockSim.objects.tracks.TrackBlock
17-
import java.awt.Point
1817
import java.awt.event.ActionEvent
1918
import java.awt.event.MouseEvent
2019
import javax.swing.AbstractAction
@@ -54,7 +53,7 @@ abstract class GridCanvasPopupMenu : JPopupMenu() {
5453
fun show(
5554
canvas: RailwayNetGridCanvas,
5655
e: MouseEvent,
57-
key: Point?,
56+
key: cz.vutbr.fit.interlockSim.util.Point?,
5857
cell: Cell?
5958
) {
6059
assert(canvas != null && e != null) { "Canvas and event cannot be null" }
@@ -66,7 +65,7 @@ abstract class GridCanvasPopupMenu : JPopupMenu() {
6665

6766
// Reorganize menu based on the clicked cell type
6867
private fun reorganizeMenu(
69-
key: Point,
68+
key: cz.vutbr.fit.interlockSim.util.Point,
7069
cell: Cell
7170
) {
7271
when (cell) {
@@ -86,7 +85,7 @@ abstract class GridCanvasPopupMenu : JPopupMenu() {
8685
protected abstract fun reorganizeMenu(line: TrackBlock)
8786

8887
protected abstract fun reorganizeMenu(
89-
key: Point,
88+
key: cz.vutbr.fit.interlockSim.util.Point,
9089
cell: NodeCell
9190
)
9291

src/main/kotlin/cz/vutbr/fit/interlockSim/objects/cells/Cell.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010
package cz.vutbr.fit.interlockSim.objects.cells
1111

12-
import java.awt.Point
12+
import cz.vutbr.fit.interlockSim.util.Point
1313
import java.util.Set
1414

1515
/**
@@ -82,9 +82,7 @@ interface Cell {
8282
*/
8383
fun transform(from: Point): Point {
8484
assert(from != null)
85-
val tr = from.clone() as Point
86-
tr.x += dx
87-
tr.y += dy
85+
val tr = Point(from.x + dx, from.y + dy)
8886
assert(!from.equals(tr)) { this }
8987
return tr
9088
}

0 commit comments

Comments
 (0)