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

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

09 Aug 2025 05:15PM UTC coverage: 75.676% (+1.6%) from 74.056%
#247

push

github

srs-mate
feat(config): implement serialization of environment

21 of 26 new or added lines in 8 files covered. (80.77%)

11 existing lines in 4 files now uncovered.

980 of 1295 relevant lines covered (75.68%)

10.84 hits per line

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

92.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 cats.Monad
4
import cats.syntax.all.*
5
import io.github.srs.model.PositiveDouble
6
import io.github.srs.model.entity.dynamicentity.{ DynamicEntity, Robot }
7
import io.github.srs.model.entity.{ Orientation, Point2D }
8
import io.github.srs.model.environment.Environment
9
import io.github.srs.model.validation.Validation
10
import io.github.srs.utils.Ray.intersectRay
11
import io.github.srs.utils.SimulationDefaults.DynamicEntity.Sensor.ProximitySensor as ProximitySensorDefaults
12

13
/**
14
 * Represents the range of a sensor.
15
 */
16
type Range = Double
UNCOV
17

×
18
/**
19
 * Represents the distance from the center of a dynamic entity to a sensor.
20
 */
21
type Distance = Double
22

23
/**
24
 * Represents a sensor that can sense the environment for a dynamic entity.
25
 * @tparam Entity
26
 *   the type of dynamic entity that the sensor can act upon.
27
 * @tparam Env
28
 *   the type of environment in which the sensor operates.
29
 */
30
trait Sensor[-Entity <: DynamicEntity, -Env <: Environment]:
31
  /**
32
   * The type of data that the sensor returns. This type can vary based on the specific sensor implementation.
33
   */
34
  type Data
35

36
  /**
37
   * The offset orientation of the sensor relative to the entity's orientation.
38
   * @return
39
   *   the orientation offset of the sensor.
40
   */
41
  def offset: Orientation
42

43
  /**
44
   * The distance from the center of the entity to the sensor.
45
   * @return
46
   *   the distance of the sensor from the entity's center.
47
   */
48
  def distance: Distance
49

50
  /**
51
   * The range of the sensor, which defines how far it can sense.
52
   * @note
53
   *   The range is typically a positive value that indicates the maximum distance the sensor can detect.
54
   * @return
55
   *   the range of the sensor.
56
   */
57
  def range: Range
58

59
  /**
60
   * Senses the environment for the given entity and returns the data collected by the sensor.
61
   * @param entity
62
   *   the dynamic entity that the sensor is attached to.
63
   * @param env
64
   *   the environment in which the sensor operates.
65
   * @param x$3
66
   *   the implicit Monad instance for the effect type `F`.
67
   * @tparam F
68
   *   the effect type in which the sensing operation is performed.
69
   * @return
70
   *   a monadic effect containing the data sensed by the sensor.
71
   */
72
  def sense[F[_]](entity: Entity, env: Env)(using Monad[F]): F[Data]
73
end Sensor
74

75
/**
76
 * Represents a reading from a sensor. This case class encapsulates the sensor and the value it has sensed.
77
 * @param sensor
78
 *   the sensor that has taken the reading.
79
 * @param value
80
 *   the value sensed by the sensor.
81
 * @tparam S
82
 *   the type of sensor, which is a subtype of [[Sensor]].
83
 * @tparam A
84
 *   the type of data sensed by the sensor.
85
 */
86
final case class SensorReading[S <: Sensor[?, ?], A](sensor: S, value: A)
87

68✔
88
/**
89
 * A collection of sensor readings. This type is used to represent multiple sensor readings from a dynamic entity. It is
90
 * a vector of [[SensorReading]] instances, allowing for efficient access and manipulation of sensor data.
91
 */
92
type SensorReadings = Vector[SensorReading[? <: Sensor[?, ?], ?]]
93

94
/**
95
 * A proximity sensor that can sense the distance to other entities in the environment. It calculates the distance to
96
 * the nearest entity within its range and returns a normalized value. The value is normalized to a range between 0.0
97
 * (closest) and 1.0 (farthest).
98
 * @param offset
99
 *   the offset orientation of the sensor relative to the entity's orientation.
100
 * @param distance
101
 *   the distance from the center of the entity to the sensor.
102
 * @param range
103
 *   the range of the sensor, which defines how far it can sense.
104
 * @tparam Entity
105
 *   the type of dynamic entity that the sensor can act upon.
106
 * @tparam Env
107
 *   the type of environment in which the sensor operates.
108
 */
109
final case class ProximitySensor[Entity <: DynamicEntity, Env <: Environment](
110
    offset: Orientation = Orientation(ProximitySensorDefaults.defaultOffset),
103✔
111
    distance: Distance = ProximitySensorDefaults.defaultDistance,
24✔
112
    range: Range = ProximitySensorDefaults.defaultRange,
16✔
113
) extends Sensor[Entity, Env]:
16✔
114

115
  override type Data = Double
116

117
  override def sense[F[_]](entity: Entity, env: Env)(using Monad[F]): F[Data] =
118
    import Point2D.*
4✔
119
    val globalOrientation = entity.orientation.toRadians + offset.toRadians
120
    val direction = Point2D(math.cos(globalOrientation), -math.sin(globalOrientation))
20✔
121
    val origin = entity.position + direction * distance
26✔
122
    val end = origin + direction * range
26✔
123

19✔
124
    val distances = env.entities
125
      .filter(!_.equals(entity))
5✔
126
      .flatMap(intersectRay(_, origin, end))
7✔
127
      .filter(_ <= range)
8✔
128

8✔
129
    summon[Monad[F]].pure(distances.minOption.map(_ / range).getOrElse(1.0))
130

35✔
131
end ProximitySensor
132

133
object Sensor:
UNCOV
134

×
135
  extension [E <: DynamicEntity, Env <: Environment](s: Sensor[E, Env])
136

5✔
137
    /**
138
     * Validates the properties of a sensor.
139
     */
140
    def validate: Validation[Sensor[E, Env]] =
141
      for
4✔
142
        _ <- PositiveDouble(s.distance).validate
1✔
143
        _ <- PositiveDouble(s.range).validate
26✔
144
      yield s
145

3✔
146
  extension (r: Robot)
147

148
    /**
149
     * Senses all sensors of the robot in the given environment.
150
     * @param env
151
     *   the environment in which to sense.
152
     * @return
153
     *   a vector of sensor readings.
154
     */
155
    def senseAll[F[_]: Monad](env: Environment): F[SensorReadings] =
156
      r.sensors.traverse: sensor =>
4✔
157
        sensor.sense(r, env).map(reading => SensorReading(sensor, reading))
17✔
158
end Sensor
6✔
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