From: David B. <db...@op...> - 2006-04-18 22:08:40
|
Andrea Aime wrote: > Hum.... I'm wondering what changes did you made. It's easy to make > decimation more efficient > by making it more aggressive, but a properly working decimation > generates results that cannot > be distinguished from not having applied decimation at all. > When I coded it, I made sure the decimation distance was not over 1 > pixel on screen, but I > don't really know what happened in the meantime. It, basically, wasnt actually decimating. It would, however, generate lines with 0 or 1 point in them, and polygon rings with 0, 1, 2 points and 1st point != last point. These geometry issues were causing problems, which this version solves. Note - MathTransform in this code is always an affine transform (see my earlier message about CRS being done in the wrong place). Also note that this is always done on a copy of the geometry since its destructive. A better way to do this would be to generate a spanx/spany for each geometry instead of one thats "good for all geometries", then (hopefully) you'll be able to do this in 1 step instead of 2. dave /** * 1. remove any points that are within the spanx,spany. We ALWAYS keep 1st and last point * 2. transform to screen coordinates * 3. remove any points that are close (span <1) * * @param seq * @param tranform */ private final void decimateTransformGeneralize(LiteCoordinateSequence seq,MathTransform transform) throws TransformException { //decimates before XFORM int ncoords = seq.size(); double originalOrds[] = seq.getXYArray(); // 2*#of points if (ncoords <2) { if (ncoords ==1) // 1 coordinate -- just xform it { double[] newCoordsXformed2= new double[2]; transform.transform(originalOrds, 0, newCoordsXformed2, 0, 1); seq.setArray(newCoordsXformed2); return; } else return; // ncoords =0 } // unfortunately, we have to keep things in double precion until after the transform or we could move things. double[] allCoords = new double[ncoords*2]; // preallocate -- might not be full (throw away Z) allCoords[0] = originalOrds[0]; //allways have 1st one allCoords[1] = originalOrds[1]; int actualCoords = 1; double lastX = allCoords[0]; double lastY = allCoords[1]; for (int t=1;t<(ncoords-1);t++) { //see if this one should be added double x = originalOrds[t*2]; double y = originalOrds[t*2+1]; if ( (Math.abs(x-lastX )> spanx) || ( Math.abs(y-lastY )) >spany) { allCoords[actualCoords*2] = x; allCoords[actualCoords*2+1] = y; lastX = x; lastY = y; actualCoords++; } } allCoords[actualCoords*2] = originalOrds[(ncoords-1)*2]; //always have last one allCoords[actualCoords*2+1] = originalOrds[(ncoords-1)*2+1]; actualCoords++; double[] newCoordsXformed; //DO THE XFORM if ((transform == null) || (transform.isIdentity()) ) // no actual xform { newCoordsXformed = allCoords; } else { newCoordsXformed= new double[actualCoords*2]; transform.transform(allCoords, 0, newCoordsXformed, 0, actualCoords); } //GENERLIZE -- we should be in screen space so spanx=spany=1.0 // unfortunately, we have to keep things in double precion until after the transform or we could move things. double[] finalCoords = new double[ncoords*2]; // preallocate -- might not be full (throw away Z) finalCoords[0] = newCoordsXformed[0]; //allways have 1st one finalCoords[1] = newCoordsXformed[1]; int actualCoordsGen = 1; lastX = newCoordsXformed[0]; lastY = newCoordsXformed[1]; for (int t=1;t<(actualCoords-1);t++) { //see if this one should be added double x = newCoordsXformed[t*2]; double y = newCoordsXformed[t*2+1]; if ( (Math.abs(x-lastX )> 1) || ( Math.abs(y-lastY )) >1) { finalCoords[actualCoordsGen*2] = x; finalCoords[actualCoordsGen*2+1] = y; lastX = x; lastY = y; actualCoordsGen++; } } finalCoords[actualCoordsGen*2] = newCoordsXformed[(actualCoords-1)*2]; //always have last one finalCoords[actualCoordsGen*2+1] = newCoordsXformed[(actualCoords-1)*2+1]; actualCoordsGen++; //stick back in double[] seqDouble = new double[2*actualCoordsGen]; System.arraycopy(finalCoords,0,seqDouble, 0, actualCoordsGen*2); seq.setArray(seqDouble); } |