Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,11 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>8</release>
<release>11</release>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
<useIncrementalCompilation>false</useIncrementalCompilation>
<compilerArgs>
<arg>--doclint-format</arg> <arg>html5</arg>
<arg>-h</arg> <arg>${project.build.sourceDirectory}/../cpp</arg>
</compilerArgs>
</configuration>
Expand Down
61 changes: 60 additions & 1 deletion src/main/cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ using osgeo::proj::cs::TemporalMeasureCS;
using osgeo::proj::cs::VerticalCS;
using osgeo::proj::cs::VerticalCSNNPtr;
using osgeo::proj::datum::Datum;
using osgeo::proj::datum::DatumNNPtr;
using osgeo::proj::datum::Ellipsoid;
using osgeo::proj::datum::EllipsoidNNPtr;
using osgeo::proj::datum::EngineeringDatum;
Expand Down Expand Up @@ -788,6 +789,8 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_UnitOfMeasure_create
JNIEXPORT jlong JNICALL Java_org_kortforsyningen_proj_Context_create(JNIEnv *env, jclass caller) {
static_assert(sizeof(PJ_CONTEXT*) <= sizeof(jlong), "Can not store PJ_CONTEXT* in a jlong.");
PJ_CONTEXT *ctx = proj_context_create();
//TODO: method analogue to setSearchPath
proj_log_level(ctx, PJ_LOG_NONE);
return reinterpret_cast<jlong>(ctx);
}

Expand Down Expand Up @@ -886,6 +889,51 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_Context_createFromUserIn





// </editor-fold>
// ┌────────────────────────────────────────────────────────────────────────────────────────────┐
// │ INITIALIZATION 2 (CLASS NativeResource) │
// └────────────────────────────────────────────────────────────────────────────────────────────┘
// <editor-fold desc="Initialization 2">

/**
* Set the search path for data files.
*
* @param env The JNI environment.
* @param caller The class from which this method has been invoked.
* @param context The Context object for the current thread.
* @param paths The search paths.
*/
JNIEXPORT void JNICALL Java_org_kortforsyningen_proj_NativeResource_setSearchPath(JNIEnv *env, jclass caller, jobject context, jobjectArray paths) {
BaseObjectPtr result = nullptr;

const char *searchPaths[8];
jsize stringCount = (*env).GetArrayLength(paths);

for (int i=0; i<stringCount; i++) {
jstring path = (jstring) (*env).GetObjectArrayElement( paths, i);
searchPaths[i] = (*env).GetStringUTFChars( path, nullptr);
}

if (stringCount > 0) {
try {
PJ_CONTEXT *ctx = context ? get_context(env, context) : nullptr;
proj_context_set_search_paths(ctx, (int)stringCount, searchPaths);
} catch (const std::exception &e) {
rethrow_as_java_exception(env, JPJ_FACTORY_EXCEPTION, e);
}
// Must be after the catch block in case an exception happens.
for (int i=0; i<stringCount; i++) {
jstring path = (jstring) (*env).GetObjectArrayElement( paths, i);
env->ReleaseStringUTFChars(path, searchPaths[i]);
}
}
}




// </editor-fold>
// ┌────────────────────────────────────────────────────────────────────────────────────────────┐
// │ CLASS SharedPointer (except format and inverse) │
Expand Down Expand Up @@ -948,6 +996,9 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_getObjectP
}
case org_kortforsyningen_proj_Property_DATUM: {
value = get_shared_object<SingleCRS>(env, object)->datum();
if (value == nullptr) {
value = get_shared_object<SingleCRS>(env, object)->datumEnsemble()->datums().front().as_nullable();
}
type = org_kortforsyningen_proj_Type_DATUM;
break;
}
Expand Down Expand Up @@ -2628,6 +2679,7 @@ JNIEXPORT void JNICALL Java_org_kortforsyningen_proj_Transform_transform
env->ReleasePrimitiveArrayCritical(coordinates, data, 0);
const int err = proj_errno(pj);
if (err) {
proj_errno_reset(pj);
jclass c = env->FindClass(JPJ_TRANSFORM_EXCEPTION);
if (c) env->ThrowNew(c, proj_errno_string(err));
} else if (isCopy) {
Expand Down Expand Up @@ -2677,7 +2729,14 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_normalizeF
BaseObjectPtr ptr = cop.as_nullable();
return specific_subclass(env, operation, ptr, org_kortforsyningen_proj_Type_COORDINATE_OPERATION);
} catch (const std::exception &e) {
rethrow_as_java_exception(env, JPJ_ILLEGAL_ARGUMENT_EXCEPTION, e);
try {
CRSNNPtr crs = get_shared_object<CRS>(env, operation);
crs = crs->normalizeForVisualization();
BaseObjectPtr ptr = crs.as_nullable();
return specific_subclass(env, operation, ptr, org_kortforsyningen_proj_Type_COORDINATE_REFERENCE_SYSTEM);
} catch (const std::exception &e) {
rethrow_as_java_exception(env, JPJ_ILLEGAL_ARGUMENT_EXCEPTION, e);
}
}
return nullptr;
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/cpp/org_kortforsyningen_proj_NativeResource.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions src/main/java/org/kortforsyningen/proj/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ final class Context extends NativeResource implements AutoCloseable {
*/
private static final Deque<Context> CONTEXTS = new ConcurrentLinkedDeque<>();

private static String[] searchPath = null;

/**
* Timestamp (as given by {@link System#nanoTime()}) of last use of this context.
* Used for determining if the {@link #TIMEOUT} has been elapsed for this context.
Expand Down Expand Up @@ -102,6 +104,10 @@ private Context() {
*/
private static native long create();

static void setSearchPath(String[] paths) {
searchPath = paths;
}

/**
* Gets a PROJ context, creating a new one if needed.
* This method shall be invoked in a {@code try} block as below:
Expand All @@ -118,7 +124,10 @@ private Context() {
*/
static Context acquire() {
final Context c = CONTEXTS.pollLast();
return (c != null) ? c : new Context();
if (c != null) return c;
Context nc = new Context();
if (searchPath != null) NativeResource.setSearchPath(nc, searchPath);
return nc;
}

/**
Expand Down Expand Up @@ -192,7 +201,7 @@ private static void destroyExpired() {
Context c = CONTEXTS.peekFirst();
if (c != null) {
final long time = System.nanoTime();
while (time - c.lastUse > TIMEOUT) {
while (c != null && time - c.lastUse > TIMEOUT) {
c = CONTEXTS.pollFirst(); // Verify again since it may have changed concurrently.
if (c == null) return;
if (time - c.lastUse <= TIMEOUT) try {
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/org/kortforsyningen/proj/NativeResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ abstract class NativeResource {
*/
static native String version();

/**
* Set the search path for data files.
*
* @param context pointer to the PROJ thread context.
* @param paths The search paths.
*
* @see Proj#setSearchPath(String[] paths)
*/
static native void setSearchPath(Context context, String[] paths);

/**
* Returns an absolute path to the Java Native Interface C/C++ code.
* If the resources can not be accessed by an absolute path,
Expand Down Expand Up @@ -148,7 +158,7 @@ private static Path libraryPath() throws URISyntaxException, IOException {
if (res == null) {
throw new UnsatisfiedLinkError("Missing native file: " + nativeFile);
}
if (!"jar".equals(res.getProtocol()) && !"bundleresource".equals(res.getProtocol())) {
if (!"jar".equals(res.getProtocol()) && !"bundle".equals(res.getProtocol()) && !"bundleresource".equals(res.getProtocol()) && !"resource".equals(res.getProtocol()) && !"jrt".equals(res.getProtocol())) {
return Paths.get(res.toURI());
}
/*
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/kortforsyningen/proj/Proj.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ public static Optional<String> version() {
return Optional.empty();
}

/**
* Set the search path for data files.
*
* @param paths The search path.
*/
public static void setSearchPath(String... paths) {
Context.setSearchPath(paths);
}

/**
* Returns a factory for creating coordinate reference systems from codes allocated by the given authority.
* The authority is typically "EPSG", but not necessarily; other authorities like "IAU" are also allowed.
Expand Down Expand Up @@ -400,6 +409,17 @@ public static CoordinateOperation normalizeForVisualization(final CoordinateOper
}
}



public static CoordinateReferenceSystem normalizeForVisualization(final CoordinateReferenceSystem crs) {
Objects.requireNonNull(crs);
if (crs instanceof IdentifiableObject) {
return (CoordinateReferenceSystem) ((IdentifiableObject) crs).impl.normalizeForVisualization();
} else {
throw new UnsupportedImplementationException("crs", crs);
}
}

/**
* Returns {@code true} if the given objects are equivalent according the given criterion.
* If the two given objects are {@code null}, this method returns {@code true}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,13 @@ public void testToWKT() throws FactoryException {
final String wkt = crs.toWKT();
assertTrue(wkt, wkt.startsWith(
"GEOGCRS[\"WGS 84\",\n" +
" DATUM[\"World Geodetic System 1984\",\n" +
" ENSEMBLE[\"World Geodetic System 1984 ensemble\",\n" +
" MEMBER[\"World Geodetic System 1984 (Transit)\"],\n" +
" MEMBER[\"World Geodetic System 1984 (G730)\"],\n" +
" MEMBER[\"World Geodetic System 1984 (G873)\"],\n" +
" MEMBER[\"World Geodetic System 1984 (G1150)\"],\n" +
" MEMBER[\"World Geodetic System 1984 (G1674)\"],\n" +
" MEMBER[\"World Geodetic System 1984 (G1762)\"],\n" +
" ELLIPSOID[\"WGS 84\","));
/*
* We verify only the first few lines in order to reduce the risk to break the tests
Expand Down