1

次のPiP検索は、ユーザーが住所またはlat / lng(http://staging.placeanddisplaced.org)でニューヨークの政府地区を検索できるようにするプロジェクト用に作成されました。動作しますが、特に複雑なポリゴンを持つ地区を検索する場合は、少し遅くなります。誰かが私にこのコードを最適化するためのいくつかの指針を与えることができますか?

私が持っていた1つの考えは、point_in_polygonを実行することでしたか?各ポリゴンの簡略化されたバージョン、つまりより少ない座標での方法。これは、処理時間が短くなるだけでなく、精度も低下することを意味します。

class DistrictPolygonsController < ApplicationController

  def index

    ...

    if coordinates?
      @district_polygons = DistrictPolygon.
      coordinates_within_bounding_box(params[:lat], params[:lng]).
      find(:all, :include => :district, :select => select).
      select { |dp| dp.contains_coordinates?(params[:lat], params[:lng]) }
    else
      @district_polygons = DistrictPolygon.find(:all, :include => :district, :select => select)
    end

    ...

  end

end

class DistrictPolygon < ActiveRecord::Base

  named_scope :coordinates_within_bounding_box, lambda { |lat,lng| { :conditions => ['min_lat<? AND max_lat>? AND min_lng<? AND max_lng>?', lat.to_f, lat.to_f, lng.to_f, lng.to_f] } }
  named_scope :with_district_type, lambda { |t| { :conditions => ['district_type=?', t] } }

  before_save :get_bounding_box_from_geometry

  def get_bounding_box_from_geometry
    # return true unless self.new_record? || self.geometry_changed? || self.bounds_unknown?
    self.min_lat = all_lats.min
    self.max_lat = all_lats.max
    self.min_lng = all_lngs.min
    self.max_lng = all_lngs.max
    true # object won't save without this return
  end

  def bounds_unknown?
    %w(min_lat max_lat min_lng max_lng).any? {|b| self[b.to_sym].blank? }
  end

  def bounds_known?; !bounds_unknown?; end

  # Returns an array of XML objects containing each polygons coordinates
  def polygons
    Nokogiri::XML(self.geometry).search("Polygon/outerBoundaryIs/LinearRing/coordinates")
  end

  def multi_geometric?
    Nokogiri::XML(self.geometry).search("MultiGeometry").size > 0
  end

  # Returns an array of [lng,lat] arrays
  def all_coordinates
    pairs = []
    polygons.map do |polygon|
      polygon.content.split("\n").map do |coord|
        # Get rid of third 'altitude' param from coordinate..
        pair = coord.strip.split(",")[0..1].map(&:to_f)
        # Don't let any nils, blanks, or zeros through..
        pairs << pair unless pair.any? {|point| point.blank? || point.zero? }
      end
    end
    pairs
  end

  # All latitudes, regardless of MultiPolygonal geometry
  def all_lats
    all_coordinates.map(&:last).reject{|lat| lat.blank? || lat.zero?}    
  end

  # All longitudes, regardless of MultiPolygonal geometry  
  def all_lngs
    all_coordinates.map(&:first).reject{|lng| lng.blank? || lng.zero?}
  end

  # Check to see if coordinates are in the rectangular bounds of this district
  def contains_coordinates?(lat, lng)
    return false unless coordinates_within_bounding_box?(lat.to_f, lng.to_f)
    polygons.any? { |polygon| DistrictPolygon.point_in_polygon?(all_lats, all_lngs, lat.to_f, lng.to_f) }
  end

  def coordinates_within_bounding_box?(lat, lng)
    return false if (max_lat > lat.to_f == min_lat > lat.to_f) # Not between lats
    return false if (max_lng > lng.to_f == min_lng > lng.to_f) # Not between lngs
    true
  end

  # This algorithm came from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
  def self.point_in_polygon?(x_points, y_points, x_target, y_target)
    num_points = x_points.size
    j = num_points-1
    c = false
    for i in 0...num_points do
      c = !c if ( ((y_points[i]>y_target) != (y_points[j]>y_target)) && (x_target < (x_points[j]-x_points[i]) * (y_target-y_points[i]) / (y_points[j]-y_points[i]) + x_points[i]) )
      j = i
    end
    return c
  end

end
4

3 に答える 3

1

より複雑な形状の場合、ランタイムが長くなる場合は、パフォーマンスがpoint_in_polygon?のO(n)ループにあることを示しています。

プロファイリングはその仮定を裏付けていますか?

パフォーマンスが重要な場合は、ネイティブコードとまったく同じアルゴリズムを実装することを検討してください。

于 2009-09-15T16:46:42.813 に答える
0

作業の大部分を DB にプッシュできるのではないかと思います。PostgreSQL には、空間認識クエリの実行を可能にする PostGIS プラグインがあります。

PostGIS: http://postgis.refractions.net/ ドキュメント: http://postgis.refractions.net/documentation/manual-1.4/

これはデータベースの移植性の概念を破りますが、パフォーマンスが重要な場合は価値があるかもしれません。

于 2009-09-15T17:13:17.003 に答える
0

アルゴリズムはさておき、ポリゴン データをローカル メモリに保持し、これを静的に型付けされたコンパイル済み言語で再コーディングすると、速度が 100 倍から 1000 倍向上する可能性があります。

于 2009-09-15T17:30:52.927 に答える