module NSWTopo::Grid
def get_features
def get_features @params["edge"]["stroke-width"] ||= 2 * @params["stroke-width"] Projection.utm_zones(@map.neatline).flat_map do |zone| utm, utm_geometry = Projection.utm(zone), Projection.utm_geometry(zone) map_geometry = @map.neatline(**MARGIN).reproject_to_wgs84 eastings, northings = @map.neatline.reproject_to(utm).bounds.map do |min, max| (min / @interval).floor..(max / @interval).ceil end.map do |counts| counts.map { |count| count * @interval } end grid = eastings.map do |easting| [easting].product northings.reverse end eastings, northings = [grid, grid.transpose].map.with_index do |lines, index| lines.inject GeoJSON::Collection.new(projection: utm) do |collection, line| coord = line[0][index] label = [coord / 100000, (coord / 1000) % 100] label << coord % 1000 unless @interval % 1000 == 0 collection.add_linestring line, "label" => label, "ends" => [0, 1], "category" => index.zero? ? "easting" : "northing" end.reproject_to_wgs84.clip(utm_geometry).clip(map_geometry).explode.each do |linestring| linestring["ends"].delete 0 if linestring.coordinates.first.x % 6 < 0.00001 linestring["ends"].delete 1 if linestring.coordinates.last.x % 6 < 0.00001 end end boundary_points = GeoJSON.multilinestring(grid.transpose, projection: utm).reproject_to_wgs84.clip(utm_geometry).coordinates.map(&:first) boundary = GeoJSON.linestring boundary_points, properties: { "category" => "boundary" } [eastings, northings, boundary] end.tap do |collections| next unless @border @map.neatline.reproject_to_wgs84.map! do |border| border.with_properties("category" => "edge") end.tap do |border| collections << border end end.inject(&:merge) end
def label_element(labels, label_params)
def label_element(labels, label_params) font_size = label_params["font-size"] parts = labels.zip(["%d\u00a0", "%02d", "\u00a0%03d"]).map do |part, format| format % part end.zip([80, 100, 80]) text_path = REXML::Element.new("textPath") parts.each.with_index do |(text, percent), index| tspan = text_path.add_element "tspan", "font-size" => "#{percent}%" tspan.add_attributes "dy" => VALUE % (Labels::CENTRELINE_FRACTION * font_size) if index.zero? tspan.add_text text end text_length = parts.sum do |text, percent| Font.glyph_length text, label_params.merge("font-size" => font_size * percent / 100.0) end text_path.add_attribute "textLength", VALUE % text_length [text_length, text_path] end
def labeling_features
def labeling_features return [] if @params["unlabeled"] label_params = @params["labels"] font_size = label_params["font-size"] offset = -0.85 * font_size inset = INSET + font_size * 0.5 * Math::sin(@map.rotation.abs * Math::PI / 180) inset_geometry = @map.neatline(mm: -inset).map!(&:remove_holes) eastings, northings = features.select do |linestring| linestring["label"] end.partition do |gridline| gridline["category"] == "easting" end flip_eastings = eastings.partition do |easting| Math::atan2(*easting.coordinates.values_at(0, -1).inject(&:-)) * 180.0 / Math::PI > @map.rotation end.map(&:length).inject(&:>) eastings.each do |easting| easting["ends"].map! { |index| 1 - index } end.map!(&:reverse) if flip_eastings eastings.concat(northings).inject(GeoJSON::Collection.new(projection: @map.neatline.projection)) do |collection, gridline| collection << gridline.offset(offset, splits: false) end.clip(inset_geometry).explode.flat_map do |gridline| label, ends = gridline.values_at "label", "ends" %i[itself reverse].values_at(*ends).map do |order| text_length, text_path = label_element(label, label_params) p0, p1 = gridline.coordinates.send(order).take(2) fraction = text_length / (p1 - p0).norm p01 = p1 * fraction + p0 * (1 - fraction) coordinates = [p0, p01].send(order) GeoJSON::LineString[coordinates, "label" => text_path] end end end
def to_s
def to_s @name end