• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Scala-Robotics-Simulator / PPS-22-srs / #104

26 Jul 2025 09:36AM UTC coverage: 76.435% (+8.6%) from 67.873%
#104

Pull #13

github

sceredi
docs: add scaladoc to ray
Pull Request #13: feat: implement proximity sensor

105 of 113 new or added lines in 8 files covered. (92.92%)

2 existing lines in 2 files now uncovered.

253 of 331 relevant lines covered (76.44%)

11.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.0
/src/main/scala/io/github/srs/model/entity/dynamicentity/sensor/Sensor.scala
1
package io.github.srs.model.entity.dynamicentity.sensor
2

3
import io.github.srs.model.PositiveDouble
4
import io.github.srs.model.entity.dynamicentity.DynamicEntity
5
import io.github.srs.model.entity.{ Orientation, Point2D }
6
import io.github.srs.model.environment.Environment
7
import io.github.srs.model.validation.Validation
8
import io.github.srs.utils.Ray.intersectRay
9

10
/**
11
 * Represents the range of a sensor.
12
 */
13
type Range = PositiveDouble
NEW
14

×
15
/**
16
 * Represents the distance from the center of a dynamic entity to a sensor.
17
 */
18
type Distance = PositiveDouble
19

20
/**
21
 * Represents a sensor reading for a specific sensor type and value.
22
 *
23
 * @tparam S
24
 *   the type of sensor.
25
 * @tparam A
26
 *   the type of value that the sensor returns.
27
 * @param sensor
28
 *   the sensor that produced the reading.
29
 * @param value
30
 *   the value sensed by the sensor.
31
 */
32
final case class SensorReading[S <: Sensor[?, ?, A], A](sensor: S, value: A)
33

26✔
34
/**
35
 * Represents a collection of sensor readings for a dynamic entity.
36
 *
37
 * @param proximity
38
 *   a sequence of proximity sensor readings, each containing the sensor and its sensed value.
39
 */
40
final case class SensorReadings(
41
    proximity: Vector[SensorReading[ProximitySensor[?, ?], Double]],
16✔
42
)
3✔
43

44
/**
45
 * Represents a sensor for a dynamic entity.
46
 *
47
 * @tparam Entity
48
 *   the type of dynamic entity that the sensor can sense.
49
 * @tparam Env
50
 *   the type of environment in which the sensor operates.
51
 * @tparam Data
52
 *   the type of data that the sensor returns.
53
 */
54
trait Sensor[-Entity <: DynamicEntity, -Env <: Environment, +Data]:
55
  /**
56
   * The offset orientation of the sensor relative to the entity.
57
   *
58
   * This is used to determine the direction in which the sensor is oriented.
59
   */
60
  val offset: Orientation
61

62
  /**
63
   * The distance from the center of the entity to the sensor.
64
   */
65
  val distance: Distance
66

67
  /**
68
   * The range of the sensor, which defines how far it can sense.
69
   */
70
  val range: Range
71

72
  /**
73
   * Senses the environment using the given entity.
74
   *
75
   * @param entity
76
   *   the entity that is sensing the environment.
77
   * @param environment
78
   *   the environment in which the entity is operating.
79
   * @return
80
   *   the data sensed by the sensor.
81
   */
82
  def sense(entity: Entity)(environment: Env): Data
83

84
end Sensor
85

86
trait ProximitySensor[Entity <: DynamicEntity, Env <: Environment] extends Sensor[Entity, Env, Double]:
87

5✔
88
  override val offset: Orientation
89

90
  override val distance: Distance
91

92
  override val range: Range
93

94
  /**
95
   * Senses the environment using the given entity.
96
   *
97
   * @param entity
98
   *   the entity that is sensing the environment.
99
   * @param environment
100
   *   the environment in which the entity is operating.
101
   * @return
102
   *   the data sensed by the sensor, which is a normalized distance to the nearest obstacle.
103
   */
104
  def sense(entity: Entity)(environment: Env): Double =
105
    import Point2D.*
4✔
106
    val globalOrientation = entity.orientation.toRadians + offset.toRadians
107
    val direction = Point2D(math.cos(globalOrientation), -math.sin(globalOrientation)) // x is right, y is down
20✔
108
    val origin = entity.position + direction * distance.toDouble
26✔
109
    val end = origin + direction * range.toDouble
34✔
110

27✔
111
    val distances = environment.entities.filter(!_.equals(entity)).flatMap(intersectRay(_, origin, end))
112

20✔
113
    distances.filter(_ <= range.toDouble).minOption.getOrElse(range.toDouble) / range.toDouble
114

48✔
115
end ProximitySensor
116

117
object ProximitySensor:
NEW
118

×
119
  /**
120
   * Creates a new `ProximitySensor` with the specified offset, distance, and range.
121
   *
122
   * @param offset
123
   *   the offset orientation of the sensor relative to the entity.
124
   * @param distance
125
   *   the distance from the center of the entity to the sensor.
126
   * @param range
127
   *   the range of the sensor.
128
   * @return
129
   *   a new instance of `ProximitySensor`.
130
   */
131
  def apply(
132
      offset: Orientation,
9✔
133
      distance: Double,
134
      range: Double,
135
  ): Validation[ProximitySensor[DynamicEntity, Environment]] =
136
    for
137
      distance <- PositiveDouble(distance)
1✔
138
      range <- PositiveDouble(range)
13✔
139
    yield new ProximitySensorImpl(offset, distance, range)
140

3✔
141
  private class ProximitySensorImpl(
142
      override val offset: Orientation,
12✔
143
      override val distance: Distance,
3✔
144
      override val range: Range,
3✔
145
  ) extends ProximitySensor[DynamicEntity, Environment]
3✔
146

147
end ProximitySensor
148

149
object Sensor:
NEW
150

×
151
  extension (e: DynamicEntity)
NEW
152

×
153
    /**
154
     * Senses the environment using the entity's sensors.
155
     *
156
     * @param env
157
     *   the environment in which the entity is operating.
158
     * @return
159
     *   a collection of sensor readings.
160
     */
161
    def sense(env: Environment): SensorReadings =
NEW
162
      e.sensors.sense(e, env)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc