diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 48275eb0f..9d182a52c 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -381,6 +381,18 @@ export function addCommands( } }); + commands.addCommand(CommandIDs.reproject, { + label: trans.__('Reproject'), + isEnabled: () => selectedLayerIsOfType(['VectorLayer'], tracker), + execute: async () => { + await processSelectedLayer(tracker, formSchemaRegistry, 'Reproject', { + sqlQueryFn: (layerName, targetSRS) => `${targetSRS}`, + gdalFunction: 'ogr2ogr', + options: (sqlQuery: string) => ['-f', 'GeoJSON', '-t_srs', sqlQuery] + }); + } + }); + commands.addCommand(CommandIDs.newGeoJSONEntry, { label: trans.__('New GeoJSON layer'), isEnabled: () => { diff --git a/packages/base/src/constants.ts b/packages/base/src/constants.ts index c7c63fad4..f50245aeb 100644 --- a/packages/base/src/constants.ts +++ b/packages/base/src/constants.ts @@ -38,6 +38,7 @@ export namespace CommandIDs { // Processing commands export const buffer = 'jupytergis:buffer'; export const dissolve = 'jupytergis:dissolve'; + export const reproject = 'jupytergis:reproject'; // Sources only commands export const newRasterSource = 'jupytergis:newRasterSource'; diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 238613c30..4260fc391 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -18,7 +18,7 @@ export interface IProcessingFormDialogOptions extends IBaseFormProps { parentType: 'dialog' | 'panel' ) => void; model: IJupyterGISModel; - processingType: 'Buffer' | 'Dissolve' | 'Export'; + processingType: 'Buffer' | 'Dissolve' | 'Export' | 'Reproject'; } /** @@ -52,6 +52,7 @@ const ProcessingFormWrapper = (props: IProcessingFormWrapperProps) => { break; case 'Buffer': case 'Export': + case 'Reproject': default: FormComponent = BaseForm; } diff --git a/packages/base/src/processing.ts b/packages/base/src/processing.ts index 23fb245ce..fa9975e0b 100644 --- a/packages/base/src/processing.ts +++ b/packages/base/src/processing.ts @@ -90,7 +90,7 @@ export type GdalFunctions = export async function processSelectedLayer( tracker: JupyterGISTracker, formSchemaRegistry: IJGISFormSchemaRegistry, - processingType: 'Buffer' | 'Dissolve', + processingType: 'Buffer' | 'Dissolve' | 'Reproject', processingOptions: { sqlQueryFn: (layerName: string, param: any) => string; gdalFunction: GdalFunctions; @@ -150,6 +150,9 @@ export async function processSelectedLayer( case 'Dissolve': processParam = formValues.dissolveField; break; + case 'Reproject': + processParam = formValues.targetCRS; + break; default: console.error(`Unsupported processing type: ${processingType}`); return; @@ -191,7 +194,7 @@ export async function executeSQLProcessing( gdalFunction: GdalFunctions, options: string[], layerNamePrefix: string, - processingType: 'Buffer' | 'Dissolve', + processingType: 'Buffer' | 'Dissolve' | 'Reproject' embedOutputLayer: boolean, tracker: JupyterGISTracker, app: JupyterFrontEnd diff --git a/packages/schema/src/schema/processing/reproject.json b/packages/schema/src/schema/processing/reproject.json new file mode 100644 index 000000000..d69494f43 --- /dev/null +++ b/packages/schema/src/schema/processing/reproject.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "description": "Reproject", + "title": "IReproject", + "required": ["inputLayer", "targetCRS"], + "additionalProperties": false, + "properties": { + "inputLayer": { + "type": "string", + "description": "The input layer for reprojection." + }, + "targetCRS": { + "type": "string", + "default": "EPSG:4326", + "description": "The target coordinate reference system (CRS) for reprojection." + } + } +} diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts index 412b7958e..769883189 100644 --- a/packages/schema/src/types.ts +++ b/packages/schema/src/types.ts @@ -22,6 +22,7 @@ export * from './_interface/project/layers/heatmapLayer'; // Processing export * from './_interface/processing/buffer'; export * from './_interface/processing/dissolve'; +export * from './_interface/processing/reproject'; // exportLayer export * from './_interface/export/exportGeojson'; diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index d5a068c93..3e99c512c 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -199,6 +199,10 @@ const plugin: JupyterFrontEndPlugin = { command: CommandIDs.dissolve }); + processingSubmenu.addItem({ + command: CommandIDs.reproject + }); + app.contextMenu.addItem({ type: 'submenu', selector: '.jp-gis-layerItem',