From 13f701978a4aebab8b4cf61b983daa138e0591fd Mon Sep 17 00:00:00 2001 From: Mathieu LEFEBVRE Date: Wed, 1 Jul 2026 18:21:30 +0200 Subject: [PATCH 1/5] java/iot3mobility: add length, width and footprint calculation to SensorObject Signed-off-by: Mathieu LEFEBVRE --- .../iot3mobility/roadobjects/RoadSensor.java | 27 +++++++++-- .../roadobjects/SensorObject.java | 47 ++++++++++++++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java index 9f823daf..1cd653d9 100644 --- a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java +++ b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java @@ -12,6 +12,7 @@ import com.orange.iot3mobility.messages.cpm.core.CpmCodec; import com.orange.iot3mobility.messages.cpm.core.CpmVersion; import com.orange.iot3mobility.messages.cpm.v121.model.CpmEnvelope121; +import com.orange.iot3mobility.messages.cpm.v121.model.perceivedobjectcontainer.ObjectClass; import com.orange.iot3mobility.messages.cpm.v121.model.perceivedobjectcontainer.ObjectClassification; import com.orange.iot3mobility.messages.cpm.v121.model.perceivedobjectcontainer.PerceivedObject; import com.orange.iot3mobility.messages.cpm.v211.model.CpmEnvelope211; @@ -100,8 +101,15 @@ public void updateSensorObjects() { double objectHeading = EtsiConverter.cpmDerivedHeadingDegrees( perceivedObject.xSpeed(), perceivedObject.ySpeed()); - int infoQuality = 3; + Double objectLength = null, objectWidth = null; + if(perceivedObject.planarObjectDimension1() != null + && perceivedObject.planarObjectDimension2() != null) { + objectLength = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.planarObjectDimension1()); + objectWidth = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.planarObjectDimension2()); + } + + int infoQuality = 3; if(perceivedObject.classification() != null && !perceivedObject.classification().isEmpty()) { infoQuality = perceivedObject.classification().get(0).confidence(); @@ -119,12 +127,14 @@ public void updateSensorObjects() { sensorObject.setSpeed(objectSpeed); sensorObject.setHeading(objectHeading); sensorObject.setInfoQuality(infoQuality); + sensorObject.setDimensions(objectLength, objectWidth); ioT3RoadSensorCallback.sensorObjectUpdate(sensorObject); } } } else { // create new SensorObject - sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, objectHeading, infoQuality); + sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, + objectHeading, infoQuality, objectLength, objectWidth); synchronized (sensorObjects) { sensorObjects.add(sensorObject); } @@ -206,6 +216,13 @@ public void updateSensorObjects() { } } + Double objectLength = null, objectWidth = null; + if(perceivedObject.objectDimensionX() != null + && perceivedObject.objectDimensionY() != null) { + objectLength = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.objectDimensionX().value()); + objectWidth = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.objectDimensionY().value()); + } + int infoQuality = 3; if(perceivedObject.classification() != null && !perceivedObject.classification().isEmpty()) { @@ -224,12 +241,14 @@ public void updateSensorObjects() { sensorObject.setSpeed(objectSpeed); sensorObject.setHeading(objectHeading); sensorObject.setInfoQuality(infoQuality); + sensorObject.setDimensions(objectLength, objectWidth); ioT3RoadSensorCallback.sensorObjectUpdate(sensorObject); } } } else { // create new SensorObject - sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, objectHeading, infoQuality); + sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, + objectHeading, infoQuality, objectLength, objectWidth); synchronized (sensorObjects) { sensorObjects.add(sensorObject); } @@ -309,7 +328,7 @@ public boolean stillLiving() { /* --------------------------------------------------------------------- */ private SensorObjectType cpm121ObjectTypeFromObjectClass( - com.orange.iot3mobility.messages.cpm.v121.model.perceivedobjectcontainer.ObjectClass objectClass) { + ObjectClass objectClass) { if(objectClass.vehicle() != null) { return switch (objectClass.vehicle()) { case 1 -> SensorObjectType.PASSENGER_CAR; diff --git a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java index 90887c20..899548d8 100644 --- a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java +++ b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java @@ -7,8 +7,11 @@ */ package com.orange.iot3mobility.roadobjects; +import com.orange.iot3mobility.Utils; import com.orange.iot3mobility.quadkey.LatLng; +import java.util.List; + public class SensorObject { private static final int LIFETIME = 1500; // 1.5 seconds @@ -19,15 +22,27 @@ public class SensorObject { private double speed; // m/s private double heading; // degree private int infoQuality; + private Double length; // meter + private Double width; // meter + private List footprint; private long timestamp; - public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double heading, int infoQuality) { + public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double heading, + int infoQuality) { + this(uuid, type, position, speed, heading, infoQuality, null, null); + } + + public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double heading, + int infoQuality, Double length, Double width) { this.uuid = uuid; this.type = type; this.position = position; this.speed = speed; this.heading = heading; this.infoQuality = infoQuality; + this.length = length; + this.width = width; + computeFootprint(); updateTimestamp(); } @@ -79,6 +94,36 @@ public void setInfoQuality(int infoQuality) { this.infoQuality = infoQuality; } + public void setDimensions(Double length, Double width) { + this.length = length; + this.width = width; + computeFootprint(); + } + + public Double getLength() { + return length; + } + + public Double getWidth() { + return width; + } + + private void computeFootprint() { + if(length != null && width != null) { + LatLng frontCenter = Utils.pointFromPosition(position, heading, length / 2); + LatLng frontLeft = Utils.pointFromPosition(frontCenter, (heading - 90 + 360) % 360, width / 2); + LatLng frontRight = Utils.pointFromPosition(frontCenter, (heading + 90 + 360) % 360, width / 2); + LatLng rearCenter = Utils.pointFromPosition(position, (heading + 180 + 360) % 360, length / 2); + LatLng rearLeft = Utils.pointFromPosition(rearCenter, (heading - 90 + 360) % 360, width / 2); + LatLng rearRight = Utils.pointFromPosition(rearCenter, (heading + 90 + 360) % 360, width / 2); + footprint = List.of(frontLeft, frontRight, rearRight, rearLeft); + } + } + + public List getFootprint() { + return footprint; + } + public long getTimestamp() { return timestamp; } From 080ec2bfcce0d080933ddf1d0e4407caad2755f6 Mon Sep 17 00:00:00 2001 From: Mathieu LEFEBVRE Date: Thu, 2 Jul 2026 17:17:59 +0200 Subject: [PATCH 2/5] java/iot3mobility: fix SensorObject orientation handling - heading has been renamed into bearing to more accurately describe the speed vector direction. - orientation has been added to represent the physical orientation of the object (equivalent to its heading). The footprint is now calculated based on this value. Signed-off-by: Mathieu LEFEBVRE --- .../iot3mobility/roadobjects/RoadSensor.java | 23 ++++++---- .../roadobjects/SensorObject.java | 44 ++++++++++++------- .../roadobjects/SensorObjectTest.java | 6 +-- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java index 1cd653d9..91429897 100644 --- a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java +++ b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/RoadSensor.java @@ -102,12 +102,15 @@ public void updateSensorObjects() { perceivedObject.xSpeed(), perceivedObject.ySpeed()); - Double objectLength = null, objectWidth = null; + Double objectLength = null, objectWidth = null, objectOrientation = null; if(perceivedObject.planarObjectDimension1() != null && perceivedObject.planarObjectDimension2() != null) { objectLength = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.planarObjectDimension1()); objectWidth = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.planarObjectDimension2()); } + if(perceivedObject.yawAngle() != null) { + objectOrientation = EtsiConverter.cpmAngleDegrees(perceivedObject.yawAngle()); + } int infoQuality = 3; if(perceivedObject.classification() != null @@ -125,16 +128,17 @@ public void updateSensorObjects() { sensorObject.setPosition(objectPosition); sensorObject.setType(objectType); sensorObject.setSpeed(objectSpeed); - sensorObject.setHeading(objectHeading); + sensorObject.setBearing(objectHeading); sensorObject.setInfoQuality(infoQuality); sensorObject.setDimensions(objectLength, objectWidth); + sensorObject.setOrientation(objectOrientation); ioT3RoadSensorCallback.sensorObjectUpdate(sensorObject); } } } else { // create new SensorObject sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, - objectHeading, infoQuality, objectLength, objectWidth); + objectHeading, infoQuality, objectLength, objectWidth, objectOrientation); synchronized (sensorObjects) { sensorObjects.add(sensorObject); } @@ -216,12 +220,14 @@ public void updateSensorObjects() { } } - Double objectLength = null, objectWidth = null; - if(perceivedObject.objectDimensionX() != null - && perceivedObject.objectDimensionY() != null) { + Double objectLength = null, objectWidth = null, objectOrientation = null; + if(perceivedObject.objectDimensionX() != null && perceivedObject.objectDimensionY() != null) { objectLength = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.objectDimensionX().value()); objectWidth = EtsiConverter.cpmObjectDimensionMeters(perceivedObject.objectDimensionY().value()); } + if(perceivedObject.angles() != null && perceivedObject.angles().zAngle() != null) { + objectOrientation = EtsiConverter.cpmAngleDegrees(perceivedObject.angles().zAngle().value()); + } int infoQuality = 3; if(perceivedObject.classification() != null @@ -239,16 +245,17 @@ public void updateSensorObjects() { sensorObject.setPosition(objectPosition); sensorObject.setType(objectType); sensorObject.setSpeed(objectSpeed); - sensorObject.setHeading(objectHeading); + sensorObject.setBearing(objectHeading); sensorObject.setInfoQuality(infoQuality); sensorObject.setDimensions(objectLength, objectWidth); + sensorObject.setOrientation(objectOrientation); ioT3RoadSensorCallback.sensorObjectUpdate(sensorObject); } } } else { // create new SensorObject sensorObject = new SensorObject(objectId, objectType, objectPosition, objectSpeed, - objectHeading, infoQuality, objectLength, objectWidth); + objectHeading, infoQuality, objectLength, objectWidth, objectOrientation); synchronized (sensorObjects) { sensorObjects.add(sensorObject); } diff --git a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java index 899548d8..1890e3ec 100644 --- a/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java +++ b/java/iot3/mobility/src/main/java/com/orange/iot3mobility/roadobjects/SensorObject.java @@ -20,28 +20,30 @@ public class SensorObject { private SensorObjectType type; private LatLng position; private double speed; // m/s - private double heading; // degree + private double bearing; // degree private int infoQuality; private Double length; // meter private Double width; // meter + private Double orientation; // degree private List footprint; private long timestamp; - public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double heading, + public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double bearing, int infoQuality) { - this(uuid, type, position, speed, heading, infoQuality, null, null); + this(uuid, type, position, speed, bearing, infoQuality, null, null, null); } - public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double heading, - int infoQuality, Double length, Double width) { + public SensorObject(String uuid, SensorObjectType type, LatLng position, double speed, double bearing, + int infoQuality, Double length, Double width, Double orientation) { this.uuid = uuid; this.type = type; this.position = position; this.speed = speed; - this.heading = heading; + this.bearing = bearing; this.infoQuality = infoQuality; this.length = length; this.width = width; + this.orientation = orientation; computeFootprint(); updateTimestamp(); } @@ -78,12 +80,12 @@ public void setSpeed(double speed) { this.speed = speed; } - public double getHeading() { - return heading; + public double getBearing() { + return bearing; } - public void setHeading(double heading) { - this.heading = heading; + public void setBearing(double bearing) { + this.bearing = bearing; } public int getInfoQuality() { @@ -108,14 +110,22 @@ public Double getWidth() { return width; } + public Double getOrientation() { + return orientation; + } + + public void setOrientation(Double orientation) { + this.orientation = orientation; + } + private void computeFootprint() { - if(length != null && width != null) { - LatLng frontCenter = Utils.pointFromPosition(position, heading, length / 2); - LatLng frontLeft = Utils.pointFromPosition(frontCenter, (heading - 90 + 360) % 360, width / 2); - LatLng frontRight = Utils.pointFromPosition(frontCenter, (heading + 90 + 360) % 360, width / 2); - LatLng rearCenter = Utils.pointFromPosition(position, (heading + 180 + 360) % 360, length / 2); - LatLng rearLeft = Utils.pointFromPosition(rearCenter, (heading - 90 + 360) % 360, width / 2); - LatLng rearRight = Utils.pointFromPosition(rearCenter, (heading + 90 + 360) % 360, width / 2); + if(length != null && width != null && orientation != null) { + LatLng frontCenter = Utils.pointFromPosition(position, orientation, length / 2); + LatLng frontLeft = Utils.pointFromPosition(frontCenter, (orientation - 90 + 360) % 360, width / 2); + LatLng frontRight = Utils.pointFromPosition(frontCenter, (orientation + 90 + 360) % 360, width / 2); + LatLng rearCenter = Utils.pointFromPosition(position, (orientation + 180 + 360) % 360, length / 2); + LatLng rearLeft = Utils.pointFromPosition(rearCenter, (orientation - 90 + 360) % 360, width / 2); + LatLng rearRight = Utils.pointFromPosition(rearCenter, (orientation + 90 + 360) % 360, width / 2); footprint = List.of(frontLeft, frontRight, rearRight, rearLeft); } } diff --git a/java/iot3/mobility/src/test/java/com/orange/iot3mobility/roadobjects/SensorObjectTest.java b/java/iot3/mobility/src/test/java/com/orange/iot3mobility/roadobjects/SensorObjectTest.java index fcda0a35..28ff28b8 100644 --- a/java/iot3/mobility/src/test/java/com/orange/iot3mobility/roadobjects/SensorObjectTest.java +++ b/java/iot3/mobility/src/test/java/com/orange/iot3mobility/roadobjects/SensorObjectTest.java @@ -53,7 +53,7 @@ void getSpeedReturnsConstructedValue() { @Test void getHeadingReturnsConstructedValue() { - assertEquals(90.0, makeSensorObject().getHeading(), 1e-9); + assertEquals(90.0, makeSensorObject().getBearing(), 1e-9); } @Test @@ -100,8 +100,8 @@ void setSpeedUpdatesValue() { @Test void setHeadingUpdatesValue() { SensorObject obj = makeSensorObject(); - obj.setHeading(270.0); - assertEquals(270.0, obj.getHeading(), 1e-9); + obj.setBearing(270.0); + assertEquals(270.0, obj.getBearing(), 1e-9); } @Test From de53cd9a383b9ff9f5c96c1e0cfd4fe97f04d6b5 Mon Sep 17 00:00:00 2001 From: Mathieu LEFEBVRE Date: Thu, 9 Jul 2026 11:26:43 +0200 Subject: [PATCH 3/5] java/iot3mobility: v0.2.1 Signed-off-by: Mathieu LEFEBVRE --- java/iot3/mobility/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/iot3/mobility/build.gradle b/java/iot3/mobility/build.gradle index 9e33038b..314ec4f7 100644 --- a/java/iot3/mobility/build.gradle +++ b/java/iot3/mobility/build.gradle @@ -12,7 +12,7 @@ plugins { } group 'com.orange.iot3mobility' -version '0.2.1-dev' +version '0.2.1' repositories { // Use Maven Central for resolving dependencies. From 00626c161cec8733dc4315147a56bff405c2723e Mon Sep 17 00:00:00 2001 From: Mathieu LEFEBVRE Date: Thu, 9 Jul 2026 11:07:48 +0200 Subject: [PATCH 4/5] java/iot3examples: add dimensions to perceived objects of CPMs v1.2.1 and v2.1.1 Note: orientation is voluntarily not set for the pedestrian object. Signed-off-by: Mathieu LEFEBVRE --- .../main/java/com/orange/CpmV121Factory.java | 3 ++- .../main/java/com/orange/CpmV211Factory.java | 27 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/java/iot3/examples/src/main/java/com/orange/CpmV121Factory.java b/java/iot3/examples/src/main/java/com/orange/CpmV121Factory.java index 6bdc6502..230e1fd1 100644 --- a/java/iot3/examples/src/main/java/com/orange/CpmV121Factory.java +++ b/java/iot3/examples/src/main/java/com/orange/CpmV121Factory.java @@ -73,8 +73,9 @@ static CpmEnvelope121 createTestCpmEnvelope( .objectAge(1500) .distance(bicycleX, bicycleY) .speed(0, 0) - .planarObjectDimension(20, 20) + .planarObjectDimension(20, 10) .verticalObjectDimension(15) + .yawAngle(120) .classification(List.of(new ObjectClassification( new ObjectClass(null, new ObjectClassVru(null, 1, null, null), diff --git a/java/iot3/examples/src/main/java/com/orange/CpmV211Factory.java b/java/iot3/examples/src/main/java/com/orange/CpmV211Factory.java index e9bf11ef..aecc1ff6 100644 --- a/java/iot3/examples/src/main/java/com/orange/CpmV211Factory.java +++ b/java/iot3/examples/src/main/java/com/orange/CpmV211Factory.java @@ -4,23 +4,10 @@ import com.orange.iot3mobility.messages.EtsiConverter; import com.orange.iot3mobility.messages.cpm.v211.model.CpmEnvelope211; import com.orange.iot3mobility.messages.cpm.v211.model.CpmMessage211; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.Altitude; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.CartesianCoordinateWithConfidence; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.CartesianPosition3d; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.CartesianPosition3dWithConfidence; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.Circular; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.MapReference; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.PositionConfidenceEllipse; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.ReferencePosition; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.RoadSegment; -import com.orange.iot3mobility.messages.cpm.v211.model.defs.Shape; +import com.orange.iot3mobility.messages.cpm.v211.model.defs.*; import com.orange.iot3mobility.messages.cpm.v211.model.managementcontainer.ManagementContainer; import com.orange.iot3mobility.messages.cpm.v211.model.originatingrsucontainer.OriginatingRsuContainer; -import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.ObjectClass; -import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.ObjectClassVru; -import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.ObjectClassification; -import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.PerceivedObject; -import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.PerceivedObjectContainer; +import com.orange.iot3mobility.messages.cpm.v211.model.perceivedobjectcontainer.*; import com.orange.iot3mobility.messages.cpm.v211.model.sensorinformationcontainer.SensorInformation; import com.orange.iot3mobility.messages.cpm.v211.model.sensorinformationcontainer.SensorInformationContainer; import com.orange.iot3mobility.quadkey.LatLng; @@ -56,6 +43,9 @@ static CpmEnvelope211 createTestCpmEnvelope( .classification(List.of(new ObjectClassification( ObjectClass.vru(ObjectClassVru.pedestrian(1)), 100))) + .objectDimensionX(new ObjectDimension(10, 1)) + .objectDimensionY(new ObjectDimension(10, 1)) + .objectDimensionZ(new ObjectDimension(20, 1)) .sensorIdList(List.of(SENSOR_ID)) .build(); @@ -70,6 +60,13 @@ static CpmEnvelope211 createTestCpmEnvelope( .classification(List.of(new ObjectClassification( ObjectClass.vru(ObjectClassVru.bicyclistAndLightVruVehicle(1)), 100))) + .objectDimensionX(new ObjectDimension(20, 1)) + .objectDimensionY(new ObjectDimension(10, 1)) + .objectDimensionZ(new ObjectDimension(15, 1)) + .angles(new EulerAngles( + new Angle(120, 1), + new Angle(0, 1), + new Angle(0, 1))) .sensorIdList(List.of(SENSOR_ID)) .build(); From c135e4b8dc6ba9de6b4f376f487a5db11cd7e8ab Mon Sep 17 00:00:00 2001 From: Mathieu LEFEBVRE Date: Thu, 9 Jul 2026 11:05:58 +0200 Subject: [PATCH 5/5] java/iot3examples: v0.2.1 Signed-off-by: Mathieu LEFEBVRE --- java/iot3/examples/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/iot3/examples/build.gradle b/java/iot3/examples/build.gradle index 04ddd815..cf715a44 100644 --- a/java/iot3/examples/build.gradle +++ b/java/iot3/examples/build.gradle @@ -3,7 +3,7 @@ plugins { } group = 'com.orange' -version = '0.2.0' +version = '0.2.1' repositories { mavenCentral()