crs-l2-fiji-antimeridian
Model error
Retrospective
assessed 2026-06-09T12:12:04Z
Map (reference ← swipe → agent)
0:00
I'm pulling together per-transect coverage figures for our survey report, but some of the lines in fiji_transects_wgs84.geojson render as arcs spanning the entire globe instead of short local segments. Can you fix the geometries so they render correctly, convert them to Fiji's national metric grid, and give me each transect as one MultiLineString feature with a length_m attribute in metres?
Every feature must come out as a MultiLineString, so do not leave any transects as plain LineString, and the problematic ones must end up as multi-part geometries that faithfully represent the actual survey path. Carry the survey attributes (vessel and survey_date) through unchanged, use transect_id as the key field, and write the result as GeoJSON named fiji_transects_fmg.geojson.
0:00
System info
{
"adapter": "openrouter",
"model": "google/gemma-4-26b-a4b-it",
"base_url": "https://openrouter.ai/api/v1"
}
0:03
Bash
ls -F
fiji_transects_wgs84.geojson
0:05
Bash
head -n 20 fiji_transects_wgs84.geojson
{
"type": "FeatureCollection",
"name": "fiji_transects_wgs84",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "transect_id": "T001", "vessel": "Taveuni II", "survey_date": "2025-08-15", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 178.941879580782086, -17.632301816020771 ], [ 179.456655009654696, -17.623768593111961 ], [ 179.971430438527307, -17.611072392823225 ], [ -179.513794132600054, -17.596198176111951 ], [ -178.999018703727444, -17.579632069513806 ], [ -178.484243274854833, -17.577321872344196 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T002", "vessel": "Bligh", "survey_date": "2025-08-12", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 179.070288824800542, -17.334767984150709 ], [ 179.725942881740252, -17.171343988196945 ], [ -179.618403061320009, -17.007726843860763 ], [ -178.962749004380299, -16.834850408534852 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T003", "vessel": "Lomaiviti", "survey_date": "2025-08-12", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 177.636947428758333, -17.358837040696127 ], [ 178.462815605623859, -17.416074837434927 ], [ 179.288683782489386, -17.471713663377283 ], [ -179.885448040645059, -17.527675804260884 ], [ -179.059579863779533, -17.590577543375694 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T004", "vessel": "Vanua I", "survey_date": "2025-08-15", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 178.873696381462679, -17.803295238757038 ], [ 179.542254331047587, -17.598477321703708 ], [ -179.789187719367533, -17.405549472537043 ], [ -179.120629769782624, -17.19411411231702 ], [ -178.452071820197745, -16.992332922174427 ], [ -177.783513870612836, -16.795171196845544 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T005", "vessel": "Bligh", "survey_date": "2025-08-19", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 177.596924830927293, -17.923255155112717 ], [ 178.160696712947697, -18.010328270600898 ], [ 178.724468594968101, -18.099224972140938 ], [ 179.288240476988506, -18.17532145144995 ], [ 179.85201235900891, -18.270380145331412 ], [ -179.584215758970686, -18.358875431719703 ], [ -179.020443876950281, -18.437390943572723 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T006", "vessel": "Cakaulevu", "survey_date": "2025-08-13", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 178.622166647099931, -18.382052393687179 ], [ 179.205668025282989, -18.184610858038685 ], [ 179.789169403466019, -17.991866703295319 ], [ -179.627329218350923, -17.789532271264445 ], [ -179.043827840167864, -17.595682751178369 ], [ -178.460326461984835, -17.393483000040479 ], [ -177.876825083801776, -17.203490564162109 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T007", "vessel": "Vanua I", "survey_date": "2025-08-19", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 177.920101619592742, -17.14979850360189 ], [ 178.697177550619955, -17.100522188212071 ], [ 179.474253481647168, -17.053867486482115 ], [ -179.74867058732562, -17.004197778897627 ], [ -178.971594656298407, -16.959481244370728 ], [ -178.194518725271195, -16.911697858015476 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T008", "vessel": "Taveuni II", "survey_date": "2025-08-12", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 179.401134548056262, -17.934415957637167 ], [ 179.67454249485786, -17.899654147497863 ], [ 179.947950441659486, -17.858130727687527 ], [ -179.778641611538916, -17.811143619533269 ], [ -179.50523366473729, -17.768768396969666 ], [ -179.231825717935692, -17.724708363613253 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T009", "vessel": "Vanua I", "survey_date": "2025-08-13", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 178.068433112639013, -16.657838811131668 ], [ 178.561564721122721, -16.689731320158675 ], [ 179.054696329606429, -16.72173241552732 ], [ 179.547827938090137, -16.748891897767297 ], [ -179.959040453426155, -16.775241845025921 ], [ -179.465908844942447, -16.799281899607834 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T010", "vessel": "Vanua I", "survey_date": "2025-08-15", "crosses_antimeridian_flag": true }, "geometry": { "type": "LineString", "coordinates": [ [ 177.602847396853463, -17.277026295424367 ], [ 179.128053569323441, -17.468285296635063 ], [ -179.346740258206609, -17.65419136085664 ], [ -177.82153408573663, -17.837325774502055 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T011", "vessel": "Taveuni II", "survey_date": "2025-08-20", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -176.863797870333627, -17.7932433540029 ], [ -176.985724572324699, -17.81273654528005 ], [ -177.107651274315742, -17.824236921378098 ], [ -177.229577976306814, -17.835861250474697 ], [ -177.351504678297886, -17.857559546831705 ], [ -177.473431380288929, -17.871769203842408 ], [ -177.595358082280001, -17.890225470404214 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T012", "vessel": "Taveuni II", "survey_date": "2025-08-20", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.312195951017685, -17.976122209608448 ], [ 176.362236324041447, -17.722210270969462 ], [ 176.412276697065209, -17.470306839752467 ], [ 176.462317070088972, -17.226475769084448 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T013", "vessel": "Bligh", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -176.70823848972006, -17.696306145080879 ], [ -177.205026853648661, -17.960082567744127 ], [ -177.701815217577291, -18.210737758337459 ], [ -178.198603581505893, -18.469124252379427 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T014", "vessel": "Lomaiviti", "survey_date": "2025-08-13", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.538496893308832, -16.594358164012139 ], [ 176.861572490827996, -16.71494251806207 ], [ 177.184648088347188, -16.832251271240672 ], [ 177.507723685866381, -16.976116506165042 ], [ 177.830799283385545, -17.090939089364483 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T015", "vessel": "Vanua I", "survey_date": "2025-08-15", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -177.278377449219306, -16.724372731501912 ], [ -177.470251917030794, -16.761535677586746 ], [ -177.662126384842253, -16.787182414326686 ], [ -177.854000852653712, -16.818799270133983 ], [ -178.0458753204652, -16.856282470705128 ], [ -178.237749788276659, -16.891308864567598 ], [ -178.429624256088147, -16.914729063096839 ] ] } },
0:55
Write
content · 331 lines
import geopandas as gpd
import pandas as pd
from shapely.geometry import LineString, MultiLineString
from shapely.ops import split, transform
import pyproj
def fix_antimeridian_lines(gdf):
"""
Fixes LineStrings that cross the antimeridian by splitting them into
multiple segments and wrapping longitudes to a consistent range.
"""
new_features = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom is None:
continue
# Get coordinates
coords = list(geom.coords)
# Check for antimeridian crossing (jump in longitude > 180)
# However, in WGS84, the jump is usually from +180 to -180 or vice versa.
# A simple way is to detect if the diff between consecutive longitudes is > 180.
split_points = []
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
# Jump from -179 to 179 (wrong direction for a short segment)
# or jump from 179 to -179 (correct direction)
# Actually, if diff > 180, it means it's going "the long way"
# around the world if we assume it should be a short segment.
# But wait, if lon1=179 and lon2=-179, diff = -358.
# If lon1=-179 and lon2=179, diff = 358.
pass
# Let's use a more robust logic:
# If the absolute difference is > 180, it crossed the antimeridian.
if abs(diff) > 180:
# We need to split at this point.
# But where is the "split" point? The segment itself crosses it.
# For a LineString, we can't easily "split" a single segment unless we
# interpolate the crossing point.
# However, the prompt says "render as arcs spanning the entire globe".
# This usually means the coordinates are like [179, -17], [-179, -17].
# When plotted, this goes the long way around.
# If we want it to be a short segment, we should treat the jump
# as crossing the antimeridian.
# A better approach:
# 1. Normalize all longitudes to be continuous.
# 2. Detect where the jump occurs.
# 3. Split the geometry there.
pass
# Let's try a different approach:
# For each segment, if abs(lon2 - lon1) > 180:
# adjust lon2 so that |lon2 - lon1| < 180
# this will create a "jump" in the coordinates, which we can then split.
adjusted_coords = []
if len(coords) > 0:
adjusted_coords.append(coords[0])
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
lon2 -= 360
elif diff < -180:
lon2 += 360
adjusted_coords.append((lon2, lat2))
# Now adjusted_coords might have values like 181, 182...
# We want to split the LineString where the longitude crosses the 180/-180 boundary.
# Or more simply, where the "wrapped" longitude would cross 180 or -180.
# Let's create a LineString from adjusted_coords.
# Then we split it where the longitude is 180 or -180.
# But we need to be careful with the coordinates.
# Actually, the most robust way to handle antimeridian in GeoPandas/Shapely
# is to use the 'antimeridian' library if available, but it's not.
# Let's do it manually:
if not adjusted_coords:
continue
# Create segments
segments = []
current_segment = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
prev_lon = adjusted_coords[i-1][0]
curr_lon = adjusted_coords[i][0]
# Check if this segment crosses the 180 line
# We normalize the line to a continuous range, then split at 180.
# But the "jump" happens when we transition between the 180/-180 boundary.
# Let's check if the segment crosses the boundary (wrapping around 180)
# Since we adjusted lon2, a crossing happens if the segment
# crosses an integer multiple of 180.
# Actually, let's just use the adjusted_coords and split
# when the coordinate crosses the boundary.
# Wait, if I have coords [179, 181], it's a segment crossing the line.
# I can split it at 180.
# To keep it simple:
# 1. Generate segments that don't cross the 180 meridian.
# 2. For each segment, normalize its coordinates back to [-180, 180].
# Let's refine the "split" logic.
# For each segment (p1, p2) in adjusted_coords:
# if the segment crosses a multiple of 180:
# split it into (p1, p_boundary) and (p_boundary, p2)
# But wait, if we just want to FIX the "arcs", we just need to
# make sure the line doesn't go the "long way".
# The "long way" is when |lon2 - lon1| > 180.
# The "short way" is when |lon2 - lon1| < 180.
# My `adjusted_coords` logic already converts "long way" to "short way"
# by adjusting lon2.
# For example: [179, -179] -> diff = -358. diff < -180, so lon2 += 360 -> lon2 = 181.
# Coords: [179, -179] -> [179, 181]. This is a short segment.
# Now we just need to split this LineString where it crosses 180.
# Let's do that.
pass
# Re-implementing the logic inside the loop properly.
pass
def solve():
gdf = gpd.read_file('fiji_transects_wgs84.geojson')
# 1. Fix Antimeridian
fixed_geoms = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom is None or geom.is_empty:
fixed_geoms.append(geom)
continue
coords = list(geom.coords)
adjusted_coords = [coords[0]]
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
lon2 -= 360
elif diff < -180:
lon2 += 360
adjusted_coords.append((lon2, lat2))
# Now we have a continuous path in "unwrapped" longitude space.
# We need to split this path whenever it crosses a multiple of 180.
# Or more accurately, whenever the longitude crosses the boundary.
# Since we want the output in [-180, 180], we split at 180, -180, etc.
# A simpler way to split:
# Iterate through segments. If a segment crosses a boundary,
# split it and start a new segment.
sub_segments = []
current_sub_coords = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
p1 = adjusted_coords[i-1]
p2 = adjusted_coords[i]
# Check if the segment [p1, p2] crosses a multiple of 180
# The multiples of 180 are ... -180, 0, 180, 360 ...
# But we only care about the boundaries of the [-180, 180] range.
# Since we are in "unwrapped" space, we look for crossings of 180, -180, 360, etc.
# Wait, the simplest way to find if it crosses is to check if
# floor(lon1/180) != floor(lon2/180) ? No, that's not quite right.
# The boundaries are ..., -180, 180, 360, ...
# If the segment crosses 180, or -180, or 360...
# Let's find if there is an integer k such that 180*k is between lon1 and lon2.
# (Wait, 0 is also a multiple, but we don't want to split at 0).
# The boundaries are 180, -180, 360, -360, etc.
# So we check for crossings of 180 * k where k is an ODD integer.
# 180 * 1 = 180
# 180 * -1 = -180
# 180 * 3 = 540
# 180 * -3 = -540
# Actually, even simpler:
# In our "unwrapped" space, the boundaries are at ... -180, 180, 360 ...
# These are (2k+1)*180.
# Let's check if the segment (p1, p2) crosses any (2k+1)*180.
def get_boundary(lon1, lon2):
# Find k such that (2k+1)*180 is between lon1 and lon2
# We can check if floor(lon/180) is odd or even?
# Let's just check the range.
# Check for the crossing point
# The boundaries are 180, -180, 360, -360, 540, -540...
# We can iterate through possible boundaries.
# But since the segments are short, there's at most one.
# Let's try to find the boundary.
# We are looking for B = (2k+1)*180
# such that min(lon1, lon2) < B < max(lon1, lon2)
# We can estimate k.
# B/180 = 2k+1 => k = (B/180 - 1) / 2
# Let's just check a few k's around lon1/180.
low_k = int(lon1 / 180) - 2
high_k = int(lon1 / 180) + 2
for k in range(low_k, high_k + 1):
B = (2 * k + 1) * 180
if min(lon1, lon2) < B < max(lon1, lon2):
# Found it!
# Interpolate to find the exact lon at this B
# (Actually, for a LineString, we usually just split at the boundary)
# We need the lat at this B.
# Linear interpolation:
t = (B - lon1) / (lon2 - lon1)
lat_at_B = lat1 + t * (lat2 - lat1)
return B, lat_at_B
return None
boundary = get_boundary(p1[0], p2[0])
if boundary:
B_lon, B_lat = boundary
# Split: current_sub_coords ends at (B_lon, B_lat)
# New segment starts at (B_lon, B_lat)
current_sub_coords.append((B_lon, B_lat))
sub_segments.append(LineString(current_sub_coords))
current_sub_coords = [(p2[0], p2[1])] # This is wrong, should be the second part of the split
# Wait, the split is: segment is (p1, p2).
# We split it at B into (p1, B) and (B, p2).
# But our `current_sub_coords` already has p1.
# So the segment is [..., p1, B].
# The next segment is [B, p2].
# However, we are iterating segment by segment.
# If we find a boundary in (p1, p2), we:
# 1. finish current_sub_coords with (B_lon, B_lat).
# 2. start a new current_sub_coords with (B_lon, B_lat) and (p2[0], p2[1]).
# Let's redo this loop logic.
pass
# Corrected loop logic:
sub_segments = []
current_sub_coords = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
p1 = adjusted_coords[i-1]
p2 = adjusted_coords[i]
boundary = get_boundary(p1[0], p2[0])
if boundary:
B_lon, B_lat = boundary
# Finish current sub-segment
current_sub_coords.append((B_lon, B_lat))
sub_segments.append(LineString(current_sub_coords))
# Start new sub-segment
current_sub_coords = [(B_lon, B_lat), (p2[0], p2[1])]
else:
current_sub_coords.append(p2)
# Last one
if len(current_sub_coords) >= 2:
sub_segments.append(LineString(current_sub_coords))
# Now, normalize all coordinates in all sub_segments back to [-180, 180]
final_sub_geoms = []
for sg in sub_segments:
# Normalize longitudes: (lon + 180) % 360 - 180
new_coords = []
for x, y in sg.coords:
new_x = (x + 180) % 360 - 180
# Handle the case where % 360 returns 0 for -180 (which is fine)
# but we want to ensure we don't get +180 if we wanted -180.
# Actually, -180 and 180 are the same.
new_coords.append((new_x, y))
final_sub_geoms.append(LineString(new_coords))
if not final_sub_geoms:
fixed_geoms.append(geom) # Fallback
else:
fixed_geoms.append(MultiLineString(final_sub_geoms))
gdf.geometry = fixed_geoms
# 2. Convert to Fiji National Metric Grid
# Fiji uses Fiji Grid (EPSG:2978 or similar? Let's check)
# Actually, common for Fiji is Fiji Transverse Mercator.
# Let's search for Fiji CRS.
# EPSG:2978 is "Fiji Grid".
# Let's try to use EPSG:2978.
fiji_crs = "EPSG:2978"
gdf = gdf.to_crs(fiji_crs)
# 3. Calculate length in metres
gdf['length_m'] = gdf.geometry.length
# 4. Ensure all are MultiLineString
def ensure_multilinestring(geom):
if geom.geom_type == 'LineString':
return MultiLineString([geom])
return geom
gdf.geometry = gdf.geometry.map(ensure_multilinestring)
# 5. Save to GeoJSON
# The prompt asks for 'fiji_transects_fmg.geojson'
gdf.to_file('fiji_transects_fmg.geojson', driver='GeoJSON')
# ... wait, I need to define get_boundary inside solve or pass it.
# And I'll use a more robust way to ensure MultiLineString.
solve()
` , file_path: `/work/solve.py`
missing or non-string argument: 'file_path'
1:30
Write
`/work/solve.py`
content · 121 lines · py`
import geopandas as gpd
import pandas as pd
from shapely.geometry import LineString, MultiLineString
import pyproj
def get_boundary(lon1, lon2):
"""
Find k such that (2k+1)*180 is between lon1 and lon2.
Returns (B_lon, B_lat) or None.
"""
# Boundaries are ..., -180, 180, 360, ...
# We look for B = (2k+1)*180
# We can estimate k.
# B/180 = 2k+1 => k = (B/180 - 1) / 2
# Let's check a few k's around lon1/180.
low_k = int(lon1 / 180) - 2
high_k = int(lon1 / 180) + 2
for k in range(low_k, high_k + 1):
B = (2 * k + 1) * 180
if min(lon1, lon2) < B < max(lon1, lon2):
return B
return None
def solve():
gdf = gpd.read_file('fiji_transects_wgs84.geojson')
# 1. Fix Antimeridian
fixed_geoms = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom is None or geom.is_empty:
fixed_geoms.append(geom)
continue
coords = list(geom.coords)
adjusted_coords = [coords[0]]
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
lon2 -= 360
elif diff < -180:
lon2 += 360
adjusted_coords.append((lon2, lat2))
sub_segments = []
current_sub_coords = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
p1 = adjusted_coords[i-1]
p2 = adjusted_coords[i]
B_lon = get_boundary(p1[0], p2[0])
if B_lon is not None:
# Interpolate lat at B_lon
t = (B_lon - p1[0]) / (p2[0] - p1[0])
B_lat = p1[1] + t * (p2[1] - p1[1])
# Finish current sub-segment
current_sub_coords.append((B_lon, B_lat))
sub_segments.append(LineString(current_sub_coords))
# Start new sub-segment
current_sub_coords = [(B_lon, B_lat), (p2[0], p2[1])]
else:
current_sub_coords.append(p2)
if len(current_sub_coords) >= 2:
sub_segments.append(LineString(current_sub_coords))
# Normalize all coordinates in all sub_segments back to [-180, 180]
final_sub_geoms = []
for sg in sub_segments:
new_coords = []
for x, y in sg.coords:
# Normalize longitude to [-180, 180]
# Using (x + 180) % 360 - 180 works well.
nx = (x + 180) % 360 - 180
# If nx is -180, it's fine.
new_coords.append((nx, y))
final_sub_geoms.append(LineString(new_coords))
if not final_sub_geoms:
fixed_geoms.append(geom)
else:
fixed_geoms.append(MultiLineString(final_sub_geoms))
gdf.geometry = fixed_geoms
# 2. Convert to Fiji National Metric Grid (EPSG:2978)
# Note: EPSG:2978 is Fiji Grid.
fiji_crs = "EPSG:2978"
gdf = gdf.to_crs(fiji_crs)
# 3. Calculate length in metres
gdf['length_m'] = gdf.geometry.length
# 4. Ensure all are MultiLineString
def ensure_multilinestring(geom):
if geom.geom_type == 'LineString':
return MultiLineString([geom])
return geom
gdf.geometry = gdf.geometry.map(ensure_multilinestring)
# 5. Save to GeoJSON
# Keeping original columns and adding length_m
# Columns to keep: transect_id, vessel, survey_date, length_m
# We'll keep all and ensure the ones requested are there.
# The user said: "Carry the survey attributes (vessel and survey_date) through unchanged,
# use transect_id as the key field".
gdf.to_file('fiji_transects_fmg.geojson', driver='GeoJSON')
if __name__ == "__main__":
solve()
Wrote `/work/solve.py` (3954 chars).
1:32
Bash
python solve.py
python: can't open file '/work/solve.py': [Errno 2] No such file or directory
1:33
Bash
ls -l /work/solve.py
ls: cannot access '/work/solve.py': No such file or directory
1:57
Write
`/work/solve.py`
content · 108 lines · py`
import geopandas as gpd
import pandas as pd
from shapely.geometry import LineString, MultiLineString
import pyproj
import os
def get_boundary(lon1, lon2):
"""
Find k such that (2k+1)*180 is between lon1 and lon2.
Returns B_lon or None.
"""
low_k = int(lon1 / 180) - 2
high_k = int(lon1 / 180) + 2
for k in range(low_k, high_k + 1):
B = (2 * k + 1) * 180
if min(lon1, lon2) < B < max(lon1, lon2):
return B
return None
def solve():
input_file = 'fiji_transects_wgs84.geojson'
output_file = 'fiji_transects_fmg.geojson'
if not os.path.exists(input_file):
print(f"Error: {input_file} not found")
return
gdf = gpd.read_file(input_file)
# 1. Fix Antimeridian
fixed_geoms = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom is None or geom.is_empty:
fixed_geoms.append(geom)
continue
coords = list(geom.coords)
adjusted_coords = [coords[0]]
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
lon2 -= 360
elif diff < -180:
lon2 += 360
adjusted_coords.append((lon2, lat2))
sub_segments = []
current_sub_coords = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
p1 = adjusted_coords[i-1]
p2 = adjusted_coords[i]
B_lon = get_boundary(p1[0], p2[0])
if B_lon is not None:
t = (B_lon - p1[0]) / (p2[0] - p1[0])
B_lat = p1[1] + t * (p2[1] - p1[1])
current_sub_coords.append((B_lon, B_lat))
sub_segments.append(LineString(current_sub_coords))
current_sub_coords = [(B_lon, B_lat), (p2[0], p2[1])]
else:
current_sub_coords.append(p2)
if len(current_sub_coords) >= 2:
sub_segments.append(LineString(current_sub_coords))
final_sub_geoms = []
for sg in sub_segments:
new_coords = []
for x, y in sg.coords:
nx = (x + 180) % 360 - 180
new_coords.append((nx, y))
final_sub_geoms.append(LineString(new_coords))
if not final_sub_geoms:
fixed_geoms.append(geom)
else:
fixed_geoms.append(MultiLineString(final_sub_geoms))
gdf.geometry = fixed_geoms
# 2. Convert to Fiji National Metric Grid (EPSG:2978)
fiji_crs = "EPSG:2978"
gdf = gdf.to_crs(fiji_crs)
# 3. Calculate length in metres
gdf['length_m'] = gdf.geometry.length
# 4. Ensure all are MultiLineString
def ensure_multilinestring(geom):
if geom.geom_type == 'LineString':
return MultiLineString([geom])
return geom
gdf.geometry = gdf.geometry.map(ensure_multilinestring)
# 5. Save to GeoJSON
gdf.to_file(output_file, driver='GeoJSON')
print(f"Successfully saved to {output_file}")
if __name__ == "__main__":
solve()
Wrote `/work/solve.py` (3250 chars).
1:59
Bash
python /work/solve.py
python: can't open file '/work/solve.py': [Errno 2] No such file or directory
2:02
Bash
pwd && ls -l /work/solve.py
/work
ls: cannot access '/work/solve.py': No such file or directory
2:26
Write
/work/solve.py
content · 95 lines · py
import geopandas as gpd
import pandas as pd
from shapely.geometry import LineString, MultiLineString
import pyproj
import os
def get_boundary(lon1, lon2):
low_k = int(lon1 / 180) - 2
high_k = int(lon1 / 180) + 2
for k in range(low_k, high_k + 1):
B = (2 * k + 1) * 180
if min(lon1, lon2) < B < max(lon1, lon2):
return B
return None
def solve():
input_file = 'fiji_transects_wgs84.geojson'
output_file = 'fiji_transects_fmg.geojson'
if not os.path.exists(input_file):
print(f"Error: {input_file} not found")
return
gdf = gpd.read_file(input_file)
fixed_geoms = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom is None or geom.is_empty:
fixed_geoms.append(geom)
continue
coords = list(geom.coords)
adjusted_coords = [coords[0]]
for i in range(len(coords) - 1):
lon1, lat1 = coords[i]
lon2, lat2 = coords[i+1]
diff = lon2 - lon1
if diff > 180:
lon2 -= 360
elif diff < -180:
lon2 += 360
adjusted_coords.append((lon2, lat2))
sub_segments = []
current_sub_coords = [adjusted_coords[0]]
for i in range(1, len(adjusted_coords)):
p1 = adjusted_coords[i-1]
p2 = adjusted_coords[i]
B_lon = get_boundary(p1[0], p2[0])
if B_lon is not None:
t = (B_lon - p1[0]) / (p2[0] - p1[0])
B_lat = p1[1] + t * (p2[1] - p1[1])
current_sub_coords.append((B_lon, B_lat))
sub_segments.append(LineString(current_sub_coords))
current_sub_coords = [(B_lon, B_lat), (p2[0], p2[1])]
else:
current_sub_coords.append(p2)
if len(current_sub_coords) >= 2:
sub_segments.append(LineString(current_sub_coords))
final_sub_geoms = []
for sg in sub_segments:
new_coords = []
for x, y in sg.coords:
nx = (x + 180) % 360 - 180
new_coords.append((nx, y))
final_sub_geoms.append(LineString(new_coords))
if not final_sub_geoms:
fixed_geoms.append(geom)
else:
fixed_geoms.append(MultiLineString(final_sub_geoms))
gdf.geometry = fixed_geoms
fiji_crs = "EPSG:2978"
gdf = gdf.to_crs(fiji_crs)
gdf['length_m'] = gdf.geometry.length
def ensure_multilinestring(geom):
if geom.geom_type == 'LineString':
return MultiLineString([geom])
return geom
gdf.geometry = gdf.geometry.map(ensure_multilinestring)
gdf.to_file(output_file, driver='GeoJSON')
print(f"Successfully saved to {output_file}")
if __name__ == "__main__":
solve()
Wrote /work/solve.py (2936 chars).
2:28
Bash
python solve.py
Successfully saved to fiji_transects_fmg.geojson
2:32
Bash
head -n 30 fiji_transects_fmg.geojson
{
"type": "FeatureCollection",
"name": "fiji_transects_fmg",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::2978" } },
"features": [
{ "type": "Feature", "properties": { "transect_id": "T001", "vessel": "Taveuni II", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": true, "length_m": 469778.0392762142 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4057186.978743994608521, 7501490.88197785243392 ], [ -3990562.989241968840361, 7519594.794576410204172 ], [ -3924416.543200526386499, 7537849.291802688501775 ], [ -3920759.107582556083798, 7538866.691560555249453 ] ], [ [ -3920759.107582556083798, 7538866.691560555249453 ], [ -3858667.620355263352394, 7555989.889927031472325 ], [ -3921224.141555075533688, 7540758.967933808453381 ] ], [ [ -3921224.141555075533688, 7540758.967933808453381 ], [ -3793290.10984324477613, 7573957.023025639355183 ], [ -3727783.917402566410601, 7589643.742623878642917 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T002", "vessel": "Bligh", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": true, "length_m": 371738.08447511279 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4050666.360438455827534, 7546185.034948678687215 ], [ -3970687.292615190148354, 7589390.559027340263128 ], [ -3937322.345388594083488, 7607190.942745195701718 ] ], [ [ -3937322.345388594083488, 7607190.942745195701718 ], [ -3890927.465044286102057, 7631716.099139807745814 ], [ -3940390.813088754191995, 7620064.841459836810827 ] ], [ [ -3940390.813088754191995, 7620064.841459836810827 ], [ -3811664.771456338465214, 7674399.22692909091711 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T003", "vessel": "Lomaiviti", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": true, "length_m": 474776.33939123643 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4238464.044482219964266, 7494401.466757215559483 ], [ -4127423.395279933698475, 7514911.95050223916769 ], [ -4017538.704912162385881, 7534715.435817249119282 ], [ -3923738.96952037140727, 7551017.537043021060526 ] ], [ [ -3923738.96952037140727, 7551017.537043021060526 ], [ -3908705.45139485783875, 7553582.410255588591099 ], [ -3923482.769804353825748, 7549970.464843736961484 ] ], [ [ -3923482.769804353825748, 7549970.464843736961484 ], [ -3800680.829582385718822, 7570665.165481228381395 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T004", "vessel": "Vanua I", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": true, "length_m": 518491.62272010022 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4060091.600163659080863, 7475969.832558298483491 ], [ -3980323.588479558005929, 7525790.475991999730468 ], [ -3925498.555483118630946, 7558221.040468060411513 ] ], [ [ -3925498.555483118630946, 7558221.040468060411513 ], [ -3900270.937357514165342, 7573002.724729908630252 ], [ -3927496.721503143198788, 7566427.228859775699675 ] ], [ [ -3927496.721503143198788, 7566427.228859775699675 ], [ -3820935.502705058082938, 7621722.866998837329447 ], [ -3741414.285797285847366, 7668195.316860696300864 ], [ -3661895.434108520392329, 7713133.789540608413517 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T005", "vessel": "Bligh", "survey_date": "2025-08-19T00:00:00", "crosses_antimeridian_flag": true, "length_m": 565754.55301404977 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4222895.19729661475867, 7415185.388047736138105 ], [ -4145678.684903216548264, 7423249.230821310542524 ], [ -4068983.365978632122278, 7430700.200429175049067 ], [ -3993312.783225270919502, 7439525.055308904498816 ], [ -3917533.39457643404603, 7445440.026264045387506 ], [ -3897793.419999377802014, 7447168.838590987026691 ] ], [ [ -3897793.419999377802014, 7447168.838590987026691 ], [ -3842532.220792734064162, 7451902.551046738401055 ], [ -3895558.093753315508366, 7438419.663100691512227 ] ], [ [ -3895558.093753315508366, 7438419.663100691512227 ], [ -3768394.03990045003593, 7459356.669023869559169 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T006", "vessel": "Cakaulevu", "survey_date": "2025-08-13T00:00:00", "crosses_antimeridian_flag": true, "length_m": 586828.91494491871 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4072013.386766273528337, 7388770.954151820391417 ], [ -4003641.895763976499438, 7435495.569693414494395 ], [ -3935118.956585772335529, 7480783.979957517236471 ], [ -3910483.250813558697701, 7497419.776652405969799 ] ], [ [ -3910483.250813558697701, 7497419.776652405969799 ], [ -3866939.571860705502331, 7526575.4268246460706 ], [ -3914812.7821672745049, 7514797.978187005966902 ] ], [ [ -3914812.7821672745049, 7514797.978187005966902 ], [ -3798506.913532365113497, 7570462.772388414479792 ], [ -3730371.628425966016948, 7614711.890129117295146 ], [ -3661909.508072525262833, 7656612.145196046680212 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T007", "vessel": "Vanua I", "survey_date": "2025-08-19T00:00:00", "crosses_antimeridian_flag": true, "length_m": 587585.79784131888 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4208449.214158964343369, 7533040.314834531396627 ], [ -4107569.493033709004521, 7565889.221566676162183 ], [ -4007329.480703122913837, 7597350.279799181967974 ], [ -3939982.613208837807178, 7618348.189319109544158 ] ], [ [ -3939982.613208837807178, 7618348.189319109544158 ], [ -3907900.934754991903901, 7628228.465925454162061 ], [ -3940499.140250832773745, 7620520.611577075906098 ] ], [ [ -3940499.140250832773745, 7620520.611577075906098 ], [ -3809012.704658505506814, 7657485.830707443878055 ], [ -3710900.52556583750993, 7686235.015292932279408 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T008", "vessel": "Taveuni II", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": true, "length_m": 241736.64133164781 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3987120.015662517398596, 7475802.004374167881906 ], [ -3953018.114732967689633, 7489459.673317324370146 ], [ -3919208.816735017113388, 7503888.893989851698279 ], [ -3912813.907736542634666, 7506759.62408684566617 ] ], [ [ -3912813.907736542634666, 7506759.62408684566617 ], [ -3885639.076961605809629, 7518910.683297421783209 ], [ -3914085.879759171977639, 7511871.765220342203975 ] ], [ [ -3914085.879759171977639, 7511871.765220342203975 ], [ -3851972.68114697933197, 7533174.503237062133849 ], [ -3818418.152347727678716, 7547526.283450357615948 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T009", "vessel": "Vanua I", "survey_date": "2025-08-13T00:00:00", "crosses_antimeridian_flag": true, "length_m": 344369.59048031922 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4205976.70141220279038, 7605929.22117679938674 ], [ -4139426.793498487211764, 7617749.036489377729595 ], [ -4073273.364599361084402, 7629233.930149489082396 ], [ -4007668.725306287407875, 7641063.830649314448237 ], [ -3947868.932651279494166, 7651736.524888152256608 ] ], [ [ -3947868.932651279494166, 7651736.524888152256608 ], [ -3942467.472642532549798, 7652690.454885971732438 ], [ -3947799.465135023929179, 7651440.338843306526542 ] ], [ [ -3947799.465135023929179, 7651440.338843306526542 ], [ -3877706.942803180776536, 7664320.699712052941322 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T010", "vessel": "Vanua I", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": true, "length_m": 786191.05169202061 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4245965.656445472501218, 7504512.560660600662231 ], [ -4038574.179807452484965, 7529930.589867516420782 ], [ -3921937.695375851355493, 7543665.347142620012164 ] ], [ [ -3921937.695375851355493, 7543665.347142620012164 ], [ -3835383.041818223893642, 7553399.042971541173756 ], [ -3919293.686256753280759, 7532913.260297977365553 ] ], [ [ -3919293.686256753280759, 7532913.260297977365553 ], [ -3636030.718867635820061, 7574709.881422424688935 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T011", "vessel": "Taveuni II", "survey_date": "2025-08-20T00:00:00", "crosses_antimeridian_flag": false, "length_m": 94827.713405829592 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3517268.127865444868803, 7607585.376898313872516 ], [ -3531931.115169481374323, 7601661.157163100317121 ], [ -3546838.167644052766263, 7596756.03092491067946 ], [ -3561754.908018881455064, 7591812.159641010686755 ], [ -3576386.686157986987382, 7585527.288464969024062 ], [ -3591251.239713742397726, 7580197.791360345669091 ], [ -3606000.856782448012382, 7574287.721548304893076 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T012", "vessel": "Taveuni II", "survey_date": "2025-08-20T00:00:00", "crosses_antimeridian_flag": false, "length_m": 110759.82324191411 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4391164.571518260985613, 7360320.613502792082727 ], [ -4394530.046042634174228, 7397650.021330624818802 ], [ -4397657.184081426821649, 7434726.764913761988282 ], [ -4400317.44597178325057, 7470699.160521870478988 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T013", "vessel": "Bligh", "survey_date": "2025-08-19T00:00:00", "crosses_antimeridian_flag": false, "length_m": 217667.98690759443 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3500634.66661041136831, 7624488.529779511503875 ], [ -3555019.78079743264243, 7576273.736240705475211 ], [ -3609635.98526506870985, 7529185.577286700718105 ], [ -3663853.314219099935144, 7480489.774256192147732 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T014", "vessel": "Lomaiviti", "survey_date": "2025-08-13T00:00:00", "crosses_antimeridian_flag": false, "length_m": 192985.46945932449 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4413774.153938710689545, 7562150.586639955639839 ], [ -4365658.892802538350224, 7556679.867402884177864 ], [ -4317929.406769572757185, 7551632.806110155768692 ], [ -4269506.442580503411591, 7542865.706725970841944 ], [ -4222392.127146146260202, 7538103.418793024495244 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T015", "vessel": "Vanua I", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": false, "length_m": 152272.26172544161 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3599741.177476593758911, 7736212.745857689529657 ], [ -3623035.573182810563594, 7726141.690671050921082 ], [ -3646682.824379864614457, 7717526.470636084675789 ], [ -3670190.43756432691589, 7708062.71239205263555 ], [ -3693556.10919238999486, 7697759.517956076189876 ], [ -3717019.016520280390978, 7687716.44325372390449 ], [ -3740853.234124850481749, 7679150.475810619071126 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T016", "vessel": "Taveuni II", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": false, "length_m": 67656.12720294467 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4100682.025228454731405, 7403861.670867463573813 ], [ -4084495.422882405109704, 7408737.328602271154523 ], [ -4067970.726826228201389, 7412243.751201774924994 ], [ -4051150.533411594107747, 7414525.191715514287353 ], [ -4035286.142096712253988, 7420304.588720072060823 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T017", "vessel": "Taveuni II", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": false, "length_m": 184670.49256340988 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3561712.670831091701984, 7762173.437280626036227 ], [ -3571770.743310764431953, 7732279.147927755489945 ], [ -3582115.905092332046479, 7704162.682494780048728 ], [ -3591960.86162349069491, 7674129.711269719526172 ], [ -3602016.852133523207158, 7645485.724518963135779 ], [ -3612005.26394061697647, 7616929.932320784777403 ], [ -3621715.642344930209219, 7587537.784111866727471 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T018", "vessel": "Bligh", "survey_date": "2025-08-19T00:00:00", "crosses_antimeridian_flag": false, "length_m": 147355.05713202301 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4462123.444380414672196, 7510544.93428553827107 ], [ -4430710.601116840727627, 7491378.522975526750088 ], [ -4399257.654556686989963, 7471766.769270030781627 ], [ -4368137.635694316588342, 7453077.762156526558101 ], [ -4336752.643661714158952, 7433126.185787388123572 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T019", "vessel": "Lomaiviti", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": false, "length_m": 232764.1914454615 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4176851.705811001360416, 7459432.844160176813602 ], [ -4234651.248703385703266, 7458726.175438466481864 ], [ -4292666.868704052641988, 7457333.072217276319861 ], [ -4350927.18282030057162, 7455346.205549153499305 ], [ -4409516.225984890013933, 7453055.635055471211672 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T020", "vessel": "Taveuni II", "survey_date": "2025-08-13T00:00:00", "crosses_antimeridian_flag": false, "length_m": 277199.46117691754 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4350910.062632170505822, 7505239.048665195703506 ], [ -4281165.944424076937139, 7496325.606074972078204 ], [ -4212400.957525409758091, 7488938.498835166916251 ], [ -4143841.310585814528167, 7480197.145220424979925 ], [ -4075803.210624480620027, 7471335.400718780234456 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T021", "vessel": "Vanua I", "survey_date": "2025-08-16T00:00:00", "crosses_antimeridian_flag": false, "length_m": 298679.96831559524 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4432894.922866867855191, 7481944.414852473884821 ], [ -4339715.385359331965446, 7442961.49750720243901 ], [ -4247826.534178294241428, 7405378.32000738568604 ], [ -4156854.957871247082949, 7367880.07575336843729 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T022", "vessel": "Vanua I", "survey_date": "2025-08-15T00:00:00", "crosses_antimeridian_flag": false, "length_m": 66018.4566335868 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4290373.67644941713661, 7411969.506152883172035 ], [ -4284262.951733545400202, 7423280.151753674261272 ], [ -4278368.822872160933912, 7435430.017478138208389 ], [ -4272225.438446197658777, 7446713.317690638825297 ], [ -4266477.219423810951412, 7459509.236932834610343 ], [ -4260280.488234144635499, 7470690.401950720697641 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T023", "vessel": "Lomaiviti", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": false, "length_m": 99434.640040401122 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3561531.550839005503803, 7613272.104708673432469 ], [ -3577690.090686303097755, 7601348.943141364492476 ], [ -3594036.502204718068242, 7590229.953301530331373 ], [ -3610777.861766006797552, 7580801.746638044714928 ], [ -3626666.002666668500751, 7567601.691654571332037 ], [ -3643087.810354783665389, 7556694.620280769653618 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T024", "vessel": "Vanua I", "survey_date": "2025-08-12T00:00:00", "crosses_antimeridian_flag": false, "length_m": 306700.81760221143 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -3829965.167181461118162, 7668176.042211830615997 ], [ -3767862.083356587216258, 7666414.750467590987682 ], [ -3706092.278463845141232, 7664256.13918883074075 ], [ -3644837.109403938986361, 7662548.670569711364806 ], [ -3584257.482800531201065, 7662082.654382421635091 ], [ -3523444.398040698841214, 7658740.193409200757742 ] ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T025", "vessel": "Taveuni II", "survey_date": "2025-08-19T00:00:00", "crosses_antimeridian_flag": false, "length_m": 141676.28992404148 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -4346307.11330899503082, 7335661.405004533007741 ], [ -4358893.576485850848258, 7380368.914957183413208 ], [ -4371676.896148102357984, 7426576.505353206768632 ], [ -4384070.571196650154889, 7472211.062794471159577 ] ] ] } },
2:40