草庐IT

java - 从符号到地形的 Worldwind 线

coder 2024-03-20 原文

Worldwind 的 Point PlaceMark 可渲染具有通过调用 setLineEnabled 从地标向下到地形放置一条线的功能。如此屏幕截图所示:



我想要做的是添加这样的一行,它也适用于可渲染的战术符号。我的第一个想法是从 PointPlacemark 借用逻辑来做到这一点。可渲染并将其添加到 AbstractTacticalSymbol可渲染。我已经尝试过了,到目前为止我一直没有成功。

这是我到目前为止所做的:

  • 将此添加到 OrderedSymbol 类:
    public Vec4 terrainPoint;
    
  • 更新了计算符号点以计算地形点
    protected void computeSymbolPoints(DrawContext dc, OrderedSymbol osym)
    {
        osym.placePoint = null;
        osym.screenPoint = null;
        osym.terrainPoint = null;
        osym.eyeDistance = 0;
    
        Position pos = this.getPosition();
        if (pos == null)
            return;
    
        if (this.altitudeMode == WorldWind.CLAMP_TO_GROUND || dc.is2DGlobe())
        {
            osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
        }
        else if (this.altitudeMode == WorldWind.RELATIVE_TO_GROUND)
        {
            osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), pos.getAltitude());
        }
        else // Default to ABSOLUTE
        {
            double height = pos.getElevation() * dc.getVerticalExaggeration();
            osym.placePoint = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), height);
        }
    
        if (osym.placePoint == null)
            return;
    
        // Compute the symbol's screen location the distance between the eye point and the place point.
        osym.screenPoint = dc.getView().project(osym.placePoint);
        osym.eyeDistance = osym.placePoint.distanceTo3(dc.getView().getEyePoint());
    
        // Compute a terrain point if needed.
        if (this.isLineEnabled() && this.altitudeMode != WorldWind.CLAMP_TO_GROUND && !dc.is2DGlobe())
            osym.terrainPoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
    
    }
    
  • 添加了此逻辑(取自 PointPlacemark.java 并更新以符合 AbstractTacticalSymbol.java)。请注意,我将 lineEnabled 设置为 true,因此默认情况下它应该绘制线条。
    boolean lineEnabled = true;
    
    
    double lineWidth = 1;
    protected int linePickWidth = 10;
    Color lineColor = Color.white;
    
    /**
     * Indicates whether a line from the placemark point to the corresponding position on the terrain is drawn.
     *
     * @return true if the line is drawn, otherwise false.
     */
    public boolean isLineEnabled()
    {
        return lineEnabled;
    }
    
    /**
     * Specifies whether a line from the placemark point to the corresponding position on the terrain is drawn.
     *
     * @param lineEnabled true if the line is drawn, otherwise false.
     */
    public void setLineEnabled(boolean lineEnabled)
    {
        this.lineEnabled = lineEnabled;
    }
    
    /**
     * Determines whether the placemark's optional line should be drawn and whether it intersects the view frustum.
     *
     * @param dc the current draw context.
     *
     * @return true if the line should be drawn and it intersects the view frustum, otherwise false.
     */
    protected boolean isDrawLine(DrawContext dc, OrderedSymbol opm)
    {
        if (!this.isLineEnabled() || dc.is2DGlobe() || this.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND
            || opm.terrainPoint == null)
            return false;
    
        if (dc.isPickingMode())
            return dc.getPickFrustums().intersectsAny(opm.placePoint, opm.terrainPoint);
        else
            return dc.getView().getFrustumInModelCoordinates().intersectsSegment(opm.placePoint, opm.terrainPoint);
    }
    
    
    
    
    /**
     * Draws the placemark's line.
     *
     * @param dc             the current draw context.
     * @param pickCandidates the pick support object to use when adding this as a pick candidate.
     */
    protected void drawLine(DrawContext dc, PickSupport pickCandidates, OrderedSymbol opm)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
        if ((!dc.isDeepPickingEnabled()))
            gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);
        gl.glDepthMask(true);
    
        try
        {
            dc.getView().pushReferenceCenter(dc, opm.placePoint); // draw relative to the place point
    
            this.setLineWidth(dc);
            this.setLineColor(dc, pickCandidates);
    
            gl.glBegin(GL2.GL_LINE_STRIP);
            gl.glVertex3d(Vec4.ZERO.x, Vec4.ZERO.y, Vec4.ZERO.z);
            gl.glVertex3d(opm.terrainPoint.x - opm.placePoint.x, opm.terrainPoint.y - opm.placePoint.y,
                opm.terrainPoint.z - opm.placePoint.z);
            gl.glEnd();
        }
        finally
        {
            dc.getView().popReferenceCenter(dc);
        }
    }
    
    
    /**
     * Sets the width of the placemark's line during rendering.
     *
     * @param dc the current draw context.
     */
    protected void setLineWidth(DrawContext dc)
    {
        Double lineWidth = this.lineWidth;
        if (lineWidth != null)
        {
            GL gl = dc.getGL();
    
            if (dc.isPickingMode())
            {
                gl.glLineWidth(lineWidth.floatValue() + linePickWidth);
            }
            else
                gl.glLineWidth(lineWidth.floatValue());
    
            if (!dc.isPickingMode())
            {
                gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_FASTEST);
                gl.glEnable(GL.GL_LINE_SMOOTH);
            }
        }
    }
    
    
    /**
     * Sets the color of the placemark's line during rendering.
     *
     * @param dc             the current draw context.
     * @param pickCandidates the pick support object to use when adding this as a pick candidate.
     */
    protected void setLineColor(DrawContext dc, PickSupport pickCandidates)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
        if (!dc.isPickingMode())
        {
            Color color = this.lineColor;
            gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(),
                (byte) color.getAlpha());
        }
        else
        {
            Color pickColor = dc.getUniquePickColor();
            Object delegateOwner = this.getDelegateOwner();
            pickCandidates.addPickableObject(pickColor.getRGB(), delegateOwner != null ? delegateOwner : this,
                this.getPosition());
            gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue());
        }
    }
    
  • 将此调用添加到 drawOrderedRenderable 方法的开头:
    boolean drawLine = this.isDrawLine(dc, osym);
    if (drawLine)
        this.drawLine(dc, pickCandidates, osym);
    

  • 我相信这密切反射(reflect)了 PointPlacemark 正在做的使线到地形出现的工作,但这就是我运行 TacticalSymbols 时得到的结果。我的更改示例:



    这是我(尝试)更改的整个 AbsractTacticalSymbol 文件:http://pastebin.com/aAC7zn0p (对于SO来说太大了)

    最佳答案

    好的,所以这里的问题是框架内正投影和透视投影的混合。至关重要的是,如果我们查看 PointPlaceMark 的 beginDrawing我们看:

    GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
    int attrMask =
            GL2.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func
                ... bunch more bits being set ...
    
    gl.glPushAttrib(attrMask);
    
    if (!dc.isPickingMode())
    {
        gl.glEnable(GL.GL_BLEND);
        OGLUtil.applyBlending(gl, false);
    }
    

    而已。但是如果我们看一下 AbstractTacticalSymbol 的 beginDrawing我们看到了更多的代码,特别是这两行:
    this.BEogsh.pushProjectionIdentity(gl);
    gl.glOrtho(0d, viewport.getWidth(), 0d, viewport.getHeight(), 0d, -1d);
    

    这将 OpenGL 投影从透视模式切换到正交模式,这两种截然不同的投影技术不能很好地混合,除了一些值得注意的情况:其中一种在 3D 场景上渲染 UI,例如:渲染图标! video showing the difference between orthographic and perspective rendering

    我觉得用文字解释很尴尬,但是透视渲染给了你透视,而正交渲染没有,所以你得到的东西很像 2D 游戏,它适用于 UI,但不适用于逼真的 3D 图像。

    但是PointPlaceMark也会渲染一个图标,那么那个文件在两种投影模式之间切换在哪里呢?原来他们在 doDrawOrderedRenderable 中这样做了调用后drawLine (第 976 行)。

    那么,为什么会出错呢?现在框架内部发生了很多神奇的事情,所以我不能完全确定会发生什么,但我已经大致了解出了什么问题。这是错误的,因为透视投影允许您以与正交投影(在框架中)截然不同的方式提供坐标,在这种情况下,可能将 (x,y,z) 提供给投影渲染会在 (X,Y,Z ) 世界空间,而正交渲染渲染在 (x,y,z) 屏幕空间(或剪辑空间,我不是这方面的专业人士)。因此,当您现在从图标到地面绘制一条线时,在坐标 (300000,300000,z) 处,它们当然会从您的屏幕上掉下来,并且不可见,因为您没有 300000x3000000 像素的屏幕.也可能两种方法都允许在世界空间中提供坐标(尽管这似乎不太可能),在这种情况下,下图说明了问题。在下面的框中,两个摄像头都指向同一方向,但看到的东西不同。


    请特别注意透视渲染如何让您看到更多的框。

    所以,因为渲染代码是从 render() 中的透视投影开始的。方法,解决这个问题就像在我们画线后延迟正投影开始一样简单,就像在 PointPlaceMark 的代码中一样。
    这正是我所做的here (第 1962 行到 1968 行),它只是将几行代码移到正投影之外,所以在 beginDrawing 之前,你快完成了。

    现在这个解决方案不是很优雅,因为代码的功能现在在很大程度上取决于它的执行顺序,这通常很容易出错。这部分是因为我做了简单的修复,但主要是因为该框架遵循已弃用的 OpenGL 标准来切换视角(除其他外),所以我无法产生真正完美的解决方案,无论这样的解决方案是否属于我的能力。

    根据您的偏好,您可能希望使用继承来创建 SymbolWithLine父类(super class)或接口(interface),或使用组合来添加功能。或者,如果您不需要在许多其他类中使用此功能,您可以保持这种状态。无论如何,我希望这是足够的信息来解决这个问题。

    根据您的要求,以下几行演示了线宽和线颜色的变化(第 1965 行):
    this.lineColor = Color.CYAN;
    this.lineWidth = 3;
    this.drawLine(dc, this.pickSupport, osym);
    



    Updated code for AbstractTacticalSymbol

    我不确定这是否符合“规范答案”,但我很乐意用任何建议更新答案,或者进一步澄清我的解释。我认为答案的关键在于对正交投影与透视投影的理解,但我觉得这并不是对这个问题给出规范答案的地方。

    关于java - 从符号到地形的 Worldwind 线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37900553/

    有关java - 从符号到地形的 Worldwind 线的更多相关文章

    1. java - 等价于 Java 中的 Ruby Hash - 2

      我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

    2. java - 从 JRuby 调用 Java 类的问题 - 2

      我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

    3. java - 我的模型类或其他类中应该有逻辑吗 - 2

      我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

    4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

      什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

    5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

      这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

    6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

      HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

    7. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    8. 【Java入门】使用Java实现文件夹的遍历 - 2

      遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

    9. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

      我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

    10. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

      Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

    随机推荐