! Writes out a single grid to destination */
| 5762 | |
| 5763 | /*! Writes out a single grid to destination */ |
| 5764 | GMT_LOCAL int gmtapi_export_grid (struct GMTAPI_CTRL *API, int object_ID, unsigned int mode, struct GMT_GRID *G_obj) { |
| 5765 | int item, error; |
| 5766 | bool done = true, row_by_row; |
| 5767 | unsigned int method; |
| 5768 | openmp_int row, col, i0, i1, j0, j1; |
| 5769 | uint64_t ij, ijp, ij_orig; |
| 5770 | size_t size; |
| 5771 | double dx, dy; |
| 5772 | p_func_uint64_t GMT_2D_to_index = NULL; |
| 5773 | GMT_putfunction api_put_val = NULL; |
| 5774 | struct GMTAPI_DATA_OBJECT *S_obj = NULL; |
| 5775 | struct GMT_GRID *G_copy = NULL; |
| 5776 | struct GMT_MATRIX *M_obj = NULL; |
| 5777 | struct GMT_MATRIX_HIDDEN *MH = NULL; |
| 5778 | struct GMT_GRID_HIDDEN *GH = gmt_get_G_hidden (G_obj), *GH2 = NULL; |
| 5779 | struct GMT_CTRL *GMT = API->GMT; |
| 5780 | |
| 5781 | GMT_Report (API, GMT_MSG_DEBUG, "gmtapi_export_grid: Passed ID = %d and mode = %d\n", object_ID, mode); |
| 5782 | |
| 5783 | if (object_ID == GMT_NOTSET) return (gmtlib_report_error (API, GMT_OUTPUT_NOT_SET)); |
| 5784 | if (G_obj->data == NULL && !(mode & GMT_CONTAINER_ONLY)) return (gmtlib_report_error (API, GMT_PTR_IS_NULL)); |
| 5785 | if ((item = gmtlib_validate_id (API, GMT_IS_GRID, object_ID, GMT_OUT, GMT_NOTSET)) == GMT_NOTSET) return (gmtlib_report_error (API, API->error)); |
| 5786 | |
| 5787 | S_obj = API->object[item]; /* The current object whose data we will export */ |
| 5788 | if (S_obj->status != GMT_IS_UNUSED && !(mode & GMT_IO_RESET)) |
| 5789 | return (gmtlib_report_error (API, GMT_WRITTEN_ONCE)); /* Only allow writing of a data set once, unless overridden by mode */ |
| 5790 | if (mode & GMT_IO_RESET) mode -= GMT_IO_RESET; |
| 5791 | row_by_row = ((mode & GMT_GRID_ROW_BY_ROW) || (mode & GMT_GRID_ROW_BY_ROW_MANUAL)); |
| 5792 | if (row_by_row && S_obj->method != GMT_IS_FILE) { |
| 5793 | GMT_Report (API, GMT_MSG_ERROR, "Can only use method GMT_IS_FILE when row-by-row writing of grid is selected\n"); |
| 5794 | return (gmtlib_report_error (API, GMT_NOT_A_VALID_METHOD)); |
| 5795 | } |
| 5796 | if (S_obj->region) { /* See if this is really a subset or just the same region as the grid */ |
| 5797 | if (G_obj->header->wesn[XLO] == S_obj->wesn[XLO] && G_obj->header->wesn[XHI] == S_obj->wesn[XHI] && G_obj->header->wesn[YLO] == S_obj->wesn[YLO] && G_obj->header->wesn[YHI] == S_obj->wesn[YHI]) S_obj->region = false; |
| 5798 | } |
| 5799 | if (mode & GMT_DATA_IS_GEO) /* From API to tell grid is geographic */ |
| 5800 | gmt_set_geographic (GMT, GMT_OUT); |
| 5801 | else { |
| 5802 | /* Some grids are geographic and others are Cartesian, but the user may wish to flip this fact |
| 5803 | * via -f. Here we catch such deviousness and set the desired output geo/cart mode imposed by -f. */ |
| 5804 | if (GMT->common.f.is_geo[GMT_OUT]) |
| 5805 | gmt_set_geographic (GMT, GMT_OUT); |
| 5806 | else if (GMT->common.f.is_cart[GMT_OUT]) |
| 5807 | gmt_set_cartesian (GMT, GMT_OUT); |
| 5808 | } |
| 5809 | |
| 5810 | gmtlib_grd_set_units (GMT, G_obj->header); /* Ensure unit strings are set, regardless of destination */ |
| 5811 | method = gmtapi_set_method (S_obj); /* Get the actual method to use since may be MATRIX or VECTOR masquerading as GRID */ |
| 5812 | switch (method) { |
| 5813 | case GMT_IS_FILE: /* Name of a grid file on disk */ |
| 5814 | if (mode & GMT_CONTAINER_ONLY) { /* Update header structure only */ |
| 5815 | GMT_Report (API, GMT_MSG_INFORMATION, "Updating grid header for file %s\n", S_obj->filename); |
| 5816 | if (row_by_row) { /* Special row-by-row processing mode */ |
| 5817 | char w_mode = (mode & GMT_GRID_NO_HEADER) ? 'W' : 'w'; |
| 5818 | /* Since we may get here twice (initial write; later update) we only allocate extra if NULL */ |
| 5819 | if (GH->extra == NULL) GH->extra = gmt_M_memory (GMT, NULL, 1, struct GMT_GRID_ROWBYROW); |
| 5820 | if (GH->extra == NULL) { |
| 5821 | return (gmtlib_report_error (API, GMT_MEMORY_ERROR)); |
no test coverage detected