मानचित्र बनाना और इसे जियोटूल के साथ छवि में सहेजना [बंद]


9

मैं जियोटूल के साथ एक नक्शा बनाना चाहता हूं और इसे एक छवि (जैसे जेपीईजी) में सहेजना चाहता हूं। मेरी आवश्यकताएं सरल हैं:

  1. 2 परतों के साथ दुनिया का एक नक्शा बनाएँ: राजनीतिक सीमाएँ और एक स्थैतिक। परतें विभिन्न स्रोतों और विभिन्न अनुमानों से हैं।
  2. विभिन्न अनुमानों के लिए मानचित्र को आउटपुट करें (जैसे "EPSG: 5070", "EPSG: 4326", "EPSG: 54012", "EPSG: 54009", आदि)
  3. आउटपुट को अलग-अलग AOI (जैसे -124.79 से -66.9 लोन, 24.4 से 49.4 लैट) पर क्लिप करें।

मैं इस प्रोग्राम को एपीआई के माध्यम से करना चाहता हूं। अब तक, मुझे सीमित सफलता मिली है। मैंने इस दृष्टिकोण का उपयोग करके विभिन्न अनुमानों में एक नक्शा और आउटपुट बनाना सीखा है:

//Step 1: Create map
MapContent map = new MapContent();
map.setTitle("World");

//Step 2: Set projection
CoordinateReferenceSystem crs = CRS.decode("EPSG:5070"); //Conic projection over US
MapViewport vp = map.getViewport();
vp.setCoordinateReferenceSystem(crs);

//Step 3: Add layers to map
CoordinateReferenceSystem mapCRS = map.getCoordinateReferenceSystem();
map.addLayer(reproject(getPoliticalBoundaries(), mapCRS));
map.addLayer(reproject(getGraticules(), mapCRS));

//Step 4: Save image
saveImage(map, "/temp/graticules.jpg", 800);

सेव विधि जियोटूलस वेबसाइट से सीधी है :

public void saveImage(final MapContent map, final String file, final int imageWidth) {

    GTRenderer renderer = new StreamingRenderer();
    renderer.setMapContent(map);

    Rectangle imageBounds = null;
    ReferencedEnvelope mapBounds = null;
    try {
        mapBounds = map.getMaxBounds();
        double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0);
        imageBounds = new Rectangle(
                0, 0, imageWidth, (int) Math.round(imageWidth * heightToWidth));

    } catch (Exception e) {
        // failed to access map layers
        throw new RuntimeException(e);
    }

    BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB);

    Graphics2D gr = image.createGraphics();
    gr.setPaint(Color.WHITE);
    gr.fill(imageBounds);

    try {
        renderer.paint(gr, imageBounds, mapBounds);
        File fileToSave = new File(file);
        ImageIO.write(image, "jpeg", fileToSave);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

पुनर्विचार विधि मेरा आविष्कार है। यह एक हैक का एक सा है, लेकिन इसका एक ही तरीका है कि मैं एक विशिष्ट प्रक्षेपण के लिए एक छवि उत्पादन करने के लिए मिल सकता है।

private static Layer reproject(Layer layer, CoordinateReferenceSystem mapCRS) throws Exception {

    SimpleFeatureSource featureSource = (SimpleFeatureSource) layer.getFeatureSource();


  //Define coordinate transformation
    CoordinateReferenceSystem dataCRS = featureSource.getSchema().getCoordinateReferenceSystem();
    boolean lenient = true; // allow for some error due to different datums
    MathTransform transform = CRS.findMathTransform(dataCRS, mapCRS, lenient);


  //Create new feature collection
    SimpleFeatureCollection copy = FeatureCollections.newCollection("internal");
    SimpleFeatureType featureType = SimpleFeatureTypeBuilder.retype(featureSource.getSchema(), mapCRS);
    SimpleFeatureIterator iterator = featureSource.getFeatures().features();
    try {

        while (iterator.hasNext()) {

            SimpleFeature feature = iterator.next();
            Geometry geometry = (Geometry) feature.getDefaultGeometry();
            Geometry geometry2 = JTS.transform(geometry, transform);
            copy.add( SimpleFeatureBuilder.build( featureType, new Object[]{ geometry2 }, null) );
        }

    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        iterator.close();
    }


  //Return new layer
    Style style = SLD.createLineStyle(Color.BLACK, 1);
    layer = new FeatureLayer(copy, style);
    layer.setTitle("Graticules");
    return layer;
}

आउटपुट वास्तव में खराब है:

प्रतिक्षेप से उत्पादन

इसलिए, मुझे लगता है कि मेरे पास कुछ अलग सवाल हैं:

  1. क्या यह सही दृष्टिकोण है? क्या मुझे वास्तव में परतों को मैन्युअल रूप से रद्द करने की आवश्यकता है या क्या MapViewport मेरे लिए ऐसा करने वाला है?
  2. मैं किसी विशिष्ट AOI को आउटपुट कैसे क्लिप करूं? मैंने MapViewport.setBounds (लिफ़ाफ़े) विधि का उपयोग करके सीमा निर्धारित करने की कोशिश की है, लेकिन saveImage विधि सीमा की उपेक्षा करती है।
  3. आर्क्स के रूप में रेंडर करने के लिए मुझे अपनी अक्षांश रेखाएँ कैसे मिलेंगी? क्या कोई परिवर्तन सेटिंग है जो मुझे याद आ रही है?

मैं जियोटूल 8.7 का इस्तेमाल कर रहा हूं।

जवाबों:


1

1) नक्शे को आपके लिए अस्वीकृति को संभालना चाहिए। एक उदाहरण के लिए QuickStart देखें ।

2) आप मानचित्र के लिए पूछते हैं कि यह अधिकतम सीमा है, वर्तमान सीमा नहीं है, और आप अप्रिय अजीब से बचने के लिए सीआरएस के डोमेनऑफवैलिडिटी द्वारा क्लिप करना चाह सकते हैं।

3) मुझे यकीन नहीं है कि आप कैसे अपने graticles पैदा कर रहे हैं, लेकिन अगर आप ग्रिड मॉड्यूल का उपयोग करते हैं तो आप उन्हें आर्क्स बनने के लिए लाइनों को सघन कर सकते हैं।

अगर मैं स्टेट्स का उपयोग करता हूं तो संपादित करें (जियो सेवर से) मुझे यह मिलता है:

यहां छवि विवरण दर्ज करें

यहाँ कोड का उपयोग कर ।

अंत संपादित करें

अंत में हाल ही में प्रोजेक्शन हैंडलिंग में सुधार किया गया है ताकि आप जियोटूल 12 या 13 में जाना चाहें।

उदाहरण का नक्शा


2

इयान का जवाब सही है, और मैंने इसे इस तरह चिह्नित किया है। किसी और के लिए पूर्णता के लिए जो रुचि हो सकती है ...


प्रश्न 1

नहीं, आपको लेयर्स को मैनुअली रिप्रेजेंट करने की जरूरत नहीं है। व्यूपोर्ट पर प्रक्षेपण को निर्दिष्ट करना पर्याप्त होना चाहिए। उदाहरण:

    MapViewport vp = map.getViewport();
    CoordinateReferenceSystem crs = CRS.decode("EPSG:5070");
    vp.setCoordinateReferenceSystem(crs);

प्रश्न 2

मानचित्र को क्लिप करने के लिए, आपको व्यूपोर्ट सीमा निर्धारित करने और saveImage फ़ंक्शन को अपडेट करने की आवश्यकता है। यहाँ एक उदाहरण दिया गया है कि प्रक्षेपण विस्तार की सीमा कैसे तय करें:

    Extent crsExtent = crs.getDomainOfValidity();
    for (GeographicExtent element : crsExtent.getGeographicElements()) {
        if (element instanceof GeographicBoundingBox) {
            GeographicBoundingBox bounds = (GeographicBoundingBox) element;
            ReferencedEnvelope bbox = new ReferencedEnvelope(
                bounds.getSouthBoundLatitude(),
                bounds.getNorthBoundLatitude(),
                bounds.getWestBoundLongitude(),
                bounds.getEastBoundLongitude(),

                CRS.decode("EPSG:4326")
            );
            ReferencedEnvelope envelope = bbox.transform(crs, true);
            vp.setBounds(envelope);
        }
    }

व्यूपोर्ट सीमा निर्धारित करने के अलावा, SaveImage फ़ंक्शन को map.getMaxBounds () के बजाय व्यूपोर्ट सीमा का उपयोग करने के लिए संशोधित किया जाना चाहिए।

परिवर्तन:

mapBounds = map.getMaxBounds();

इसके लिए:

mapBounds = map.getViewport().getBounds();

यहाँ उत्पादन है:

अमेरिका


प्रश्न 3

इयान के सुझाव के लिए धन्यवाद, मैं लाइन स्ट्रिंग को सघन करके वक्र रेखाओं को प्राप्त करने में सक्षम था। यहाँ मूल पोस्ट में संदर्भित getGraticules () विधि से प्रमुख स्निपिट है:

  //Add lines of latitude
    for (int y=-90; y<=90; y+=15){
        java.util.ArrayList<Coordinate> coords = new java.util.ArrayList<Coordinate>();
        for (double x=-135; x<=-45; x+=0.5){
            coords.add(new Coordinate(y,x,0));
        }
        LineString line = new LineString(coords.toArray(new Coordinate[coords.size()]), precisionModel, 4326);
        collection.add( SimpleFeatureBuilder.build( TYPE, new Object[]{ line }, null) );
    }

आउटपुट इस प्रकार है:

प्रतिक्षेप 2 से आउटपुट

हालांकि यह दृष्टिकोण काम करता है, मैं एक ट्रांसफ़ॉर्मिंग सेटिंग या कुछ ऐसा करने की उम्मीद कर रहा था जो मेरे लिए लाइनों को आर्कषित करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.