/// <summary> /// Execute command. /// </summary> /// <param name="args">Command args.</param> protected override void _Execute(params object[] args) { System.Windows.Point point = (System.Windows.Point)args[0]; ESRI.ArcLogistics.Geometry.Point location = new ESRI.ArcLogistics.Geometry.Point(point.X, point.Y); IGeocodable geocodable = (IGeocodable)args[1]; // Save new GeoLocation anyway. geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point(point.X, point.Y); // If one or more address fields is not empty - do not fill them with new values // otherwise make reversegeocoding request and fill address fields. if (CommonHelpers.IsAllAddressFieldsEmpty(geocodable.Address)) { args[IS_RESPONSE_RECEIVED_INDEX] = _ProcessReverseGeocode(geocodable, location); } else { args[IS_RESPONSE_RECEIVED_INDEX] = true; // In case of manually filled address fields after setting position. // set locator to manually edited xy string manuallyEditedXY = (string)System.Windows.Application.Current.FindResource(MANUALLY_EDITED_XY_RESOURCE_NAME); if (geocodable.Address.MatchMethod == null || !geocodable.Address.MatchMethod.Equals(manuallyEditedXY, StringComparison.OrdinalIgnoreCase)) { geocodable.Address.MatchMethod = manuallyEditedXY; } } // Workaround - see method comment. CommonHelpers.FillAddressWithSameValues(geocodable.Address); }
/// <summary> /// Does objects reverse geocoding. /// </summary> /// <param name="objects">Objects to geocoding.</param> private void _ReverseGeocode(IList <AppData.DataObject> objects) { Debug.Assert(null != objects); // created Debug.Assert(0 < objects.Count); // not empty Debug.Assert(null != _checker); // inited AppGeometry.Envelope extent = App.Current.Map.ImportCheckExtent; int count = objects.Count; for (int index = 0; index < count; ++index) { _checker.ThrowIfCancellationRequested(); if (null == _detectedException) { // NOTE: do if geocoder in valid state IGeocodable geocodable = _GetGeocodable(objects[index]); if (geocodable.GeoLocation.HasValue) { if (extent.IsPointIn(geocodable.GeoLocation.Value)) { // reverse geocode Address geocodedAddress = _ReverseGeocodeSave(geocodable.GeoLocation.Value); if (null != geocodedAddress) { geocodedAddress.CopyTo(geocodable.Address); ++_geocodedCount; } } } } } }
/// <summary> /// Pan object geometry. /// </summary> /// <param name="editingObject">Editing object.</param> /// <param name="dx">Pan dx.</param> /// <param name="dy">Pan dy.</param> private void _PanObject(object editingObject, double dx, double dy) { Debug.Assert(editingObject != null); Debug.Assert(_markersLayer != null); IList <EditingMarker> list = (IList <EditingMarker>)_markersLayer.Collection; if (editingObject is IGeocodable) { IGeocodable geocodable = (IGeocodable)editingObject; if (geocodable.GeoLocation.HasValue) { geocodable.GeoLocation = new Point(geocodable.GeoLocation.Value.X + dx, geocodable.GeoLocation.Value.Y + dy); string manuallyEditedXY = (string)System.Windows.Application.Current.FindResource(MANUALLY_EDITED_XY_RESOURCE_NAME); if (geocodable.Address.MatchMethod == null || !geocodable.Address.MatchMethod.Equals(manuallyEditedXY, StringComparison.OrdinalIgnoreCase)) { geocodable.Address.MatchMethod = manuallyEditedXY; } } } else if (editingObject is Zone) { Zone zone = (Zone)editingObject; zone.Geometry = _PanGeometry(zone.Geometry, dx, dy); } else if (editingObject is Barrier) { Barrier barrier = (Barrier)editingObject; barrier.Geometry = _PanGeometry(barrier.Geometry, dx, dy); } }
/// <summary> /// Make string like 'Bevmo could not be found in Redlands,CA.' /// </summary> /// <param name="item">Geocodable item.</param> /// <returns>Geocode result string.</returns> private string _MakeNotFoundString(IGeocodable item) { string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME); string cityStateString = string.Empty; // Use both fields if both not empty. Use not empty otherwise. if (!string.IsNullOrEmpty(item.Address.Locality3) && !string.IsNullOrEmpty(item.Address.StateProvince)) { cityStateString = string.Format(CITY_STATE_FMT, item.Address.Locality3, item.Address.StateProvince); } else if (!string.IsNullOrEmpty(item.Address.Locality3)) { cityStateString = item.Address.Locality3; } else if (!string.IsNullOrEmpty(item.Address.StateProvince)) { cityStateString = item.Address.StateProvince; } string inString = string.Empty; // If city or state present - make "in" string. if (!string.IsNullOrEmpty(cityStateString)) { inString = string.Format((string)App.Current.FindResource(IN_ADDRESS_RESOURCE_NAME), cityStateString); } string result = string.Format(resultFmt, item.ToString(), inString); return(result); }
/// <summary> /// Parses batch geocoding result. Set geocode candidates values to relative object. /// </summary> /// <param name="candidates">Candidates from geocoding.</param> /// <param name="objects">Objects to geocoding.</param> private void _ParseBatchGeocodeResult(AddressCandidate[] candidates, IList <AppData.DataObject> objects) { Debug.Assert(null != objects); // created Debug.Assert(null != candidates); // created Debug.Assert(candidates.Length == objects.Count); // valid state Debug.Assert(null != _checker); // inited // valid check extent var importExtent = App.Current.Map.ImportCheckExtent; // init progress int count = objects.Count; for (int index = 0; index < count; ++index) { _checker.ThrowIfCancellationRequested(); // get current object AppData.DataObject obj = objects[index]; IGeocodable geocodable = _GetGeocodable(obj); bool needMessage = false; if (geocodable.IsGeocoded) { // add message - Could not locate object using X/Y attributes. // Order was located using address information instead Debug.Assert(!importExtent.IsPointIn(geocodable.GeoLocation.Value)); needMessage = true; } AddressCandidate candidate = candidates[index]; _UpdateGeocodableInfo(needMessage, candidate, obj); } }
/// <summary> /// Updates geocodable information. /// </summary> /// <param name="needMessage">Need show message.</param> /// <param name="candidate">Geocoded candidate (can be NULL).</param> /// <param name="obj">Source object to geocoded candidate.</param> private void _UpdateGeocodableInfo(bool needMessage, AddressCandidate candidate, AppData.DataObject obj) { Debug.Assert(null != obj); // Created. IGeocodable geocodable = _GetGeocodable(obj); geocodable.GeoLocation = null; if ((null == candidate) || (candidate.Score <= App.Current.Geocoder.MinimumMatchScore)) { // Not geocoded. geocodable.Address.MatchMethod = string.Empty; } else { GeocodeHelpers.SetCandidate(geocodable, candidate); ++_geocodedCount; // Store warning. if (needMessage) { string objectName = _informer.ObjectName; string errorTextFormat = App.Current.GetString("ImportProcessStatusRecordOutMapExtendGeocodedFormat", objectName.ToLower(), "{0}", objectName); var description = new MessageDetail(MessageType.Warning, errorTextFormat, obj); _details.Add(description); } } }
/// <summary> /// Make reverse geocode request and fill geocodable object with new address fields values. /// </summary> /// <param name="geocodable">Geocodable to fill.</param> /// <param name="location">Geolocation point for request.</param> /// <returns>Is responce was received.</returns> private bool _ProcessReverseGeocode(IGeocodable geocodable, ESRI.ArcLogistics.Geometry.Point location) { bool result = false; try { Address geocodedAddress = App.Current.Geocoder.ReverseGeocode(location); // In case of not empty response - fill address. if (geocodedAddress != null) { geocodedAddress.CopyTo(geocodable.Address); } else { geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME); } result = true; } catch (Exception ex) { if (ex is AuthenticationException || ex is CommunicationException) { string service = (string)App.Current.FindResource(GEOCODING_SERVICE_NAME_RESOURCE_NAME); CommonHelpers.AddServiceMessage(service, ex); } else { throw; } } return(result); }
/// <summary> /// Geocode order /// </summary> private void _Geocode() { if (OptimizePage.SelectedItems.Count == 1) { IGeocodable order = (IGeocodable)OptimizePage.SelectedItems[0]; OptimizePage.StartGeocoding(order); } }
/// <summary> /// Geocode locations /// </summary> protected override void _Geocode() { if (((ISupportSelection)ParentPage).SelectedItems.Count == 1) { IGeocodable location = (IGeocodable)((ISupportSelection)ParentPage).SelectedItems[0]; ((LocationsPage)ParentPage).StartGeocoding(location); } }
/// <summary> /// Check is location of geocodable object valid and replace it by candidate from local /// geocoder if exists. /// </summary> /// <param name="geocodable">Geocodable object to check.</param> /// <returns>Is geocodable object valid.</returns> private bool _SourceGeocodedObject(IGeocodable geocodable) { Debug.Assert(null != geocodable); // created bool isObjectGeocoded = false; // First check if name address pair exists in local geocoder database. // If exists - overwrite geolocation and address from it. App currentApp = App.Current; var localGeocoder = new LocalGeocoder(currentApp.Geocoder, currentApp.NameAddressStorage); var nameAddress = new NameAddress(); nameAddress.Name = geocodable.ToString(); nameAddress.Address = geocodable.Address.Clone() as Address; AddressCandidate localCandidate = localGeocoder.Geocode(nameAddress); if (localCandidate == null) { // Update from internal object information. AppGeometry.Envelope extent = currentApp.Map.ImportCheckExtent; if (extent.IsPointIn(geocodable.GeoLocation.Value)) { geocodable.Address.MatchMethod = currentApp.FindString("ImportSourceMatchMethod"); isObjectGeocoded = true; // Full address property must be combined from other fields, because // it is not importing field. if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields) { GeocodeHelpers.SetFullAddress(geocodable.Address); } else { // Do nothing: do not update full address since // it is used for geocoding in Single Address Field Format. } } // Else could not locate object using X/Y attributes - need geocode. } else { // Init from local candidate. // Set location. geocodable.GeoLocation = new AppGeometry.Point(localCandidate.GeoLocation.X, localCandidate.GeoLocation.Y); // Set address. localCandidate.Address.CopyTo(geocodable.Address); isObjectGeocoded = true; } return(isObjectGeocoded); }
/// <summary> /// Get geocode result for subpage. /// </summary> /// <param name="item">Geocoded item.</param> /// <param name="context">Ignored.</param> /// <returns>Current geocode process result.</returns> public string GetGeocodeResultString(IGeocodable item, object context) { if (item == null) { return(string.Empty); } string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME); string result = string.Format(resultFmt, item.ToString()); return(result); }
/// <summary> /// Get current geocodable object. /// </summary> /// <param name="mapctrl">Map control.</param> /// <returns>Current geocodable object.</returns> private IGeocodable _GetCurrentGeocodableObject(MapControl mapctrl) { // Current geocodable object is edited object or, // in case of address by point tool activated, selected object. IGeocodable result = mapctrl.EditedObject as IGeocodable; if (result == null && mapctrl.CurrentTool is AddressByPointTool) { Debug.Assert(mapctrl.SelectedItems.Count == 1); result = mapctrl.SelectedItems[0] as IGeocodable; } return(result); }
/// <summary> /// Get street candidate. Extract street name, check that part of street name wasn't removed and try to geocode. /// </summary> /// <param name="geocodable">Geocodable object to geocode,</param> /// <param name="streetLocators">Street locators.</param> /// <param name="candidatesIncludedDisabledLocators">Geocoded candidates.</param> /// <returns>Street candidate.</returns> private static List <AddressCandidate> _GetStreetCandidates( IGeocodable geocodable, IEnumerable <LocatorInfo> streetLocators, IEnumerable <AddressCandidate> candidatesIncludedDisabledLocators) { Debug.Assert(geocodable != null); Debug.Assert(streetLocators != null); Debug.Assert(candidatesIncludedDisabledLocators != null); List <AddressCandidate> streetCandidates = null; if (!string.IsNullOrEmpty(geocodable.Address.AddressLine)) { string street = _ExtractStreet(geocodable.Address.AddressLine); if (!street.Equals(geocodable.Address.AddressLine, StringComparison.OrdinalIgnoreCase)) { // If number removed from street address check that number wasn't part of street name. For example "8th ave". ICloneable cloneableItem = geocodable as ICloneable; IGeocodable geocodableWithoutHouseNumber = (IGeocodable)cloneableItem.Clone(); geocodableWithoutHouseNumber.Address.AddressLine = street; // Get candidates for address with removed number. List <AddressCandidate> candidatesForRemovedHouseNumber = DoGeocode(geocodableWithoutHouseNumber, true, false); List <AddressCandidate> streetCandidatesForRemovedHouseNumber = _GetCandidatesFromLocators(streetLocators, candidatesForRemovedHouseNumber); // If best candidate from street locator exists - use it. if (streetCandidatesForRemovedHouseNumber.Count > 0) { streetCandidates = streetCandidatesForRemovedHouseNumber; } } } // If street candidate not set yet - find best candidate from already geocoded candidates. if (streetCandidates == null) { streetCandidates = _GetCandidatesFromLocators(streetLocators, candidatesIncludedDisabledLocators); } // Fill address fields of street candidate. foreach (AddressCandidate candidate in streetCandidates) { ParseAndFillAddress(candidate.Address); } return(streetCandidates); }
/// <summary> /// Is locator address fields empty. /// </summary> /// <param name="geocodable">Geocodable object.</param> /// <returns>Is locator address fields empty.</returns> public static bool IsActiveAddressFieldsEmpty(IGeocodable geocodable) { bool isEmpty = true; foreach (AddressField addressField in App.Current.Geocoder.AddressFields) { if (!string.IsNullOrEmpty(geocodable.Address[addressField.Type])) { isEmpty = false; break; } } return(isEmpty); }
/// <summary> /// Show hint "Could not located, but zoomed..." /// </summary> /// <param name="geocodableItem">Geocodable object.</param> /// <param name="candidatesToZoom">Address to which map was zoomed. Null if not zoomed.</param> public void ShowZoomToCandidatePopup(IGeocodable geocodableItem, AddressCandidate[] candidatesToZoom) { if (_isGeocodingHintInitialized) { // Show hint suspendedly because final selection changed event in datagrid control is suspended. // And so hint will be hided on selection changed. Dispatcher.BeginInvoke(new Action(delegate() { if (SelectedItems.Count > 0 && SelectedItems[0] == geocodableItem) { GeocodingHint.ShowHint(geocodableItem, candidatesToZoom); } }), DispatcherPriority.Background); } }
/// <summary> /// Populate update object warning. /// </summary> /// <param name="obj">Updated object.</param> private void _AddUpdateObjectWarning(AppData.DataObject obj) { Debug.Assert(null != obj); // created IGeocodable geocodable = obj as IGeocodable; if (null != geocodable) { // NOTE: workaround - see method comment CommonHelpers.FillAddressWithSameValues(geocodable.Address); } string statusText = App.Current.FindString("ImportProcessStatusUpdated"); string textFormat = _objectsName + FORMAT_UPDATE_MESSAGE_PART + statusText; _details.Add(new MessageDetail(MessageType.Warning, textFormat, obj)); }
/// <summary> /// Does source geocoding. /// </summary> /// <param name="objects">Objects to geocoding.</param> private void _SourceGeocode(IList <AppData.DataObject> objects) { Debug.Assert(null != objects); // created Debug.Assert(0 < objects.Count); // not empty Debug.Assert(null != _checker); // inited // init progress int count = objects.Count; // geocode process var ungeocoded = new List <AppData.DataObject>(); for (int index = 0; index < count; ++index) { _checker.ThrowIfCancellationRequested(); AppData.DataObject obj = objects[index]; IGeocodable geocodable = _GetGeocodable(obj); bool isObjectGeocoded = false; if (geocodable.IsGeocoded) { // check is geocodable object valid and set candidate // from local geocoder if exists isObjectGeocoded = _SourceGeocodedObject(geocodable); if (isObjectGeocoded) { ++_geocodedCount; } } if (!isObjectGeocoded) { ungeocoded.Add(obj); } } _checker.ThrowIfCancellationRequested(); // geocode all ungeocoded object by batch geocode if (0 < ungeocoded.Count) { _BatchGeocode(ungeocoded); } }
/// <summary> /// Does empty geocoding. /// </summary> /// <param name="objects">Objects to geocoding.</param> private void _EmptyGeocode(IList <AppData.DataObject> objects) { Debug.Assert(null != objects); // created Debug.Assert(0 < objects.Count); // not empty Debug.Assert(null != _checker); // inited int count = objects.Count; for (int index = 0; index < objects.Count; ++index) { _checker.ThrowIfCancellationRequested(); IGeocodable geocodable = _GetGeocodable(objects[index]); geocodable.GeoLocation = null; Debug.Assert(null != geocodable.Address); // created geocodable.Address.MatchMethod = string.Empty; } }
/// <summary> /// Method gets location point of Depot. /// </summary> /// <param name="loc">Depot to get information from.</param> /// <returns>Point location.</returns> /// <exception cref="RouteException">If location is not geocoded.</exception> private static Point _GetDepotPoint(Location loc) { Debug.Assert(loc != null); IGeocodable gc = loc as IGeocodable; Debug.Assert(gc != null); if (!gc.IsGeocoded) { throw new RouteException(String.Format( Properties.Messages.Error_LocationIsUngeocoded, loc.Id)); } Debug.Assert(gc.GeoLocation != null); return((Point)gc.GeoLocation); }
/// <summary> /// React on mouse up. /// </summary> /// <param name="modifierKeys">Modifier keys state.</param> /// <param name="x">X coord.</param> /// <param name="y">Y coord.</param> public void OnMouseUp(MouseButton pressedButton, ModifierKeys modifierKeys, double x, double y) { Debug.Assert(_mapControl != null); _EndPan(); if (_editingInProcess) { App.Current.Project.Save(); // Save to local geocoder database. Order order = _mapControl.EditedObject as Order; if (order != null) { NameAddressRecord nameAddressRecord = CommonHelpers.CreateNameAddressPair(order, null); // Do save in local storage. App.Current.NameAddressStorage.InsertOrUpdate(nameAddressRecord, App.Current.Geocoder.AddressFormat); } // Check new position is near to road. Set match method if not. IGeocodable geocodable = _mapControl.EditedObject as IGeocodable; if (geocodable != null) { Address addressUnderPoint = _ReverseGeocode(geocodable.GeoLocation.Value); if (addressUnderPoint == null) { geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME); } } if (OnComplete != null) { OnComplete(this, EventArgs.Empty); } _editingInProcess = false; _editedGraphic = null; } }
/// <summary> /// Creates address list for input objects. /// </summary> /// <param name="objects">Source object.</param> /// <returns>Created address list for input objects.</returns> /// <remarks>Progress show.</remarks> private Address[] _CreateAddressList(IList <AppData.DataObject> objects) { Debug.Assert(null != objects); // created Debug.Assert(0 < objects.Count); // not empty Debug.Assert(null != _checker); // inited // init progress int count = objects.Count; var addresses = new Address[count]; for (int index = 0; index < count; ++index) { _checker.ThrowIfCancellationRequested(); IGeocodable geocodable = _GetGeocodable(objects[index]); addresses[index] = geocodable.Address; } return(addresses); }
/// <summary> /// Make string parts like 'We couldn’t find… so we’ve zoomed to…' /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address. /// </summary> /// <param name="item">Geocodable item.</param> /// <param name="candidateToZoom">First candidate to zoom.</param> /// <returns>Geocode result string parts.</returns> public static string GetZoomedAddress(IGeocodable item, AddressCandidate candidateToZoom) { LocatorType?locatorType = GeocodeHelpers.GetLocatorTypeOfCandidate(candidateToZoom); string zoomedAddress; // If locator type of candidate is street than get Address Line. if (locatorType.HasValue && locatorType.Value == LocatorType.Street && !string.IsNullOrEmpty(item.Address.AddressLine)) { // Extract street name. zoomedAddress = GeocodeHelpers.ExtractStreet(item.Address.AddressLine); } else { // Otherwise use full address. zoomedAddress = candidateToZoom.Address.FullAddress; } return(zoomedAddress); }
/// <summary> /// Get geocode result for subpage. /// </summary> /// <param name="item">Geocoded item.</param> /// <param name="context">Candidates to zoom.</param> /// <returns>Current geocode process result.</returns> public string GetGeocodeResultString(IGeocodable item, object context) { if (item == null) { return(string.Empty); } AddressCandidate[] candidatesToZoom = context as AddressCandidate[]; string result; if (candidatesToZoom == null || candidatesToZoom.Length == 0) { result = _MakeNotFoundString(item); } else { result = _MakeNotFoundButZoomedString(item, candidatesToZoom[0]); } return(result); }
/// <summary> /// Show hint. /// </summary> /// <param name="geocodableItem">Geocodable item.</param> /// <param name="candidatesToZoom">Candidates to zoom.</param> public void ShowHint(IGeocodable geocodableItem, AddressCandidate[] candidatesToZoom) { _candidatesToZoom = candidatesToZoom; string titleFmt = (string)App.Current.FindResource(GEOCODE_RESULT_NOT_ZOOMED_RESOURCE_NAME); TitleText.Text = string.Format(titleFmt, geocodableItem.ToString()); if (candidatesToZoom == null || candidatesToZoom.Length == 0) { // If we cant zoom to candidtes - hide corresponding rextblocks. ZoomedToText.Visibility = Visibility.Collapsed; ZoomedAddress.Visibility = Visibility.Collapsed; ZoomedAddressType.Visibility = Visibility.Collapsed; } else { string zoomedAddress = GeocodeHelpers.GetZoomedAddress(geocodableItem, candidatesToZoom[0]); _InitZoomedAddressTypeText(candidatesToZoom[0]); // Show "Zoomed to..." text. ZoomedAddress.Text = zoomedAddress; ZoomedAddress.Visibility = Visibility.Visible; ZoomedToText.Visibility = Visibility.Visible; } Visibility = Visibility.Visible; UpdateLayout(); Vector toolsPanelOffset = VisualTreeHelper.GetOffset(_mapControl.toolPanel); // Set top of hint under title, tools. Canvas.SetTop(this, _mapControl.toolPanel.Margin.Top + toolsPanelOffset.Y + _mapControl.toolPanel.ActualHeight); Canvas.SetLeft(this, _mapControl.ActualWidth - this.ActualWidth - _mapControl.toolPanel.Margin.Right); }
/// <summary> /// Do geocode of geocodable object. /// </summary> /// <param name="geocodable">Item to geocode.</param> /// <param name="useLocalAsPrimary">Is item just created.</param> /// <param name="includeDisabledLocators">Is need to add candidates from disabled locators.</param> /// <returns>Candidates list.</returns> public static List <AddressCandidate> DoGeocode(IGeocodable geocodable, bool useLocalAsPrimary, bool includeDisabledLocators) { List <AddressCandidate> candidates = null; App.Current.MainWindow.Cursor = Cursors.Wait; try { Order order = geocodable as Order; Location location = geocodable as Location; if (order != null) { candidates = _DoLocalOrderGeocode(order, useLocalAsPrimary, includeDisabledLocators); } else if (location != null) { candidates = _DoGeocodeLocation(location, includeDisabledLocators); } } catch (Exception ex) { if (MustThrowException(ex)) { throw; } } finally { App.Current.MainWindow.Cursor = Cursors.Arrow; } if (candidates == null) { candidates = new List <AddressCandidate>(); } return(candidates); }
/// <summary> /// Make string like 'Bevmo couldn’t be located, we’ve zoomed to Pat’s Ranch Rd. Use the pushpin tool to locate exactly.' /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address. /// </summary> /// <param name="item">Geocodable item.</param> /// <param name="candidateToZoom">First candidate to zoom.</param> /// <returns>Geocode result string.</returns> private string _MakeNotFoundButZoomedString(IGeocodable item, AddressCandidate candidateToZoom) { string messageFmt = (string)App.Current.FindResource(GEOCODE_RESULT_ZOOMED_RESOURCE_NAME); StringBuilder stringBuilder = new StringBuilder(); // Add "Not located, but zoomed to..." string. stringBuilder.AppendFormat(messageFmt, item.ToString()); // Add zoomed address. string zoomedAddress = GeocodeHelpers.GetZoomedAddress(item, candidateToZoom); stringBuilder.Append(zoomedAddress); // Add dot at the end of sentence. stringBuilder.Append(MESSAGE_STRING_PARTS_DELIMETER); // Add "Use pushpin" string. stringBuilder.Append((string)App.Current.FindResource(USE_PUSHPIN_RESOURCE_NAME)); string result = stringBuilder.ToString(); return(result); }
/// <summary> /// Save manual order geocoding results to local storage. /// </summary> /// <param name="geocodable">Geocoding object.</param> /// <param name="oldAddress">Address before geocoding.</param> private void _SaveToLocalAddressNameStorage(IGeocodable geocodable, Address oldAddress) { // Do nothing in case of geocodable object is location. Order order = geocodable as Order; if (order != null) { NameAddressRecord nameAddressRecord = CommonHelpers.CreateNameAddressPair(order, oldAddress); // Do save in local storage. App.Current.NameAddressStorage.InsertOrUpdate(nameAddressRecord, App.Current.Geocoder.AddressFormat); } }
/// <summary> /// Get candidates from not primary sublocators. City, Zip, Street candidates. /// </summary> /// <param name="geocodable">Geocodable object to validation</param> /// <param name="candidatesIncludedDisabledLocators">Candidates from all locators.</param> /// <returns>City, Zip, Street candidates.</returns> public static IEnumerable <AddressCandidate> GetBestCandidatesFromNotPrimaryLocators(IGeocoder geocoder, IGeocodable geocodable, IEnumerable <AddressCandidate> candidatesIncludedDisabledLocators) { Debug.Assert(geocodable != null); Debug.Assert(candidatesIncludedDisabledLocators != null); List <AddressCandidate> candidatesFromNotPrimaryLocators = new List <AddressCandidate>(); // If current geocoder is ArcGiscomGeocoder. var arcgisgeocoder = geocoder as ArcGiscomGeocoder; if (arcgisgeocoder != null) { // If we have candidates - return first of them as a result. if (candidatesIncludedDisabledLocators.Any()) { candidatesFromNotPrimaryLocators.Add(candidatesIncludedDisabledLocators.First()); } return(candidatesFromNotPrimaryLocators); } if (App.Current.Geocoder.IsCompositeLocator) { List <LocatorInfo> sublocators = new List <LocatorInfo>(); sublocators.AddRange(App.Current.Geocoder.Locators); // Get best street candidate. List <LocatorInfo> streetLocators = _ExtractLocators(AddressPart.AddressLine, sublocators); List <AddressCandidate> streetCandidates = _GetStreetCandidates(geocodable, streetLocators, candidatesIncludedDisabledLocators); if (streetCandidates != null) { candidatesFromNotPrimaryLocators.AddRange(streetCandidates); } if (candidatesFromNotPrimaryLocators.Count == 0) { // Get best zip candidate. List <LocatorInfo> zipLocators = _ExtractLocators(AddressPart.PostalCode1, sublocators); AddressCandidate bestCandidate = _GetBestCandidateFromLocators(zipLocators, candidatesIncludedDisabledLocators); if (bestCandidate == null) { // Get best cityState candidate. List <LocatorInfo> cityStateLocators = _ExtractLocators(AddressPart.StateProvince, sublocators); bestCandidate = _GetBestCandidateFromLocators(cityStateLocators, candidatesIncludedDisabledLocators); } if (bestCandidate != null) { candidatesFromNotPrimaryLocators.Add(bestCandidate); } } } return(candidatesFromNotPrimaryLocators); }
/// <summary> /// Get geocode result for subpage. /// </summary> /// <param name="item">Geocoded item.</param> /// <param name="context">Candidates to zoom.</param> /// <returns>Current geocode process result.</returns> public string GetGeocodeResultString(IGeocodable item, object context) { if (item == null) return string.Empty; AddressCandidate[] candidatesToZoom = context as AddressCandidate[]; string result; if (candidatesToZoom == null || candidatesToZoom.Length == 0) { result = _MakeNotFoundString(item); } else { result = _MakeNotFoundButZoomedString(item, candidatesToZoom[0]); } return result; }
/// <summary> /// Make reverse geocode request and fill geocodable object with new address fields values. /// </summary> /// <param name="geocodable">Geocodable to fill.</param> /// <param name="location">Geolocation point for request.</param> /// <returns>Is responce was received.</returns> private bool _ProcessReverseGeocode(IGeocodable geocodable, ESRI.ArcLogistics.Geometry.Point location) { bool result = false; try { Address geocodedAddress = App.Current.Geocoder.ReverseGeocode(location); // In case of not empty response - fill address. if (geocodedAddress != null) { geocodedAddress.CopyTo(geocodable.Address); } else { geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME); } result = true; } catch (Exception ex) { if (ex is AuthenticationException || ex is CommunicationException) { string service = (string)App.Current.FindResource(GEOCODING_SERVICE_NAME_RESOURCE_NAME); CommonHelpers.AddServiceMessage(service, ex); } else throw; } return result; }
/// <summary> /// Show popup with geocoded address. /// </summary> /// <param name="e">Reverse geocoding completed event args.</param> private void _ShowAddress(AsyncReverseGeocodedEventArgs e) { IGeocodable geocodable = _GetCurrentGeocodableObject(_mapControl); System.Windows.Point initialPoint = (System.Windows.Point)e.UserState; if (geocodable != null && _enabled && _mapControl.LastCursorPos.HasValue && _mapControl.LastCursorPos.Value.X == initialPoint.X && _mapControl.LastCursorPos.Value.Y == initialPoint.Y) { Point cursorPos = _mapControl.LastCursorPos.Value; _HideAddressPopups(); Rect mapRect = new Rect(0, 0, _mapControl.map.ActualWidth, _mapControl.map.ActualHeight); Point objectLocation = _ConvertToScreenPos(e.Location); // Create canvas with dotted line. Canvas canvas = _CreateDottedLineCanvas(objectLocation, _mapControl.LastCursorPos.Value); // Get coordinates of top left of canvas. double canvasLeft = cursorPos.X; if (objectLocation.X < canvasLeft) { canvasLeft = objectLocation.X; } double canvasTop = cursorPos.Y; if (objectLocation.Y < canvasTop) { canvasTop = objectLocation.Y; } Rect canvasRect = new System.Windows.Rect(canvasLeft, canvasTop, canvas.Width, canvas.Height); if (mapRect.Contains(canvasRect)) { canvasRect.Offset(0, -canvasRect.Height); _dottedLinePopup = _CreatePopup(null, canvas, canvasRect); Point popupPosition = _ConvertToScreenPos(e.Location); // Show ellipse popup in position of reverse geocoded object. Rect ellipseRect = new System.Windows.Rect(popupPosition.X - _sizeOfEllipse / 2, popupPosition.Y - 3 * _sizeOfEllipse / 2, _popupWidth, _popupHeigth); _ellipsePopup = _CreatePopup("MapPopupEllipseStyle", null, ellipseRect); // Set cursor to popup. Cursor will be set on ellipse. _ellipsePopup.Cursor = _mapControl.map.Cursor; // Subscribe on mouse down to reraise mouse down on map. _ellipsePopup.MouseDown += new MouseButtonEventHandler(_EllipsePopupMouseDown); // Show address popup higher than IGeocodable object. Rect addressRect = new System.Windows.Rect(popupPosition.X + _popupX, popupPosition.Y - _popupY, _popupWidth, _popupHeigth); string address = _GetAddressValue(e.Address); _addressPopup = _CreatePopup("MapPopupStyle", address, addressRect); } } }
/// <summary> /// Do regeocoding /// </summary> /// <param name="location">Location to regeocode</param> public void StartGeocoding(IGeocodable location) { _geocodablePage.StartGeocoding(location); }
/// <summary> /// Start geocoding. /// </summary> /// <param name="geocodable">Item to geocode.</param> /// <param name="useLocalAsPrimary">Is item just created.</param> private void _StartGeocoding(IGeocodable geocodable, bool useLocalAsPrimary) { CandidatesToZoom = null; _mapCtrl.HideZoomToCandidatePopup(); // Do not need to start geocoding if geocodable object is far from road. Geocode will be failed. string farFromRoadMatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME); if (geocodable.Address.MatchMethod != null && geocodable.Address.MatchMethod.Equals(farFromRoadMatchMethod, StringComparison.OrdinalIgnoreCase)) { return; } // If try to geocode with edited address fields during another geocoding process. if (IsGeocodingInProcess) { _candidateSelect.CandidateChanged -= new EventHandler(_CandidateChanged); _Clear(); _candidateSelect.CandidateChanged += new EventHandler(_CandidateChanged); } IsGeocodingInProcess = true; if (GeocodingStarted != null) { GeocodingStarted(this, EventArgs.Empty); } List<AddressCandidate> candidates = GeocodeHelpers.DoGeocode(geocodable, useLocalAsPrimary, true); var minimumMatchScore = App.Current.Geocoder.MinimumMatchScore; _ProcessGeocodingResults(geocodable, candidates, minimumMatchScore); _isAddressChanged = false; }
/// <summary> /// Finish geocoding and try to zoom near. /// </summary> /// <param name="geocoder">Geocoder which found candidates.</param> /// <param name="geocodable">Item to geocode.</param> /// <param name="allCandidates">All candidates, returned for current geocoded item.</param> private void _ProcessCandidatesNotFound(IGeocoder geocoder, IGeocodable geocodable, IEnumerable<AddressCandidate> allCandidates) { // Set candidates to zoom. var candidatesFromNotPrimaryLocators = GeocodeHelpers.GetBestCandidatesFromNotPrimaryLocators(geocoder, geocodable, allCandidates); CandidatesToZoom = candidatesFromNotPrimaryLocators.ToArray(); if (CandidatesNotFound != null) CandidatesNotFound(this, EventArgs.Empty); AddressCandidate zoomedCandidate = null; // Zoom to candidates from not primary locators. if (CandidatesToZoom != null && CandidatesToZoom.Length > 0) { MapExtentHelpers.ZoomToCandidates(_mapCtrl, CandidatesToZoom); zoomedCandidate = CandidatesToZoom[0]; } // Show popup on map if not in fleet wizard. if (!ParentIsFleetWisard) _mapCtrl.ShowZoomToCandidatePopup(geocodable, CandidatesToZoom); IsGeocodingInProcess = false; }
/// <summary> /// React on new item commited. /// </summary> public void OnNewItemCommitted() { Debug.Assert(_currentItem != null); _canceledByGrid = true; EditEnded(false); _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged); _canceledByGrid = false; _SetAddressByPointToolEnabled(false); _currentItem = null; }
/// <summary> /// React on cancelling new item. /// </summary> public void OnNewItemCancelling() { Debug.Assert(_parentLayer != null); // Supporting API issues. Needed in case of external new item creating canceling. if (_currentItem == null) return; _canceledByGrid = true; ObjectLayer.DeleteObject(_currentItem, _parentLayer.MapLayer); EditEnded(false); _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged); if (IsGeocodingInProcess) { _EndGeocoding(false); } else { _currentItem = null; } _canceledByGrid = false; _SetAddressByPointToolEnabled(false); }
/// <summary> /// Process geocoding result. /// </summary> /// <param name="geocodable">Item to geocode.</param> /// <param name="allCandidates">Candidates list from all locators, include not primary.</param> /// <param name="minimumMatchScore">Specifies the minimum score value at which candidate /// will be treated as matched.</param> private void _ProcessGeocodingResults( IGeocodable geocodable, List<AddressCandidate> allCandidates, int minimumMatchScore) { _ProcessGeocodingCandidates(allCandidates, geocodable, minimumMatchScore); if (IsGeocodingInProcess) { _ExpandCandidateSelect(); _SetMapviewToCandidates(); _mapCtrl.SetEditingMapLayersOpacity(true); // React on map size changing only if map is initialized. if (_mapCtrl.Map.IsInitialized()) _mapCtrl.map.SizeChanged += new SizeChangedEventHandler(_MapSizeChanged); } else { // In case of we have geocode candidates at start, but with newly address data we haven't. _CollapseCandidateSelect(); // Current item can be not null only in case of geocoding in progress or editing in progress. if (!_geocodableGrid.IsItemBeingEdited) _currentItem = null; } }
/// <summary> /// React on commiting edit. /// </summary> /// <param name="args">Commiting event args.</param> /// <param name="canStartGeocoding">Flag for accepting geocoding start.</param> public void OnCommittingEdit(DataGridItemCancelEventArgs args, bool canStartGeocoding) { Debug.Assert(args != null); _canceledByGrid = true; IGeocodable geocodable = (IGeocodable)args.Item; if (geocodable != _currentItem) { args.Cancel = true; } if (_isAddressChanged && canStartGeocoding) { _StartGeocoding(_currentItem, true); if (!IsGeocodingInProcess) { _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged); } } EditEnded(false); _canceledByGrid = false; if (!IsGeocodingInProcess) { _currentItem = null; } }
/// <summary> /// React on beginning edit. /// </summary> /// <param name="args">Beginning edit args.</param> public void OnBeginningEdit(DataGridItemCancelEventArgs args) { Debug.Assert(args != null); // if geocoding in process and try to edit not geocoding geocodable object - than cancel it IGeocodable current = (IGeocodable)args.Item; // in case of deleting edited - cancel beginning edit if ((IsGeocodingInProcess && current != _currentItem)) { args.Cancel = true; } else { _currentItem = args.Item as IGeocodable; _currentItem.Address.PropertyChanged += new PropertyChangedEventHandler(_AddressPropertyChanged); _editStartedByGrid = true; _StartEdit(_currentItem); _editStartedByGrid = false; } }
/// <summary> /// End geocoding. /// </summary> /// <param name="needToCancelEdit">Is need to cancel edit. Is used because /// on "cancelling new item" call "cancelling new item" again.</param> private void _EndGeocoding(bool needToCancelEdit) { Debug.Assert(_mapCtrl != null); Debug.Assert(IsGeocodingInProcess); _mapCtrl.IgnoreSizeChanged = true; // Workaround - see method comment. CommonHelpers.FillAddressWithSameValues(_currentItem.Address); _mapCtrl.SetEditingMapLayersOpacity(false); IsGeocodingInProcess = false; _isAddressChanged = false; _parentLayer.Selectable = true; _Clear(); _CollapseCandidateSelect(); if (_currentItem != null) { _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged); } if (App.Current.Project != null) { App.Current.Project.Save(); } // End edit in data grid. if (needToCancelEdit && !_canceledByGrid && _geocodableGrid.IsItemBeingEdited) { _EndEditInGrid(); } _currentItem = null; }
/// <summary> /// Do regeocoding. /// </summary> /// <param name="geocodable">Geocodable to regeocode.</param> public void StartGeocoding(IGeocodable geocodable) { Debug.Assert(geocodable != null); _currentItem = geocodable; _StartGeocoding(geocodable, false); }
/// <summary> /// If address is empty show message. /// </summary> /// <param name="geocodable">Geocodable item.</param> private void _ShowReverseGeocodingErrorMessage(IGeocodable geocodable) { string name = string.Empty; string formatStr = string.Empty; // Extract name and format string. Order order = geocodable as Order; Location location = geocodable as Location; if (order != null) { name = order.Name; formatStr = (string)App.Current.FindResource(ORDER_FAR_FROM_ROAD_RESOURCE_NAME); } else if (location != null) { name = location.Name; formatStr = (string)App.Current.FindResource(LOCATION_FAR_FROM_ROAD_RESOURCE_NAME); } else { // Geocodable object must be order or location. Debug.Assert(false); } if (!string.IsNullOrEmpty(formatStr)) { // Show error. string message = string.Format(formatStr, name); App.Current.Messenger.AddError(message); } }
/// <summary> /// Validates and fixes candidates with incorrect locations. /// </summary> /// <param name="candidates">The reference to the collection of address candidates to /// be validated and fixed.</param> /// <param name="geocodable">The reference to the geocodable object used for retrieving /// candidates collection.</param> /// <returns>A reference to the collection of address candidates with fixed /// locations.</returns> private IEnumerable<AddressCandidate> _GetValidLocations( IEnumerable<AddressCandidate> candidates, IGeocodable geocodable) { Debug.Assert(candidates != null); Debug.Assert(candidates.All(candidate => candidate != null)); Debug.Assert(geocodable != null); List<int> incorrectCandidates = new List<int>(); try { var streetsGeocoder = App.Current.StreetsGeocoder; var locationValidator = new LocationValidator(streetsGeocoder); incorrectCandidates = locationValidator .FindIncorrectLocations(candidates) .ToList(); } catch (Exception ex) { if (GeocodeHelpers.MustThrowException(ex)) { throw; } } if (!incorrectCandidates.Any()) { return candidates; } // Get incorrect address candidates. List<AddressCandidate> allCandidates = candidates.ToList(); var invalidAddressCandidates = incorrectCandidates .Select(index => allCandidates[index]) .ToList(); // Get all candidates which is not invalid. var result = candidates .Except(invalidAddressCandidates) .ToList(); return result; }
/// <summary> /// Processes geocoding candidates. /// </summary> /// <param name="allCandidates">The reference to a collection of all geocoding /// candidates.</param> /// <param name="geocodable">The reference to an object to be geocoded.</param> /// <param name="minimumMatchScore">Specifies the minimum score value at which candidate /// will be treated as matched.</param> private void _ProcessGeocodingCandidates( IEnumerable<AddressCandidate> allCandidates, IGeocodable geocodable, int minimumMatchScore) { Debug.Assert(allCandidates != null); Debug.Assert(allCandidates.All(candidate => candidate != null)); Debug.Assert(geocodable != null); var candidates = GeocodeHelpers.SortCandidatesByPrimaryLocators( App.Current.Geocoder, allCandidates); if (!candidates.Any()) { _ProcessCandidatesNotFound(App.Current.Geocoder, geocodable, allCandidates.ToList()); return; } candidates = _GetValidLocations(candidates, geocodable).ToList(); var distinctCandidates = _FilterSameCandidates(candidates, minimumMatchScore).ToList(); var matchedCandidates = distinctCandidates .Where(candidate => candidate.Score >= minimumMatchScore) .ToList(); if (matchedCandidates.Count == 1) { _ProcessMatchFound(geocodable, matchedCandidates.First()); } else if (matchedCandidates.Count > 0) { // Find candidates with 100% score. var maxScoreCandidates = matchedCandidates .Where(candidate => candidate.Score == 100) .ToList(); if (maxScoreCandidates.Count == 1) // If found ONE candidate with 100% score, then choose it. _ProcessMatchFound(geocodable, maxScoreCandidates.First()); else // If not found 100% candidates or found more than ONE, show candidates. _ProcessCandidatesFound(matchedCandidates); } else { var topCandidates = distinctCandidates .OrderByDescending(candidate => candidate.Score) .Take(MAX_CANDIDATE_COUNT) .ToList(); if (topCandidates.Count > 0) _ProcessCandidatesFound(topCandidates); else _ProcessCandidatesNotFound(App.Current.Geocoder, geocodable, allCandidates); } }
/// <summary> /// Do geocode of geocodable object. /// </summary> /// <param name="geocodable">Item to geocode.</param> /// <param name="useLocalAsPrimary">Is item just created.</param> /// <param name="includeDisabledLocators">Is need to add candidates from disabled locators.</param> /// <returns>Candidates list.</returns> public static List<AddressCandidate> DoGeocode(IGeocodable geocodable, bool useLocalAsPrimary, bool includeDisabledLocators) { List<AddressCandidate> candidates = null; App.Current.MainWindow.Cursor = Cursors.Wait; try { Order order = geocodable as Order; Location location = geocodable as Location; if (order != null) { candidates = _DoLocalOrderGeocode(order, useLocalAsPrimary, includeDisabledLocators); } else if (location != null) { candidates = _DoGeocodeLocation(location, includeDisabledLocators); } } catch (Exception ex) { if (MustThrowException(ex)) { throw; } } finally { App.Current.MainWindow.Cursor = Cursors.Arrow; } if (candidates == null) { candidates = new List<AddressCandidate>(); } return candidates; }
/// <summary> /// Get candidates from not primary sublocators. City, Zip, Street candidates. /// </summary> /// <param name="geocodable">Geocodable object to validation</param> /// <param name="candidatesIncludedDisabledLocators">Candidates from all locators.</param> /// <returns>City, Zip, Street candidates.</returns> public static IEnumerable<AddressCandidate> GetBestCandidatesFromNotPrimaryLocators(IGeocoder geocoder, IGeocodable geocodable, IEnumerable<AddressCandidate> candidatesIncludedDisabledLocators) { Debug.Assert(geocodable != null); Debug.Assert(candidatesIncludedDisabledLocators != null); List<AddressCandidate> candidatesFromNotPrimaryLocators = new List<AddressCandidate>(); // If current geocoder is ArcGiscomGeocoder. var arcgisgeocoder = geocoder as ArcGiscomGeocoder; if (arcgisgeocoder != null) { // If we have candidates - return first of them as a result. if (candidatesIncludedDisabledLocators.Any()) candidatesFromNotPrimaryLocators.Add(candidatesIncludedDisabledLocators.First()); return candidatesFromNotPrimaryLocators; } if (App.Current.Geocoder.IsCompositeLocator) { List<LocatorInfo> sublocators = new List<LocatorInfo>(); sublocators.AddRange(App.Current.Geocoder.Locators); // Get best street candidate. List<LocatorInfo> streetLocators = _ExtractLocators(AddressPart.AddressLine, sublocators); List<AddressCandidate> streetCandidates = _GetStreetCandidates(geocodable, streetLocators, candidatesIncludedDisabledLocators); if (streetCandidates != null) candidatesFromNotPrimaryLocators.AddRange(streetCandidates); if (candidatesFromNotPrimaryLocators.Count == 0) { // Get best zip candidate. List<LocatorInfo> zipLocators = _ExtractLocators(AddressPart.PostalCode1, sublocators); AddressCandidate bestCandidate = _GetBestCandidateFromLocators(zipLocators, candidatesIncludedDisabledLocators); if (bestCandidate == null) { // Get best cityState candidate. List<LocatorInfo> cityStateLocators = _ExtractLocators(AddressPart.StateProvince, sublocators); bestCandidate = _GetBestCandidateFromLocators(cityStateLocators, candidatesIncludedDisabledLocators); } if (bestCandidate != null) { candidatesFromNotPrimaryLocators.Add(bestCandidate); } } } return candidatesFromNotPrimaryLocators; }
/// <summary> /// Make string parts like 'We couldn’t find… so we’ve zoomed to…' /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address. /// </summary> /// <param name="item">Geocodable item.</param> /// <param name="candidateToZoom">First candidate to zoom.</param> /// <returns>Geocode result string parts.</returns> public static string GetZoomedAddress(IGeocodable item, AddressCandidate candidateToZoom) { LocatorType? locatorType = GeocodeHelpers.GetLocatorTypeOfCandidate(candidateToZoom); string zoomedAddress; // If locator type of candidate is street than get Address Line. if (locatorType.HasValue && locatorType.Value == LocatorType.Street && !string.IsNullOrEmpty(item.Address.AddressLine)) { // Extract street name. zoomedAddress = GeocodeHelpers.ExtractStreet(item.Address.AddressLine); } else { // Otherwise use full address. zoomedAddress = candidateToZoom.Address.FullAddress; } return zoomedAddress; }
/// <summary> /// Make string like 'Bevmo could not be found in Redlands,CA.' /// </summary> /// <param name="item">Geocodable item.</param> /// <returns>Geocode result string.</returns> private string _MakeNotFoundString(IGeocodable item) { string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME); string cityStateString = string.Empty; // Use both fields if both not empty. Use not empty otherwise. if (!string.IsNullOrEmpty(item.Address.Locality3) && !string.IsNullOrEmpty(item.Address.StateProvince)) { cityStateString = string.Format(CITY_STATE_FMT, item.Address.Locality3, item.Address.StateProvince); } else if (!string.IsNullOrEmpty(item.Address.Locality3)) { cityStateString = item.Address.Locality3; } else if (!string.IsNullOrEmpty(item.Address.StateProvince)) { cityStateString = item.Address.StateProvince; } string inString = string.Empty; // If city or state present - make "in" string. if (!string.IsNullOrEmpty(cityStateString)) { inString = string.Format((string)App.Current.FindResource(IN_ADDRESS_RESOURCE_NAME), cityStateString); } string result = string.Format(resultFmt, item.ToString(), inString); return result; }
/// <summary> /// Is locator address fields empty. /// </summary> /// <param name="geocodable">Geocodable object.</param> /// <returns>Is locator address fields empty.</returns> public static bool IsActiveAddressFieldsEmpty(IGeocodable geocodable) { bool isEmpty = true; foreach (AddressField addressField in App.Current.Geocoder.AddressFields) { if (!string.IsNullOrEmpty(geocodable.Address[addressField.Type])) { isEmpty = false; break; } } return isEmpty; }
/// <summary> /// Make string like 'Bevmo couldn’t be located, we’ve zoomed to Pat’s Ranch Rd. Use the pushpin tool to locate exactly.' /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address. /// </summary> /// <param name="item">Geocodable item.</param> /// <param name="candidateToZoom">First candidate to zoom.</param> /// <returns>Geocode result string.</returns> private string _MakeNotFoundButZoomedString(IGeocodable item, AddressCandidate candidateToZoom) { string messageFmt = (string)App.Current.FindResource(GEOCODE_RESULT_ZOOMED_RESOURCE_NAME); StringBuilder stringBuilder = new StringBuilder(); // Add "Not located, but zoomed to..." string. stringBuilder.AppendFormat(messageFmt, item.ToString()); // Add zoomed address. string zoomedAddress = GeocodeHelpers.GetZoomedAddress(item, candidateToZoom); stringBuilder.Append(zoomedAddress); // Add dot at the end of sentence. stringBuilder.Append(MESSAGE_STRING_PARTS_DELIMETER); // Add "Use pushpin" string. stringBuilder.Append((string)App.Current.FindResource(USE_PUSHPIN_RESOURCE_NAME)); string result = stringBuilder.ToString(); return result; }
/// <summary> /// Set geocoded fields to address. /// </summary> /// <param name="geocodable">Geocodable object to set address and position.</param> /// <param name="candidate">Source candidate.</param> public static void SetCandidate(IGeocodable geocodable, AddressCandidate candidate) { Debug.Assert(geocodable != null); Debug.Assert(candidate != null); // Set geolocation. geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point( candidate.GeoLocation.X, candidate.GeoLocation.Y); geocodable.Address.MatchMethod = candidate.Address.MatchMethod ?? string.Empty; if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields) { // Concatenate Full Address from other address fields. SetFullAddress(geocodable.Address); } else if (App.Current.Geocoder.AddressFormat == AddressFormat.SingleField) { // Do nothing: don't touch user entered\imported Full Address // and can't parse Full Address to address parts. } else { // Do nothing. Debug.Assert(false); } }
/// <summary> /// Check is location of geocodable object valid and replace it by candidate from local /// geocoder if exists. /// </summary> /// <param name="geocodable">Geocodable object to check.</param> /// <returns>Is geocodable object valid.</returns> private bool _SourceGeocodedObject(IGeocodable geocodable) { Debug.Assert(null != geocodable); // created bool isObjectGeocoded = false; // First check if name address pair exists in local geocoder database. // If exists - overwrite geolocation and address from it. App currentApp = App.Current; var localGeocoder = new LocalGeocoder(currentApp.Geocoder, currentApp.NameAddressStorage); var nameAddress = new NameAddress(); nameAddress.Name = geocodable.ToString(); nameAddress.Address = geocodable.Address.Clone() as Address; AddressCandidate localCandidate = localGeocoder.Geocode(nameAddress); if (localCandidate == null) { // Update from internal object information. AppGeometry.Envelope extent = currentApp.Map.ImportCheckExtent; if (extent.IsPointIn(geocodable.GeoLocation.Value)) { geocodable.Address.MatchMethod = currentApp.FindString("ImportSourceMatchMethod"); isObjectGeocoded = true; // Full address property must be combined from other fields, because // it is not importing field. if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields) GeocodeHelpers.SetFullAddress(geocodable.Address); else { // Do nothing: do not update full address since // it is used for geocoding in Single Address Field Format. } } // Else could not locate object using X/Y attributes - need geocode. } else { // Init from local candidate. // Set location. geocodable.GeoLocation = new AppGeometry.Point(localCandidate.GeoLocation.X, localCandidate.GeoLocation.Y); // Set address. localCandidate.Address.CopyTo(geocodable.Address); isObjectGeocoded = true; } return isObjectGeocoded; }
/// <summary> /// Get street candidate. Extract street name, check that part of street name wasn't removed and try to geocode. /// </summary> /// <param name="geocodable">Geocodable object to geocode,</param> /// <param name="streetLocators">Street locators.</param> /// <param name="candidatesIncludedDisabledLocators">Geocoded candidates.</param> /// <returns>Street candidate.</returns> private static List<AddressCandidate> _GetStreetCandidates( IGeocodable geocodable, IEnumerable<LocatorInfo> streetLocators, IEnumerable<AddressCandidate> candidatesIncludedDisabledLocators) { Debug.Assert(geocodable != null); Debug.Assert(streetLocators != null); Debug.Assert(candidatesIncludedDisabledLocators != null); List<AddressCandidate> streetCandidates = null; if (!string.IsNullOrEmpty(geocodable.Address.AddressLine)) { string street = _ExtractStreet(geocodable.Address.AddressLine); if (!street.Equals(geocodable.Address.AddressLine, StringComparison.OrdinalIgnoreCase)) { // If number removed from street address check that number wasn't part of street name. For example "8th ave". ICloneable cloneableItem = geocodable as ICloneable; IGeocodable geocodableWithoutHouseNumber = (IGeocodable)cloneableItem.Clone(); geocodableWithoutHouseNumber.Address.AddressLine = street; // Get candidates for address with removed number. List<AddressCandidate> candidatesForRemovedHouseNumber = DoGeocode(geocodableWithoutHouseNumber, true, false); List<AddressCandidate> streetCandidatesForRemovedHouseNumber = _GetCandidatesFromLocators(streetLocators, candidatesForRemovedHouseNumber); // If best candidate from street locator exists - use it. if (streetCandidatesForRemovedHouseNumber.Count > 0) { streetCandidates = streetCandidatesForRemovedHouseNumber; } } } // If street candidate not set yet - find best candidate from already geocoded candidates. if (streetCandidates == null) { streetCandidates = _GetCandidatesFromLocators(streetLocators, candidatesIncludedDisabledLocators); } // Fill address fields of street candidate. foreach (AddressCandidate candidate in streetCandidates) { ParseAndFillAddress(candidate.Address); } return streetCandidates; }
/// <summary> /// React on creating new item. /// </summary> /// <param name="args">New item creating args.</param> public void OnCreatingNewItem(DataGridCreatingNewItemEventArgs args) { Debug.Assert(_parentLayer != null); Debug.Assert(args != null); _currentItem = (IGeocodable)args.NewItem; _currentItem.Address.PropertyChanged += new PropertyChangedEventHandler(_AddressPropertyChanged); Graphic graphic = _parentLayer.CreateGraphic(_currentItem); _parentLayer.MapLayer.Graphics.Add(graphic); _editStartedByGrid = true; _StartEdit(_currentItem); _editStartedByGrid = false; _SetAddressByPointToolEnabled(true); }
/// <summary> /// End geocoding with match found. Save candidate position to edited item. /// </summary> /// <param name="geocodable">Item to geocode.</param> /// <param name="candidate">Matched candidate.</param> private void _ProcessMatchFound(IGeocodable geocodable, AddressCandidate candidate) { string manuallyEditedXY = (string)Application.Current.FindResource("ManuallyEditedXY"); if (string.Equals(candidate.Address.MatchMethod, manuallyEditedXY)) { geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point(candidate.GeoLocation.X, candidate.GeoLocation.Y); ; candidate.Address.CopyTo(geocodable.Address); } else { GeocodeHelpers.SetCandidate(geocodable, candidate); } if (MatchFound != null) MatchFound(this, EventArgs.Empty); IsGeocodingInProcess = false; }
/// <summary> /// React on cancelling edit. /// </summary> /// <param name="args">Datagrid item args.</param> public void OnEditCanceled(DataGridItemEventArgs args) { Debug.Assert(args != null); _canceledByGrid = true; if (IsGeocodingInProcess) { _EndGeocoding(false); } IGeocodable geocodable = args.Item as IGeocodable; geocodable.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged); _currentItem = null; _isAddressChanged = false; EditEnded(false); _canceledByGrid = false; }