⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 surfaceshapegeometry.java

📁 world wind java sdk 源码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
                    splitAtDateline(t, terrain);                else                    intersectTerrain(t, terrain);            }        }    }    //    // Computes the intersect of a Triangle with the given terrain grid. Output is a collection of    // 3,4,5,6 sided polygons.    //    // This algorithm is modelled after a standard polygon scan-line conversion algorithm (see Foley and Van Dam),    // except that rather than a boolean decision about whether a "pixel" is inside/outside, we need to compute    // the exact intersect wherever terrain gridcells intersect the Triangle edges.    //    private void intersectTerrain(Triangle t, RectangularTessellator.RectGeometry terrain) {        ActiveEdge e0 = new ActiveEdge(t.vertices[0], t.vertices[1]);        ActiveEdge e1 = new ActiveEdge(t.vertices[1], t.vertices[2]);        ActiveEdge e2 = new ActiveEdge(t.vertices[0], t.vertices[2]);        ArrayList<ActiveEdge> edges = new ArrayList<ActiveEdge>(3);        // Insert the edges into the list sorted by their p0-latitude. Don't insert an edge whose endpoints        // have equal latitude; i.e,. one that runs horizontally.        if (Math.abs(e0.deltaY) > EPSILON) {            edges.add(e0);        }        if (Math.abs(e1.deltaY) > EPSILON) {            if (e1.p0Lat < e0.p0Lat) {                edges.add(0, e1);            } else {                edges.add(e1);            }        }        if (Math.abs(e2.deltaY) > EPSILON) {            if (e2.p0Lat < edges.get(0).p0Lat) {                edges.add(0, e2);            } else if (edges.size() == 2 && e2.p0Lat < edges.get(1).p0Lat) {                edges.add(1, e2);            } else {                edges.add(e2);            }        }        if (edges.size() < 2) { // degenerate triangle!            return;        }        // Get the first two edges;  skip any edge that is completely below our terrain grid...        Iterator<ActiveEdge> iter = edges.iterator();        e0 = iter.next();        e1 = iter.next();        if (e0.p1Lat <= terrain.getMinLatitude()) {            if (iter.hasNext()) {                e0 = e1;                e1 = iter.next();            } else {                return;            }        }        if (e1.p1Lat <= terrain.getMinLatitude()) {            if (iter.hasNext()) {                e1 = iter.next();            } else {                return;            }        }        double leftLon = e0.p0Lon;        double rightLon = e1.p0Lon;        double lowerLat = e0.p0Lat;        int currRow = terrain.getRowAtLat(lowerLat);        if (currRow >= terrain.getNumRows()) { // all edges above our terrain...            return;        }        if (currRow < 0) {            // one or both edges extend below our terrain grid            currRow = 0;            lowerLat = terrain.getLatAtRow(currRow);            leftLon = e0.getLonAtLat(lowerLat);            rightLon = e1.getLonAtLat(lowerLat);        }        // make sure left is left, right is right...        if (leftLon > rightLon) {            double tmp = leftLon;            leftLon = rightLon;            rightLon = tmp;        }        Vertex lowerLeft = new Vertex(leftLon, lowerLat);        Vertex lowerRight = new Vertex(rightLon, lowerLat);        // Begin the "scan converting" against the rows of the terrain grid...        while (true) {            double upperLat = terrain.getLatAtRow(currRow + 1);            if (upperLat <= e0.p1Lat && upperLat <= e1.p1Lat) {                currRow++;            } else {                if (upperLat > e0.p1Lat) {                    upperLat = e0.p1Lat;                }                if (upperLat > e1.p1Lat) {                    upperLat = e1.p1Lat;                }            }            Vertex upperLeft;            upperLeft = new Vertex(e0.getLonAtLat(upperLat), upperLat);            Vertex upperRight;            upperRight = new Vertex(e1.getLonAtLat(upperLat), upperLat);            if (upperLeft.x > upperRight.x) {                Vertex tmp = upperLeft;                upperLeft = upperRight;                upperRight = tmp;            }            // At this point, we have a quad that has two parallel sides coinciding with rows of the terrain grid,            // the other two opposite sides are from the triangle. This quad possibly extends out beyond the            // grid. Clip it against each grid cell that it touches.            double minLon = (lowerLeft.x < upperLeft.x) ? lowerLeft.x : upperLeft.x;            double maxLon = (lowerRight.x > upperRight.x) ? lowerRight.x : upperRight.x;            int begCol = terrain.getColAtLon(minLon);            int endCol = terrain.getColAtLon(maxLon);            if (!(begCol >= terrain.getNumCols() || endCol < 0)) {                Polygon quadStrip = new Polygon();                quadStrip.addVertex(lowerLeft.x, lowerLeft.y);                quadStrip.addVertex(upperLeft.x, upperLeft.y);                quadStrip.addVertex(upperRight.x, upperRight.y);                quadStrip.addVertex(lowerRight.x, lowerRight.y);                if (begCol < 0) {                    // clip at left edge of our terrain grid...                    quadStrip.splitAtXPlane(terrain.getMinLongitude());                    begCol = 0;                }                if (endCol >= terrain.getNumCols()) {                    // clip at right edge of a our terrain grid...                    quadStrip = quadStrip.splitAtXPlane(terrain.getMaxLongitude());                    endCol = terrain.getNumCols() - 1;                }                // now clip against any interior grid cells...                for (int i = begCol + 1; i <= endCol; i++) {                    // clip against the ith grid boundary...                    double lon = terrain.getLonAtCol(i);                    Polygon left = quadStrip.splitAtXPlane(lon);                    if (left != null) {                        left.convertToXYZ(terrain);                        this.polygons.add(left);                    }                }                quadStrip.convertToXYZ(terrain);                this.polygons.add(quadStrip);            }            // reached the "upper" vertex of an edge?            if (upperLat >= e0.p1Lat) {                if (iter.hasNext()) {                    e0 = iter.next();                } else {                    break;                }            }            if (upperLat >= e1.p1Lat) {                if (iter.hasNext()) {                    e1 = iter.next();                } else {                    break;                }            }            // off the top of our terrain grid?            if (currRow >= terrain.getNumRows()) {                break;            }            lowerLeft = upperLeft;            lowerRight = upperRight;        }    }    private void splitAtDateline(Triangle t, RectangularTessellator.RectGeometry terrain) {        Polygon right = new Polygon();        for (int i=0; i<3; i++) {            double lat = t.vertices[i].getLatitude().degrees;            double lon = t.vertices[i].getLongitude().degrees;            if (lon > 0.) lon -= Angle.POS360.degrees;            right.addVertex(lon, lat);        }        Polygon left = right.splitAtXPlane(Angle.NEG180.degrees);        // Make triangles out of our two polygons and throw them at the terrain intersector.        // Since the polygons are convex, we'll effectively generate a triangle fan.        Triangle tri = new Triangle();        for (int i=2; i<left.numVerts; i++) {            // We need to "normalize" the longitudes for the "left" polygon...            tri.vertices[0] = new LatLon(Angle.fromDegrees(left.xy[0][1]), Angle.fromDegrees(left.xy[0][0]+Angle.POS360.degrees));            tri.vertices[1] = new LatLon(Angle.fromDegrees(left.xy[i-1][1]), Angle.fromDegrees(left.xy[i-1][0]+Angle.POS360.degrees));            tri.vertices[2] = new LatLon(Angle.fromDegrees(left.xy[i][1]), Angle.fromDegrees(left.xy[i][0]+Angle.POS360.degrees));            intersectTerrain(tri, terrain);        }        for (int i=2; i<right.numVerts; i++) {            tri.vertices[0] = new LatLon(Angle.fromDegrees(right.xy[0][1]), Angle.fromDegrees(right.xy[0][0]));            tri.vertices[1] = new LatLon(Angle.fromDegrees(right.xy[i-1][1]), Angle.fromDegrees(right.xy[i-1][0]));            tri.vertices[2] = new LatLon(Angle.fromDegrees(right.xy[i][1]), Angle.fromDegrees(right.xy[i][0]));             intersectTerrain(tri, terrain);        }    }    //    // This Polygon class is used to encode pieces of the intersect of our SurfaceShapeGeometry with a terrain grid.    //    private class Polygon {        double[][] xy;        int numVerts;        public Polygon() {            xy = new double[6][2];            numVerts = 0;        }        public void addVertex(double x, double y) throws IllegalStateException {            if (numVerts >= xy.length) {                // TODO:  I8N this                throw new IllegalStateException("SOMETHING'S DREADFULLY WRONG!!");            }            xy[numVerts][0] = x;            xy[numVerts][1] = y;            ++numVerts;        }        //        // Splits this Polygon into two at the given "splitPlane". The splitPlane is presumed to be vertical,        // i.e., a line of constant longitude.        //        // Returns the Polygon to the left of the splitPlane, and modifies this Polygon to contain the        // righthand result of the split.        //        public Polygon splitAtXPlane(double splitPlane) {            double[][] leftPoly = new double[6][2];            double[][] rightPoly = new double[6][2];            int numLeft = 0;            int numRight = 0;            for (int i = 0; i < numVerts; i++) {                if (xy[i][0] < splitPlane) {                    leftPoly[numLeft++] = xy[i];                } else if (xy[i][0] > splitPlane) {                    rightPoly[numRight++] = xy[i];                }                int j = (i + 1) % numVerts;                double t = intersectAtX(splitPlane, xy[i][0], xy[j][0]);                if (t < 0. || t > 1.) {                    continue;                }                double[] newXY = new double[2];                newXY[0] = splitPlane;                newXY[1] = valAtParam(t, xy[i][1], xy[j][1]);                if (newXY[1] == Double.MAX_VALUE) {                    newXY[1] = xy[i][1];                }  // parallel...                // NOTE THAT BOTH POLYGONS SHARE A REFERENCE TO THE SAME ARRAY!                leftPoly[numLeft++] = newXY;                rightPoly[numRight++] = newXY;            }            xy = rightPoly;            numVerts = numRight;            Polygon p = null;            if (numLeft > 0) {                p = new Polygon();                p.xy = leftPoly;                p.numVerts = numLeft;            }            return p;        }        //        // Computes the value along a parameterized line.        //        private double valAtParam(double t, double p0, double p1) {            double delta = p1 - p0;            if (Math.abs(delta) < 1.e-10) {                return Double.MAX_VALUE;            }            return p0 + t * delta;        }        //        // Returns the parameter along a parameterized line where the given X-intersect occurs.        //        private double intersectAtX(double x, double x2, double x1) {            double delta = x2 - x1;            if (Math.abs(delta) < 1.e-10) {                return Double.MAX_VALUE;            }            return (x2 - x) / delta;        }        //        // Replaces the lat-lon coordinates with XYZ values interpolated from the terrain grid.        //        public void convertToXYZ(RectangularTessellator.RectGeometry terrain) {            Vec4 refPoint = getReferencePoint();            for (int i=0; i<this.numVerts; i++) {                // Note in the following call, we have a double[2] going in, replaced by a double[3] coming out...                xy[i] = terrain.getPointAt(xy[i][Y], xy[i][X]);                xy[i][X] -= refPoint.x;                xy[i][Y] -= refPoint.y;                xy[i][Z] -= refPoint.z;            }        }    }    //    // TODO:  Is there still utility in using this class in leu of something else?   --RLB    //    private class Vertex {        public Vertex(double x, double y) {            this.x = x;            this.y = y;        }        double x;        double y;    }    //    // A bundle of info needed to track "active edges" during our "scan conversion" of triangles against the    // terrain raster (grid).    //    private class ActiveEdge {        double p0Lon, p0Lat;        double p1Lon, p1Lat;        double deltaX;        double deltaY;        int begRow, endRow;        int begCol, endCol;        public ActiveEdge(LatLon p0, LatLon p1) {            // we want to guarantee p0 <= p1            if (p0.getLatitude().degrees > p1.getLatitude().degrees) {                this.p0Lon = p1.getLongitude().degrees;                this.p0Lat = p1.getLatitude().degrees;                this.p1Lon = p0.getLongitude().degrees;                this.p1Lat = p0.getLatitude().degrees;            } else {                this.p0Lon = p0.getLongitude().degrees;                this.p0Lat = p0.getLatitude().degrees;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -