Skip to content

Commit 9f6f328

Browse files
authored
Added support for loading CSV with WGS84 (#23)
* Added support for loading CSV with WGS84 * Adjusted to review, refactor columns to use AZStd::optional * update readme --------- Signed-off-by: Michał Pełka <[email protected]>
1 parent 5bfa2d2 commit 9f6f328

File tree

5 files changed

+101
-47
lines changed

5 files changed

+101
-47
lines changed

Gems/RobotecSplineTools/Code/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
126126
AZ::AzToolsFramework
127127
$<TARGET_OBJECTS:Gem::${gem_name}.Private.Object>
128128
Gem::AtomLyIntegration_CommonFeatures.Static
129+
Gem::ROS2.Editor.Static
129130
)
130131

131132
ly_add_target(

Gems/RobotecSplineTools/Code/Source/Tools/SplineToolsEditorComponent.cpp

Lines changed: 91 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#include "SplineToolsEditorComponent.h"
2-
#include "AzCore/Debug/Trace.h"
32

43
#include <AzCore/Component/TransformBus.h>
5-
#include <AzCore/IO/Path/Path.h>
64
#include <AzCore/Serialization/EditContext.h>
7-
#include <AzFramework/Physics/Common/PhysicsTypes.h>
8-
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
5+
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
96
#include <LmbrCentral/Shape/SplineComponentBus.h>
7+
#include <QFileDialog>
8+
#include <QMessageBox>
9+
#include <ROS2/Georeference/GeoreferenceBus.h>
10+
#include <ROS2/Georeference/GeoreferenceStructures.h>
1011
#include <csv/csv.hpp>
1112

1213
namespace SplineTools
@@ -23,10 +24,8 @@ namespace SplineTools
2324
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
2425
if (serializeContext)
2526
{
26-
serializeContext->Class<SplineToolsEditorComponent, AzToolsFramework::Components::EditorComponentBase>()
27-
->Version(2)
28-
->Field("CsvAssetId", &SplineToolsEditorComponent::m_csvAssetId)
29-
->Field("IsLocalCoordinates", &SplineToolsEditorComponent::m_isLocalCoordinates);
27+
serializeContext->Class<SplineToolsEditorComponent, AzToolsFramework::Components::EditorComponentBase>()->Version(2)->Field(
28+
"IsLocalCoordinates", &SplineToolsEditorComponent::m_isLocalCoordinates);
3029

3130
AZ::EditContext* editContext = serializeContext->GetEditContext();
3231
if (editContext)
@@ -41,9 +40,7 @@ namespace SplineTools
4140
&SplineToolsEditorComponent::m_isLocalCoordinates,
4241
"Local coordinates",
4342
"Local coordinates")
44-
->DataElement(AZ::Edit::UIHandlers::Default, &SplineToolsEditorComponent::m_csvAssetId, "CSV Asset", "CSV asset")
45-
->Attribute(AZ::Edit::Attributes::SourceAssetFilterPattern, "*.csv")
46-
->UIElement(AZ::Edit::UIHandlers::Button, "Reload spline", "Reload spline")
43+
->UIElement(AZ::Edit::UIHandlers::Button, "Load spline", "Load spline")
4744
->Attribute(AZ::Edit::Attributes::ButtonText, "Load")
4845
->Attribute(AZ::Edit::Attributes::ChangeNotify, &SplineToolsEditorComponent::ReloadCSVAsset)
4946
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
@@ -74,20 +71,16 @@ namespace SplineTools
7471
LmbrCentral::SplineComponentRequestBus::EventResult(
7572
splinePtr, GetEntityId(), &LmbrCentral::SplineComponentRequestBus::Events::GetSpline);
7673
auto vertices = splinePtr->GetVertices();
77-
using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
78-
AZ::Data::AssetInfo sourceAssetInfo;
79-
bool ok{ false };
80-
AZStd::string watchFolder;
81-
AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
82-
83-
AssetSysReqBus::BroadcastResult(
84-
ok, &AssetSysReqBus::Events::GetSourceInfoBySourceUUID, m_csvAssetId.m_guid, sourceAssetInfo, watchFolder);
85-
if (!ok)
74+
75+
QString fileName = QFileDialog::getSaveFileName(AzToolsFramework::GetActiveWindow(), "Open CSV File", "", "CSV Files (*.csv)");
76+
77+
if (fileName.isEmpty())
8678
{
87-
AZ_Error("SplineToolsEditorComponent", false, "Failed to get source info for referenced CSV asset. Saving aborted");
79+
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), "Error", "Please specify file", QMessageBox::Ok);
8880
return;
8981
}
90-
const AZ::IO::Path sourcePath = AZ::IO::Path(watchFolder) / AZ::IO::Path(sourceAssetInfo.m_relativePath);
82+
83+
const AZ::IO::Path sourcePath = AZ::IO::Path(fileName.toUtf8().constData());
9184

9285
if (!m_isLocalCoordinates)
9386
{
@@ -103,33 +96,40 @@ namespace SplineTools
10396
return worldTm.TransformPoint(point);
10497
});
10598
}
106-
AZ_Printf("SplineToolsEditorComponent", "Save CSV asset to %s", sourceAssetInfo.m_relativePath.c_str());
99+
AZ_Printf("SplineToolsEditorComponent", "Save CSV asset to %s", sourcePath.c_str());
107100
SavePointsToCsv(sourcePath.c_str(), vertices);
108101
}
109102

110103
void SplineToolsEditorComponent::ReloadCSVAsset()
111104
{
112-
using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
113-
AZ::Data::AssetInfo sourceAssetInfo;
114-
bool ok{ false };
115-
AZStd::string watchFolder;
116-
AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
117-
118-
AssetSysReqBus::BroadcastResult(
119-
ok, &AssetSysReqBus::Events::GetSourceInfoBySourceUUID, m_csvAssetId.m_guid, sourceAssetInfo, watchFolder);
120-
const AZ::IO::Path sourcePath = AZ::IO::Path(watchFolder) / AZ::IO::Path(sourceAssetInfo.m_relativePath);
105+
QString fileName = QFileDialog::getOpenFileName(AzToolsFramework::GetActiveWindow(), "Open CSV File", "", "CSV Files (*.csv)");
121106

107+
if (fileName.isEmpty())
108+
{
109+
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), "Error", "Please specify file", QMessageBox::Ok);
110+
return;
111+
}
112+
AZStd::string sourcePath = AZStd::string(fileName.toUtf8().constData());
122113
AZ_Printf("SplineToolsEditorComponent", "Reload csv asset from %s", sourcePath.c_str());
123114

124115
auto points = GetSplinePointsFromCsv(sourcePath.c_str());
125116

126117
if (points.empty())
127118
{
128119
AZ_Error("SplineToolsEditorComponent", false, "No points found in CSV file");
120+
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), "Error", "No points found in CSV file", QMessageBox::Ok);
129121
return;
130122
}
131123

132124
AZ::Transform worldInvTm(AZ::Transform::Identity());
125+
if (m_isLocalCoordinates && m_isCoordinateLatLon)
126+
{
127+
AZ_Error("SplineToolsEditorComponent", false, "Cannot use lat, lon, alt coordinates in local coordinates");
128+
QMessageBox::warning(
129+
AzToolsFramework::GetActiveWindow(), "Error", "Cannot use lat, lon, alt coordinates in local coordinates", QMessageBox::Ok);
130+
return;
131+
}
132+
133133
if (!m_isLocalCoordinates)
134134
{
135135
AZ::TransformBus::EventResult(worldInvTm, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
@@ -178,41 +178,87 @@ namespace SplineTools
178178

179179
AZStd::vector<AZ::Vector3> SplineToolsEditorComponent::GetSplinePointsFromCsv(const AZStd::string& csvFilePath)
180180
{
181+
auto getOptionalColumn = [](int column) -> AZStd::optional<int>
182+
{
183+
if (column < 0)
184+
{
185+
return AZStd::nullopt;
186+
}
187+
return column;
188+
};
189+
181190
try
182191
{
183192
AZStd::vector<AZ::Vector3> ret;
184193

185194
csv::CSVReader reader(csvFilePath.c_str());
186195
reader.get_col_names();
187196

188-
const int index_X = reader.index_of("x");
189-
const int index_Y = reader.index_of("y");
190-
const int index_Z = reader.index_of("z");
197+
const auto indexX = getOptionalColumn(reader.index_of("x"));
198+
const auto indexY = getOptionalColumn(reader.index_of("y"));
199+
const auto indexZ = getOptionalColumn(reader.index_of("z"));
200+
201+
const auto indexLat = getOptionalColumn(reader.index_of("lat"));
202+
const auto indexLon = getOptionalColumn(reader.index_of("lon"));
203+
const auto indexAlt = getOptionalColumn(reader.index_of("alt"));
204+
205+
m_isCoordinateXY = indexX && indexY;
206+
m_isCoordinateLatLon = indexLat && indexLon && indexAlt;
207+
const bool isCoordinateCorrect = (m_isCoordinateLatLon || m_isCoordinateXY);
191208

192-
const bool isCoordinateCorrect = !(index_X < 0 || index_Y < 0);
193209
if (!isCoordinateCorrect)
194210
{
195-
AZ_Error("SplineToolsEditorComponent", false, "CSV file must have columns named x, y");
211+
AZ_Error("SplineToolsEditorComponent", false, "CSV file must have columns named x, y or lat, lon, alt");
212+
AZStd::string columns;
213+
for (const auto& columnName : reader.get_col_names())
214+
{
215+
columns += AZStd::string(columnName.c_str()) + ", ";
216+
}
217+
AZ_Printf("SplineToolsEditorComponent", "CSV file columns: %s", columns.c_str());
218+
QMessageBox::warning(
219+
AzToolsFramework::GetActiveWindow(),
220+
"Error",
221+
"CSV file must have columns named x, y or lat, lon, alt",
222+
QMessageBox::Ok);
196223
return {};
197224
}
198225

199-
for (csv::CSVRow& row : reader)
226+
if (m_isCoordinateXY)
200227
{
201-
AZ::Vector3 point = AZ::Vector3(row[index_X].get<float>(), row[index_Y].get<float>(), 0);
228+
for (csv::CSVRow& row : reader)
229+
{
230+
AZ::Vector3 point = AZ::Vector3(row[*indexX].get<float>(), row[*indexY].get<float>(), 0);
231+
232+
if (indexZ > 0)
233+
{
234+
point.SetZ(row[*indexZ].get<float>());
235+
}
202236

203-
// handle Z column
204-
if (index_Z > 0)
237+
ret.emplace_back(AZStd::move(point));
238+
}
239+
}
240+
else if (m_isCoordinateLatLon)
241+
{
242+
for (csv::CSVRow& row : reader)
205243
{
206-
point.SetZ(row[index_Z].get<float>());
244+
ROS2::WGS::WGS84Coordinate coordinate;
245+
coordinate.m_latitude = row[*indexLat].get<double>();
246+
coordinate.m_longitude = row[*indexLon].get<double>();
247+
coordinate.m_altitude = row[*indexAlt].get<float>();
248+
auto coordinateInLevel = AZ::Vector3(-1);
249+
ROS2::GeoreferenceRequestsBus::BroadcastResult(
250+
coordinateInLevel, &ROS2::GeoreferenceRequests::ConvertFromWGS84ToLevel, coordinate);
251+
252+
ret.emplace_back(AZStd::move(coordinateInLevel));
207253
}
208-
209-
ret.emplace_back(AZStd::move(point));
210254
}
211255

212256
return ret;
213257
} catch (std::runtime_error& exception)
214258
{
215-
AZ_Error("SplineToolsEditorComponent", false, "Error parsing CSV file: %s", exception.what());
259+
AZStd::string error = AZStd::string::format("Error parsing CSV file: %s", exception.what());
260+
AZ_Error("SplineToolsEditorComponent", false, error.c_str());
261+
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), "Error", error.c_str(), QMessageBox::Ok);
216262
}
217263
return {};
218264
}

Gems/RobotecSplineTools/Code/Source/Tools/SplineToolsEditorComponent.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ namespace SplineTools
3838
void BuildGameEntity(AZ::Entity* gameEntity) override;
3939

4040
private:
41-
AZ::Data::AssetId m_csvAssetId; //!< Asset ID of the CSV
4241
bool m_isLocalCoordinates = true;
42+
bool m_isCoordinateXY = false;
43+
bool m_isCoordinateLatLon = false;
4344

4445
void ReloadCSVAsset();
4546
AZStd::vector<AZ::Vector3> GetSplinePointsFromCsv(const AZStd::string& csvFilePath);

Gems/RobotecSplineTools/gem.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"icon_path": "preview.png",
2121
"requirements": "No requirements",
2222
"documentation_url": "",
23-
"dependencies": [],
23+
"dependencies": ["ROS2"],
2424
"repo_uri": "",
2525
"compatible_engines": [],
2626
"engine_api_dependencies": [],

readme.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ Add SplineToolsEditorComponent next to the [Spline component](https://docs.o3de.
3232
If you switch `Local Coordinates` to true, the component will interpret coordinates as local to entity origin.
3333
![](doc/SplineToolsEditorComponent.png)
3434

35+
## Using geo-referenced data
36+
37+
The CSV file can contain the following columns: `lat`, `lon`, `alt` where every row contains the WGS-84 coordinate of the spline's node.
38+
It can be loaded to a georeferenced level as explained in [Georeference section of O3DE documentation]
39+
(https://development--o3deorg.netlify.app/docs/user-guide/interactivity/robotics/georeference/).
40+
It is useful for visualizing paths, roads, and other things at the O3DE level.
3541

3642
# ROS2ScriptIntegration
3743

0 commit comments

Comments
 (0)