四、路径选择及KML导出

2 篇文章 0 订阅
1 篇文章 0 订阅

我在WorldWind项目中,遇到过这样一个问题。加载本地影像时,由于投影转换的问题,有些地理区域存在挺明显的误差情况。具体一个例子就是,我在GoogleEarth中画了一个区域,另存为kml文件,在WorldWind中导入时一些地理标志明显不重合。我为了项目展示时的整齐一致,所以采用在WorldWind中画取路径区域,并导出为kml文件。也许这种方法并不见得多可取,不过也是写出来留作参考,为了以后也许能够用到的地方。
通过分析源代码可以发现,在src->gov.nasa.worldwindx.examples中的LineBuilder.java文件可以在球体上勾画路径并能够把相应点的坐标输出,再结合src->gov.nasa.worldwindx.examples.kml中的ExportKML.java文件,就可以达到我们需要的目的。
一、创建自己的WWJLineBuilder.java文件

package esi.control;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;

import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.avlist.AVListImpl;
import gov.nasa.worldwind.event.PositionEvent;
import gov.nasa.worldwind.event.PositionListener;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.Polyline;

public class WWJLineBuilder extends AVListImpl 
{ 
private final WorldWindow wwd; 
private boolean armed = false; 
private List<Position> positions; 
private final RenderableLayer layer; 
private final Polyline line; 
private boolean active = false;

public WWJLineBuilder(final WorldWindow wwd, RenderableLayer lineLayer, Polyline polyline)
{

    this.wwd = wwd;
    positions=new ArrayList<Position>();

    if (polyline != null)
    {
        this.line = polyline;
    }
    else
    {
        this.line = new Polyline();
        this.line.setFollowTerrain(true);
    }
    this.layer = lineLayer != null ? lineLayer : new RenderableLayer();
    this.layer.addRenderable(this.line);
    this.wwd.getModel().getLayers().add(this.layer);

    this.wwd.getInputHandler().addMouseListener(new MouseAdapter()
    {
        public void mousePressed(MouseEvent mouseEvent)
        {
            if (armed && mouseEvent.getButton() == MouseEvent.BUTTON1)
            {
                if (armed && (mouseEvent.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0)
                {
                    if (!mouseEvent.isControlDown())
                    {
                        active = true;
                        addPosition();
                    }
                }
                mouseEvent.consume();
            }
        }

        public void mouseReleased(MouseEvent mouseEvent)
        {
            if (armed && mouseEvent.getButton() == MouseEvent.BUTTON1)
            {
                if (positions.size() == 1)
                    removePosition();
                active = false;
                mouseEvent.consume();
            }
        }

        public void mouseClicked(MouseEvent mouseEvent)
        {
            if (armed && mouseEvent.getButton() == MouseEvent.BUTTON1)
            {
                if (mouseEvent.isControlDown())
                    removePosition();
                mouseEvent.consume();
            }
        }
    });

    this.wwd.getInputHandler().addMouseMotionListener(new MouseMotionAdapter()
    {
        public void mouseDragged(MouseEvent mouseEvent)
        {
            if (armed && (mouseEvent.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0)
            {
                if (active)
                    mouseEvent.consume();
            }
        }
    });

    this.wwd.addPositionListener(new PositionListener()
    {
        public void moved(PositionEvent event)
        {
            if (!active)
                return;

            if (positions.size() == 1)
                addPosition();
            else
                replacePosition();
        }
    });
}

/**
 * Returns the layer holding the polyline being created.
 */
public RenderableLayer getLayer()
{
    return this.layer;
}

/**
 * Returns the layer currently used to display the polyline.
 */
public Polyline getLine()
{
    return this.line;
}

/**
 * Removes all positions from the polyline.
 */
public void clear()
{
    while (this.positions.size() > 0)
        this.removePosition();
}

/**
 * Identifies whether the line builder is armed.
 */
public boolean isArmed()
{
    return this.armed;
}

/**
 * Arms and disarms the line builder. When armed, the line builder monitors user input and builds the polyline in
 * response to the actions mentioned in the overview above. When disarmed, the line builder ignores all user input.
 */
public void setArmed(boolean armed)
{
    this.armed = armed;
}

private void addPosition()
{
    Position curPos = this.wwd.getCurrentPosition();
    if (curPos == null)
        return;

    this.positions.add(curPos);
    this.line.setPositions(this.positions);
    this.firePropertyChange("wwjExportKML.AddPosition", null, curPos);
    this.wwd.redraw();
}

private void replacePosition()
{
    Position curPos = this.wwd.getCurrentPosition();
    if (curPos == null)
        return;

    int index = this.positions.size() - 1;
    if (index < 0)
        index = 0;

    Position currentLastPosition = this.positions.get(index);
    this.positions.set(index, curPos);
    this.line.setPositions(this.positions);
    this.firePropertyChange("wwjExportKML.ReplacePosition", currentLastPosition, curPos);
    this.wwd.redraw();
}

private void removePosition()
{
    if (this.positions.size() == 0)
        return;

    Position currentLastPosition = this.positions.get(this.positions.size() - 1);
    this.positions.remove(this.positions.size() - 1);
    this.line.setPositions(this.positions);
    this.firePropertyChange("wwjExportKML.RemovePosition", currentLastPosition, null);
    this.wwd.redraw();
}
} 

这个文件主要作用是勾画路径,下面我们创建WWJLinePanel.java文件,主要是为了操作面板的设计以及编写导出kml函数的接口。
主要代码如下:

package esi.control;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.render.Path;
import gov.nasa.worldwind.render.Polygon;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwindx.examples.kml.KMLDocumentBuilder;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.CompoundBorder;
import javax.swing.border.TitledBorder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class WWJLinePanel extends JPanel
{
    private final WorldWindow wwd;
    private final WWJLineBuilder wwjExportKML;
    private JButton newButton;
    private JButton pauseButton;
    private JButton endButton;
    private JButton exportButton;
    private JLabel[] pointLabels;
    /**
     * 构造函数
     */
    public WWJLinePanel(WorldWindow wwd, WWJLineBuilder wwjExportKML)
    {
        super(new BorderLayout());
        this.wwd = wwd;
        this.wwjExportKML = wwjExportKML;
        this.makePanel(new Dimension(100,50));
    }
    /**
     * 构造面板
     */
    private void makePanel(Dimension size)
    {
        JPanel buttonPanel = new JPanel(new GridLayout(2, 2, 5, 5));
        newButton = new JButton("New");
        newButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent actionEvent)
            {
                wwjExportKML.clear();
                wwjExportKML.setArmed(true);
                pauseButton.setText("Pause");
                pauseButton.setEnabled(true);
                endButton.setEnabled(true);
                newButton.setEnabled(false);
                ((Component) wwd).setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
            }
        });
        buttonPanel.add(newButton);
        newButton.setEnabled(true);

        pauseButton = new JButton("Pause");
        pauseButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent actionEvent)
            {
                wwjExportKML.setArmed(!wwjExportKML.isArmed());
                pauseButton.setText(!wwjExportKML.isArmed() ? "Resume" : "Pause");
                ((Component) wwd).setCursor(Cursor.getDefaultCursor());
            }
        });
        buttonPanel.add(pauseButton);
        pauseButton.setEnabled(false);

        endButton = new JButton("End");
        endButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent actionEvent)
            {
                wwjExportKML.setArmed(false);
                newButton.setEnabled(true);
                pauseButton.setEnabled(false);
                pauseButton.setText("Pause");
                endButton.setEnabled(false);
                ((Component) wwd).setCursor(Cursor.getDefaultCursor());
            }
        });
        buttonPanel.add(endButton);
        endButton.setEnabled(false);

        exportButton=new JButton("Export");
        exportButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                WExportKML();
            }
        });
        buttonPanel.add(exportButton);
        exportButton.setEnabled(true);


        JPanel pointPanel = new JPanel(new GridLayout(0, 1, 0, 10));
        pointPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        this.pointLabels = new JLabel[20];
        for (int i = 0; i < this.pointLabels.length; i++)
        {
            this.pointLabels[i] = new JLabel("");
            pointPanel.add(this.pointLabels[i]);
        }

        // Add the buttons, scroll bar and inner panel to a titled panel that will resize with the main window.
        JPanel outerPanel = new JPanel(new BorderLayout());
        outerPanel.setBorder(
            new CompoundBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9), new TitledBorder("Line")));
        outerPanel.setToolTipText("Line control and info");
        outerPanel.add(buttonPanel, BorderLayout.NORTH);
        this.add(outerPanel, BorderLayout.CENTER);
    }

    /**
     * 定义路径并将所画点置入该路径
     */
    private Path makePath(){
        Path path=new Path();
        List<Position> positions=new ArrayList<Position>();         
//        int i=0;
        for (Position pos : wwjExportKML.getLine().getPositions())
        {
            /*if (i == this.pointLabels.length)
                break;*/
           positions.add(Position.fromDegrees(pos.getLatitude().getDegrees(), pos.getLongitude().getDegrees(),0));
        };
        path.setPositions(positions);
        return path;
    }

    /**
     * 导出路径
     */
    public void WExportKML(){
        try {
            // Create a StringWriter to collect KML in a string buffer
            Writer stringWriter = new StringWriter();

            // Create a document builder that will write KML to the StringWriter
            KMLDocumentBuilder kmlBuilder = new KMLDocumentBuilder(stringWriter);

            // Export the objects
            kmlBuilder.writeObjects(makePath());
            kmlBuilder.close();

            // Get the exported document as a string
            String xmlString = stringWriter.toString();

            // Set up a transformer to pretty-print the XML
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            // Write the pretty-printed document to stdout
            transformer.transform(new StreamSource(new StringReader(xmlString)), new StreamResult(System.out));
        } catch (Exception e) {
            String message = Logging.getMessage("generic.ExceptionAttemptingToWriteXml", e.toString());
            Logging.logger().severe(message);
            e.printStackTrace();
        }
    }
}

再然后就需要在WWJMFS.java 文件中进行调用,代码如下,

WWJLineBuilder wlb=new WWJLineBuilder(wwd, null, null);
WWJLinePanel wlp=new WWJLinePanel(wwd, wlb);
this.getContentPane().add(wlp,BorderLayout.PAGE_END);

这里写图片描述
单击导出按钮,就可以在控制台打印出一段kml代码,复制粘贴到一个新文件中即可。
这里写图片描述

注:由于该文章仅供测试用,所以就没有进行细节的处理。
1、在实例中,我们仅仅是路径的确定,向其他形状(如多边形)则需要更改代码

    /**
     * 定义多边形并将所画点置入该多边形
     */
    private Polygon makePoly(){
        Polygon poly=null;
        List<Position> positions=new ArrayList<Position>();         
        for (Position pos : wwjExportKML.getLine().getPositions())
        {
         positions.add(Position.fromDegrees(pos.getLatitude().getDegrees(), pos.getLongitude().getDegrees(),0));
        };
        poly=new Polygon(positions);
        return poly;
    }
然后在WExportKml方法中更改部分代码如下
            // Export the objects
            kmlBuilder.writeObjects(makePoly());
            kmlBuilder.close();

即可以画出多边形。本来想采用的是测量工具中选择的形式,不过涉及代码太复杂,作为测试用这种方法即可,所以就没有多做深究。

2、在WExportKml方法中输出的信息是在控制台中,也可以直接打印出文件。在该方法中,// Get the exported document as a string
String xmlString = stringWriter.toString();

这个xmlString字符串即为所需kml全部代码,后面的那些代码主要作用是以一种结构清晰的格式去输出kml代码。如果仅是一段字符串,是可以很简单的在一个文件中进行输出。如果想在一个文件中也采用结构清晰的格式去输出,这方面我还没有很清晰的思路。如果大家有什么好的方法,还望赐教。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值