| 3195 | */ |
| 3196 | |
| 3197 | double OGRSpatialReference::GetTargetLinearUnits(const char *pszTargetKey, |
| 3198 | const char **ppszName) const |
| 3199 | |
| 3200 | { |
| 3201 | TAKE_OPTIONAL_LOCK(); |
| 3202 | |
| 3203 | d->refreshProjObj(); |
| 3204 | |
| 3205 | pszTargetKey = d->nullifyTargetKeyIfPossible(pszTargetKey); |
| 3206 | if (pszTargetKey == nullptr) |
| 3207 | { |
| 3208 | // Use cached result if available |
| 3209 | if (!d->m_osLinearUnits.empty()) |
| 3210 | { |
| 3211 | if (ppszName) |
| 3212 | *ppszName = d->m_osLinearUnits.c_str(); |
| 3213 | return d->dfToMeter; |
| 3214 | } |
| 3215 | |
| 3216 | while (true) |
| 3217 | { |
| 3218 | if (d->m_pj_crs == nullptr) |
| 3219 | { |
| 3220 | break; |
| 3221 | } |
| 3222 | |
| 3223 | d->demoteFromBoundCRS(); |
| 3224 | PJ *coordSys = nullptr; |
| 3225 | if (d->m_pjType == PJ_TYPE_COMPOUND_CRS) |
| 3226 | { |
| 3227 | for (int iComponent = 0; iComponent < 2; iComponent++) |
| 3228 | { |
| 3229 | auto subCRS = proj_crs_get_sub_crs(d->getPROJContext(), |
| 3230 | d->m_pj_crs, iComponent); |
| 3231 | if (subCRS && proj_get_type(subCRS) == PJ_TYPE_BOUND_CRS) |
| 3232 | { |
| 3233 | auto temp = |
| 3234 | proj_get_source_crs(d->getPROJContext(), subCRS); |
| 3235 | proj_destroy(subCRS); |
| 3236 | subCRS = temp; |
| 3237 | } |
| 3238 | if (subCRS && |
| 3239 | (proj_get_type(subCRS) == PJ_TYPE_PROJECTED_CRS || |
| 3240 | proj_get_type(subCRS) == PJ_TYPE_ENGINEERING_CRS || |
| 3241 | proj_get_type(subCRS) == PJ_TYPE_VERTICAL_CRS)) |
| 3242 | { |
| 3243 | coordSys = proj_crs_get_coordinate_system( |
| 3244 | d->getPROJContext(), subCRS); |
| 3245 | proj_destroy(subCRS); |
| 3246 | break; |
| 3247 | } |
| 3248 | else if (subCRS) |
| 3249 | { |
| 3250 | proj_destroy(subCRS); |
| 3251 | } |
| 3252 | } |
| 3253 | if (coordSys == nullptr) |
| 3254 | { |