MarvinLitt commented on a change in pull request #3481: [CARBONDATA-3548]Geospatial Support: add hash id create,query condition analyze and generate hash id list
URL: https://github.com/apache/carbondata/pull/3481#discussion_r357007769 ########## File path: geo/src/main/java/org/apache/carbondata/geo/GeoHashImpl.java ########## @@ -168,20 +238,151 @@ public String generate(List<?> sources) throws Exception { if (!(sources.get(0) instanceof Long) || !(sources.get(1) instanceof Long)) { throw new RuntimeException("Source columns must be of Long type."); } - //TODO: generate geohashId - return String.valueOf(0); + Long longitude = (Long) sources.get(0); + Long latitude = (Long) sources.get(1); + // generate the hash code + int[] gridPoint = calculateID(longitude, latitude); + Long hashId = createHashID(gridPoint[0], gridPoint[1]); + return String.valueOf(hashId); } /** * Query processor for GeoHash. - * @param polygon + * example: (`LONGITUDE`, `LATITUDE`, '116270714,40112476;116217155,40028403; + * 116337318,39927378;116459541,39966859;116447868,40076233;116385384,40129279;') + * @param polygon a group of pints, close out to form an area * @return Returns list of ranges of GeoHash IDs * @throws Exception */ @Override public List<Long[]> query(String polygon) throws Exception { - List<Long[]> rangeList = new ArrayList<Long[]>(); - // TODO: process the polygon coordinates and generate the list of ranges of GeoHash IDs - return rangeList; + String[] pointList = polygon.split(";"); + if (3 > pointList.length) { + throw new RuntimeException("polygon need at least 3 points, really has " + pointList.length); + } else { + List<double[]> queryList = new ArrayList<>(); + for (String str: pointList) { + String[] points = str.split(","); + if (2 != points.length) { + throw new RuntimeException("longitude and latitude is a pair need 2 data"); + } else { + try { + queryList.add(new double[] {Double.valueOf(points[0]), Double.valueOf(points[1])}); + } catch (NumberFormatException e) { + throw new RuntimeException("can not covert the string data to double", e); + } + } + } + if (3 > queryList.size()) { + throw new RuntimeException("polygon list size" + queryList.size() + " less than three"); + } else { + List<Long[]> rangeList = getPolygonRangeList(queryList); + return rangeList; + } + } + } + + /** + * use query polygon condition to get the hash id list, the list is merged and sorted. + * @param queryList polygon points close out to form an area + * @return hash id list + * @throws Exception + */ + private List<Long[]> getPolygonRangeList(List<double[]> queryList) throws Exception { + QuadTreeCls qTreee = new QuadTreeCls(userDefineMinLongitude, userDefineMinLatitude, + CalculateMaxLongitude, CalculateMaxLatitude, cutLevel); + qTreee.insert(queryList); + return qTreee.getNodesData(); + } + + /** + * After necessary attributes, perform necessary calculation + * @throws Exception + */ + private void calculateData() throws Exception { + // Angular to radian, radians = (Math.PI / 180) * degrees + // Cosine value of latitude angle of origin + this.mCos = Math.cos(this.oriLatitude / this.conversionRatio * Math.PI / CONVERT_FACTOR); + // get δx=L∗360/(2πR∗cos(lat)) + this.deltaX = (this.gridSize * 360) / (2 * Math.PI * EARTH_RADIUS * this.mCos); + this.deltaXByRatio = this.deltaX * this.conversionRatio; + // get δy=L∗360/2πR + this.deltaY = (this.gridSize * 360) / (2 * Math.PI * EARTH_RADIUS); + this.deltaYByRatio = this.deltaY * this.conversionRatio; + LOGGER.info("after spatial calculate delta X is: " + String.format("%f", this.deltaX) + + "the delta Y is: " + String.format("%f", this.deltaY)); + LOGGER.info("after spatial calculate X ByRatio is: " + String.format("%f", this.deltaXByRatio) + + "the Y ByRatio is: " + String.format("%f", this.deltaYByRatio)); + // Calculate the complement area and grid i,j for grid number + // Xmax = x0+(2^n∗δx) Ymax = y0+(2^n∗δx) Where n is the number of cut + // Where x0, Y0 are the minimum x, y coordinates of a given region, + // Xmax >= maxLongitude Ymax >= maxLatitude + // In the calculation process, first substitute maxlongitude and maxlatitude to calculate n. + // if n is not an integer, then take the next integer of N, and then substitute to find + // xmax and ymax。 + this.calculateArea(); + } + + /** + * Calculate the complement area, including the range of the complement area, t + * he number of knives cut and the depth of the quad tree + */ + private void calculateArea() { + // step 1 calculate xn, yn by using maxLongitude, maxLatitude, minLongitude, minLatitude + // substitution formula + // Here, the user's given area is mostly rectangle, which needs to be extended to + // square processing to find the maximum value of XN and yn + // n=log_2 (Xmax−X0)/δx, log_2 (Ymax−Y0)/δy + double Xn = Math.log((userDefineMaxLongitude - userDefineMinLongitude) / deltaX) + / Math.log(2); + double Yn = Math.log((userDefineMaxLatitude - userDefineMinLatitude) / deltaY) + / Math.log(2); + double doubleMax = Math.max(Xn, Yn); + this.cutLevel = doubleMax % 1 == 0 ? (int) doubleMax : (int) (doubleMax + 1); + // setep 2 recalculate the region according to the number of segmentation + this.CalculateMaxLongitude = userDefineMinLongitude + Math.pow(2, this.cutLevel) + * deltaX; + this.CalculateMaxLatitude = userDefineMinLatitude + Math.pow(2, this.cutLevel) + * deltaY; + LOGGER.info("After spatial calculate the cut level is: " + String.format("%d", this.cutLevel)); + LOGGER.info("the min longitude is: " + String.format("%f", this.userDefineMinLongitude) + + " the max longitude is: " + String.format("%f", this.CalculateMaxLongitude)); + LOGGER.info("the min latitude is: " + String.format("%f", this.userDefineMinLatitude) + + " the max latitude is: " + String.format("%f", this.CalculateMaxLatitude)); + } + + /** + * Through grid index coordinates and calculation of hashid, grid latitude and longitude + * coordinates can be transformed by latitude and longitude + * @param longitude Longitude, the actual longitude and latitude are processed by * coefficient, + * and the floating-point calculation is converted to integer calculation + * @param latitude Latitude, the actual longitude and latitude are processed by * coefficient, + * and the floating-point calculation is converted to integer calculation. + * @return Grid ID value [row, column] column starts from 1 + */ + private int[] calculateID(long longitude, long latitude) throws Exception { + try { + int row = (int) ((longitude - this.lon0ByRation) / this.deltaXByRatio); + int column = (int) ((latitude - this.lat0ByRation) / this.deltaYByRatio); + return new int[]{row, column}; + } catch (ArithmeticException e) { + throw new RuntimeException("can not divide by zero."); + } + } + + /** + * Calculate the corresponding hashid value from the grid coordinates + * @param row Gridded row index + * @param column Gridded column index + * @return hash id + */ + private long createHashID(long row, long column) { + long index = 0L; + for (int i = 0; i < cutLevel + 1; i++) { + long x = (row >> i) & 1; //取第i位 Review comment: done ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [hidden email] With regards, Apache Git Services |
Free forum by Nabble | Edit this page |