首页 > 解决方案 > 使指南针始终指向 Xamarin 表单中的特定位置

问题描述

我正在尝试按照Xamarin.Essentials 实施 Compass:Compass以前往特定点。为了实现和测试,我添加了 SfCircularGauge ,它在相同的逻辑下运行良好。因为,我不想使用 XF,所以在没有 XF 的情况下尝试了它。但是在没有 XF 的情况下工作时,箭头不指向正确的方向,箭头只指向北方。计算和点是相同的,都是关于箭头没有指向正确的方向。(我在 iOS 中测试,没有在 Android 中检查)

double current_latitude = 25.2618616; // changed on Appearing
double current_longitude = 55.3254198; // changed on Appearing
readonly double QiblaLatitude = 21.4224779; //remains --> pointing to this location
readonly double QiblaLongitude = 39.8251832; //remains --> pointing to this location
readonly SensorSpeed speed = SensorSpeed.UI;
public MainPage()
{
  InitializeComponent();
  Compass.ReadingChanged += Compass_ReadingChanged;
  if (!Compass.IsMonitoring) Compass.Start(speed);
}
void Compass_ReadingChanged(object sender, CompassChangedEventArgs e)
{
    circularGauge.RotateTo(360 - e.Reading.HeadingMagneticNorth); // this is XF
    compassImage.RotateTo(360 - e.Reading.HeadingMagneticNorth);
    ImageArrow.RotateTo(360 - e.Reading.HeadingMagneticNorth);
    PointToQibla();
}
private async void GetLocation()
{
   try
   {
      var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromMilliseconds(10));
      var location = await Geolocation.GetLocationAsync(request);
      current_latitude = location.Latitude;
      current_longitude = location.Longitude;
    }
    catch(Exception ex){System.Diagnostics.Debug.WriteLine(ex.Message);}
}
private double Mod(double a, double b)
{
   return a - b * Math.Floor(a / b);
}
void PointToQibla()
{
   double latt_from_radians = current_latitude * Math.PI / 180;
   double long_from_radians = current_longitude * Math.PI / 180;
   double latt_to_radians = QiblaLatitude * Math.PI / 180;
   double lang_to_radians = QiblaLongitude * Math.PI / 180;
   double bearing = Math.Atan2(Math.Sin(lang_to_radians - long_from_radians) * Math.Cos(latt_to_radians), (Math.Cos(latt_from_radians) * Math.Sin(latt_to_radians)) - (Math.Sin(latt_from_radians) * Math.Cos(latt_to_radians) * Math.Cos(lang_to_radians - long_from_radians)));
   bearing = Mod(bearing, 2 * Math.PI);
   double bearing_degree = bearing * 180 / Math.PI;
   //normal arrow and XF
   ImageArrow.Rotation = pointer1.Value = bearing_degree;
   // Labels to show value 
   lblG.Text = LabelInfo.Text = string.Format("Lat: {0} Long: {1} degree:{2}", current_latitude,current_longitude,bearing_degree.ToString());
}
protected override void OnAppearing()
{
    base.OnAppearing();
    GetLocation();
}

XAML(XF 和普通)

<Grid Padding="20" BackgroundColor="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackLayout Grid.Row="0">
            <SyncfusionGauge:SfCircularGauge
                                         x:Name="circularGauge"
                                         BackgroundColor="Transparent"
                                         HorizontalOptions="CenterAndExpand"
                                         VerticalOptions="CenterAndExpand">
                <SyncfusionGauge:SfCircularGauge.Scales>
                    <SyncfusionGauge:Scale x:Name="scale"
                                       StartAngle="270"
                                       StartValue="0"
                                       EndValue="360"
                                       Interval="45"
                                       LabelOffset="0.75"
                                       SweepAngle="360"
                                       MinorTicksPerInterval="1"
                                       ShowLastLabel="False"
                                       ScaleStartOffset="0.99"
                                       ScaleEndOffset="0.9"
                                       LabelCreated="Scale_LabelCreated">
                        <SyncfusionGauge:Scale.Pointers>
                            <SyncfusionGauge:NeedlePointer x:Name="pointer1"
                                                       Type="Triangle"
                                                       LengthFactor="0.65"
                                                       KnobColor="White"
                                                       Thickness="25"
                                                       EnableAnimation="True">
                                <SyncfusionGauge:NeedlePointer.KnobRadius>
                                    <OnPlatform x:TypeArguments="x:Double">
                                        <On Platform="UWP"
                                        Value="15" />
                                        <On Platform="Android"
                                        Value="25" />
                                        <On Platform="iOS"
                                        Value="25" />
                                    </OnPlatform>
                                </SyncfusionGauge:NeedlePointer.KnobRadius>
                            </SyncfusionGauge:NeedlePointer>
                        </SyncfusionGauge:Scale.Pointers>
                        <SyncfusionGauge:Scale.MajorTickSettings>
                            <SyncfusionGauge:TickSettings StartOffset="0.9"
                                                      EndOffset="0.83"
                                                      Thickness="2" />
                        </SyncfusionGauge:Scale.MajorTickSettings>
                        <SyncfusionGauge:Scale.MinorTickSettings>
                            <SyncfusionGauge:TickSettings StartOffset="0.9"
                                                      EndOffset="0.85"
                                                      Thickness="2" />
                        </SyncfusionGauge:Scale.MinorTickSettings>
                    </SyncfusionGauge:Scale>
                </SyncfusionGauge:SfCircularGauge.Scales>
            </SyncfusionGauge:SfCircularGauge>
            <Label x:Name="lblG" TextColor="Red"></Label>
        </StackLayout>
        <StackLayout Grid.Row="1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Image HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:Name="compassImage" Source="compass.png"/>
                <Image HorizontalOptions="Center" VerticalOptions="Center" Source="arrow.png" x:Name="ImageArrow"/>
                <Label Grid.Row="1" x:Name="LabelInfo" TextColor="Blue"
                       VerticalOptions="Center" HorizontalOptions="Center" />
            </Grid>
        </StackLayout>
    </Grid>

问题是箭头不指向特定方向,但它始终保持在北方。该项目也可以在GitHub 上找到

iOS 截图

标签: xamarin.formsxamarin.androidxamarin.ios

解决方案


我在如何在 Compass Windows Phone 8 上获得朝拜方向之后解决了这个谜团. 更新后的代码如下所示;

void Compass_ReadingChanged(object sender, CompassChangedEventArgs e)
        {
            try
            {
                //Qibla lat and long
                var qiblaLocation = new Location(QiblaLatitude, QiblaLongitude);
                //current position
                var position = new Location(current_latitude, current_longitude);
                var res = DistanceCalculator.Bearing(position, qiblaLocation);
                var TargetHeading = (360 - res) % 360;

                var currentHeading = 360 - e.Reading.HeadingMagneticNorth;
                Heading = currentHeading - TargetHeading;
                
                Info = string.Format("Lat: {0} Long: {1} degree:{2}", current_latitude, current_longitude, Heading);

            }catch(Exception ex){//log exception}
        }

完整的项目在GitHub


推荐阅读