crs-l2-fiji-antimeridian

Status: done
Score: 1.000
Duration: 3:09
Cost: 1.58¢
Model: deepseek/deepseek-v4-flash

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": "deepseek/deepseek-v4-flash",
  "base_url": "https://openrouter.ai/api/v1"
}
0:01
Let me start by reading the input file to understand the data structure and identify the problematic geometries.
0:01
Bash head -c 5000 /work/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_antimeridi
0:02
Let me see the full file to understand all the features and their structures.
0:02
Bash wc -l /work/fiji_transects_wgs84.geojson
37 /work/fiji_transects_wgs84.geojson
0:02
Bash cat /work/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 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T016", "vessel": "Taveuni II", "survey_date": "2025-08-15", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 178.445325115686984, -18.225562645051426 ], [ 178.570919872630384, -18.22187730118792 ], [ 178.696514629573755, -18.228085980840198 ], [ 178.822109386517127, -18.243164774607269 ], [ 178.947704143460527, -18.232257588046291 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T017", "vessel": "Taveuni II", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -176.949497668404376, -16.593233226112279 ], [ -177.073130399044231, -16.796136633276152 ], [ -177.196763129684086, -16.985064764093782 ], [ -177.320395860323913, -17.188172387851619 ], [ -177.444028590963768, -17.380278567766066 ], [ -177.567661321603623, -17.571298263401527 ], [ -177.691294052243478, -17.76827441812642 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T018", "vessel": "Bligh", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.111138114901024, -16.851117503263293 ], [ 176.291399614433374, -17.034309766495799 ], [ 176.471661113965695, -17.221302006070296 ], [ 176.651922613498016, -17.402317112686557 ], [ 176.832184113030365, -17.592994204367653 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T019", "vessel": "Lomaiviti", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 178.007516628261584, -17.706954766350957 ], [ 177.596962177324428, -17.607161226082525 ], [ 177.186407726387301, -17.511279680346377 ], [ 176.775853275450146, -17.418568907300433 ], [ 176.36529882451299, -17.326891370330944 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T020", "vessel": "Taveuni II", "survey_date": "2025-08-13", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.869640838143511, -17.085093978662378 ], [ 177.34023164697706, -17.269542693344249 ], [ 177.810822455810609, -17.442447410976666 ], [ 178.281413264644158, -17.624621823987695 ], [ 178.752004073477707, -17.807162082048386 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T021", "vessel": "Vanua I", "survey_date": "2025-08-16", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.258661225850091, -17.092877710432774 ], [ 176.830345357965598, -17.521807453385343 ], [ 177.402029490081105, -17.943438299004075 ], [ 177.973713622196613, -18.366984215963161 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T022", "vessel": "Vanua I", "survey_date": "2025-08-15", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 177.115699442929383, -17.820293640195572 ], [ 177.180354072206086, -17.755581112632651 ], [ 177.245008701482789, -17.684692899482695 ], [ 177.30966333075952, -17.61995755685173 ], [ 177.374317960036223, -17.544174647257226 ], [ 177.438972589312925, -17.479955835030527 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T023", "vessel": "Lomaiviti", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -177.191351883954098, -17.679938619650844 ], [ -177.334313691261116, -17.740394590021616 ], [ -177.477275498568133, -17.794367957957562 ], [ -177.62023730587515, -17.835119945356809 ], [ -177.763199113182168, -17.904282380225705 ], [ -177.906160920489185, -17.955635131096855 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T024", "vessel": "Vanua I", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -179.108274205314615, -16.84950325482971 ], [ -178.651703763804733, -16.962456436762313 ], [ -178.195133322294822, -17.077410225872036 ], [ -177.73856288078494, -17.187966865781235 ], [ -177.281992439275029, -17.288042922581088 ], [ -176.825421997765147, -17.40904519070677 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T025", "vessel": "Taveuni II", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 176.574749815324452, -18.225329195672629 ], [ 176.575711406506713, -17.903825702399828 ], [ 176.576672997688945, -17.572376190438085 ], [ 176.577634588871206, -17.245872893430239 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T026", "vessel": "Cakaulevu", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ 178.630248956242411, -17.547785158041279 ], [ 178.44215451378426, -17.570057172060459 ], [ 178.254060071326109, -17.598148620651486 ], [ 178.065965628867986, -17.611819625668215 ], [ 177.877871186409834, -17.645164465599024 ], [ 177.689776743951683, -17.659546383089758 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T027", "vessel": "Vanua I", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -177.773526218774975, -17.183972526301677 ], [ -177.993798674497214, -17.290101550005915 ], [ -178.214071130219452, -17.383420029016879 ], [ -178.434343585941718, -17.487055860389813 ], [ -178.654616041663957, -17.584325384194859 ], [ -178.874888497386195, -17.694189986558115 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T028", "vessel": "Vanua I", "survey_date": "2025-08-12", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -178.154921880223981, -16.519500569812283 ], [ -177.760867938660567, -16.61473611015824 ], [ -177.366813997097154, -16.706948361526067 ], [ -176.972760055533769, -16.779276042892469 ], [ -176.578706113970355, -16.874986722588798 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T029", "vessel": "Lomaiviti", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -176.563841265411412, -18.091246216590591 ], [ -176.943316553982299, -17.796168551154441 ], [ -177.322791842553215, -17.510273970538908 ], [ -177.702267131124103, -17.231705179840109 ], [ -178.08174241969499, -16.949176694851047 ] ] } },
{ "type": "Feature", "properties": { "transect_id": "T030", "vessel": "Cakaulevu", "survey_date": "2025-08-19", "crosses_antimeridian_flag": false }, "geometry": { "type": "LineString", "coordinates": [ [ -177.772700226865993, -16.898671712097919 ], [ -177.981739053528088, -17.042373280579991 ], [ -178.190777880190183, -17.175821795383495 ], [ -178.399816706852278, -17.32978967298839 ], [ -178.608855533514344, -17.474383681681747 ], [ -178.817894360176439, -17.613581860280195 ], [ -179.026933186838534, -17.755873350663471 ] ] } }
]
}
0:21
Let me analyze this problem. The transects that cross the antimeridian (180° longitude) have coordinates that go from positive longitudes (like +179°) to negative longitudes (like -179°). Since the coordinates in the GeoJSON are in WGS84 (lat/lon), rendering them as a simple LineString causes the line to wrap all the way around the globe instead of crossing locally.

The fix is to split these transects at the antimeridian into multiple LineString parts, creating a MultiLineString geometry. For transects that don't cross the antimeridian, they should also be MultiLineString (as the instruction says "Every feature must come out as a MultiLineString").

The key insight: For points crossing the antimeridian, I need to convert longitudes that are on the "other side" by adding or subtracting 360 to keep the coordinates continuous. For example, -179° becomes 181° (or -179 + 360 = 181). Then the line segments will be continuous instead of wrapping around the globe.

Wait, actually let me think about this differently. The problem is that when you have longitude values like:
- 179.97... then -179.51... 

This jumps from 179.97 to -179.51, which is a difference of about 359 degrees longitude - going the long way around.

But actually the real-world path should be 179.97 to 180.49 (or 179.97 to -179.51 + 360 = 180.49). The difference is only about 0.5 degrees.

So the approach is:
1. For each transect that crosses the antimeridian, split it at the 180° meridian.
2. Convert coordinates so that longitudes west of the antimeridian are shifted by +360 to make them continuous.
3. Then split into multiple LineStrings where each part stays on one side of 180°.
4. Project to Fiji's metric grid system.

Wait, let me think about this more carefully.

The standard approach for antimeridian crossing:
1. For each line, check if it crosses the antimeridian (180° longitude). This happens when consecutive longitudes jump from > 170 to < -170 or vice versa.
2. For crossing segments, interpolate the intersection point at 180° longitude.
3. Split the line into segments that don't cross 180°.
4. For segments west of the antimeridian (longitudes < 0 in the -180 to 0 range), add 360 to the longitudes so they become continuous (e.g., -179 → 181).

Actually, looking more carefully - the real issue is that we need to split at the antimeridian and then project to a local Fiji grid. Fiji uses a metric grid - let me find the right EPSG code.

Fiji's national metric grid is likely EPSG:3460 (Fiji 1956 / Fiji Central Grid) or EPSG:3461 (Fiji 1956 / Fiji East Grid)... Actually, let me think about this.

The common CRS for Fiji is "Fiji 1956 / Fiji Central Grid" (EPSG:3460) or "Fiji 1986 / Fiji Central Grid" (EPSG: 1753).

But actually, let me search for the right Fiji metric grid. The most common ones:
- EPSG:3460 - Fiji 1956 / Fiji Central Grid
- EPSG:3461 - Fiji 1956 / Fiji East Grid
- EPSG:3462 - Fiji 1956 / Fiji West Grid
- EPSG:3139 - Fiji 1956 / Fiji Central Grid (different authority)

Actually, the "Fiji Metric Grid" is a specific system. Let me look it up.

Actually for modern work, EPSG:3460 (Fiji 1956 / Fiji Central Grid) or its WGS84 equivalent would be used. But there's also EPSG:3139 "Fiji 1956 / Fiji Central Grid" from EPSG.

Let me just check what's commonly available in pyproj.

Actually, let me just use a reasonable Fiji metric CRS. The most common one is EPSG:3460 (Fiji 1956 / Fiji Central Grid). But these transects span the whole Fiji area, so we might need a wider one.

Wait - actually for Fiji-wide work, EPSG:3460 (Fiji 1956 / Fiji Central Grid) covers longitudes 177°E to 179°E? No, let me check...

Fiji Central Grid (EPSG:3460) - central meridian at 178°E
Fiji East Grid (EPSG:3461) - central meridian at 180°E  
Fiji West Grid (EPSG:3462) - central meridian at 176°E

Since our transects span across a wide area, we probably need the central grid.

Actually, I think a simpler approach might be better. Let me just use a CRS that covers Fiji well. Let me check what's available.

Let me just look at this pragmatically. I'll use geopandas with a suitable CRS. Let me first figure out the right approach.

For the antimeridian crossing issue, here's my plan:

1. Read the GeoJSON
2. For each feature:
   a. If it crosses the antimeridian: split into parts, each part as a continuous LineString
   b. All features become MultiLineString
3. Project to Fiji's metric grid (I'll need to figure out the correct EPSG)
4. Calculate length in meters
5. Write output as GeoJSON

Let me write a Python script to do this.

For the antimeridian fix, the standard algorithm:
1. Iterate through coordinates
2. When a segment crosses the antimeridian (|lon1 - lon2| > 180), split it
3. Interpolate the crossing point at lon=180 (or -180)
4. Continue building line segments

For the projection, I'll use pyproj. Let me figure out the right CRS.

Actually, let me think about this differently. Instead of trying to find the exact Fiji metric grid EPSG code, let me search for it.

Let me write a comprehensive Python script.

For the antimeridian crossing fix:
- When coordinates go from positive (e.g., 179.9) to negative (e.g., -179.5), the actual path crosses the 180° meridian with a longitude difference of only about 0.6°.
- To fix this, I'll shift the negative longitudes by +360 (so -179.5 becomes 180.5), then the line is continuous.
- Then I need to split at 180° to create separate line segments.

Let me write the script.

Actually, let me think about the longitude normalization more carefully.

The coordinates in the geojson use -180 to +180 convention. When a transect crosses the antimeridian going eastward, the longitudes go from e.g., +179.97 to -179.51. The actual geographic path is a short segment from 179.97°E to 180.49°E (which is -179.51° + 360°).

So my approach:
1. Detect antimeridian crossing: when consecutive longitudes have |lon₁ - lon₂| > 180 (or more specifically, when they change sign and have a large gap).
2. For segments crossing the antimeridian, interpolate the intersection at 180°.
3. Split the line into separate segments on each side of 180°.
4. For segments on the western side (longitudes < 0), add 360 to make them continuous.

Let me code this up properly with Python.

For the CRS - Fiji's metric grid. Let me try to use EPSG:3460 (Fiji 1956 / Fiji Central Grid). But I should check if that covers all the transects.

The transect longitudes range from about 176° to -179° (or 181° after shifting). So the central meridian at 178°E should work.

Actually, let me check what CRS to use. I'll search for it.
0:21
Bash python3 -c "import pyproj; crs = pyproj.CRS.from_epsg(3460); print(crs)"
EPSG:3460
0:22
Bash python3 -c "import pyproj; crs = pyproj.CRS.from_epsg(3139); print(crs)"
EPSG:3139
0:22
Bash python3 -c "import pyproj; list(pyproj.database.query_crs_codes(auth_name='EPSG'...
---
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import pyproj; print([c for c in pyproj.database.query_crs_codes(auth_name='EPSG', pj_types='PROJECTED_CRS') if 'Fiji' in c[1]])
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pyproj.database' has no attribute 'query_crs_codes'. Did you mean: 'query_crs_info'?
0:27
Let me check for the right Fiji projected CRS. The Fiji Map Grid (FMG) is EPSG:3460. Let me verify this.
0:27
Bash python3 -c "
python3 -c "
import pyproj
# List CRS info for EPSG:3460
print(pyproj.CRS.from_epsg(3460).to_wkt())
print('---')
print(pyproj.CRS.from_epsg(3460).name)
"
PROJCRS["Fiji 1986 / Fiji Map Grid",BASEGEOGCRS["Fiji 1986",DATUM["Fiji Geodetic Datum 1986",ELLIPSOID["WGS 72",6378135,298.26,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4720]],CONVERSION["Fiji Map Grid",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",-17,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",178.75,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.99985,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",2000000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",4000000,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping."],AREA["Fiji - onshore. Includes Viti Levu, Vanua Levu, Taveuni, the Yasawa Group, the Kadavu Group, the Lau Islands and Rotuma Islands."],BBOX[-20.81,176.81,-12.42,-178.15]],ID["EPSG",3460]]
---
Fiji 1986 / Fiji Map Grid
0:27
Bash python3 -c "
python3 -c "
import pyproj
crs_list = pyproj.database.query_crs_info(pj_types='PROJECTED_CRS')
for c in crs_list:
    if 'fiji' in c.name.lower() or 'fmg' in c.name.lower():
        print(c.code, c.name)
" 2>/dev/null; echo "==="; python3 -c "
import pyproj
crs_list = pyproj.database.query_crs_info(pj_types='PROJECTED_CRS')
for c in crs_list:
    if '3460' in c.code:
        print(c.code, c.name)
" 2>/dev/null
3141 Fiji 1956 / UTM zone 60S
3142 Fiji 1956 / UTM zone 1S
3460 Fiji 1986 / Fiji Map Grid
===
3460 Fiji 1986 / Fiji Map Grid
63460 Polydeuces (2015) - Sphere / Ocentric / Tranverse Mercator
1:41
Now I understand the problem. The data has transects that cross the antimeridian (180° longitude). When plotted, the coordinates in these transects go from positive longitudes (e.g., 179.9) to negative longitudes (e.g., -179.5), which causes the line to wrap all the way around the globe instead of crossing locally.

The fix is:
1. For transects that cross the antimeridian, split the LineString at the antimeridian into multiple parts, creating a MultiLineString.
2. Convert coordinates from WGS84 (EPSG:4326) to Fiji Map Grid (EPSG:3460).
3. Ensure every feature has a MultiLineString geometry.
4. Add a length_m attribute.

Let me also check EPSG:3139 - what was that?

Actually, EPSG:3460 is "Fiji 1986 / Fiji Map Grid" which is the national metric grid for Fiji. That's the one to use. EPSG:3139 is "Fiji 1956 / UTM zone 60S" which might be another option but 3460 is specifically the Fiji Map Grid.

Now the key issue: the antimeridian crossing. The data has coordinates in WGS84 (EPSG:4326). When coordinates jump from positive to negative across 180°, the line wraps around the globe.

For the Fiji Map Grid (EPSG:3460), the central meridian is 178.75°E, which covers Fiji nicely. But the antimeridian-crossing transects need to be split properly.

Let me look at T001, which has coordinates:
[178.94, -17.63], [179.45, -17.62], [179.97, -17.61], [-179.51, -17.60], [-178.99, -17.58], [-178.48, -17.58]

So it goes from ~179.97 to ~-179.51. The actual path crosses near 180° but doesn't go all the way around. To fix this, I need to add 360° to the negative longitudes (or shift coordinates) so that the line is continuous, then split it at the antimeridian (180°).

Actually, the approach is:
1. For each coordinate, if the longitude jumps by more than 180° from the previous one (more than ~180°), the segment crosses the antimeridian.
2. Split the line at the antimeridian (180°E).
3. Convert each segment to the projected CRS.

Let me write a Python script to handle all of this.

The algorithm:
- For each feature:
  - Take the LineString coordinates
  - Identify where crossings occur (longitude differences > 180° in absolute value, or sign changes around 180°)
  - Split the line into segments at those crossing points
  - For each segment, shift coordinates so that longitudes are continuous (add/subtract 360° to make them monotonic)
  - Then convert to Fiji Map Grid
  - Collect as MultiLineString

Actually let me think more carefully. The typical approach for antimeridian crossing:

1. Detect crossings: when consecutive longitudes differ by more than 180° in absolute value.
2. For each part between crossings, adjust longitudes by adding/subtracting 360 to make them continuous (e.g., all negative longitudes in a part that's mostly positive get +360).
3. Then create the geometry, reproject, and collect.

Let me write the script.

For the Fiji Map Grid, the central meridian is 178.75°E, so it handles longitudes around 180° fine. But we need to make sure the geometry is continuous before reprojecting.

Here's my plan:

```python
import geopandas as gpd
import shapely.geometry as geom
import shapely.ops as ops
import pyproj
import json

# Read the GeoJSON
gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')

# Define CRS
wgs84 = pyproj.CRS.from_epsg(4326)
fmg = pyproj.CRS.from_epsg(3460)  # Fiji 1986 / Fiji Map Grid

# Transformer for coordinates
transformer = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True)

def fix_antimeridian(coords):
    """Split a LineString crossing the antimeridian into parts.
    Returns a list of lists of (lon, lat) tuples, each being a continuous segment.
    """
    if len(coords) < 2:
        return [coords]
    
    # First, identify crossing points
    # A crossing occurs when absolute longitude difference > 180 degrees
    parts = []
    current_part = [coords[0]]
    
    for i in range(1, len(coords)):
        lons_prev, lats_prev = coords[i-1]
        lon_curr, lat_curr = coords[i]
        
        lon_diff = abs(lon_curr - lons_prev)
        
        if lon_diff > 180:
            # Crossing detected - need to split here
            # First, finish the current part (but we need to interpolate the crossing point)
            # Actually, we need to split at the antimeridian
            
            # Calculate where the segment crosses 180° (or -180°)
            # The antimeridian is at 180° or -180° (same line)
            
            # Determine direction
            if lons_prev < 0:
                # Crossing from negative to positive? Or positive to negative?
                pass
            
            # We can interpolate to find the exact crossing point at longitude 180° (or -180°)
            
            # Start a new part
            current_part.append(coords[i])
            parts.append(current_part)
            current_part = [coords[i]]
        else:
            current_part.append(coords[i])
    
    if current_part:
        parts.append(current_part)
    
    # Now adjust longitudes to be continuous within each part
    # For each part, check if the longitudes are a mix of positive and negative
    for part_idx in range(len(parts)):
        part = parts[part_idx]
        adjusted = [part[0]]
        for j in range(1, len(part)):
            lon_prev = adjusted[j-1][0]
            lon, lat = part[j]
            # If there's a big jump, adjust
            if lon - lon_prev > 180:
                lon -= 360
            elif lon_prev - lon > 180:
                lon += 360
            adjusted.append((lon, lat))
        parts[part_idx] = adjusted
    
    return parts
```

Wait, I need to be more careful. The approach should be:

1. For each feature, detect if the coordinates cross the antimeridian.
2. If they don't, just wrap it in a MultiLineString.
3. If they do:
   a. Find where the crossings occur (consecutive points with longitude difference > 180°).
   b. For each segment between crossings, adjust longitudes to make them continuous.
   c. Optionally, interpolate the exact crossing point at the antimeridian (180°).
   d. Then reproject each segment.

Actually, a simpler and more robust approach:
1. For each feature, figure out if it crosses the antimeridian.
2. If it does, for each segment, shift the longitudes so it doesn't cross (e.g., add 360 to negative longitudes), then reproject. 
3. But if we just add 360 to all negative longitudes, features that are entirely in negative longitudes will be shifted incorrectly.

Better approach: For each consecutive pair of points, if the longitude difference is > 180° (in absolute value), we cut there. Each resulting segment gets its longitudes adjusted to be continuous.

Let me write the complete script.

Actually, thinking about this more carefully with the Fiji Map Grid projection (central meridian 178.75), I think the key issue is just about creating the correct geometry before reprojecting.

Let me use Shapely's `split` function or manually handle it.

Actually, there's a well-known approach using geopandas and shapely:

```python
import shapely
from shapely.geometry import LineString, MultiLineString, Point

def cut_line_at_antimeridian(line):
    coords = list(line.coords)
    # Detect crossings
    parts = []
    current = [coords[0]]
    for i in range(1, len(coords)):
        x1, y1 = coords[i-1]
        x2, y2 = coords[i]
        if abs(x2 - x1) > 180:
            # Crossing
            # Interpolate the crossing point
            # Find t where x = 180 or -180
            # Line: x = x1 + t*(x2-x1), y = y1 + t*(y2-y1)
            # Solve for t: 180 = x1 + t*(x2-x1) => t = (180 - x1)/(x2-x1)
            # Or -180 = x1 + t*(x2-x1) => t = (-180 - x1)/(x2-x1)
            # We want the one between 0 and 1
            
            # Determine which side we're crossing
            if x1 < 0 and x2 > 0:
                # Crossing from west to east, crossing at 180? No, crossing at -180 to 180
                # Actually if x1 = -179.5 and x2 = 179.5, diff is 359 which is > 180
                # They cross at the antimeridian. The antimeridian is both 180 and -180.
                t = (180 - x1) / (x2 - x1)  # Crossing at x=180
                # Check if t is in [0,1]
                if t < 0 or t > 1:
                    t = (-180 - x1) / (x2 - x1)  # Crossing at x=-180
            elif x1 > 0 and x2 < 0:
                # Crossing from east to west
                t = (-180 - x1) / (x2 - x1)  # Crossing at x=-180
                if t < 0 or t > 1:
                    t = (180 - x1) / (x2 - x1)  # Crossing at x=180
            else:
                # Shouldn't happen
                continue
            
            cross_x = x1 + t * (x2 - x1)
            cross_y = y1 + t * (y2 - y1)
            
            # Finish current part
            current.append((cross_x, cross_y))
            parts.append(current)
            
            # Start new part
            current = [(cross_x, cross_y), coords[i]]
        else:
            current.append(coords[i])
    
    if current:
        parts.append(current)
    
    # Now adjust longitudes
    adjusted_parts = []
    for part in parts:
        adj = [part[0]]
        for j in range(1, len(part)):
            lon_prev, lat_prev = adj[j-1]
            lon, lat = part[j]
            if lon - lon_prev > 180:
                lon -= 360
            elif lon - lon_prev < -180:
                lon += 360
            adj.append((lon, lat))
        adjusted_parts.append(adj)
    
    return adjusted_parts
```

Hmm, but I also need to consider that when crossing from say 179.5 to -179.5 (in terms of the actual geography), the line goes through the antimeridian (180°). The longitude difference is -359°, which is less than -180, so it's a crossing.

Let me simplify. The key insight: for Fiji, the central meridian is 178.75°E. The antimeridian is at 180°/-180°. Features that cross the antimeridian have longitudes that jump from ~+179 to ~-179 or vice versa.

Instead of handling it with complex interpolation, I can use a simpler approach:

1. Shift all coordinates so they're continuous by checking the order.
2. For the Fiji Map Grid projection, the longitude range that makes sense is roughly 176°E to 180° and -180° to -176° (i.e., 176°W to 180°W). 

Actually, let me think about this differently. The Fiji Map Grid (EPSG:3460) has a central meridian at 178.75°E. All points in the Fiji area should be within the projection's usable range. The problem is just the antimeridian crossing.

Let me write a clean script:

For each feature:
1. Get the coordinates.
2. Check if there are antimeridian crossings (abs(lon diff) > 180).
3. If no crossings, just convert to MultiLineString (with one part), reproject, calculate length.
4. If crossings:
   a. Split at each crossing, interpolating the exact crossing point at 180° (or -180°).
   b. Adjust longitudes within each part to be continuous.
   c. Create LineString for each part, reproject, collect as MultiLineString.

Let me use a simpler approach with geopandas and shapely:

```python
import geopandas as gpd
from shapely.geometry import LineString, MultiLineString, Point, box
from shapely.ops import transform, split, linemerge
import pyproj
import json

# Read
gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')

# CRS
wgs84 = pyproj.CRS.from_epsg(4326)
fmg = pyproj.CRS.from_epsg(3460)
project = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True).transform

results = []

for idx, row in gdf.iterrows():
    geom = row.geometry
    props = row.drop('geometry').to_dict()
    
    coords = list(geom.coords)
    
    # Check for antimeridian crossings
    parts = []
    current_seg = [coords[0]]
    
    for i in range(1, len(coords)):
        x1, y1 = coords[i-1]
        x2, y2 = coords[i]
        
        if abs(x2 - x1) > 180:
            # Crossing detected. Interpolate the crossing point on the antimeridian.
            # The antimeridian is at lon=180 (or -180, same line)
            # Find where the line crosses
            if x1 < 0 and x2 > 0:
                # From negative to positive - crossing at lon=180 (same as -180)
                # Since x1 is negative and x2 is positive, we cross at 180 (or -180, same)
                target_x = 180.0
            elif x1 > 0 and x2 < 0:
                # From positive to negative
                target_x = -180.0
            else:
                # Both same sign? shouldn't happen with diff > 180
                target_x = 180.0 if x2 > 0 else -180.0
            
            # Linear interpolation
            t = (target_x - x1) / (x2 - x1)
            cross_y = y1 + t * (y2 - y1)
            
            # Close current segment at the antimeridian
            current_seg.append((target_x, cross_y))
            parts.append(current_seg)
            
            # Start new segment
            current_seg = [(target_x, cross_y), (x2, y2)]
        else:
            current_seg.append((x2, y2))
    
    if current_seg:
        parts.append(current_seg)
    
    # Adjust longitudes in each part for continuity
    for p_idx in range(len(parts)):
        adj = [parts[p_idx][0]]
        for j in range(1, len(parts[p_idx])):
            lon_prev, lat_prev = adj[j-1]
            lon, lat = parts[p_idx][j]
            # Shift if needed
            if lon - lon_prev > 180:
                lon -= 360
            elif lon - lon_prev < -180:
                lon += 360
            adj.append((lon, lat))
        parts[p_idx] = adj
    
    # Create LineStrings and reproject
    lines_wgs84 = [LineString(part) for part in parts]
    lines_fmg = [transform(project, line) for line in lines_wgs84]
    
    # Create MultiLineString
    multi = MultiLineString(lines_fmg)
    
    # Calculate length
    length_m = multi.length
    
    # Add length to properties
    props['length_m'] = length_m
    
    results.append({
        'type': 'Feature',
        'properties': props,
        'geometry': multi
    })
```

Wait, but I also need to handle features that don't cross the antimeridian but are LineStrings - they need to be MultiLineStrings too. So I'll just wrap them.

Also, for non-crossing features that are entirely on the negative side (west of 180°), the longitudes will be e.g. -177... -176... and that's fine for the Fiji Map Grid.

Let me code this up more carefully.

Actually, I realize there might be an issue with the interpolation. When going from x1 > 0 to x2 < 0 (or vice versa), the line crosses the antimeridian. But the antimeridian is at 180° (which equals -180°). So:

If x1 = 179.5 and x2 = -179.5: 
- The shortest path crosses from 179.5 to 180 to -180 to -179.5 (going through the antimeridian)
- To find the interpolation: the distance from 179.5 to -179.5 going through the antimeridian is: (180 - 179.5) + (180 - 179.5) = 1°
- But if we just do linear interpolation on the raw longitude values: from 179.5 to -179.5 (a difference of -359°), we could also go the other way (-179.5 - 179.5 = -359°)
- The antimeridian crossing point is at 180° (which is -180°). The linear interpolation parameter t = (180 - 179.5) / (-179.5 - 179.5) = 0.5 / (-359) = -0.00139 which is not in [0,1].

Hmm, so linear interpolation on raw coordinates doesn't directly work. I need to adjust.

The better approach: When we detect a crossing, the segment goes from (x1, y1) to (x2, y2) where the difference in longitude crosses the antimeridian. I should adjust one of the longitudes by ±360 to make the segment continuous in terms of longitude values.

For x1 = 179.5, x2 = -179.5:
- We can adjust x2 to x2 + 360 = 180.5 (since going east across the antimeridian, the longitude goes from 179.5→180→-179.5, which is 179.5→180.5 in continuous terms)
- Now linear interpolation: t = (180 - 179.5) / (180.5 - 179.5) = 0.5/1 = 0.5. That's in [0,1].
- Cross y = y1 + 0.5*(y2-y1)

For x1 = -179.5, x2 = 179.5:
- We can adjust x2 to x2 - 360 = -180.5 (going west across the antimeridian)
- t = (-180 - (-179.5)) / (-180.5 - (-179.5)) = (-0.5)/(-1) = 0.5. In [0,1].

Great, that works. Let me write the full script.

Let me think about a clean implementation:

```python
import geopandas as gpd
import shapely.geometry as geom
import shapely.ops as ops
import pyproj
import json

gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')

wgs84 = pyproj.CRS.from_epsg(4326)
fmg = pyproj.CRS.from_epsg(3460)
project = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True).transform

def split_at_antimeridian(coords):
    """Split a line at antimeridian crossings. Returns list of coordinate lists."""
    if len(coords) < 2:
        return [coords]
    
    parts = []
    current = [coords[0]]
    
    for i in range(1, len(coords)):
        x1, y1 = coords[i-1]
        x2, y2 = coords[i]
        
        if abs(x2 - x1) > 180:
            # Crossing the antimeridian
            # Adjust x2 to make the segment continuous through the antimeridian
            if x1 < 0 and x2 > 0:
                # Going west to east: x1=-179.5, x2=179.5
                # In continuous space: x1=-179.5, x2=179.5 (this is actually going from -179.5 to 180.5)
                # Or: x1=179.5, x2=-179.5 going east: x1=-179.5, x2=180.5
                adj_x2 = x2 - 360  # Shift to make it continuous
                # The antimeridian is at 180° or -180°
                # We're crossing from negative to positive = going east
                # The crossing point at 180° = 180
                target_lon = 180.0
            elif x1 > 0 and x2 < 0:
                # Going east to west: x1=179.5, x2=-179.5
                adj_x2 = x2 + 360  # Shift to make it continuous
                target_lon = -180.0
            else:
                # Shouldn't happen, but handle anyway
                adj_x2 = x2 + 360 if x2 < 0 else x2 - 360
                target_lon = 180.0 if x2 > 0 else -180.0
            
            # Interpolate
            t = (target_lon - x1) / (adj_x2 - x1)
            cross_y = y1 + t * (y2 - y1)
            
            # Finish current segment at the antimeridian
            current.append((target_lon, cross_y))
            parts.append(current)
            
            # Start new segment
            # The new segment starts at the antimeridian (same point, but we need the 
            # "other side" longitude representation)
            if target_lon == 180:
                other_side_lon = -180.0
            else:
                other_side_lon = 180.0
            
            current = [(other_side_lon, cross_y), (x2, y2)]
        else:
            current.append((x2, y2))
    
    if current:
        parts.append(current)
    
    return parts
```

Wait, there's a subtlety. When we split at the antimeridian, we want:
- Part 1: from start to the antimeridian (at 180° or -180°)
- Part 2: from the antimeridian to end

For part 1, the last point should have longitude = 180 (or -180).
For part 2, the first point should have longitude = -180 (or 180) - same line but different representation.

Then when we adjust longitudes within each part:
- Part 1: all longitudes that are negative stay negative (~179 to 180), positive stay positive. No adjustment needed if they're already monotonic.
- Part 2: all longitudes that are positive... wait, part 2 starts at 180° (or -180°) and goes to the next coordinate.

Hmm, let me reconsider. Let me just adjust longitudes within each part to be continuous:

For each part:
- Start with the first point as-is
- For each subsequent point, if the longitude jumps by > 180° from the previous adjusted value, add/subtract 360

This should make each part continuous for reprojection.

Let me write the full script now.

Actually, I realize for parts that don't cross the antimeridian, the adjustment is trivial (no change). For parts that do cross... wait, by splitting at the antimeridian, no individual part should cross it. But they might have longitudes that are "on the other side" of the antimeridian relative to the central meridian.

For the Fiji Map Grid (central meridian 178.75°E), longitudes from about 175°E to 180°E and from 180°W to 175°W are all valid. The projection handles both positive and negative longitudes around the antimeridian.

So after splitting, I just need to ensure each part's coordinates are continuous (no huge jumps). Since I'm splitting at the antimeridian, each part should be naturally continuous... but wait, if a part starts at e.g. 179.5 and goes to 180 (where we split), that's fine. If a part starts at -180 and goes to -179.5, that's fine too.

Let me verify: 
- Part going from 178° to 179° to 180°: continuous, no adjustment needed.
- Part going from -180° to -179° to -178°: continuous, no adjustment needed.

But what about the conversion to projected CRS? The projection uses central meridian 178.75°E. For negative longitudes like -179°, the projection should handle it correctly since it's equivalent to 181° (which is 181 - 360 = -179, i.e., 179°W).

Actually, let me check if pyproj handles negative longitude values correctly for this projection. EPSG:3460 is based on Fiji 1986 geographic CRS (EPSG:4720) which uses Greenwich prime meridian and the longitude range is typically -180 to 180. So negative longitudes should be fine.

Let me just write the script and test it.

Actually, I think my approach is sound. Let me code it properly.

Let me also handle the case where a feature is already a LineString (not crossing) - wrap it as MultiLineString with one component.

For non-crossing features, the length should be computed in the projected CRS.

Let me write the complete script:

```python
import geopandas as gpd
import shapely.geometry as geom
from shapely.ops import transform
import pyproj
import json

# Read input
gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')

# Define CRS
wgs84 = pyproj.CRS.from_epsg(4326)
fmg = pyproj.CRS.from_epsg(3460)  # Fiji 1986 / Fiji Map Grid
project = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True).transform

def split_antimeridian_coords(coords):
    """Split coordinate list at antimeridian crossings.
    Returns list of lists of (lon, lat), each being a continuous segment.
    """
    if len(coords) < 2:
        return [list(coords)]
    
    parts = []
    current = [coords[0]]
    
    for i in range(1, len(coords)):
        x1, y1 = coords[i-1]
        x2, y2 = coords[i]
        
        if abs(x2 - x1) > 180:
            # Crossing the antimeridian - need to interpolate the crossing point
            
            # Adjust x2 for continuous interpolation
            target_lon = None
            if x1 < 0 and x2 > 0:
                # Going from west to east across the antimeridian
                # e.g. x1=-179.5, x2=179.5 -> adj_x2=179.5-360=-180.5
                adj_x2 = x2 - 360
                target_lon = 180.0  # Or -180.0, same line
            elif x1 > 0 and x2 < 0:
                # Going from east to west
                adj_x2 = x2 + 360
                target_lon = -180.0
            else:
                # Both same sign but diff > 180? Unlikely but handle
                if x2 > x1:
                    adj_x2 = x2 - 360
                    target_lon = x1 + (adj_x2 - x1) / 2  # approximate
                else:
                    adj_x2 = x2 + 360
                    target_lon = x1 + (adj_x2 - x1) / 2
            
            # Interpolate the crossing point
            t = (target_lon - x1) / (adj_x2 - x1)
            if 0 <= t <= 1:
                cross_y = y1 + t * (y2 - y1)
            else:
                # Fallback: use midpoint
                cross_y = (y1 + y2) / 2
                target_lon = 180.0  # default
            
            # Finish current segment at the antimeridian
            current.append((target_lon, cross_y))
            parts.append(current)
            
            # Start new segment
            other_lon = -180.0 if target_lon >= 0 else 180.0
            current = [(other_lon, cross_y), (x2, y2)]
        else:
            current.append((x2, y2))
    
    if current:
        parts.append(current)
    
    # Adjust longitudes within each part to make them continuous (no jumps)
    adjusted_parts = []
    for part in parts:
        adj = [part[0]]
        for j in range(1, len(part)):
            lon_prev, lat_prev = adj[j-1]
            lon, lat = part[j]
            # If there's a large jump, add/subtract 360
            while lon - lon_prev > 180:
                lon -= 360
            while lon - lon_prev < -180:
                lon += 360
            adj.append((lon, lat))
        adjusted_parts.append(adj)
    
    return adjusted_parts


features_out = []

for idx, row in gdf.iterrows():
    geom_in = row.geometry
    props = {k: v for k, v in row.items() if k != 'geometry'}
    
    # Get coordinates
    if geom_in.geom_type == 'LineString':
        coords = list(geom_in.coords)
    elif geom_in.geom_type == 'MultiLineString':
        # Flatten all coordinates
        coords = []
        for line in geom_in.geoms:
            coords.extend(list(line.coords))
    else:
        raise ValueError(f"Unexpected geometry type: {geom_in.geom_type}")
    
    # Split at antimeridian if needed
    parts = split_antimeridian_coords(coords)
    
    # Create LineStrings in WGS84
    lines_wgs84 = [geom.LineString(part) for part in parts]
    
    # Reproject to Fiji Map Grid
    lines_fmg = [transform(project, line) for line in lines_wgs84]
    
    # Create MultiLineString
    multi = geom.MultiLineString(lines_fmg)
    
    # Calculate length
    length_m = multi.length
    
    # Build output feature
    feat = {
        'type': 'Feature',
        'properties': {
            **props,
            'length_m': round(length_m, 2)
        },
        'geometry': geom.mapping(multi)
    }
    features_out.append(feat)

# Build output GeoJSON
out = {
    'type': 'FeatureCollection',
    'name': 'fiji_transects_fmg',
    'crs': {'type': 'name', 'properties': {'name': 'urn:ogc:def:crs:EPSG::3460'}},
    'features': features_out
}

with open('/work/fiji_transects_fmg.geojson', 'w') as f:
    json.dump(out, f)
```

Wait, I need to double-check something. When reprojecting from WGS84 to Fiji Map Grid, the transformer should handle coordinates near the antimeridian correctly. Let me test that.

Also, I realize there might be an issue with parts that have coordinates in negative longitudes (west of the antimeridian). For example, if a part has coordinates like -179.5, -179.0, -178.5 - these are all valid and the projection should handle them.

But what about the part that starts at -180 (after splitting)? That's the same as 180, which is where the projection's central meridian is (178.75°E is close to 180°). So it should be fine.

Let me also think about T010 which has:
[177.60, -17.28], [179.13, -17.47], [-179.35, -17.65], [-177.82, -17.84]

That's 177.6 -> 179.13 -> -179.35 -> -177.82. So it crosses the antimeridian once (between 179.13 and -179.35). Let's see:

1st part: 177.6, 179.13, then split at antimeridian
2nd part: -179.35, -177.82

For the first part: coords adjusted to be continuous - no change needed (all positive longitudes near 180)
For the second part: coords adjusted to be continuous - no change needed (all negative longitudes near -180)

Reprojection should work fine.

Now let me also think about the edge case where we have points like:
[179.97, -17.61] -> [-179.51, -17.60]

Going from 179.97 to -179.51. Since x1 > 0 and x2 < 0:
adj_x2 = -179.51 + 360 = 180.49
target_lon = -180.0
t = (-180 - 179.97) / (180.49 - 179.97) = -359.97 / 0.52 ≈ -692.25

That's not in [0,1]! Something's wrong with my logic.

Let me reconsider. When x1 = 179.97 and x2 = -179.51, the line segment crosses the antimeridian going east to west. The shortest path from (179.97, y1) to (-179.51, y2) goes through 180° (or -180°). In continuous longitude space:

179.97 -> 180 -> -180 -> -179.51

So:
- In continuous space, x1 = 179.97, x2_adj = -179.51 + 360 = 180.49 (shifted eastwards)
- Or alternatively, x1_adj = 179.97 - 360 = -180.03, x2 = -179.51 (shifted westwards)

The antimeridian crossing is at 180° (which is also -180°). 

Using the first approach (x2_adj = x2 + 360 = 180.49):
- We cross from 179.97 to 180.49 going east. The antimeridian is at 180.
- t = (180 - 179.97) / (180.49 - 179.97) = 0.03 / 0.52 ≈ 0.0577 ✓ (in [0,1])

Wait, but target_lon was set to -180.0 when x1 > 0 and x2 < 0. That's wrong! The antimeridian is at 180° (also -180°). When going from east to west, we cross from positive to negative. In continuous space (adding 360 to x2), the crossing point is at 180° (not -180° because x1=179.97 and adj_x2=180.49, so we're going towards 180.49).

Let me fix this: the target longitude should always be 180° (not -180°) when interpolating using the adjusted coordinates.

Wait, actually it doesn't matter since 180° and -180° are the same line. But it matters for the interpolation calculation. If we use adj_x2 = x2 + 360 = 180.49, then we should use target_lon = 180.

If we use adj_x2 = x2 - 360 = -179.51 - 360 = -539.51... no that's wrong.

Let me re-think:

Case 1: x1 = -179.5, x2 = 179.5 (crossing west to east)
- In continuous space, the path is: -179.5 -> -180 (which is 180) -> 179.5
- If I shift x2 by -360: x2_adj = 179.5 - 360 = -180.5
- Now the continuous path from x1=-179.5 to x2_adj=-180.5 goes through -180 (the antimeridian)
- t = (-180 - (-179.5)) / (-180.5 - (-179.5)) = -0.5 / -1 = 0.5 ✓

Case 2: x1 = 179.5, x2 = -179.5 (crossing east to west)
- In continuous space, the path is: 179.5 -> 180 -> -180 -> -179.5
- If I shift x2 by +360: x2_adj = -179.5 + 360 = 180.5
- Now the continuous path from x1=179.5 to x2_adj=180.5 goes through 180 (the antimeridian)
- t = (180 - 179.5) / (180.5 - 179.5) = 0.5 / 1 = 0.5 ✓

So:
- Case 1 (x1<0, x2>0): adj_x2 = x2 - 360, target_lon = 180 (or -180, but let's use 180... actually let's use -180 since x1=-179.5 and adj_x2=-180.5, we're going from -179.5 to -180.5, crossing at -180)
  - t = (-180 - (-179.5)) / (-180.5 - (-179.5)) = -0.5 / -1 = 0.5 ✓

Actually wait, in this case, x1 = -179.5, x2_adj = -180.5. The antimeridian (at -180°) is between them. So target_lon = -180.0 makes sense for the interpolation.

- Case 2 (x1>0, x2<0): adj_x2 = x2 + 360 = 180.5, target_lon = 180
  - t = (180 - 179.5) / (180.5 - 179.5) = 0.5/1 = 0.5 ✓

So the correct logic is:
- If x1 < 0 and x2 > 0: adj_x2 = x2 - 360, target_lon = -180.0
- If x1 > 0 and x2 < 0: adj_x2 = x2 + 360, target_lon = 180.0

Let me fix this in my script.

Also, I need to be careful about what longitude value I store in the split point. For part 1 (ending at the antimeridian), I should store 180 (if going east) or -180 (if going west). For part 2 (starting at the antimeridian), I should store -180 or 180 accordingly.

Let me reconsider:
- Case 1 (x1 < 0, x2 > 0): going west to east. Part 1 ends at -180° (west side). Part 2 starts at 180° (east side).
- Case 2 (x1 > 0, x2 < 0): going east to west. Part 1 ends at 180° (east side). Part 2 starts at -180° (west side).

But actually, when adjusting longitudes within each part for continuity, having -180 and 180 doesn't matter that much since they're the same line. Let me just use 180 for one side and -180 for the other.

OK, let me write the full script properly.
1:41
Write /work/solve.py
content · 140 lines · py
import geopandas as gpd
import shapely.geometry as geom
from shapely.ops import transform
import pyproj
import json

# Read input
gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')

# Define CRS
wgs84 = pyproj.CRS.from_epsg(4326)
fmg = pyproj.CRS.from_epsg(3460)  # Fiji 1986 / Fiji Map Grid
project = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True).transform


def split_antimeridian_coords(coords):
    """Split coordinate list at antimeridian crossings.
    Returns list of lists of (lon, lat), each being a continuous segment
    in WGS84 that does not cross the antimeridian.
    """
    if len(coords) < 2:
        return [list(coords)]

    parts = []
    current = [coords[0]]

    for i in range(1, len(coords)):
        x1, y1 = coords[i - 1]
        x2, y2 = coords[i]

        # Detect antimeridian crossing: longitude difference > 180 degrees
        if abs(x2 - x1) > 180:
            # Interpolate the exact crossing point on the antimeridian (180 / -180)
            if x1 < 0 and x2 > 0:
                # West -> East: adjust x2 westwards so we can interpolate through -180°
                adj_x2 = x2 - 360.0
                target_lon = -180.0
            elif x1 > 0 and x2 < 0:
                # East -> West: adjust x2 eastwards so we can interpolate through 180°
                adj_x2 = x2 + 360.0
                target_lon = 180.0
            else:
                # Same sign but diff > 180 — should not happen for valid data
                # But handle gracefully: just split at midpoint
                adj_x2 = x2
                target_lon = (x1 + x2) / 2.0

            # Linear interpolation to find crossing latitude
            t = (target_lon - x1) / (adj_x2 - x1)
            cross_y = y1 + t * (y2 - y1)

            # Finish current segment at the antimeridian
            current.append((target_lon, cross_y))
            parts.append(current)

            # Start new segment from the other side of the antimeridian
            other_lon = 180.0 if target_lon < 0 else -180.0
            current = [(other_lon, cross_y), (x2, y2)]
        else:
            current.append((x2, y2))

    if current:
        parts.append(current)

    # Adjust longitudes within each part to be continuous (no jumps)
    adjusted_parts = []
    for part in parts:
        adj = [part[0]]
        for j in range(1, len(part)):
            lon_prev, lat_prev = adj[j - 1]
            lon, lat = part[j]
            # Shift longitude by ±360 to eliminate any large jumps
            while lon - lon_prev > 180:
                lon -= 360
            while lon - lon_prev < -180:
                lon += 360
            adj.append((lon, lat))
        adjusted_parts.append(adj)

    return adjusted_parts


features_out = []

for idx, row in gdf.iterrows():
    geom_in = row.geometry
    props = {k: v for k, v in row.items() if k != 'geometry'}

    # Get coordinates (handle both LineString and MultiLineString input)
    if geom_in.geom_type == 'LineString':
        coords = list(geom_in.coords)
    elif geom_in.geom_type == 'MultiLineString':
        coords = []
        for line in geom_in.geoms:
            coords.extend(list(line.coords))
    else:
        raise ValueError(f"Unexpected geometry type: {geom_in.geom_type}")

    # Split at antimeridian crossings
    parts = split_antimeridian_coords(coords)

    # Build LineStrings, reproject to Fiji Map Grid
    lines_fmg = []
    for part in parts:
        line_wgs84 = geom.LineString(part)
        line_fmg = transform(project, line_wgs84)
        lines_fmg.append(line_fmg)

    # Ensure MultiLineString
    multi = geom.MultiLineString(lines_fmg)

    # Calculate length in projected units (metres)
    length_m = multi.length

    # Build output dict for GeoJSON serialisation
    feat = {
        'type': 'Feature',
        'properties': {
            **props,
            'length_m': round(length_m, 2)
        },
        'geometry': geom.mapping(multi)
    }
    features_out.append(feat)

# Assemble output FeatureCollection
out_collection = {
    'type': 'FeatureCollection',
    'name': 'fiji_transects_fmg',
    'crs': {
        'type': 'name',
        'properties': {'name': 'urn:ogc:def:crs:EPSG::3460'}
    },
    'features': features_out
}

with open('/work/fiji_transects_fmg.geojson', 'w') as f:
    json.dump(out_collection, f, indent=2)

print(f"Wrote {len(features_out)} features to /work/fiji_transects_fmg.geojson")
Wrote /work/solve.py (4440 chars).
2:01
Let me think about the antimeridian crossing issue more carefully. The problem is that when coordinates cross the antimeridian (180°/-180°), the raw longitude values jump from ~180 to ~-180, which makes the line wrap around the globe. 

Looking at the data:

**T001**: 178.94, 179.46, 179.97, **-179.51**, -178.99, -178.48
This goes from ~180°E to ~-180°W, which is a tiny step across the dateline, but because of the coordinate representation, it wraps the wrong way around the globe.

The approach:
1. Split each LineString at antimeridian crossings into segments
2. For segments east of the antimeridian, use normal positive longitudes
3. For segments west of the antimeridian, use negative longitudes
4. But wait - we need to handle the continuity properly.

Actually, let me think about this differently. The issue is:
- T001 goes: 178.94, 179.46, 179.97, -179.51, -178.99, -178.48
- This is actually a continuous path crossing the 180° meridian from east to west
- But when rendered as-is, it wraps all the way around the globe the long way

For proper handling:
1. We split the coordinates into parts where longitude crosses ±180
2. Each part gets adjusted so longitudes are continuous (no big jumps)
3. We reproject each part individually
4. Combine as MultiLineString

Let me think about my splitting logic more carefully.

For T001: [178.94, 179.46, 179.97, -179.51, -178.99, -178.48]
Between index 2 (179.97) and index 3 (-179.51): diff = -179.51 - 179.97 = -359.48, abs > 180, so crossing detected.
- x1=179.97 > 0, x2=-179.51 < 0, so East -> West crossing
- adj_x2 = -179.51 + 360 = 180.49
- target_lon = 180
- Interpolate: t = (180 - 179.97) / (180.49 - 179.97) = 0.03 / 0.52 ≈ 0.0577
- cross_y = y1 + t*(y2 - y1) ≈ -17.611 + 0.0577*(-17.596 + 17.611) ≈ -17.611 + 0.0577*0.015 ≈ -17.610
- Current part before crossing: [(178.94, -17.632), (179.46, -17.624), (179.97, -17.611), (180, crossing_y)]
- New part after: [(-180, crossing_y), (-179.51, -17.596), (-178.99, -17.580), (-178.48, -17.577)]

Then I adjust longitudes within each part to be continuous. In the first part, all positive, fine. In the second part, they're all negative, fine.

Wait, but when I project, I need to make sure the coordinates are in the right range for the projection. The Fiji Map Grid (EPSG:3460) uses Transverse Mercator with central meridian at 178.75°E. So longitudes around -180° should be -180° (or 180°) which is close to the central meridian.

Actually, for the projection, I need to be careful. The FMG is a Transverse Mercator projection with central meridian 178.75°E. Points at -180°W and 180°E are the same line, but the projection handles them differently. In practice, pyproj should handle -180° and 180° correctly for this projection.

Let me think about the interpolation more carefully. Between 179.97° (at index 2) and -179.51° (at index 3), the actual shortest path is across 180° (or -180°). So the crossing point is at longitude 180° (or -180°).

Actually, I think there's a subtlety. When x1 > 0 and x2 < 0, we're going from east to west. The shortest path crosses 180° (from positive longitude to negative). So:
- We interpolate to find where the path crosses 180°
- adj_x2 = x2 + 360 to make it continuous
- target_lon = 180

Similarly, when x1 < 0 and x2 > 0, going from west to east, we cross -180°.

Let me also think about the case where the path goes from something like 179.97 to -179.51. The actual difference is -179.51 + 360 - 179.97 = 0.52 degrees, so it's a tiny step eastwards... wait no. From 179.97°E to 179.51°W (which is 180.49°E), going eastward you'd pass through 180°. So the crossing is at exactly 180°.

Let me reconsider. 179.97 -> -179.51 in the data. The actual geographic path is from 179.97°E to 179.51°W. Going eastward from 179.97°E, you hit 180° then go to 179.51°W (which is -179.51°). So:
- adj_x2 = -179.51 + 360 = 180.49
- We're going from 179.97 to 180.49 in adjusted space
- target_lon = 180

That looks right.

Let me trace through T001 step by step:
- coords = [(178.94, -17.632), (179.46, -17.624), (179.97, -17.611), (-179.51, -17.596), (-178.99, -17.580), (-178.48, -17.577)]
- Start: current = [(178.94, -17.632)]
- i=1: x1=178.94, x2=179.46, diff=0.52, no crossing. current = [(178.94, -17.632), (179.46, -17.624)]
- i=2: x1=179.46, x2=179.97, diff=0.51, no crossing. current = [(178.94, -17.632), (179.46, -17.624), (179.97, -17.611)]
- i=3: x1=179.97, x2=-179.51, diff=-359.48, abs > 180, crossing!
  - x1>0, x2<0 -> East->West, adj_x2 = -179.51+360 = 180.49, target_lon = 180
  - t = (180 - 179.97) / (180.49 - 179.97) = 0.03/0.52 = 0.0577
  - cross_y = -17.611 + 0.0577*(-17.596+17.611) = -17.611 + 0.0577*0.015 = -17.6101
  - current.append((180, -17.6101))
  - parts = [[(178.94, -17.632), (179.46, -17.624), (179.97, -17.611), (180, -17.6101)]]
  - current = [(-180, -17.6101), (-179.51, -17.596)]
- i=4: x1=-179.51, x2=-178.99, diff=0.52, no crossing. current = [(-180, -17.6101), (-179.51, -17.596), (-178.99, -17.580)]
- i=5: x1=-178.99, x2=-178.48, diff=0.51, no crossing. current = [(-180, -17.6101), (-179.51, -17.596), (-178.99, -17.580), (-178.48, -17.577)]
- End: parts = [[(178.94, ...), (179.46, ...), (179.97, ...), (180, -17.6101)], [(-180, -17.6101), (-179.51, -17.596), (-178.99, -17.580), (-178.48, -17.577)]]

Then the adjustment phase: in part 1, all longitudes are positive with no jumps. In part 2, all are negative with no jumps. Good.

Then project and create MultiLineString.

This should work! Let me also check T010 which has a large jump:
T010: 177.60, 179.13, -179.35, -177.82
Between 179.13 and -179.35: diff = -358.48, abs > 180, crossing.
- x1=179.13 > 0, x2=-179.35 < 0, East->West
- adj_x2 = -179.35 + 360 = 180.65
- target_lon = 180
- t = (180 - 179.13) / (180.65 - 179.13) = 0.87/1.52 = 0.572
- cross_y = -17.468 + 0.572*(-17.654+17.468) = -17.468 + 0.572*(-0.186) = -17.468 - 0.106 = -17.574

That seems right. Part 1: [177.60, 179.13, ... 180], Part 2: [-180, ..., -179.35, ..., -177.82]

Now let me think about a potential issue with T008:
T008: 179.40, 179.67, 179.95, -179.78, -179.51, -179.23
Between 179.95 and -179.78: diff = -359.73, abs > 180, crossing.

So it goes from 179.95 to -179.78. These are both very close to 180/-180. adj_x2 = -179.78 + 360 = 180.22. target_lon = 180. t = (180-179.95)/(180.22-179.95) = 0.05/0.27 = 0.185. Fine.

Alright, the script looks correct. Let me also make sure I'm handling T011 and others that DON'T cross the antimeridian. For those, the crossing check will never trigger, and we'll have a single part, which gets transformed to a single LineString, then wrapped in MultiLineString. Good.

Actually wait, I need to also handle the case where the input is already a MultiLineString - but looking at the data, all features are LineString type. So that's fine.

Let me also think about whether `crosses_antimeridian_flag` is a property we should carry through. The instruction says "Carry the survey attributes (vessel and survey_date) through unchanged". So we keep those. The `crosses_antimeridian_flag` is also a property - let me keep all properties.

Wait, I'm iterating over `props` with `{k: v for k, v in row.items() if k != 'geometry'}` which will capture all properties including transect_id, vessel, survey_date, crosses_antimeridian_flag. Good.

Let me run the script and check the output.
2:01
Bash cd /work && python solve.py
Traceback (most recent call last):
  File "/work/solve.py", line 138, in <module>
    json.dump(out_collection, f, indent=2)
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.14/json/__init__.py", line 181, in dump
    for chunk in iterable:
                 ^^^^^^^^
  File "/usr/local/lib/python3.14/json/encoder.py", line 444, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "/usr/local/lib/python3.14/json/encoder.py", line 413, in _iterencode_dict
    yield from chunks
  File "/usr/local/lib/python3.14/json/encoder.py", line 326, in _iterencode_list
    yield from chunks
  File "/usr/local/lib/python3.14/json/encoder.py", line 413, in _iterencode_dict
    yield from chunks
  File "/usr/local/lib/python3.14/json/encoder.py", line 413, in _iterencode_dict
    yield from chunks
  File "/usr/local/lib/python3.14/json/encoder.py", line 451, in _iterencode
    newobj = _default(o)
  File "/usr/local/lib/python3.14/json/encoder.py", line 182, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
                    f'is not JSON serializable')
TypeError: Object of type Timestamp is not JSON serializable
when serializing dict item 'survey_date'
when serializing dict item 'properties'
when serializing list item 0
when serializing dict item 'features'
2:05
The issue is that `survey_date` is being loaded as a Timestamp type (from pandas). I need to convert it to a string before serialization. Let me fix the script.
2:05
Edit /work/solve.py
Edited /work/solve.py.
2:08
Wait, I also need to remove the `crosses_antimeridian_flag` property since we're carrying the survey attributes through but the task says "Carry the survey attributes (vessel and survey_date) through unchanged, use transect_id as the key field". Actually it says survey attributes vessel and survey_date, and transect_id as key field. It doesn't explicitly say to remove crosses_antimeridian_flag, but it says "Carry the survey attributes (vessel and survey_date) through unchanged". So I should keep only those three? Let me re-read:

"Carry the survey attributes (vessel and survey_date) through unchanged, use transect_id as the key field"

I think this means carry through vessel and survey_date, and transect_id is also needed as the key. The other field `crosses_antimeridian_flag` is not mentioned but it's in the original data. Since they said "survey attributes (vessel and survey_date)" maybe they just want those. But to be safe, I'll keep all properties except I'll also keep the crosses_antimeridian_flag... Actually, let me just keep vessel, survey_date, and transect_id as specified. I'll also add length_m.

Wait, let me re-read: "Carry the survey attributes (vessel and survey_date) through unchanged, use transect_id as the key field"

I think they're saying:
- The attributes to carry through are vessel and survey_date
- transect_id is the key/identifier field

So I should keep transect_id, vessel, survey_date, and add length_m. I can drop crosses_antimeridian_flag since it's not a survey attribute they asked for. Actually, it's harmless to keep it. Let me just keep all original properties but also ensure the Timestamp conversion is done.

Let me run it again.
2:08
Bash cd /work && python solve.py
Wrote 30 features to /work/fiji_transects_fmg.geojson
2:11
Let me verify the output to make sure it's correct.
2:11
Bash cat /work/fiji_transects_fmg.geojson
{
  "type": "FeatureCollection",
  "name": "fiji_transects_fmg",
  "crs": {
    "type": "name",
    "properties": {
      "name": "urn:ogc:def:crs:EPSG::3460"
    }
  },
  "features": [
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T001",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 273335.11
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2020343.340583844,
              3930017.4674364463
            ],
            [
              2074969.3287187445,
              3930832.111936373
            ],
            [
              2129608.4030453707,
              3931959.043532026
            ],
            [
              2132641.3519591475,
              3932030.6236885176
            ]
          ],
          [
            [
              2132641.3519591503,
              3932030.6236885176
            ],
            [
              2184265.933617849,
              3933178.8742693216
            ],
            [
              2238946.8792888806,
              3934438.0861816974
            ],
            [
              2293630.6493575512,
              3933970.5213900264
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T002",
        "vessel": "Bligh",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 216575.29
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2034023.7576998495,
              3962923.9288114174
            ],
            [
              2103801.3645465984,
              3980775.0173757505
            ],
            [
              2133006.7821587846,
              3988176.984284049
            ]
          ],
          [
            [
              2133006.7821587874,
              3988176.984284049
            ],
            [
              2173711.8899896345,
              3998417.276510603
            ],
            [
              2243773.2911946434,
              4016860.265945784
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T003",
        "vessel": "Lomaiviti",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 351823.46
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1881698.8337329356,
              3959945.940913004
            ],
            [
              1969475.352082875,
              3953932.1918599945
            ],
            [
              2057192.4957280513,
              3947717.5506673623
            ],
            [
              2132707.1824515397,
              3942028.7593159503
            ]
          ],
          [
            [
              2132707.1824515425,
              3942028.7593159503
            ],
            [
              2144865.828376211,
              3941086.0440104534
            ],
            [
              2232501.11407936,
              3933301.4671774227
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T004",
        "vessel": "Vanua I",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 372666.09
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2013096.2318831745,
              3911101.2374744187
            ],
            [
              2084064.7331161185,
              3933595.078164197
            ],
            [
              2132746.0370150185,
              3947953.374021069
            ]
          ],
          [
            [
              2132746.037015021,
              3947953.374021069
            ],
            [
              2155191.552825498,
              3954527.977713378
            ],
            [
              2226505.8923469945,
              3977271.8304685825
            ],
            [
              2297989.454556443,
              3998716.763596262
            ],
            [
              2369647.398370236,
              4019426.6353879017
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T005",
        "vessel": "Bligh",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 362394.57
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1877826.2337985218,
              3897452.1115597077
            ],
            [
              1937585.6830181086,
              3888095.4565095943
            ],
            [
              1997281.7339928765,
              3878356.8414042895
            ],
            [
              2056921.5799520519,
              3869852.4157240363
            ],
            [
              2116501.4382828893,
              3859064.775548195
            ],
            [
              2132132.72367144,
              3856392.831893989
            ]
          ],
          [
            [
              2132132.723671443,
              3856392.831893989
            ],
            [
              2176031.798402194,
              3848816.3934150883
            ],
            [
              2235528.2870951835,
              3839483.53885849
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T006",
        "vessel": "Cakaulevu",
        "survey_date": "2025-08-13T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 393605.56
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1986477.0291858702,
              3847052.749570283
            ],
            [
              2048183.9264241843,
              3868847.9958887855
            ],
            [
              2110030.3122592983,
              3889929.569491461
            ],
            [
              2132414.0483812992,
              3897883.660491682
            ]
          ],
          [
            [
              2132414.048381302,
              3897883.660491682
            ],
            [
              2172028.247827847,
              3911884.2606283487
            ],
            [
              2234167.3185592326,
              3932716.7800173583
            ],
            [
              2296469.7202252313,
              3954296.42636324
            ],
            [
              2358907.291712429,
              3974351.608875371
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T007",
        "vessel": "Vanua I",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 414594.38
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1911692.438271574,
              3983231.465846738
            ],
            [
              1994362.6345828045,
              3988871.9466625084
            ],
            [
              2077074.393066105,
              3993892.378778944
            ],
            [
              2133065.3654978485,
              3997328.8452844336
            ]
          ],
          [
            [
              2133065.3654978513,
              3997328.8452844336
            ],
            [
              2159841.5664019543,
              3998918.8506064746
            ],
            [
              2242670.474942513,
              4003071.442188108
            ],
            [
              2325581.1283138376,
              4007239.653809817
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T008",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 146792.55
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2068958.3651469543,
              3896474.8093812363
            ],
            [
              2097941.3062179913,
              3900199.435533137
            ],
            [
              2126942.1228124853,
              3904630.4103711965
            ],
            [
              2132465.642506932,
              3905584.342467365
            ]
          ],
          [
            [
              2132465.6425069347,
              3905584.342467365
            ],
            [
              2155963.4499872266,
              3909624.458919142
            ],
            [
              2184998.036693292,
              3914066.6121028704
            ],
            [
              2214051.662654211,
              3918654.097943046
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T009",
        "vessel": "Vanua I",
        "survey_date": "2025-08-13T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 263388.29
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1927285.4610478787,
              4037732.1943981266
            ],
            [
              1979888.171983514,
              4034317.8200324415
            ],
            [
              2032472.1715915422,
              4030761.5922226436
            ],
            [
              2085042.7925657453,
              4027610.627861323
            ],
            [
              2133238.856866916,
              4024688.3579825987
            ]
          ],
          [
            [
              2133238.856866919,
              4024688.3579825987
            ],
            [
              2137604.3518881057,
              4024418.1879896913
            ],
            [
              2190162.2360857013,
              4021349.754676055
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T010",
        "vessel": "Vanua I",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": true,
        "length_m": 489842.48
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1878020.6287486383,
              3968978.967213469
            ],
            [
              2040133.8855144326,
              3948137.8948760154
            ],
            [
              2132667.393619207,
              3935979.8021080676
            ]
          ],
          [
            [
              2132667.39361921,
              3935979.8021080676
            ],
            [
              2201937.698953716,
              3926588.128825637
            ],
            [
              2363529.5082588177,
              3904005.3603546056
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T011",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-20T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 78492.17
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2465344.860581143,
              3906767.4726070557
            ],
            [
              2452339.7066555577,
              3904904.8687637383
            ],
            [
              2439358.6785597224,
              3903920.698017729
            ],
            [
              2426380.6456198604,
              3902914.5859909956
            ],
            [
              2413382.539078825,
              3900783.353759157
            ],
            [
              2400405.893514905,
              3899474.351449523
            ],
            [
              2387423.5467098975,
              3897686.467113443
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T012",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-20T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 84537.56
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1741748.7332561535,
              3890283.693144509
            ],
            [
              1746692.5945271784,
              3918471.030985262
            ],
            [
              1751658.9788316165,
              3946432.2638834873
            ],
            [
              1756655.23549125,
              3973496.030364219
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T013",
        "vessel": "Bligh",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 179800.48
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2482137.408760446,
              3917127.8950326387
            ],
            [
              2428688.657510872,
              3889083.6235283166
            ],
            [
              2375443.2052126382,
              3862380.253960575
            ],
            [
              2322350.650514273,
              3834700.4346561665
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T014",
        "vessel": "Lomaiviti",
        "survey_date": "2025-08-13T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 148392.88
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1763975.2418630726,
              4043578.795124353
            ],
            [
              1798590.965242443,
              4030582.772307513
            ],
            [
              1833155.9390679915,
              4017897.3350352263
            ],
            [
              1867693.298104288,
              4002219.6929108296
            ],
            [
              1902160.329611775,
              3989702.4129796983
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T015",
        "vessel": "Vanua I",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 124738.16
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2423739.783700946,
              4026263.28896241
            ],
            [
              2403163.542824007,
              4022543.302237784
            ],
            [
              2382622.078231965,
              4020081.2554188394
            ],
            [
              2362078.3244465566,
              4016938.6757560875
            ],
            [
              2341534.154948448,
              4013127.314926124
            ],
            [
              2321005.3259064667,
              4009569.4162317035
            ],
            [
              2300505.4150438267,
              4007278.1846613027
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T016",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 53310.24
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1967763.1376268503,
              3864348.9772176393
            ],
            [
              1981044.9340631447,
              3864774.370362437
            ],
            [
              1994327.5364892795,
              3864095.7190000876
            ],
            [
              2007608.7888293017,
              3862426.337582078
            ],
            [
              2020890.884403137,
              3863623.624927437
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T017",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 152432.38
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2459196.783273682,
              4040076.8577193925
            ],
            [
              2445503.0422038976,
              4017855.351608406
            ],
            [
              2431865.897774811,
              3997180.8985599047
            ],
            [
              2418220.5069328533,
              3974931.1076368974
            ],
            [
              2404624.705595245,
              3953897.7538502435
            ],
            [
              2391055.945635675,
              3932981.1069712103
            ],
            [
              2377499.6209094804,
              3911400.2397073773
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T018",
        "vessel": "Bligh",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 112421.62
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1718720.2972681404,
              4014591.143533892
            ],
            [
              1738197.5781078157,
              3994553.0214466406
            ],
            [
              1757642.797153981,
              3974080.649730659
            ],
            [
              1777042.657001174,
              3954256.1167427967
            ],
            [
              1796415.9225681531,
              3933347.3340493958
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T019",
        "vessel": "Lomaiviti",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 179435.73
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1921232.177273387,
              3921611.4164991337
            ],
            [
              1877615.3144519601,
              3932437.2333025597
            ],
            [
              1833949.291065143,
              3942738.01477121
            ],
            [
              1790234.490579545,
              3952596.93857858
            ],
            [
              1746468.6202754881,
              3962251.7484134217
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T020",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-13T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 215352.23
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1799842.78527887,
              3989614.6337389858
            ],
            [
              1850089.5464570043,
              3969622.1670543184
            ],
            [
              1900223.5116513204,
              3950791.606715858
            ],
            [
              1950261.0912236797,
              3930816.037580312
            ],
            [
              2000196.12611439,
              3910677.6427223445
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T021",
        "vessel": "Vanua I",
        "survey_date": "2025-08-16T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 230219.24
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1734792.6614569672,
              3988023.0114604924
            ],
            [
              1796140.996215118,
              3941226.4356850684
            ],
            [
              1857192.2097571124,
              3895079.338822874
            ],
            [
              1917953.2043430656,
              3848549.896766379
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T022",
        "vessel": "Vanua I",
        "survey_date": "2025-08-15T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 50981.78
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1826735.497725808,
              3908468.0307612177
            ],
            [
              1833530.8357058733,
              3915690.085356508
            ],
            [
              1840325.6909893686,
              3923592.9662667327
            ],
            [
              1847131.1924793813,
              3930812.0080819936
            ],
            [
              1853932.773435727,
              3939251.123958868
            ],
            [
              1860748.965022611,
              3946407.5329954834
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T023",
        "vessel": "Lomaiviti",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 81980.09
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2430814.5176551496,
              3920116.8471598867
            ],
            [
              2415479.5967341997,
              3913735.5872768546
            ],
            [
              2400171.1034651063,
              3908063.181956481
            ],
            [
              2384901.9803659474,
              3903846.206101202
            ],
            [
              2369582.6457509208,
              3896469.9735108716
            ],
            [
              2354312.0603208095,
              3891057.5105217276
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T024",
        "vessel": "Vanua I",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 251074.91
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2228238.4566725227,
              4015411.736894843
            ],
            [
              2276757.963919763,
              4002318.5037398003
            ],
            [
              2325229.232446313,
              3988882.404731997
            ],
            [
              2373665.340709087,
              3975810.063902585
            ],
            [
              2422085.660914305,
              3963774.4034233717
            ],
            [
              2470420.227856475,
              3949290.9864591043
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T025",
        "vessel": "Taveuni II",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 108459.05
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1769898.113943761,
              3863034.971961179
            ],
            [
              1769580.71284751,
              3898636.037103303
            ],
            [
              1769258.2869353632,
              3935337.3281767596
            ],
            [
              1768950.0859736353,
              3971489.878227382
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T026",
        "vessel": "Cakaulevu",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 100661.48
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              1987271.4052228667,
              3939376.2990370244
            ],
            [
              1967307.9907347183,
              3936889.1958410414
            ],
            [
              1947350.861923434,
              3933738.235256531
            ],
            [
              1927393.682270505,
              3932163.1557427393
            ],
            [
              1907448.9126200052,
              3928390.8376744
            ],
            [
              1887498.9116150867,
              3926697.0667341426
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T027",
        "vessel": "Vanua I",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 130089.67
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2369948.7263461673,
              3976319.9325690367
            ],
            [
              2346287.470686171,
              3964968.188987548
            ],
            [
              2322678.80831227,
              3955012.8928886973
            ],
            [
              2299080.230015055,
              3943891.124994715
            ],
            [
              2275520.6251862263,
              3933450.761366028
            ],
            [
              2251971.126515633,
              3921591.3665094175
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T028",
        "vessel": "Vanua I",
        "survey_date": "2025-08-12T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 173047.04
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2330479.7686202456,
              4050623.346325348
            ],
            [
              2372415.289708903,
              4039380.3649832667
            ],
            [
              2414329.386504559,
              4028381.670683045
            ],
            [
              2456265.7878334904,
              4019496.345153804
            ],
            [
              2498125.9280114328,
              4007925.0495241787
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T029",
        "vessel": "Lomaiviti",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 205262.64
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2496390.5070293318,
              3872926.5081186867
            ],
            [
              2456887.5880763554,
              3906639.2715288056
            ],
            [
              2417234.1074046907,
              3939224.290901031
            ],
            [
              2377443.041219402,
              3970892.0161980125
            ],
            [
              2337541.907860386,
              4002897.035326764
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "transect_id": "T030",
        "vessel": "Cakaulevu",
        "survey_date": "2025-08-19T00:00:00",
        "crosses_antimeridian_flag": false,
        "length_m": 163829.39
      },
      "geometry": {
        "type": "MultiLineString",
        "coordinates": [
          [
            [
              2370599.7528943215,
              4007936.284838661
            ],
            [
              2348033.804542877,
              3992395.776298311
            ],
            [
              2325521.730368626,
              3977972.568507736
            ],
            [
              2303009.840542533,
              3961256.978484933
            ],
            [
              2280550.736391237,
              3945560.2422843603
            ],
            [
              2258135.8435976296,
              3930440.8739923015
            ],
            [
              2235752.355614778,
              3914958.146484169
            ]
          ]
        ]
      }
    }
  ]
}
2:23
Let me check the output more carefully. For the antimeridian-crossing transects, I see that the split hasn't worked as expected. Looking at T001 for example:

The coordinates are: [178.94, -17.63], [179.46, -17.62], [179.97, -17.61], [-179.51, -17.60], [-179.00, -17.58], [-178.48, -17.58]

The jump from 179.97 to -179.51 is a ~0.5° jump going the short way (eastward) but since it crosses the antimeridian, the raw longitude difference is about 360.5°.

So my split_antimeridian_coords function should detect this. Let me trace through:

1. coords[0] = (178.94, -17.63), coords[1] = (179.46, -17.62) — diff = 0.51, no crossing
2. coords[1] = (179.46, -17.62), coords[2] = (179.97, -17.61) — diff = 0.51, no crossing
3. coords[2] = (179.97, -17.61), coords[3] = (-179.51, -17.60) — x1=179.97, x2=-179.51. abs(diff) = 359.48 > 180. So crossing detected.

x1 > 0, x2 < 0: East -> West. adj_x2 = -179.51 + 360 = 180.49. target_lon = 180.

t = (180 - 179.97) / (180.49 - 179.97) = 0.03 / 0.52 = 0.0577
cross_y = -17.61 + 0.0577 * (-17.60 - (-17.61)) = -17.61 + 0.0577 * 0.01 = -17.61 + 0.000577 = -17.6094

So current ends at (180, -17.6094)
Then new segment starts from (-180, -17.6094), (x2, y2) = (-179.51, -17.60)

Then coords[4] = (-179.00, -17.58), coords[5] = (-178.48, -17.58) — small diffs, no crossing.

So we'd get:
Part 1: [(178.94, -17.63), (179.46, -17.62), (179.97, -17.61), (180, -17.6094)]
Part 2: [(-180, -17.6094), (-179.51, -17.60), (-179.00, -17.58), (-178.48, -17.58)]

Then the adjustment step: For part 2, lon_prev starts at -180, then -179.51, -179.00, -178.48 — all fine.

Now when we project these parts:

Part 1 projected to FMG: points near 180°E longitude... The FMG uses a TM projection centered at 178.75°E. So points at 180° should be fine.

But wait, looking at the output for T001:

```
"coordinates": [
  [
    [2020343.340583844, 3930017.4674364463],
    [2074969.3287187445, 3930832.111936373],
    [2129608.4030453707, 3931959.043532026],
    [2132641.3519591475, 3932030.6236885176]
  ],
  [
    [2132641.3519591503, 3932030.6236885176],
    [2184265.933617849, 3933178.8742693216],
    [2238946.8792888806, 3934438.0861816974],
    [2293630.6493575512, 3933970.5213900264]
  ]
]
```

The last point of part 1 and first point of part 2 are very close: [2132641.35, 3932030.62] and [2132641.35, 3932030.62]. They're basically the same point (just tiny floating point diff from the +/-180 split). Good, that's a proper split at the antimeridian.

Let me verify the other split points look correct. T002:
Input: [179.07, -17.33], [179.73, -17.17], [-179.62, -17.01], [-178.96, -16.83]
From 179.73 to -179.62: x1=179.73, x2=-179.62, diff ≈ 359.35 > 180. Crossing.

Output shows part 1 has 3 points, part 2 has 2 points (plus the split point at the end of part 1, which coincides with the start of part 2). Looks good.

Now, the issue is that the split at (180, -17.6094) and (-180, -17.6094) are the same geographic point but different coordinates. When projected to FMG, they should map to the same location, and they appear to do so (2132641.35 difference is just numerical noise). Good.

Let me also verify T016 which is a normal transect that doesn't cross the antimeridian. Its output is a MultiLineString with a single LineString part - correct, as required.

I think the solution is working correctly. Let me also check if the survey_date format has an issue - it shows "2025-08-15T00:00:00" instead of "2025-08-15". Let me check the original:

Original: `"survey_date": "2025-08-15"` - looks like a string. But when geopandas reads it, it might parse it as datetime. Let me see if I should keep it as the original string format.

Actually, looking at the original JSON, the dates are in "2025-08-15" format (ISO date without time). When geopandas reads it, it probably converts to Timestamp. My code then uses `.isoformat()` which gives "2025-08-15T00:00:00". Let me fix that to preserve the original format.

Actually, "2025-08-15T00:00:00" is still valid ISO 8601, but the original was just "2025-08-15". To be precise, I should preserve the original format. Let me update the code.
2:23
2:23
Bash python3 -c "
python3 -c "
import geopandas as gpd
gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')
print(type(gdf['survey_date'].iloc[0]))
print(repr(gdf['survey_date'].iloc[0]))
"
<class 'pandas.Timestamp'>
Timestamp('2025-08-15 00:00:00')
2:26
The survey_date was originally a date string "2025-08-15" but pandas read it as a Timestamp. When we serialized, it became "2025-08-15T00:00:00" which includes the time part. The original was just "2025-08-15". Let me check the original file to see the exact format.

Looking at the input file, the survey_date values are strings like "2025-08-15". So the original format was just the date. To be faithful, I should output just the date part "2025-08-15" not "2025-08-15T00:00:00".
2:26
Bash python3 -c "
python3 -c "
import json
with open('/work/fiji_transects_wgs84.geojson') as f:
    data = json.load(f)
for feat in data['features']:
    print(feat['properties']['survey_date'])
    break
"
2025-08-15
2:29
The survey_date in the original GeoJSON is "2025-08-15" (just the date string). But when geopandas reads it, it converts it to a Timestamp. In my output, it's coming out as "2025-08-15T00:00:00" because of the `.isoformat()` call. Let me fix it to output just the date string like the original.
2:29
2:29
Read /work/solve.py
     1	import geopandas as gpd
     2	import shapely.geometry as geom
     3	from shapely.ops import transform
     4	import pyproj
     5	import json
     6	
     7	# Read input
     8	gdf = gpd.read_file('/work/fiji_transects_wgs84.geojson')
     9	
    10	# Define CRS
    11	wgs84 = pyproj.CRS.from_epsg(4326)
    12	fmg = pyproj.CRS.from_epsg(3460)  # Fiji 1986 / Fiji Map Grid
    13	project = pyproj.Transformer.from_crs(wgs84, fmg, always_xy=True).transform
    14	
    15	
    16	def split_antimeridian_coords(coords):
    17	    """Split coordinate list at antimeridian crossings.
    18	    Returns list of lists of (lon, lat), each being a continuous segment
    19	    in WGS84 that does not cross the antimeridian.
    20	    """
    21	    if len(coords) < 2:
    22	        return [list(coords)]
    23	
    24	    parts = []
    25	    current = [coords[0]]
    26	
    27	    for i in range(1, len(coords)):
    28	        x1, y1 = coords[i - 1]
    29	        x2, y2 = coords[i]
    30	
    31	        # Detect antimeridian crossing: longitude difference > 180 degrees
    32	        if abs(x2 - x1) > 180:
    33	            # Interpolate the exact crossing point on the antimeridian (180 / -180)
    34	            if x1 < 0 and x2 > 0:
    35	                # West -> East: adjust x2 westwards so we can interpolate through -180°
    36	                adj_x2 = x2 - 360.0
    37	                target_lon = -180.0
    38	            elif x1 > 0 and x2 < 0:
    39	                # East -> West: adjust x2 eastwards so we can interpolate through 180°
    40	                adj_x2 = x2 + 360.0
    41	                target_lon = 180.0
    42	            else:
    43	                # Same sign but diff > 180 — should not happen for valid data
    44	                # But handle gracefully: just split at midpoint
    45	                adj_x2 = x2
    46	                target_lon = (x1 + x2) / 2.0
    47	
    48	            # Linear interpolation to find crossing latitude
    49	            t = (target_lon - x1) / (adj_x2 - x1)
    50	            cross_y = y1 + t * (y2 - y1)
    51	
    52	            # Finish current segment at the antimeridian
    53	            current.append((target_lon, cross_y))
    54	            parts.append(current)
    55	
    56	            # Start new segment from the other side of the antimeridian
    57	            other_lon = 180.0 if target_lon < 0 else -180.0
    58	            current = [(other_lon, cross_y), (x2, y2)]
    59	        else:
    60	            current.append((x2, y2))
    61	
    62	    if current:
    63	        parts.append(current)
    64	
    65	    # Adjust longitudes within each part to be continuous (no jumps)
    66	    adjusted_parts = []
    67	    for part in parts:
    68	        adj = [part[0]]
    69	        for j in range(1, len(part)):
    70	            lon_prev, lat_prev = adj[j - 1]
    71	            lon, lat = part[j]
    72	            # Shift longitude by ±360 to eliminate any large jumps
    73	            while lon - lon_prev > 180:
    74	                lon -= 360
    75	            while lon - lon_prev < -180:
    76	                lon += 360
    77	            adj.append((lon, lat))
    78	        adjusted_parts.append(adj)
    79	
    80	    return adjusted_parts
    81	
    82	
    83	features_out = []
    84	
    85	for idx, row in gdf.iterrows():
    86	    geom_in = row.geometry
    87	    props = {}
    88	    for k, v in row.items():
    89	        if k != 'geometry':
    90	            # Convert pandas Timestamps to strings
    91	            if hasattr(v, 'isoformat'):
    92	                v = v.isoformat()
    93	            props[k] = v
    94	
    95	    # Get coordinates (handle both LineString and MultiLineString input)
    96	    if geom_in.geom_type == 'LineString':
    97	        coords = list(geom_in.coords)
    98	    elif geom_in.geom_type == 'MultiLineString':
    99	        coords = []
   100	        for line in geom_in.geoms:
   101	            coords.extend(list(line.coords))
   102	    else:
   103	        raise ValueError(f"Unexpected geometry type: {geom_in.geom_type}")
   104	
   105	    # Split at antimeridian crossings
   106	    parts = split_antimeridian_coords(coords)
   107	
   108	    # Build LineStrings, reproject to Fiji Map Grid
   109	    lines_fmg = []
   110	    for part in parts:
   111	        line_wgs84 = geom.LineString(part)
   112	        line_fmg = transform(project, line_wgs84)
   113	        lines_fmg.append(line_fmg)
   114	
   115	    # Ensure MultiLineString
   116	    multi = geom.MultiLineString(lines_fmg)
   117	
   118	    # Calculate length in projected units (metres)
   119	    length_m = multi.length
   120	
   121	    # Build output dict for GeoJSON serialisation
   122	    feat = {
   123	        'type': 'Feature',
   124	        'properties': {
   125	            **props,
   126	            'length_m': round(length_m, 2)
   127	        },
   128	        'geometry': geom.mapping(multi)
   129	    }
   130	    features_out.append(feat)
   131	
   132	# Assemble output FeatureCollection
   133	out_collection = {
   134	    'type': 'FeatureCollection',
   135	    'name': 'fiji_transects_fmg',
   136	    'crs': {
   137	        'type': 'name',
   138	        'properties': {'name': 'urn:ogc:def:crs:EPSG::3460'}
   139	    },
   140	    'features': features_out
   141	}
   142	
   143	with open('/work/fiji_transects_fmg.geojson', 'w') as f:
   144	    json.dump(out_collection, f, indent=2)
   145	
   146	print(f"Wrote {len(features_out)} features to /work/fiji_transects_fmg.geojson")
2:32
The survey_date in the original GeoJSON is a date string like "2025-08-15" (no time component). When geopandas reads it, it becomes a pandas Timestamp. When I call `isoformat()` on it, it becomes "2025-08-15T00:00:00". I should just format it as YYYY-MM-DD to match the original. Let me change the conversion.
2:32
Edit /work/solve.py
Edited /work/solve.py.
2:50
Now I also need to think about the antimeridian splitting logic more carefully. Let me re-examine the geometry output.

Looking at T001: The original coordinates jump from [179.97..., -17.61...] to [-179.51..., -17.59...]. The difference in longitude is 179.97 - (-179.51) = 359.48, which is > 180. So the antimeridian crossing is detected.

But wait - the issue is that when we cross the antimeridian, the points on one side need to be shifted by ±360 to make the geometry continuous. Let me trace through the logic:

For T001: 
- coords go from: 178.94, 179.46, 179.97, -179.51, -179.00, -178.48
- Between 179.97 and -179.51: x1=179.97 (>0), x2=-179.51 (<0), so we go East -> West.
- adj_x2 = -179.51 + 360 = 180.49
- target_lon = 180.0
- t = (180.0 - 179.97) / (180.49 - 179.97) = 0.03 / 0.52 ≈ 0.058
- cross_y = -17.61 + 0.058 * (-17.60 - (-17.61)) ≈ -17.61

So current = [..., (179.97, -17.61), (180.0, -17.61)]
Then other_lon = -180.0 (since target_lon > 0)
New current = [(-180.0, -17.61), (-179.51, -17.60), ...]

But then in the adjusted parts:
For part 1: [178.94, 179.46, 179.97, 180.0] - these should be fine
For part 2: [-180.0, -179.51, -179.00, -178.48] - these should be fine, no jumps > 180

Then when we project these, the first part has coordinates with longitudes 178.94 to 180.0, and the second has -180.0 to -178.48... 

Wait, but when projected to Fiji Map Grid (TM centered at 178.75), points at longitude 180 and -180 are at the same location (they're the same meridian). So the two parts should meet at the antimeridian.

Actually, looking at the output for T001:
Part 1: 2020343, 2074969, 2129608, 2132641
Part 2: 2132641, 2184265, 2238946, 2293630

The connection point at 2132641 is the split point. That makes sense because the TM projection at longitude 180 and -180 should give the same easting/northing.

Actually, wait. Let me look at this more carefully. The point at longitude 180 and -180 should be the same point in projected coordinates. Let me verify by looking at the coordinates at the split:

For T001, the crossing is between [179.971430438527307, -17.611072392823225] and [-179.513794132600054, -17.596198176111951].

The interpolated crossing point at lon=180 should be at lat ≈ -17.606... and the crossing point at lon=-180 should be at the same lat.

Let me check: the projected coordinates at the split are 2132641.351959... in both parts. Good, they match.

Now, actually there's another issue I want to verify. Let me check if the crossing logic is correct for the other direction. Let's look at T004:

Coords: 178.87, 179.54, -179.79, -179.12, -178.45, -177.78
Between 179.54 and -179.79: x1=179.54 (>0), x2=-179.79 (<0). So x1>0, x2<0, we go East->West.
adj_x2 = -179.79 + 360 = 180.21
target_lon = 180.0

That looks right.

Now what about T003:
Coords: 177.64, 178.46, 179.29, -179.89, -179.06
Between 179.29 and -179.89: x1=179.29 (>0), x2=-179.89 (<0). Same logic.

OK. But there's a subtle issue. When we look at the "adjusted_parts" step, for part 2, we have coordinates starting with (-180.0, cross_y). The subsequent coordinates like -179.51 are close to -180, so no adjustment needed. But what about later coordinates like -178.48? -178.48 - (-179.51) = 1.03 which is fine.

What about T010: Coords: [177.60, 179.13, -179.35, -177.82]
Between 179.13 and -179.35: x1=179.13, x2=-179.35
adj_x2 = -179.35 + 360 = 180.65
target_lon = 180.0
t = (180-179.13)/(180.65-179.13) = 0.87/1.52 ≈ 0.572
cross_y at lon=180

Then part 1: [177.60, 179.13, 180.0]
part 2: [-180.0, -179.35, -177.82]

Let me check the second part: -179.35 - (-180.0) = 0.65 (fine), -177.82 - (-179.35) = 1.53 (fine). Good.

Now there's another issue I want to verify. For the segments that don't cross the antimeridian, they should remain as single-segment MultiLineStrings. Let me check T011... T011 has no crossing, so all coordinates are in one part.

But I notice that T011 is in the western hemisphere with coordinates like -176.86, -176.98, etc. These should all project fine as they don't cross the antimeridian.

Let me think about whether there's a problem with the longitude wrapping. The Fiji Map Grid uses Transverse Mercator centered at 178.75°E. The western part of Fiji goes to about -177° (which is 183°E or -177°). But that's within the TM zone coverage.

Hmm, actually let me think more carefully about the "adjusted_parts" step. For part 1, after the split, the coordinates include a point at 180.0. In part 2, the coordinates start at -180.0. These are the same meridian but expressed differently. When projected, they should give the same easting/northing. Let me verify...

Actually, I realize there's a potential problem. In the "adjusted parts" step for the first part, I have coordinates like [178.94, 179.46, 179.97, 180.0]. The 180.0 is added to the end. But the next coordinates after 180.0 would be... well there are none in part 1. In the original data, after 179.97 came -179.51, which is where we split. So part 1 ends at 180.0.

But wait, the interpolation puts the crossing point at exactly lon=180.0. However, the actual path continues from the coordinate pair (179.97, -17.61) and (-179.51, -17.60). The crossing point is exactly on the antimeridian (at 180°). So the first part ends at (180.0, cross_y) and the second part starts at (-180.0, cross_y). These represent the same point, so the two LineStrings should connect seamlessly.

But hold on - is 180.0 within the valid range for the TM projection at central meridian 178.75? Yes, TM projections are valid for about 6 degrees on either side, and 180.0 - 178.75 = 1.25 degrees, which is well within range.

Similarly, -180.0 is -180 - 178.75 = 1.25 degrees west of the central meridian. Equivalent to 360 - 180 - 178.75 = 1.25 degrees... wait no. -180° is 180°W, and the central meridian is 178.75°E. So the distance from the central meridian going westward is: 178.75 - (-180) = 358.75... going the other way: 180 - 178.75 = 1.25. So -180° is actually 1.25° east of the central meridian... no, let me think again.

Actually, in TM projection, the "longitude" parameter is relative to the central meridian in the usual way. -180° is 180°W. The central meridian is 178.75°E. Going east from central meridian: 180 - 178.75 = 1.25. Going west: -180 - 178.75 = -358.75... but in TM, we take the shortest angular distance. 1.25° is the shortest. So -180° maps to a location 1.25° east of the central meridian, which is fine.

Actually, I realize - the TM projection in PROJ handles this correctly. The longitude -180 should be equivalent to 180, and when the central meridian is 178.75, the distance is min(|180-178.75|, 360-|180-178.75|) = min(1.25, 358.75) = 1.25. So both 180 and -180 should give the same coordinates.

Let me verify this quickly.

Actually, I think the code is working correctly. Let me move on and verify the output more carefully.

One more thing - I should double-check my splitting logic for the case where coordinates go from negative to positive (e.g., from -179 to +179). Let's trace through T009:
Coords: 178.07, 178.56, 179.05, 179.55, -179.96, -179.47

Crossing between 179.55 and -179.96: x1=179.55 (>0), x2=-179.96 (<0). So East->West.
adj_x2 = -179.96 + 360 = 180.04
target_lon = 180.0
t = (180.0-179.55)/(180.04-179.55) = 0.45/0.49 ≈ 0.918
cross_y = ...

This should work. Let me also check if the segment -179.96 to -179.47 is correctly handled: -179.47 - (-179.96) = 0.49 (fine, no crossing).

OK, I think the code is correct now. Let me verify the output once more.

Actually, I realize I should double-check one more thing. Let me verify from the output that T011 (which doesn't cross the antimeridian) is properly handled as a single MultiLineString with one line.

Looking at the output for T011:
```
"geometry": {
    "type": "MultiLineString",
    "coordinates": [
        [
            [2465344, ...], [2452339, ...], ..., [2387423, ...]
        ]
    ]
}
```

Yes - one part in the MultiLineString. Good.

And the survey_date is now formatted as "2025-08-15" instead of "2025-08-15T00:00:00".

Let me re-run the script to get the corrected output.
2:50
2:50
Bash cd /work && python solve.py
Wrote 30 features to /work/fiji_transects_fmg.geojson
2:55
Let me verify the output to check a few things:
1. The survey_date is now just YYYY-MM-DD
2. All geometries are MultiLineString
3. The T001 transect has been split into proper multi-part geometry
4. The length_m field is present
2:55
Bash python3 -c "
python3 -c "
import json
with open('/work/fiji_transects_fmg.geojson') as f:
    data = json.load(f)

print(f'Total features: {len(data[\"features\"])}')
print()

# Check T001 in detail
for feat in data['features']:
    props = feat['properties']
    if props['transect_id'] == 'T001':
        print('T001 properties:', json.dumps(props, indent=2))
        print('T001 geometry type:', feat['geometry']['type'])
        print('T001 num parts:', len(feat['geometry']['coordinates']))
        print('T001 part 0 coords:', len(feat['geometry']['coordinates'][0]))
        print('T001 part 1 coords:', len(feat['geometry']['coordinates'][1]))
        break

print()

# Check all features are MultiLineString
for feat in data['features']:
    gtype = feat['geometry']['type']
    if gtype != 'MultiLineString':
        print(f'ERROR: {feat[\"properties\"][\"transect_id\"]} has type {gtype}')
    
    # Check survey_date format
    sd = feat['properties']['survey_date']
    if 'T' in sd:
        print(f'WARNING: {feat[\"properties\"][\"transect_id\"]} survey_date has T: {sd}')

print('All checks done')

# Check some sample survey_dates
for feat in data['features'][:3]:
    print(f'{feat[\"properties\"][\"transect_id\"]}: {feat[\"properties\"][\"survey_date\"]}')
"
Total features: 30

T001 properties: {
  "transect_id": "T001",
  "vessel": "Taveuni II",
  "survey_date": "2025-08-15",
  "crosses_antimeridian_flag": true,
  "length_m": 273335.11
}
T001 geometry type: MultiLineString
T001 num parts: 2
T001 part 0 coords: 4
T001 part 1 coords: 4

All checks done
T001: 2025-08-15
T002: 2025-08-12
T003: 2025-08-12
3:05
Let me review the results carefully:

1. **All 30 features are MultiLineString** - ✓
2. **Survey attributes preserved** (transect_id, vessel, survey_date) - ✓
3. **survey_date format is YYYY-MM-DD** as original - ✓
4. **Antimeridian-crossing transects split into multi-part geometries** - ✓ T001 has 2 parts
5. **length_m calculated in projected units (metres)** - ✓
6. **Written as GeoJSON** - ✓

Let me also verify the antimeridian splitting more carefully. Let me check a few of the crossing ones to make sure the segments are correct.

For T001: coordinates go from 178.94, 179.46, 179.97, -179.51, -178.99, -178.48
The crossing happens between 179.97 and -179.51 (difference ~360.5).

With my algorithm:
- x1=179.97 (positive), x2=-179.51 (negative) -> East to West direction
- adj_x2 = -179.51 + 360 = 180.49
- target_lon = 180.0
- t = (180 - 179.97) / (180.49 - 179.97) ≈ 0.06
- cross_y ≈ -17.611 + 0.06 * (-17.596 + 17.611) ≈ -17.610

So part 0 ends at (180, cross_y) and part 1 starts at (-180, cross_y).

Looking at the output for T001:
- Part 0: 4 coords (3 original + 1 interpolated at antimeridian)
- Part 1: 4 coords (1 interpolated at antimeridian + 3 remaining)

Wait, T001 has 6 original coords. After splitting:
- Part 0: [0], [1], [2], (180, cross) = 4 coords
- Part 1: (-180, cross), [3], [4], [5] = 4 coords
Total: 6 original + 1 interpolation point duplicated at 180/-180 = 8 coords across both parts. Makes sense.

But wait - the coordinates shown are in projected FMG, not WGS84. So we can't directly compare. Let me verify the WGS84 geometry by checking the original coords before projection.

Actually, let me think about this more carefully. The algorithm adjusts longitudes within each part. So in part 0 (before crossing):
- [179.97, -17.611] stays as is
- The interpolated point at (180, cross_y) - 180 is the antimeridian

In part 1 (after crossing):
- Starts at (-180, cross_y) - other side of antimeridian
- Then [3], [4], [5] which are -179.51, -178.99, -178.48

But wait, my code does a longitude adjustment after splitting. Let me check part 1:
- Start: (-180, cross_y)
- Then (-179.51, -17.596) - difference from -180 is 0.49, which is fine
- Then (-178.99, -17.580) - difference from -179.51 is 0.52, fine
- Then (-178.48, -17.577) - fine

Part 0:
- Start: (178.94, -17.632)
- (179.46, -17.624) - diff 0.52, fine
- (179.97, -17.611) - diff 0.51, fine
- (180, cross_y) - diff 0.03, fine

So the longitude adjustment within each segment keeps things continuous. Good.

But wait, the projected coordinates for T001 part 0 range from x=2020343 to x=2132641 and part 1 from x=2132641 to x=2293630. That looks continuous! The antimeridian (180°) corresponds to longitude of natural origin 178.75°E + some offset. In FMG, the central meridian is at 178.75°E with easting 2,000,000m. So 180°E would be around 2,132,641m easting. That matches! Both segments meet at approximately 2,132,641m easting.

Let me also check what the correct projection is. The natural origin longitude is 178.75°E, which is in the 180° region. So points at 180° longitude would be east of the central meridian, and points at -180° longitude would be west of it. At the equator, 1.25° of longitude = ~139km, so easting would be ~2,000,000 + 139,000 = 2,139,000m. The value we see (2,132,641) is close enough accounting for the scale factor.

So the output looks correct. Let me also verify that non-crossing transects (like T011-T030 that have crosses_antimeridian_flag=false) are kept as single-part MultiLineStrings. Yes, T011 has just one part in the coordinates array.

All looks good! The output file is `/work/fiji_transects_fmg.geojson`.

Let me also do a quick sanity check on the geometry counts for crossing transects.
3:05
3:05
Bash python3 -c "
python3 -c "
import json
with open('/work/fiji_transects_fmg.geojson') as f:
    data = json.load(f)

for feat in data['features']:
    pid = feat['properties']['transect_id']
    crossing = feat['properties']['crosses_antimeridian_flag']
    coords = feat['geometry']['coordinates']
    n_parts = len(coords)
    if crossing:
        print(f'{pid} (crossing): {n_parts} parts, ', end='')
        # Check that consecutive parts meet (same start/end point)
        for i in range(n_parts - 1):
            p1_end = coords[i][-1]
            p2_start = coords[i+1][0]
            dx = abs(p1_end[0] - p2_start[0])
            dy = abs(p1_end[1] - p2_start[1])
            print(f'join{i}-{i+1}: Δ({dx:.1f}m, {dy:.1f}m) ', end='')
        print()
    else:
        print(f'{pid} (non-crossing): {n_parts} part(s)')
"
T001 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T002 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T003 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T004 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T005 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T006 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T007 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T008 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T009 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T010 (crossing): 2 parts, join0-1: Δ(0.0m, 0.0m) 
T011 (non-crossing): 1 part(s)
T012 (non-crossing): 1 part(s)
T013 (non-crossing): 1 part(s)
T014 (non-crossing): 1 part(s)
T015 (non-crossing): 1 part(s)
T016 (non-crossing): 1 part(s)
T017 (non-crossing): 1 part(s)
T018 (non-crossing): 1 part(s)
T019 (non-crossing): 1 part(s)
T020 (non-crossing): 1 part(s)
T021 (non-crossing): 1 part(s)
T022 (non-crossing): 1 part(s)
T023 (non-crossing): 1 part(s)
T024 (non-crossing): 1 part(s)
T025 (non-crossing): 1 part(s)
T026 (non-crossing): 1 part(s)
T027 (non-crossing): 1 part(s)
T028 (non-crossing): 1 part(s)
T029 (non-crossing): 1 part(s)
T030 (non-crossing): 1 part(s)
3:08