📄 proj.java
字号:
* Circles have the same restrictions as <a * href="#poly_restrictions"> polys </a>. * * @param c LatLonPoint center of circle * @param radians radius in radians or decimal degrees? * @param radius radius of circle (0 < radius < 180) * @param nverts number of vertices of the circle poly. * @param isFilled filled poly? */ public ArrayList forwardCircle(LatLonPoint c, boolean radians, float radius, int nverts, boolean isFilled) { // HACK-need better decision for number of vertices. if (nverts < 3) nverts = NUM_DEFAULT_CIRCLE_VERTS; float[] rawllpts = new float[(nverts << 1) + 2];// *2 for // pairs +2 // connect GreatCircle.earth_circle(c.radlat_, c.radlon_, (radians) ? radius : ProjMath.degToRad(radius), nverts, rawllpts); // connect the vertices. rawllpts[rawllpts.length - 2] = rawllpts[0]; rawllpts[rawllpts.length - 1] = rawllpts[1]; // forward project the circle-poly return forwardPoly(rawllpts, LineType.Straight, -1, isFilled); } // HACK protected transient static int XTHRESHOLD = 16384;// half range protected transient int XSCALE_THRESHOLD = 1000000;// dynamically // calculated public ArrayList forwardPoly(float[] rawllpts, int ltype, int nsegs) { return forwardPoly(rawllpts, ltype, nsegs, false); } /** * Forward project a lat/lon Poly. * <p> * Delegates to _forwardPoly(), and may do additional clipping for * Java XWindows problem. Remember to specify vertices in radians! * * @param rawllpts float[] of lat,lon,lat,lon,... in RADIANS! * @param ltype line type (straight, rhumbline, greatcircle) * @param nsegs number of segment points (only for greatcircle or * rhumbline line types, and if < 1, this value is * generated internally) * @param isFilled filled poly? * @return ArrayList of x[], y[], x[], y[], ... projected poly * @see #forwardRaw * @see LineType#Straight * @see LineType#Rhumb * @see LineType#GreatCircle */ public ArrayList forwardPoly(float[] rawllpts, int ltype, int nsegs, boolean isFilled) { ArrayList stuff = _forwardPoly(rawllpts, ltype, nsegs, isFilled); // @HACK: workaround XWindows bug. simple clip to a boundary. // this is ugly. if (Environment.doingXWindowsWorkaround && (scale <= XSCALE_THRESHOLD)) { int i, j, size = stuff.size(); int[] xpts, ypts; for (i = 0; i < size; i += 2) { xpts = (int[]) stuff.get(i); ypts = (int[]) stuff.get(i + 1); for (j = 0; j < xpts.length; j++) { if (xpts[j] <= -XTHRESHOLD) { xpts[j] = -XTHRESHOLD; } else if (xpts[j] >= XTHRESHOLD) { xpts[j] = XTHRESHOLD; } if (ypts[j] <= -XTHRESHOLD) { ypts[j] = -XTHRESHOLD; } else if (ypts[j] >= XTHRESHOLD) { ypts[j] = XTHRESHOLD; } } stuff.set(i, xpts); stuff.set(i + 1, ypts); } } return stuff; } /** * Forward project a lat/lon Poly. Remember to specify vertices in * radians! * * @param rawllpts float[] of lat,lon,lat,lon,... in RADIANS! * @param ltype line type (straight, rhumbline, greatcircle) * @param nsegs number of segment points (only for greatcircle or * rhumbline line types, and if < 1, this value is * generated internally) * @param isFilled filled poly? * @return ArrayList of x[], y[], x[], y[], ... projected poly */ protected abstract ArrayList _forwardPoly(float[] rawllpts, int ltype, int nsegs, boolean isFilled); /** * Forward project a rhumbline poly. * <p> * Draws rhumb lines between vertices of poly. Remember to specify * vertices in radians! Check in-code comments for details about * the algorithm. * * @param rawllpts float[] of lat,lon,lat,lon,... in RADIANS! * @param nsegs number of segments to draw for greatcircle or * rhumb lines (if < 1, this value is generated * internally). * @param isFilled filled poly? * @return ArrayList of x[], y[], x[], y[], ... projected poly * @see Projection#forwardPoly(float[], int, int, boolean) */ protected ArrayList forwardRhumbPoly(float[] rawllpts, int nsegs, boolean isFilled) { // IDEA: // Rhumblines are straight in the Mercator projection. // So we can use the Mercator projection to calculate // vertices along the rhumbline between two points. But // if there's a better way to calculate loxodromes, // someone please chime in (openmap@bbn.com)... // // ALG: // Project pairs of vertices through the Mercator // projection into screen XY space, pick intermediate // segment points along the straight XY line, then // convert all vertices back into LatLon space. Pass the // augmented vertices to _forwardPoly() to be drawn as // straight segments. // // WARNING: // The algorithm fixes the Cylindrical-wrapping // problem, and thus duplicates some code in // Cylindrical._forwardPoly() // if (this instanceof Mercator) {// simple return _forwardPoly(rawllpts, LineType.Straight, nsegs, isFilled); } int i, n, xp, flag = 0, xadj = 0, totalpts = 0; Point from = new Point(0, 0); Point to = new Point(0, 0); LatLonPoint llp = null; int len = rawllpts.length; float[][] augllpts = new float[len >>> 1][0]; // lock access to object global, since this is probably not // cloned and different layers may be accessing this. // synchronized (mercator) { // we now create a clone of the mercator variable in // makeClone(), so since different objects should be using // their clone instead of the main projection, the // synchronization should be unneeded. // use mercator projection to calculate rhumblines. // mercator.setParms( // new LatLonPoint(ctrLat, ctrLon, true), // scale, width, height); // Unnecessary to set parameters !! ^^^^^ // project everything through the Mercator projection, // building up lat/lon points along the original rhumb // line between vertices. mercator.forward(rawllpts[0], rawllpts[1], from, true); xp = from.x; for (i = 0, n = 2; n < len; i++, n += 2) { mercator.forward(rawllpts[n], rawllpts[n + 1], to, true); // segment crosses longitude along screen edge if (Math.abs(xp - to.x) >= mercator.half_world) { flag += (xp < to.x) ? -1 : 1;// inc/dec the wrap // count xadj = flag * mercator.world.x;// adjustment to x // coordinates // Debug.output("flag=" + flag + " xadj=" + xadj); } xp = to.x; if (flag != 0) { to.x += xadj;// adjust x coordinate } augllpts[i] = mercator.rhumbProject(from, to, false, nsegs); totalpts += augllpts[i].length; from.x = to.x; from.y = to.y; } llp = mercator.inverse(from); // }// end synchronized around mercator augllpts[i] = new float[2]; augllpts[i][0] = llp.radlat_; augllpts[i][1] = llp.radlon_; totalpts += 2; // put together all the points float[] newllpts = new float[totalpts]; int pos = 0; for (i = 0; i < augllpts.length; i++) { // Debug.output("copying " + augllpts[i].length + " // floats"); System.arraycopy( /* src */augllpts[i], 0, /* dest */newllpts, pos, augllpts[i].length); pos += augllpts[i].length; } // Debug.output("done copying " + totalpts + " total floats"); // free unused variables augllpts = null; // now delegate the work to the regular projection code. return _forwardPoly(newllpts, LineType.Straight, -1, isFilled); } /** * Forward project a greatcircle poly. * <p> * Draws great circle lines between vertices of poly. Remember to * specify vertices in radians! * * @param rawllpts float[] of lat,lon,lat,lon,... in RADIANS! * @param nsegs number of segments to draw for greatcircle or * rhumb lines (if < 1, this value is generated * internally). * @param isFilled filled poly? * @return ArrayList of x[], y[], x[], y[], ... projected poly * @see Projection#forwardPoly(float[], int, int, boolean) */ protected ArrayList forwardGreatPoly(float[] rawllpts, int nsegs, boolean isFilled) { int i, j, k, totalpts = 0; Point from = new Point(); Point to = new Point(); int end = rawllpts.length >>> 1; float[][] augllpts = new float[end][0]; end -= 1;// stop before last segment // calculate extra vertices between all the original segments. forward(rawllpts[0], rawllpts[1], from, true); for (i = 0, j = 0, k = 2; i < end; i++, j += 2, k += 2) { forward(rawllpts[k], rawllpts[k + 1], to, true); augllpts[i] = getGreatVertices(rawllpts[j], rawllpts[j + 1], rawllpts[k], rawllpts[k + 1], from, to, false, nsegs); from.x = to.x; from.y = to.y; totalpts += augllpts[i].length; } augllpts[i] = new float[2]; augllpts[i][0] = rawllpts[j]; augllpts[i][1] = rawllpts[j + 1]; totalpts += 2; // put together all the points float[] newllpts = new float[totalpts]; int pos = 0; for (i = 0; i < augllpts.length; i++) { System.arraycopy( /* src */augllpts[i], 0, /* dest */newllpts, pos, augllpts[i].length); pos += augllpts[i].length; } // free unused variables augllpts = null; // now delegate the work to the regular projection code. return _forwardPoly(newllpts, LineType.Straight, -1, isFilled); } /** * Get the vertices along the great circle between two points. * * @param latp previous float latitude * @param lonp previous float longitude * @param latn next float latitude * @param lonn next float longitude * @param from Point * @param to Point * @param include_last include n or n+1 points of the n segments? * @return float[] lat/lon points in RADIANS! * */ private float[] getGreatVertices(float latp, float lonp, float latn, float lonn, Point from, Point to, boolean include_last, int nsegs) { if (nsegs < 1) { // calculate pixel distance int dist = DrawUtil.pixel_distance(from.x, from.y, to.x, to.y); /* * determine what would be a decent number of segments to * draw. HACK: this is hardcoded calculated by what might * look ok on screen. We also put a cap on the number of * extra segments we draw. */ nsegs = dist >> 3;// dist/8 if (nsegs == 0) { nsegs = 1; } else if (nsegs > NUM_DEFAULT_GREAT_SEGS) { nsegs = NUM_DEFAULT_GREAT_SEGS; } // Debug.output( // "("+from.x+","+from.y+")("+to.x+","+to.y+") // dist="+dist+" nsegs="+nsegs); } // both of these return float[] radian coordinates! return GreatCircle.great_circle(latp, lonp, latn, lonn, nsegs, include_last); } /** * Forward projects a raster. * <p> * HACK: not implemented yet. * * @param llNW LatLonPoint of NorthWest corner of Image * @param llSE LatLonPoint of SouthEast corner of Image * @param image raster image */ public ArrayList forwardRaster(LatLonPoint llNW, LatLonPoint llSE, Image image) { Debug.error("Proj.forwardRaster(): unimplemented!"); return null; } /** * Check for complicated linetypes. * <p> * This depends on the line and this projection. * * @param ltype int LineType * @return boolean */ public boolean isComplicatedLineType(int ltype) { switch (ltype) { case LineType.Straight: return false; case LineType.Rhumb: return (getProjectionType() == Mercator.MercatorType) ? false : true; case LineType.GreatCircle: return true/* * (getProjectionType() == * Gnomonic.GnomonicType) ? false : true */; default: Debug.error("Proj.isComplicatedLineType: invalid LineType!"); return false; } } /** * Generates a complicated poly. * * @param rawllpts LatLonPoint[] * @param ltype line type * @param nsegs number of segments to draw for greatcircle or * rhumb lines (if < 1, this value is generated * internally). * @param isFilled filled poly? * @return ArrayList * @see Projection#forwardPoly */ protected ArrayList doPolyDispatch(float[] rawllpts, int ltype, int nsegs, boolean isFilled) { switch (ltype) { case LineType.Rhumb: return forwardRhumbPoly(rawllpts, nsegs, isFilled); case LineType.GreatCircle: return forwardGreatPoly(rawllpts, nsegs, isFilled); case LineType.Straight: Debug.error("Proj.doPolyDispatch: Bad Dispatch!\n"); return new ArrayList(0); default: Debug.error("Proj.doPolyDispatch: Invalid LType!\n"); return new ArrayList(0); } } /** * Pan the map/projection. * <p> * Example pans: * <ul> * <li><code>pan(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -