Мне нужно вернуть расстояния между двумя точками с помощью функции haversine

#ruby #ruby-on-rails-5

#ruby #ruby-on-rails-5

Вопрос:

Мне нужно вернуть расстояния между двумя точками с помощью функции haversine. Я извлекаю массив кординат из базы данных, используя область видимости. Но у меня возникают проблемы с циклическим перебором массива для возврата расстояний между каждой созданной парой.

В show() я хочу, чтобы просматриваемый адрес был базовой / исходной точкой, затем он должен проходить через базу данных для сопряжения со всеми другими точками адреса, чтобы вернуть их расстояния на основе @origin .

В настоящее время я возвращаю только одно значение. Мне действительно нужна помощь.

Ниже приведен мой код

 class AddressesController < ApplicationController
  before_action :set_address, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /addresses
  # GET /addresses.json
  def index
    @addresses = Address.all
  end

  def haversine_distance(geo_a, geo_b, miles=false)
    # Get latitude and longitude
    lat1, lon1 = geo_a
    lat2, lon2 = geo_b
  
    # Calculate radial arcs for latitude and longitude
    dLat = (lat2 - lat1) * Math::PI / 180
    dLon = (lon2 - lon1) * Math::PI / 180
  
    a = Math.sin(dLat / 2) * 
        Math.sin(dLat / 2)  
        Math.cos(lat1 * Math::PI / 180) * 
        Math.cos(lat2 * Math::PI / 180) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2)
  
    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
    
    d = 6371 * 1000 * c # in meters
  end

  # GET /addresses/1
  # GET /addresses/1.json
  def show()
    @origin = [@address.latitude, @address.longitude]
    @destination = Address.get_lat_lon_array

    @destination.each do |dest|
      @distance = haversine_distance(@origin, dest).to_i
    end
  end

  # GET /addresses/new
  def new
    @address = Address.new
  end

  # GET /addresses/1/edit
  def edit
  end

  # POST /addresses
  # POST /addresses.json
  def create
    @address = Address.new(address_params)
    @address.user_id = current_user.id

    respond_to do |format|
      if @address.save
        format.html { redirect_to dashboard_path, notice: 'Address was successfully created.' }
        format.json { render :show, status: :created, location: @address }
      else
        format.html { render :new }
        format.json { render json: @address.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /addresses/1
  # PATCH/PUT /addresses/1.json
  def update
    respond_to do |format|
      if @address.update(address_params)
        format.html { redirect_to my_address_path, notice: 'Address was successfully updated.' }
        format.json { render :show, status: :ok, location: @address }
      else
        format.html { render :edit }
        format.json { render json: @address.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /addresses/1
  # DELETE /addresses/1.json
  def destroy
    @address.destroy
    respond_to do |format|
      format.html { redirect_to addresses_url, notice: 'Address was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_address
      @address = Address.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def address_params
      params.require(:address).permit(:landmark, :longitude, :latitude)
    end
end

  
 <%= render "layouts/main-nav" %>

<div class="container py-5 dash-view">
    <div class="row" id="dash">
      <%= render "layouts/left" %>
      <div class="col-md-8">
        <p><%= @address.landmark %></p>
        <p><%= @distance %> meters</p>
      </div>
    </div>    
  </div>
</div>

  
 class Address < ApplicationRecord
  validates :latitude, :longitude, :landmark, presence: true

  belongs_to :user

  scope :get_lat_lon_array, -> { pluck(:latitude, :longitude) }
end
  

Я хочу, чтобы мой вывод представлял собой таблицу в представлении отображения расстояний других адресов по отношению / от к адресу текущего пользователя

Комментарии:

1. Можете ли вы опубликовать выборку массива (небольшую выборку) и ожидаемый результат?

2. Я извлекаю массив из адресной таблицы, используя это. область действия:get_lat_lon_array, -> { pluck(:широта, :долгота) }

3. Можете ли вы использовать это? Спасибо [[0.384687e0, 0.32658527e2], [0.393035e0, 0.3264051e2], [0.323493e0, 0.32647846e2], [0.364948e0, 0.32637298e2], [0.309571e0, 0.32652247e2], [0.386782e0, 0.32652977e2]]

4. Я думаю, это потому, что вы переназначаете переменную экземпляра @distance на каждой итерации цикла. Вместо использования каждого, используйте метод map для цикла. Также удалите назначение внутри блока цикла.

5. Не могли бы вы показать мне, как это сделать? потому что, когда я пытаюсь, я все равно получаю тот же результат. Спасибо

Ответ №1:

Если я понимаю вашу проблему, вам нужен массив #map, который будет использоваться таким образом:

 @destination =  [[0.384687e0, 0.32658527e2], [0.393035e0, 0.3264051e2], [0.323493e0, 0.32647846e2], [0.364948e0, 0.32637298e2], [0.309571e0, 0.32652247e2], [0.386782e0, 0.32652977e2]]
origin = [0.384687e0, 0.32658527e2]

@distances = @destination.map { |point| haversine_distance(point, origin).to_i }
@distances #=> [0, 2208, 6907, 3223, 8382, 660]
  

Пример и ссылка на документ должны вам помочь.