Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Planning counter cache & Zoning edits #207

Merged
merged 5 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
- API: Allow commas for float fields [#205](https://github.com/cartoway/planner-web/pull/205)
- Planning: Add router name to vehicle selector [#202](https://github.com/cartoway/planner-web/pull/202)
- Destination: Allow commas for float columns during import [#203](https://github.com/cartoway/planner-web/pull/203)
- Zoning: Simplify polygons geometries [#207](https://github.com/cartoway/planner-web/pull/207)

### Changed
- Allow rails to use fallback in case of missing assets [#196](https://github.com/cartoway/planner-web/pull/196)
- Rails 6 shares callbacks across threads [#197](https://github.com/cartoway/planner-web/pull/197)
- Setup cookies with same site policy [#201](https://github.com/cartoway/planner-web/pull/201)
- Set max zoom to 19 [#204](https://github.com/cartoway/planner-web/pull/204)
- Planning: stop counter now uses a cache [#207](https://github.com/cartoway/planner-web/pull/207)
- Store: use `find_in_batches` within geocoder job [#205](https://github.com/cartoway/planner-web/pull/205)
- Zoning: Improve loading performances [#199](https://github.com/cartoway/planner-web/pull/199)
- Zoning:
- Improve loading performances [#199](https://github.com/cartoway/planner-web/pull/199)
- Increase zone border weight & Change edit marker style [#207](https://github.com/cartoway/planner-web/pull/207)

### Removed

Expand Down
9 changes: 5 additions & 4 deletions app/assets/javascripts/zonings.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export const zonings_edit = function(params) {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
shapeOptions: {
color: '#707070'
color: '#707070',
weight: 5
}
},
rectangle: false,
Expand Down Expand Up @@ -243,7 +244,7 @@ export const zonings_edit = function(params) {
color: ((vehicle_id && vehiclesMap[vehicle_id]) ? vehiclesMap[vehicle_id].color : '#707070'),
fillColor: null,
opacity: 0.5,
weight: 2,
weight: 3,
dashArray: 'none',
fillPattern: null
});
Expand Down Expand Up @@ -274,7 +275,7 @@ export const zonings_edit = function(params) {
this.on('mouseover', function() {
that.setStyle({
opacity: 0.9,
weight: (zone.speed_multiplier === 0) ? 5 : 3
weight: (zone.speed_multiplier === 0) ? 5 : 5
});
if (zone.name) {
labelMarker = L.marker(that.getBounds().getCenter(), {
Expand All @@ -289,7 +290,7 @@ export const zonings_edit = function(params) {
this.on('mouseout', function() {
that.setStyle({
opacity: 0.5,
weight: (zone.speed_multiplier === 0) ? 5 : 2
weight: (zone.speed_multiplier === 0) ? 5 : 3
});
if (labelMarker) {
labelLayer.removeLayer(labelMarker);
Expand Down
10 changes: 10 additions & 0 deletions app/assets/stylesheets/bootstrap_and_overrides.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ a.btn-default {
z-index: 900 !important; /* Bootstrap also use 1000 for control */
}

.leaflet-editing-icon {
border-radius: 10px;
border: 3px dimgrey solid;
opacity: unset;
}

.leaflet-draw-tooltip {
display: none;
}

hr {
margin-bottom: 6px;
margin-top: 6px;
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/plannings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def show
@params = params
@routes = if params[:route_ids]
route_ids = params[:route_ids].split(',').map{ |s| Integer(s) }
@planning.routes.select{ |r| route_ids.include?(r.id) }
@planning.routes.includes_destinations.where(id: route_ids)
end
respond_to do |format|
format.html
Expand Down
13 changes: 13 additions & 0 deletions app/models/planning.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class Planning < ApplicationRecord
before_destroy :unlink_job_optimizer
before_save :update_vehicle_usage_set

after_save :invalidate_planning_cache
after_destroy :invalidate_planning_cache

include RefSanitizer

scope :includes_route_details, -> {
Expand Down Expand Up @@ -86,6 +89,12 @@ def duplicate
copy
end

def cached_active_stops_sum
Rails.cache.fetch("#{cache_key_with_version}/active_stops_sum", expires_in: 1.hour) do
routes.to_a.sum(0) { |route| route.vehicle_usage_id ? route.size_active : 0 }
end
end

def changed?
routes_changed? || super
end
Expand Down Expand Up @@ -781,6 +790,10 @@ def quantities

private

def invalidate_planning_cache
Rails.cache.delete("#{self.cache_key_with_version}/active_stops_sum")
end

def prefered_route_and_index(available_routes, stop, options = {})
options[:active_only] = true if options[:active_only].nil?
cache_sum_out_of_window = Hash.new{ |h, k| h[k] = k.sum_out_of_window }
Expand Down
2 changes: 1 addition & 1 deletion app/models/route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ def self.simplify_polyline_features(routes, features, options = {})
next final_features << feature unless feature.include?('polylines')

polyline_feature = JSON.parse(feature)
SimplifyGeometry.polylines_to_coordinates(polyline_feature, { precision: 1e-6, skip_simplifier: true })
SimplifyGeometry.polylines_to_coordinates(polyline_feature, **{ precision: 1e-6, skip_simplifier: true })
polyline_features << polyline_feature
}

Expand Down
15 changes: 13 additions & 2 deletions app/models/zone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,27 @@ def edit_invalid_feature(feature)
end

def feature_collection_as_geojson(features)
features.map!{ |feature|
SimplifyGeometry.polygones_to_coordinates(
RGeo::GeoJSON.encode(feature),
**{ precision: 1e-5 }
)
}
{
type: 'FeatureCollection',
features: features.map{ |feature| feature_as_geojson(feature) }
features: features
}
end

def feature_as_geojson(feature)
feature =
SimplifyGeometry.polygones_to_coordinates(
RGeo::GeoJSON.encode(feature),
**{ precision: 1e-5 }
)
{
type: 'Feature',
geometry: RGeo::GeoJSON.encode(feature)
geometry: feature
}
end

Expand Down
2 changes: 1 addition & 1 deletion app/views/plannings/show.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ else
json.distance locale_distance(@planning.routes.to_a.sum(0){ |route| route.distance || 0 }, current_user.prefered_unit)
(json.outdated true) if @planning.outdated
json.size @planning.routes.to_a.sum(0){ |route| route.stops.size }
json.size_active @planning.routes.to_a.sum(0){ |route| route.vehicle_usage_id ? route.size_active : 0 }
json.size_active @planning.cached_active_stops_sum
json.stores (@planning.vehicle_usage_set.vehicle_usages.collect(&:default_store_start) + @planning.vehicle_usage_set.vehicle_usages.collect(&:default_store_stop) + @planning.vehicle_usage_set.vehicle_usages.collect(&:default_store_rest)).compact.uniq do |store|
json.extract! store, :id, :name, :street, :postalcode, :city, :country, :lat, :lng, :color, :icon, :icon_size
end
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20241024064440_simplify_zone_polygons.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class SimplifyZonePolygons < ActiveRecord::Migration[6.1]
def up
Zone.find_each{ |zone|
next if zone.polygon.nil? || JSON.parse(zone.polygon)['geometry'].nil?

zone.validate
zone.save!
}
end
end
4 changes: 3 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20240627142001'),
('20240704115843'),
('20240719162433'),
('20240814065613');
('20240814065613'),
('20241024064440');



35 changes: 24 additions & 11 deletions lib/simplify_geometry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,35 @@
AUTHORIZED_GEOMETRY_TYPES = %w[Polygon MultiPolygon GeometryCollection].freeze

class SimplifyGeometry
def self.polylines(feature, options = { precision: 1e-6 })
if feature['geometry'] && feature['geometry']['polylines']
simplified_polyline = process(feature, options).map{ |crd| crd.reverse } # Polylines return to initial order lat/lng
feature['geometry']['polylines'] = FastPolylines.encode(simplified_polyline, 6)
def self.polygones_to_coordinates(feature, **options)
if feature['type'] == 'Polygon' && feature['coordinates']
feature['coordinates'].map!{ |coords|
process(coords.map{ |a, b| {x: a, y: b} }, **options)
}
feature
end
end

def self.polylines_to_coordinates(feature, options = { precision: 1e-6 })
def self.polylines(feature, **options)
options = { geometry: 'polylines', encode_output: true }.merge(options)
if feature['geometry'] && feature['geometry']['polylines']
simplified_polyline = process(feature, options) # coordinates require to keep the reversed order lng/lat
feature['geometry']['coordinates'] = simplified_polyline.map{ |crd| crd }
decoded_polyline = decoded_polyline = FastPolylines.decode(feature['geometry'].delete('polylines'), 6)
# Be aware the simplifier reverses polylines order lat/lng to lng/lat
coordinates = decoded_polyline.map{ |a, b| {x: b, y: a} }
simplified_polyline = process(coordinates, **options)
if options[:encode_output]
simplified_polyline.map!{ |crd| crd.reverse } # Polylines return to initial order lat/lng
feature['geometry']['polylines'] = FastPolylines.encode(simplified_polyline, 6)
else
feature['geometry']['coordinates'] = simplified_polyline.map{ |crd| crd }
end
end
end

def self.polylines_to_coordinates(feature, **options)
polylines(feature, **options.merge!(encode_output: false))
end

def self.dump_multipolygons(zoning, import = false)
import &= zoning.zones.any?{ |zone| zone.polygon&.match('MultiPolygon') || zone.polygon&.match('GeometryCollection') }
new_zones = zoning.zones.flat_map{ |zone|
Expand All @@ -33,10 +48,8 @@ def self.dump_multipolygons(zoning, import = false)

private

def self.process(feature, options = { precision: 1e-6 })
decoded_polyline = FastPolylines.decode(feature['geometry'].delete('polylines'), 6)
# Be aware the simplifier reverses polylines order lat/lng to lng/lat
coordinates = decoded_polyline.map{ |a, b| {x: b, y: a} }
def self.process(coordinates, **options)
options = { precision: 1e-6 }.merge(options)
unless options[:skip_simplifier]
coordinates = SimplifyRb::Simplifier.new.process(
coordinates,
Expand Down
14 changes: 14 additions & 0 deletions test/controllers/zonings_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ class ZoningsControllerTest < ActionController::TestCase
assert_equal @zoning.plannings.map(&:zoning_outdated), [true, true]
end

test 'should simplify polygon' do
zoning = zonings(:zoning_two)
previous_zone_polygon = JSON.parse(zoning.zones.first.polygon)
patch :update, params: { id: zoning.id, zoning: { name: 'foo', zones_attributes: [{ id: zoning.zones.first.id, name: 'bar' }] } }
new_polygon = JSON.parse(zoning.zones.first.polygon)
assert_equal(
previous_zone_polygon['features'].first['geometry']['coordinates'].first.size - 1,
new_polygon['features'].first['coordinates'].first.size
)
assert new_polygon['features'].first['coordinates'].first.all?{ |coords|
coords.all?{ |l| l.to_s.split('.').last.size <= 6 }
}
end

test 'should not create zoning' do
assert_difference('Zoning.count', 0) do
assert_difference('Zone.count', 0) do
Expand Down
6 changes: 3 additions & 3 deletions test/fixtures/zones.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

zone_one:
name: zone_one
polygon: "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.9777832031250001,49.53946900793534],[0.823974609375,49.475263243037986],[0.52734375,48.480204398955145],[-1.8896484375,48.36354888898689],[-1.5600585937499998,49.1242192485914],[-0.9777832031250001,49.53946900793534]]]}}"
polygon: "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.977783,49.539469],[0.823975,49.475263],[0.527344,48.480204],[-1.889648,48.363549],[-1.560059,49.124219],[-0.977783,49.539469]]]}}"
zoning: zoning_one
vehicle: vehicle_one

zone_two:
name: zone_two
polygon: "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.9777832031250001,49.53946900793534],[0.823974609375,49.475263243037986],[0.52734375,48.480204398955145],[-1.8896484375,48.36354888898689],[-1.5600585937499998,49.1242192485914],[-0.9777832031250001,49.53946900793534]]]}}"
polygon: "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.977783,49.539469],[0.823975,49.475263],[0.527344,48.480204],[-1.889648,48.363549],[-1.560059,49.124219],[-0.977783,49.539469]]]}}"
zoning: zoning_one
vehicle:

Expand All @@ -23,6 +23,6 @@ zone_four:
vehicle:

zone_five:
polygon: "{\"type\":\"Feature\",\"geometry\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Polygon\",\"coordinates\":[[[-0.9777832031250001,49.53946900793534],[0.823974609375,49.475263243037986],[0.52734375,48.480204398955145],[-1.8896484375,48.36354888898689],[-1.5600585937499998,49.1242192485914],[-0.9777832031250001,49.53946900793534]]]}]}}"
polygon: "{\"type\":\"Feature\",\"geometry\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Polygon\",\"coordinates\":[[[-0.977783,49.539469],[0.823975,49.475263],[0.527344,48.480204],[-1.889648,48.363549],[-1.560059,49.124219],[-0.977783,49.539469]]]}]}}"
zoning: zoning_five
vehicle:
2 changes: 1 addition & 1 deletion test/models/zone_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ZoneTest < ActiveSupport::TestCase

test 'calculate distance between point and simple polygon' do
zone = zones(:zone_one)
assert_equal 0.0014045718474348943, zone.inside_distance(49.538, -0.976)
assert_equal 0.0014045709186722257, zone.inside_distance(49.538, -0.976)
end

test 'calculate distance between point and isochrone' do
Expand Down
Loading