@@ -24,36 +24,32 @@ void AGeocoder::BeginPlay()
2424{
2525 Super::BeginPlay ();
2626
27- if (APlayerController* PlayerController = Cast<APlayerController>(GetWorld ()->GetFirstPlayerController ()))
27+ if (auto playerController = Cast<APlayerController>(GetWorld ()->GetFirstPlayerController ()))
2828 {
29- SetupPlayerInputComponent (PlayerController ->InputComponent );
30- if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem
31- <UEnhancedInputLocalPlayerSubsystem>(PlayerController ->GetLocalPlayer ()))
29+ SetupPlayerInputComponent (playerController ->InputComponent );
30+ if (auto subsystem = ULocalPlayer::GetSubsystem
31+ <UEnhancedInputLocalPlayerSubsystem>(playerController ->GetLocalPlayer ()))
3232 {
33- Subsystem ->AddMappingContext (MappingContext, 0 );
33+ subsystem ->AddMappingContext (MappingContext, 0 );
3434 }
35- }
3635
37- // Make sure mouse cursor remains visible
38- APlayerController* PC = UGameplayStatics::GetPlayerController (GetWorld (), 0 );
39- if (PC)
40- {
41- PC->bShowMouseCursor = true ;
42- PC->bEnableClickEvents = true ;
36+ // Make sure mouse cursor remains visible
37+ playerController->bShowMouseCursor = true ;
38+ playerController->bEnableClickEvents = true ;
4339 }
4440
4541 // Create the UI and add it to the viewport
4642 if (UIWidgetClass != nullptr )
4743 {
48- AActor* self = this ;
44+ auto self = this ;
4945 UIWidget = CreateWidget<UUserWidget>(GetWorld (), UIWidgetClass);
5046 if (UIWidget)
5147 {
5248 UIWidget->AddToViewport ();
53- UFunction* WidgetFunction = UIWidget->FindFunction (FName (" SetGeoCoder" ));
49+ auto widgetFunction = UIWidget->FindFunction (FName (" SetGeoCoder" ));
5450 HideInstructions = UIWidget->FindFunction (FName (" HideDirections" ));
55- if (WidgetFunction ) {
56- UIWidget->ProcessEvent (WidgetFunction , &self);
51+ if (widgetFunction ) {
52+ UIWidget->ProcessEvent (widgetFunction , &self);
5753 }
5854 WidgetSetInfoFunction = UIWidget->FindFunction (FName (" SetInfoString" ));
5955 }
@@ -72,11 +68,27 @@ void AGeocoder::Tick(float DeltaTime)
7268 }
7369}
7470
71+ FString AGeocoder::GetAPIKey ()
72+ {
73+ auto mapComponent = UArcGISMapComponent::GetMapComponent (this );
74+ auto apiKey = mapComponent ? mapComponent->GetAPIKey () : " " ;
75+
76+ if (apiKey.IsEmpty ())
77+ {
78+ if (auto settings = GetDefault<UArcGISMapsSDKProjectSettings>())
79+ {
80+ apiKey = settings->APIKey ;
81+ }
82+ }
83+
84+ return apiKey;
85+ }
86+
7587void AGeocoder::SetupPlayerInputComponent (UInputComponent* PlayerInputComponent)
7688{
77- if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
89+ if (auto enhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
7890 {
79- EnhancedInputComponent ->BindAction (mousePress, ETriggerEvent::Started, this , &AGeocoder::SelectLocation);
91+ enhancedInputComponent ->BindAction (mousePress, ETriggerEvent::Started, this , &AGeocoder::SelectLocation);
8092 }
8193}
8294
@@ -91,76 +103,78 @@ void AGeocoder::SendAddressQuery(FString Address)
91103 FString temp = " " ;
92104 UIWidget->ProcessEvent (WidgetSetInfoFunction, &temp);
93105 }
94- FString Url = " https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates" ;
95- UArcGISMapComponent* MapComponent = UArcGISMapComponent::GetMapComponent (this );
96- FString APIToken = MapComponent ? MapComponent->GetAPIKey () : " " ;
97- FString Query;
106+ FString url = " https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates" ;
107+ FString apiKey = GetAPIKey ();
108+ FString query;
98109
99110 // Set up the query
100- FHttpRequestRef Request = FHttpModule::Get ().CreateRequest ();
101- Request ->OnProcessRequestComplete ().BindUObject (this , &AGeocoder::ProcessAddressQueryResponse);
102- Query = FString::Printf (TEXT (" %s/?f=json&token=%s&address=%s" ), *Url , *APIToken , *Address);
103- Request ->SetURL (Query .Replace (TEXT (" " ), TEXT (" %20" )));
104- Request ->SetVerb (" GET" );
105- Request ->SetHeader (" Content-Type" , " x-www-form-urlencoded" );
106- Request ->ProcessRequest ();
111+ auto request = FHttpModule::Get ().CreateRequest ();
112+ request ->OnProcessRequestComplete ().BindUObject (this , &AGeocoder::ProcessAddressQueryResponse);
113+ query = FString::Printf (TEXT (" %s/?f=json&token=%s&address=%s" ), *url , *apiKey , *Address);
114+ request ->SetURL (query .Replace (TEXT (" " ), TEXT (" %20" )));
115+ request ->SetVerb (" GET" );
116+ request ->SetHeader (" Content-Type" , " x-www-form-urlencoded" );
117+ request ->ProcessRequest ();
107118 bWaitingForResponse = true ;
108119}
109120
110121// Parse the response for a geocoding query
111122void AGeocoder::ProcessAddressQueryResponse (FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSucessfully)
112123{
113- FString ResponseAddress = " " ;
114- TSharedPtr<FJsonObject> JsonObj ;
115- TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create (Response->GetContentAsString ());
124+ FString responseAddress = " " ;
125+ TSharedPtr<FJsonObject> jsonObj ;
126+ TSharedRef<TJsonReader<>> reader = TJsonReaderFactory<>::Create (Response->GetContentAsString ());
116127
117128 // Check if the query was successful
118- if (FJsonSerializer::Deserialize (Reader, JsonObj ) &&
129+ if (FJsonSerializer::Deserialize (reader, jsonObj ) &&
119130 Response->GetResponseCode () > 199 && Response->GetResponseCode () < 300 ) {
120- const TArray<TSharedPtr<FJsonValue>>* Candidates ;
121- TSharedPtr<FJsonValue> Location ;
122- TSharedPtr<FJsonValue> Error ;
123- FString Message ;
124- double PointX, PointY ;
131+ const TArray<TSharedPtr<FJsonValue>>* candidates ;
132+ TSharedPtr<FJsonValue> location ;
133+ TSharedPtr<FJsonValue> error ;
134+ FString message ;
135+ double pointX, pointY ;
125136
126- if (JsonObj ->TryGetArrayField (TEXT (" candidates" ), Candidates )) {
127- if (Candidates ->Num () > 0 ) {
128- TSharedPtr<FJsonValue> candidate = (*Candidates )[0 ];
137+ if (jsonObj ->TryGetArrayField (TEXT (" candidates" ), candidates )) {
138+ if (candidates ->Num () > 0 ) {
139+ TSharedPtr<FJsonValue> candidate = (*candidates )[0 ];
129140
130- JsonObj = candidate->AsObject ();
131- if (!JsonObj ->TryGetStringField (TEXT (" Address" ), ResponseAddress )) {
132- ResponseAddress = TEXT (" Query did not return valid response" );
141+ jsonObj = candidate->AsObject ();
142+ if (!jsonObj ->TryGetStringField (TEXT (" Address" ), responseAddress )) {
143+ responseAddress = TEXT (" Query did not return valid response" );
133144 }
134- if ((Location = JsonObj ->TryGetField (TEXT (" location" )))) {
135- JsonObj = Location ->AsObject ();
136- JsonObj ->TryGetNumberField (" x" , PointX );
137- JsonObj ->TryGetNumberField (" y" , PointY );
145+ if ((location = jsonObj ->TryGetField (TEXT (" location" )))) {
146+ jsonObj = location ->AsObject ();
147+ jsonObj ->TryGetNumberField (" x" , pointX );
148+ jsonObj ->TryGetNumberField (" y" , pointY );
138149
139150 // Spawn a QueryLocation actor if not already created
140151 if (QueryLocation == nullptr ) {
141- FActorSpawnParameters SpawnParam = FActorSpawnParameters ();
142- SpawnParam .Owner = this ;
143- QueryLocation = GetWorld ()->SpawnActor <AQueryLocation>(AQueryLocation::StaticClass (), FVector3d (0 .), FRotator3d (0 .), SpawnParam );
152+ auto spawnParam = FActorSpawnParameters ();
153+ spawnParam .Owner = this ;
154+ QueryLocation = GetWorld ()->SpawnActor <AQueryLocation>(AQueryLocation::StaticClass (), FVector3d (0 .), FRotator3d (0 .), spawnParam );
144155 }
145156 // Update the QueryLocation actor with the query response and place it at high altitude
146157 QueryLocation->SetupAddressQuery (UArcGISPoint::CreateArcGISPointWithXYZSpatialReference (
147- PointX, PointY, 10000 ,
148- UArcGISSpatialReference::CreateArcGISSpatialReference (4326 )), ResponseAddress);
149-
150- // If there are more than 1 candidate, show a notification
151- Message = FString::Printf (
152- TEXT (" The query returned multiple results. If the shown location is not the intended one, make your input more specific." ));
153- if (WidgetSetInfoFunction && Candidates->Num () > 1 ) {
154- UIWidget->ProcessEvent (WidgetSetInfoFunction, &Message);
155- }
158+ pointX, pointY, 10000 ,
159+ UArcGISSpatialReference::CreateArcGISSpatialReference (4326 )), responseAddress);
156160 }
157161 }
162+
163+ // Show a notification if the query returned no results or more than one candidate
164+ if (candidates->Num () != 1 && WidgetSetInfoFunction)
165+ {
166+ message = candidates->Num () > 1 ?
167+ " The query returned multiple results. If the shown location is not the intended one, make your input more specific." :
168+ " The query didn't return any results. Adjust the input and, if necessary, make it more specific." ;
169+
170+ UIWidget->ProcessEvent (WidgetSetInfoFunction, &message);
171+ }
158172 }
159173 // If the server responded with an error, show the error message
160- else if ((Error = JsonObj ->TryGetField (TEXT (" error" )))) {
161- JsonObj = Error ->AsObject ();
162- if (WidgetSetInfoFunction && JsonObj ->TryGetStringField (TEXT (" message" ), Message )) {
163- UIWidget->ProcessEvent (WidgetSetInfoFunction, &Message );
174+ else if ((error = jsonObj ->TryGetField (TEXT (" error" )))) {
175+ jsonObj = error ->AsObject ();
176+ if (WidgetSetInfoFunction && jsonObj ->TryGetStringField (TEXT (" message" ), message )) {
177+ UIWidget->ProcessEvent (WidgetSetInfoFunction, &message );
164178 }
165179 }
166180 }
@@ -178,62 +192,60 @@ void AGeocoder::SendLocationQuery(UArcGISPoint* InPoint)
178192 FString temp = " " ;
179193 UIWidget->ProcessEvent (WidgetSetInfoFunction, &temp);
180194 }
181- FString Url = " https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode" ;
182- UArcGISMapComponent* MapComponent = UArcGISMapComponent::GetMapComponent (this );
183- FString APIToken = MapComponent ? MapComponent->GetAPIKey () : " " ;
184- FString Query;
185- UArcGISPoint* Point (InPoint);
195+ FString url = " https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode" ;
196+ FString query;
197+ UArcGISPoint* point (InPoint);
186198
187199 // If the geographic coordinates of the point are not in terms of lat & lon, project them
188200 if (InPoint->GetSpatialReference ()->GetWKID () != 4326 ) {
189- auto ProjectedGeometry = UArcGISGeometryEngine::Project (InPoint,
201+ auto projectedGeometry = UArcGISGeometryEngine::Project (InPoint,
190202 UArcGISSpatialReference::CreateArcGISSpatialReference (4326 ));
191- if (ProjectedGeometry != nullptr )
203+ if (projectedGeometry != nullptr )
192204 {
193- Point = static_cast <UArcGISPoint*>(ProjectedGeometry );
205+ point = static_cast <UArcGISPoint*>(projectedGeometry );
194206 }
195207 }
196208 // Set up the query
197- FHttpRequestRef Request = FHttpModule::Get ().CreateRequest ();
198- Request ->OnProcessRequestComplete ().BindUObject (this , &AGeocoder::ProcessLocationQueryResponse);
199- Query = FString::Printf (TEXT (" %s/?f=json&langCode=en&location=%f,%f" ), *Url, Point ->GetX (), Point ->GetY ());
200- Request ->SetURL (Query .Replace (TEXT (" " ), TEXT (" %20" )));
201- Request ->SetVerb (" GET" );
202- Request ->SetHeader (" Content-Type" , " x-www-form-urlencoded" );
203- Request ->ProcessRequest ();
209+ auto request = FHttpModule::Get ().CreateRequest ();
210+ request ->OnProcessRequestComplete ().BindUObject (this , &AGeocoder::ProcessLocationQueryResponse);
211+ query = FString::Printf (TEXT (" %s/?f=json&langCode=en&location=%f,%f" ), *url, point ->GetX (), point ->GetY ());
212+ request ->SetURL (query .Replace (TEXT (" " ), TEXT (" %20" )));
213+ request ->SetVerb (" GET" );
214+ request ->SetHeader (" Content-Type" , " x-www-form-urlencoded" );
215+ request ->ProcessRequest ();
204216 bWaitingForResponse = true ;
205217}
206218
207219// Parse the response for a reverse geocoding query
208220void AGeocoder::ProcessLocationQueryResponse (FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSucessfully) {
209- FString ResponseAddress = " " ;
210- FString Message ;
211- TSharedPtr<FJsonValue> Error ;
212- TSharedPtr<FJsonObject> JsonObj ;
213- TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create (Response->GetContentAsString ());
221+ FString responseAddress = " " ;
222+ FString message ;
223+ TSharedPtr<FJsonValue> error ;
224+ TSharedPtr<FJsonObject> jsonObj ;
225+ TSharedRef<TJsonReader<>> reader = TJsonReaderFactory<>::Create (Response->GetContentAsString ());
214226
215227 // Check if the query was successful
216- if (FJsonSerializer::Deserialize (Reader, JsonObj ) &&
228+ if (FJsonSerializer::Deserialize (reader, jsonObj ) &&
217229 Response->GetResponseCode () > 199 && Response->GetResponseCode () < 300 ) {
218230
219- TSharedPtr<FJsonValue> AddressField ;
220- if ((AddressField = JsonObj ->TryGetField ((TEXT (" address" ))))) {
221- JsonObj = AddressField ->AsObject ();
222- if (!JsonObj ->TryGetStringField (TEXT (" Match_addr" ), ResponseAddress )) {
223- ResponseAddress = TEXT (" Query did not return valid response" );
231+ TSharedPtr<FJsonValue> addressField ;
232+ if ((addressField = jsonObj ->TryGetField ((TEXT (" address" ))))) {
233+ jsonObj = addressField ->AsObject ();
234+ if (!jsonObj ->TryGetStringField (TEXT (" Match_addr" ), responseAddress )) {
235+ responseAddress = TEXT (" Query did not return valid response" );
224236 }
225237 }
226238 // If the server responded with an error, show the error message
227- else if ((Error = JsonObj ->TryGetField (TEXT (" error" )))) {
228- JsonObj = Error ->AsObject ();
229- if (WidgetSetInfoFunction && JsonObj ->TryGetStringField (TEXT (" message" ), Message )) {
230- UIWidget->ProcessEvent (WidgetSetInfoFunction, &Message );
239+ else if ((error = jsonObj ->TryGetField (TEXT (" error" )))) {
240+ jsonObj = error ->AsObject ();
241+ if (WidgetSetInfoFunction && jsonObj ->TryGetStringField (TEXT (" message" ), message )) {
242+ UIWidget->ProcessEvent (WidgetSetInfoFunction, &message );
231243 }
232244 }
233245 }
234- // Show the receivedd address
246+ // Show the received address
235247 if (QueryLocation != nullptr ) {
236- QueryLocation->UpdateAddressCue (ResponseAddress );
248+ QueryLocation->UpdateAddressCue (responseAddress );
237249 }
238250 bWaitingForResponse = false ;
239251}
@@ -247,29 +259,29 @@ void AGeocoder::SelectLocation(const FInputActionValue& value)
247259 return ;
248260 }
249261
250- FHitResult TraceHit ;
251- FVector WorldLocation ;
252- FVector WorldDirection ;
253- float TraceLength = 100000000 .f ;
254- APlayerController* PlayerController = UGameplayStatics::GetPlayerController (GetWorld (), 0 );
255- PlayerController ->DeprojectMousePositionToWorld (WorldLocation, WorldDirection );
262+ FHitResult traceHit ;
263+ FVector worldLocation ;
264+ FVector worldDirection ;
265+ float traceLength = 100000000 .f ;
266+ APlayerController* playerController = UGameplayStatics::GetPlayerController (GetWorld (), 0 );
267+ playerController ->DeprojectMousePositionToWorld (worldLocation, worldDirection );
256268
257- if (GetWorld ()->LineTraceSingleByChannel (TraceHit ,
258- WorldLocation, WorldLocation + TraceLength * WorldDirection , ECC_Visibility, FCollisionQueryParams ()))
269+ if (GetWorld ()->LineTraceSingleByChannel (traceHit ,
270+ worldLocation, worldLocation + traceLength * worldDirection , ECC_Visibility, FCollisionQueryParams ()))
259271 {
260- if (TraceHit .GetActor ()->GetClass () == AArcGISMapActor::StaticClass ())
272+ if (traceHit .GetActor ()->GetClass () == AArcGISMapActor::StaticClass ())
261273 {
262274 // Spawn a QueryLocation actor if it doesn't already exist
263275 if (QueryLocation == nullptr )
264276 {
265- FActorSpawnParameters SpawnParam = FActorSpawnParameters ();
266- SpawnParam .Owner = this ;
277+ auto spawnParam = FActorSpawnParameters ();
278+ spawnParam .Owner = this ;
267279 QueryLocation = GetWorld ()->SpawnActor <AQueryLocation>(AQueryLocation::StaticClass (),
268- FVector3d (0 .), FRotator (0 .), SpawnParam );
280+ FVector3d (0 .), FRotator (0 .), spawnParam );
269281 }
270282
271283 // Update the QueryLocation actor with the selected location
272- QueryLocation->SetupLocationQuery (TraceHit .ImpactPoint );
284+ QueryLocation->SetupLocationQuery (traceHit .ImpactPoint );
273285 AddTickPrerequisiteComponent (QueryLocation->ArcGISLocation );
274286 bShouldSendLocationQuery = true ;
275287 }
0 commit comments