root / trunk / libraries / libRaster / src / org / gvsig / raster / util / RasterUtilities.java @ 11070
History | View | Annotate | Download (17.5 KB)
1 |
package org.gvsig.raster.util; |
---|---|
2 |
|
3 |
import java.awt.Dimension; |
4 |
import java.awt.geom.Point2D; |
5 |
import java.awt.geom.Rectangle2D; |
6 |
import java.io.File; |
7 |
import java.io.FileInputStream; |
8 |
import java.io.FileNotFoundException; |
9 |
import java.io.FileOutputStream; |
10 |
import java.io.IOException; |
11 |
import java.io.InputStream; |
12 |
import java.io.OutputStream; |
13 |
|
14 |
import org.gvsig.raster.dataaccess.buffer.RasterBuffer; |
15 |
import org.gvsig.raster.shared.Extent; |
16 |
|
17 |
import es.gva.cit.jgdal.Gdal; |
18 |
|
19 |
/**
|
20 |
*
|
21 |
* @author Nacho Brodin (nachobrodin@gmail.com)
|
22 |
*
|
23 |
*/
|
24 |
public class RasterUtilities { |
25 |
public static final int MAX_BYTE_BIT_VALUE = 255; |
26 |
public static final int MAX_SHORT_BIT_VALUE = 65535; |
27 |
|
28 |
//---------------------------------------------------------------
|
29 |
//TIPOS DE DATOS
|
30 |
|
31 |
/**
|
32 |
* Conversi?n de los tipos de datos de gdal a los tipos de datos de
|
33 |
* RasterBuf
|
34 |
* @param gdalType Tipo de dato de gdal
|
35 |
* @return Tipo de dato de RasterBuf
|
36 |
*/
|
37 |
public static int getRasterBufTypeFromGdalType(int gdalType){ |
38 |
switch(gdalType){
|
39 |
case 1:return RasterBuffer.TYPE_BYTE;//GDT_BYTE |
40 |
case 2://GDT_UInt16 |
41 |
case 8://GDT_CInt16 |
42 |
case 3:return RasterBuffer.TYPE_SHORT;//GDT_Int16 |
43 |
case 4://GDT_UInt32 |
44 |
case 9://GDT_CInt32 |
45 |
case 5:return RasterBuffer.TYPE_INT;//GDT_Int32 |
46 |
case 10://GDT_CFloat32 |
47 |
case 6:return RasterBuffer.TYPE_FLOAT;//GDT_Float32 |
48 |
case 11://GDT_CFloat64 |
49 |
case 7:return RasterBuffer.TYPE_DOUBLE;//GDT_Float64 |
50 |
} |
51 |
return RasterBuffer.TYPE_UNDEFINED;
|
52 |
} |
53 |
|
54 |
/**
|
55 |
* Conversi?n de los tipos de datos de RasterBuf en los de gdal.
|
56 |
* @param rasterBufType Tipo de dato de RasterBuf
|
57 |
* @return Tipo de dato de Gdal
|
58 |
*/
|
59 |
public static int getGdalTypeFromRasterBufType(int rasterBufType){ |
60 |
switch(rasterBufType){
|
61 |
case RasterBuffer.TYPE_BYTE:return Gdal.GDT_Byte; |
62 |
case RasterBuffer.TYPE_USHORT: return Gdal.GDT_UInt16; |
63 |
case RasterBuffer.TYPE_SHORT: return Gdal.GDT_Int16; |
64 |
case RasterBuffer.TYPE_INT: return Gdal.GDT_Int32; |
65 |
case RasterBuffer.TYPE_FLOAT: return Gdal.GDT_Float32; |
66 |
case RasterBuffer.TYPE_DOUBLE: return Gdal.GDT_Float64; |
67 |
case RasterBuffer.TYPE_UNDEFINED: return Gdal.GDT_Unknown; |
68 |
case RasterBuffer.TYPE_IMAGE: return Gdal.GDT_Byte; |
69 |
} |
70 |
return Gdal.GDT_Unknown;
|
71 |
} |
72 |
|
73 |
/**
|
74 |
* Conversi?n de los tipos de datos de MrSID a los tipos de datos de
|
75 |
* RasterBuf
|
76 |
* @param mrsidType Tipo de dato de MrSID
|
77 |
* @return Tipo de dato de RasterBuf
|
78 |
*/
|
79 |
public static int getRasterBufTypeFromMrSIDType(int mrsidType){ |
80 |
switch(mrsidType){
|
81 |
case 0:return RasterBuffer.TYPE_UNDEFINED;//INVALID |
82 |
case 1://UINT8 |
83 |
case 2:return RasterBuffer.TYPE_BYTE;//SINT8 |
84 |
case 3://UINT16 |
85 |
case 4:return RasterBuffer.TYPE_SHORT;//SINT16 |
86 |
case 5://UINT32 |
87 |
case 6:return RasterBuffer.TYPE_INT;//SINT32 |
88 |
case 7:return RasterBuffer.TYPE_FLOAT;//FLOAT32 |
89 |
case 8:return RasterBuffer.TYPE_DOUBLE;//FLOAT64 |
90 |
} |
91 |
return RasterBuffer.TYPE_UNDEFINED;
|
92 |
} |
93 |
|
94 |
/**
|
95 |
* Obtiene el n?mero de bytes que ocupa un tipo de dato concreto.
|
96 |
* Los tipos de datos son los utilizados en RasterBuffer
|
97 |
* @param rasterBufType Tipo de dato del que se solicita el n?mero de bytes ocupados
|
98 |
* @return
|
99 |
*/
|
100 |
public static int getBytesFromRasterBufType(int rasterBufType){ |
101 |
switch(rasterBufType){
|
102 |
case RasterBuffer.TYPE_BYTE:return 1; |
103 |
case RasterBuffer.TYPE_USHORT:
|
104 |
case RasterBuffer.TYPE_SHORT: return 2; |
105 |
case RasterBuffer.TYPE_INT:
|
106 |
case RasterBuffer.TYPE_FLOAT:
|
107 |
case RasterBuffer.TYPE_IMAGE: return 4; |
108 |
case RasterBuffer.TYPE_DOUBLE: return 8; |
109 |
} |
110 |
return 0; //TYPE_UNDEFINED |
111 |
} |
112 |
|
113 |
/**
|
114 |
* Convierte un tipo de dato a cadena
|
115 |
* @param type Tipo de dato
|
116 |
* @return cadena que representa el tipo de dato
|
117 |
*/
|
118 |
public static String typesToString(int type) { |
119 |
switch (type) {
|
120 |
case RasterBuffer.TYPE_IMAGE:
|
121 |
return new String("Image"); |
122 |
|
123 |
case RasterBuffer.TYPE_BYTE:
|
124 |
return new String("Byte"); |
125 |
|
126 |
case RasterBuffer.TYPE_DOUBLE:
|
127 |
return new String("Double"); |
128 |
|
129 |
case RasterBuffer.TYPE_FLOAT:
|
130 |
return new String("Float"); |
131 |
|
132 |
case RasterBuffer.TYPE_INT:
|
133 |
return new String("Integer"); |
134 |
|
135 |
case RasterBuffer.TYPE_USHORT:
|
136 |
case RasterBuffer.TYPE_SHORT:
|
137 |
return new String("Short"); |
138 |
} |
139 |
|
140 |
return null; |
141 |
} |
142 |
|
143 |
/**
|
144 |
* Parseo de las proyecciones que genera gdal para meter espaciados y saltos de l?nea HTML
|
145 |
* @param proj Proyecci?n
|
146 |
* @return Cadena con la proyecci?n parseada
|
147 |
*/
|
148 |
public static String parserGdalProj(String proj){ |
149 |
String[] list = proj.split(","); |
150 |
int level = 0; |
151 |
for(int i = 0; i < list.length; i++){ |
152 |
if(list[i].indexOf("[") >= 0){ |
153 |
level ++; |
154 |
String spaces = ""; |
155 |
for(int j = 0; j < level; j++) |
156 |
spaces += " ";
|
157 |
list[i] = spaces + list[i]; |
158 |
} |
159 |
if(list[i].indexOf("]]") >= 0) |
160 |
level = level - 2;
|
161 |
else if(list[i].indexOf("]") >= 0) |
162 |
level --; |
163 |
} |
164 |
StringBuffer str = new StringBuffer(); |
165 |
for(int i = 0; i < list.length; i++){ |
166 |
if(i < list.length){
|
167 |
if(i + 1 < list.length && list[i + 1].indexOf("[") >= 0) |
168 |
str.append(list[i] + ",<BR>");
|
169 |
else
|
170 |
str.append(list[i] + ",");
|
171 |
} |
172 |
} |
173 |
return str.toString();
|
174 |
} |
175 |
|
176 |
//---------------------------------------------------------------
|
177 |
//ESPACIO DE COLOR
|
178 |
|
179 |
/**
|
180 |
* Descompone un entero que representa un ARGB en sus 4 valores byte
|
181 |
* Obtiene un array de 4 elementos donde el elemento 0 es el Rojo, el 1 es el
|
182 |
* verde, el 2 el azul y el 3 el alpha.
|
183 |
* @param rgb Entero con el valor ARGB a descomponer;
|
184 |
* @return Array de cuatro elementos
|
185 |
*/
|
186 |
public static byte[] getARGBFromIntToByteArray(int rgb){ |
187 |
byte[] b = new byte[4]; |
188 |
b[0] = (byte)((rgb & 0x00ff0000) >> 16); |
189 |
b[1] = (byte)((rgb & 0x0000ff00) >> 8); |
190 |
b[2] = (byte)(rgb & 0x000000ff); |
191 |
b[3] = (byte)((rgb & 0xff000000) >> 24); |
192 |
return b;
|
193 |
} |
194 |
|
195 |
/**
|
196 |
* Descompone un entero que representa un ARGB en sus 4 valores byte
|
197 |
* Obtiene un array de 4 elementos donde el elemento 0 es el Rojo, el 1 es el
|
198 |
* verde, el 2 el azul y el 3 el alpha.
|
199 |
* @param rgb Entero con el valor ARGB a descomponer;
|
200 |
* @return
|
201 |
*/
|
202 |
public static int[] getARGBFromIntToIntArray(int rgb){ |
203 |
int[] i = new int[4]; |
204 |
i[0] = (((rgb & 0x00ff0000) >> 16) & 0xff); |
205 |
i[1] = (((rgb & 0x0000ff00) >> 8) & 0xff); |
206 |
i[2] = ((rgb & 0x000000ff) & 0xff); |
207 |
i[3] = (((rgb & 0xff000000) >> 24) & 0xff); |
208 |
return i;
|
209 |
} |
210 |
|
211 |
/**
|
212 |
* Obtiene un entero con los valores ARGB pasados por par?metro
|
213 |
* @param a Valor de alpha
|
214 |
* @param r Valor del rojo
|
215 |
* @param g Valor del verde
|
216 |
* @param b Valor del azul
|
217 |
* @return entero con la mezcla de valores
|
218 |
*/
|
219 |
public static int getIntFromARGB(int a, int r, int g, int b){ |
220 |
return (((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)); |
221 |
} |
222 |
|
223 |
//---------------------------------------------------------------
|
224 |
//CONVERSI?N DE COORDENADAS
|
225 |
|
226 |
/**
|
227 |
* Convierte una ventana en coordenadas del mundo real a sus coordenadas relativas en pixels teniendo
|
228 |
* en cuenta que la coordenada superior izquierda es 0,0 y la inferior derecha es maxX y maY
|
229 |
* @param extent Extent de la imagen original
|
230 |
* @param widthPx Ancho en pixeles de la imagen original
|
231 |
* @param heightPx Alto en pixeles de la imagen original
|
232 |
* @param window Ventana en coordenadas reales a transportar a coordenadas pixel
|
233 |
* @return Ventana en coordenadas pixel
|
234 |
*/
|
235 |
public static Rectangle2D getPxRectFromMapRect(Rectangle2D extent, double widthPx, double heightPx, Rectangle2D window){ |
236 |
double widthWC = extent.getWidth();
|
237 |
double heightWC = extent.getHeight();
|
238 |
|
239 |
double wWindowWC = Math.abs(window.getMaxX() - window.getMinX()); |
240 |
double hWindowWC = Math.abs(window.getMaxY() - window.getMinY()); |
241 |
|
242 |
double wWindowPx = ((wWindowWC * widthPx) / widthWC);
|
243 |
double hWindowPx = ((hWindowWC * heightPx) / heightWC);
|
244 |
|
245 |
double initDistanceX = Math.abs(window.getMinX() - extent.getMinX()); |
246 |
double initDistanceY = Math.abs(window.getMaxY() - extent.getMaxY()); |
247 |
|
248 |
double initPxX = ((initDistanceX * widthPx) / widthWC);
|
249 |
double initPxY = ((initDistanceY * heightPx) / heightWC);
|
250 |
|
251 |
Rectangle2D pxRec = new Rectangle2D.Double( initPxX, |
252 |
initPxY, |
253 |
wWindowPx, |
254 |
hWindowPx); |
255 |
return pxRec;
|
256 |
} |
257 |
|
258 |
/**
|
259 |
* Convierte una ventana en coordenadas del mundo real a sus coordenadas relativas en pixels teniendo
|
260 |
* en cuenta que la coordenada superior izquierda es 0,0 y la inferior derecha es maxX y maY
|
261 |
* @param extent Extent de la imagen original
|
262 |
* @param widthPx Ancho en pixeles de la imagen original
|
263 |
* @param heightPx Alto en pixeles de la imagen original
|
264 |
* @param window Ventana en coordenadas reales a transportar a coordenadas pixel
|
265 |
* @return Ventana en coordenadas pixel
|
266 |
*/
|
267 |
public static Rectangle2D getMapRectFromPxRect(Rectangle2D extent, double widthPx, double heightPx, Rectangle2D pxWindow){ |
268 |
double wWindowWC = ((pxWindow.getWidth() * extent.getWidth()) / widthPx);
|
269 |
double hWindowWC = ((pxWindow.getHeight() * extent.getHeight()) / heightPx);
|
270 |
|
271 |
double initWCX = extent.getMinX() + ((pxWindow.getMinX() * extent.getWidth()) / widthPx);
|
272 |
double initWCY = extent.getMaxY() - ((pxWindow.getMinY() * extent.getHeight()) / heightPx);
|
273 |
|
274 |
Rectangle2D mapRec = new Rectangle2D.Double(initWCX, |
275 |
initWCY - hWindowWC, |
276 |
wWindowWC, |
277 |
hWindowWC); |
278 |
return mapRec;
|
279 |
} |
280 |
|
281 |
/**
|
282 |
* Convierte un punto en coordenadas del mundo a coordenadas pixel
|
283 |
* @param p Punto a convertir
|
284 |
* @param ext Extent completo de la imagen
|
285 |
* @return Punto en coordenadas pixel
|
286 |
*/
|
287 |
public static Point2D worldPointToRaster(Point2D p, Extent ext, int pxWidth, int pxHeight) { |
288 |
double x = p.getX() - ext.getMin().getX();
|
289 |
double y = p.getY() - ext.getMin().getY();
|
290 |
int pxX = (int)((x * pxWidth) / ext.width()); |
291 |
int pxY = (int)((y * pxHeight) / ext.height()); |
292 |
return new Point2D.Double(pxX, pxY); |
293 |
} |
294 |
|
295 |
/**
|
296 |
* Ajusta la extensi?n pasada por par?metro a los valores m?ximos y m?nimos de la
|
297 |
* imagen. Esto sirve para que la petici?n al driver nunca sobrepase los l?mites
|
298 |
* de la imagen tratada aunque la vista donde se dibuje sea de mayor tama?o.
|
299 |
*
|
300 |
* @param imgExt Extent completo de la vista donde se va a dibujar.
|
301 |
* @param extToAdj Extent a ajustar.
|
302 |
* @return adjustedExtent Extent ajustado a m?ximos y m?nimos
|
303 |
*/
|
304 |
public static Extent calculateAdjustedView(Extent extToAdj, Extent imgExt) { |
305 |
double vx = extToAdj.minX();
|
306 |
double vy = extToAdj.minY();
|
307 |
double vx2 = extToAdj.maxX();
|
308 |
double vy2 = extToAdj.maxY();
|
309 |
|
310 |
if (extToAdj.minX() < imgExt.minX())
|
311 |
vx = imgExt.minX(); |
312 |
|
313 |
if (extToAdj.minY() < imgExt.minY())
|
314 |
vy = imgExt.minY(); |
315 |
|
316 |
if (extToAdj.maxX() > imgExt.maxX())
|
317 |
vx2 = imgExt.maxX(); |
318 |
|
319 |
if (extToAdj.maxY() > imgExt.maxY())
|
320 |
vy2 = imgExt.maxY(); |
321 |
|
322 |
Extent adjustedExtent = new Extent(vx, vy, vx2, vy2);
|
323 |
return adjustedExtent;
|
324 |
} |
325 |
|
326 |
/**
|
327 |
* Compara dos extents y devuelve true si son iguales
|
328 |
* @param e1 Extent a comparar
|
329 |
* @param e2 Extent a comparar
|
330 |
* @return true si los extents pasados por par?metro son iguales y false si no lo son
|
331 |
*/
|
332 |
public static boolean compareExtents(Extent e1, Extent e2){ |
333 |
return ((e1.getMin().getX() == e2.getMin().getX()) && (e1.getMin().getY() == e2.getMin().getY()) &&
|
334 |
(e1.getMax().getX() == e2.getMax().getX())) && (e1.getMax().getY() == e2.getMax().getY()); |
335 |
} |
336 |
|
337 |
/**
|
338 |
* Comprueba si un extent est? contenido dentro de otro y devuelve true en este caso.
|
339 |
* @param e1 Extent a comprobar si est? contenido en e2
|
340 |
* @param e2 Extent sobre el que se comprueba si e1 est? dentro
|
341 |
* @return true si e1 est? dentro de e1
|
342 |
*/
|
343 |
public static boolean isInside(Extent e1, Extent e2){ |
344 |
return ((e1.getMin().getX() >= e2.getMin().getX()) && (e1.getMin().getY() >= e2.getMin().getY()) &&
|
345 |
(e1.getMax().getX() <= e2.getMax().getX())) && (e1.getMax().getY() <= e2.getMax().getY()); |
346 |
} |
347 |
|
348 |
/**
|
349 |
* Comprueba si alguna parte de un extent est? fuera del extent que tenemos como referencia.
|
350 |
* @param e1 Extent a comprobar si est? fuera
|
351 |
* @param ref Extent de referencia
|
352 |
* @return Devuelve true si alguna parte de e1 cae fuera de ref y false si no tiene ninguna fuera.
|
353 |
*/
|
354 |
public static boolean isOutside(Extent e1, Extent ref){ |
355 |
return ((e1.getMin().getX() < ref.getMin().getX()) || (e1.getMin().getY() < ref.getMin().getY()) ||
|
356 |
(e1.getMax().getX() > ref.getMax().getX()) || (e1.getMax().getY() > ref.getMax().getY())); |
357 |
} |
358 |
|
359 |
/**
|
360 |
* Calcula los par?metros de un worl file a partir de las esquinas del raster.
|
361 |
* 1. X pixel size A
|
362 |
* 2. X rotation term D
|
363 |
* 3. Y rotation term B
|
364 |
* 4. Y pixel size E
|
365 |
* 5. X coordinate of upper left corner C
|
366 |
* 6. Y coordinate of upper left corner F
|
367 |
* where the real-world coordinates x',y' can be calculated from
|
368 |
* the image coordinates x,y with the equations
|
369 |
* x' = Ax + By + C and y' = Dx + Ey + F.
|
370 |
* The signs of the first 4 parameters depend on the orientation
|
371 |
* of the image. In the usual case where north is more or less
|
372 |
* at the top of the image, the X pixel size will be positive
|
373 |
* and the Y pixel size will be negative. For a south-up image,
|
374 |
* these signs would be reversed.
|
375 |
*
|
376 |
* You can calculate the World file parameters yourself based
|
377 |
* on the corner coordinates. The X and Y pixel sizes can be
|
378 |
* determined simply by dividing the distance between two
|
379 |
* adjacent corners by the number of columns or rows in the image.
|
380 |
* The rotation terms are calculated with these equations:
|
381 |
*
|
382 |
* # B = (A * number_of_columns + C - lower_right_x') / number_of_rows * -1
|
383 |
* # D = (E * number_of_rows + F - lower_right_y') / number_of_columns * -1
|
384 |
*
|
385 |
* @param corner (tl, tr, br, bl)
|
386 |
* @return
|
387 |
*/
|
388 |
public static double [] cornersToWorldFile(Point2D [] esq, Dimension size) { |
389 |
double a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; |
390 |
double x1 = esq[0].getX(), y1 = esq[0].getY(); |
391 |
double x2 = esq[1].getX(), y2 = esq[1].getY(); |
392 |
double x3 = esq[2].getX(), y3 = esq[2].getY(); |
393 |
double x4 = esq[3].getX(), y4 = esq[3].getY(); |
394 |
// A: X-scale
|
395 |
a = Math.abs( Math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) |
396 |
/ size.getWidth()); |
397 |
|
398 |
// E: negative Y-scale
|
399 |
e = - Math.abs(Math.sqrt((x1 - x4) * (x1 - x4) + |
400 |
(y1 - y4) * (y1 - y4)) / size.getHeight()); |
401 |
|
402 |
// C, F: upper-left coordinates
|
403 |
c = x1; |
404 |
f = y1; |
405 |
|
406 |
// B & D: rotation parameters
|
407 |
b = (a * size.getWidth() + c - x3 ) / size.getHeight() * -1;
|
408 |
d = (e * size.getHeight() + f - y3 ) / size.getWidth() * -1;
|
409 |
|
410 |
double [] wf = {a, d, b, e, c, f}; |
411 |
return wf;
|
412 |
} |
413 |
|
414 |
//---------------------------------------------------------------
|
415 |
//TRATAMIENTO DE FICHEROS
|
416 |
|
417 |
/**
|
418 |
* Copia de ficheros
|
419 |
* @param pathOrig Ruta de origen
|
420 |
* @param pathDst Ruta de destino.
|
421 |
*/
|
422 |
public static void copyFile(String pathOrig, String pathDst) |
423 |
throws FileNotFoundException, IOException{ |
424 |
InputStream in;
|
425 |
OutputStream out;
|
426 |
|
427 |
if(pathOrig == null || pathDst == null){ |
428 |
System.err.println("Error en path"); |
429 |
return;
|
430 |
} |
431 |
|
432 |
File orig = new File(pathOrig); |
433 |
if(!orig.exists() || !orig.isFile() || !orig.canRead()){
|
434 |
System.err.println("Error en fichero de origen"); |
435 |
return;
|
436 |
} |
437 |
|
438 |
File dest = new File(pathDst); |
439 |
String file = pathOrig.substring(pathOrig.lastIndexOf(File.separator), pathOrig.length()); |
440 |
if(dest.isDirectory())
|
441 |
pathDst += file; |
442 |
|
443 |
in = new FileInputStream(pathOrig); |
444 |
out = new FileOutputStream(pathDst); |
445 |
|
446 |
byte[] buf = new byte[1024]; |
447 |
int len;
|
448 |
|
449 |
while ((len = in.read(buf)) > 0) |
450 |
out.write(buf, 0, len);
|
451 |
|
452 |
in.close(); |
453 |
out.close(); |
454 |
} |
455 |
|
456 |
/**
|
457 |
* Formatea en forma de cadena un tama?o dado en bytes. El resultado
|
458 |
* ser? una cadena con GB, MB, KB y B
|
459 |
* @param size tama?o a formatear
|
460 |
* @return cadena con la cantidad formateada
|
461 |
*/
|
462 |
public static String formatFileSize(long size){ |
463 |
double bytes = (double)size, kBytes = 0, mBytes = 0, gBytes = 0; |
464 |
if(size >= 1024){ |
465 |
kBytes = (double)(size / 1024D); |
466 |
bytes = (int)(size - (((int)kBytes) * 1024)); |
467 |
if(kBytes >= 1024){ |
468 |
mBytes = (double)(((int)kBytes) / 1024D); |
469 |
kBytes = (double)(((int)kBytes) - (((int)mBytes) * 1024)); |
470 |
if(mBytes >= 1024){ |
471 |
gBytes = (int)(((int)mBytes) / 1024); |
472 |
mBytes = (int)(((int)mBytes) - (gBytes * 1024)); |
473 |
} |
474 |
} |
475 |
} |
476 |
|
477 |
if(gBytes > 0) |
478 |
return format(gBytes, 1) + "G"; |
479 |
if(mBytes > 0) |
480 |
return format(mBytes, 1) + "M"; |
481 |
if(kBytes > 0) |
482 |
return format(kBytes, 1) + "K"; |
483 |
if(bytes != 0) |
484 |
return ((int)bytes) + ""; |
485 |
|
486 |
return ""; |
487 |
} |
488 |
|
489 |
//---------------------------------------------------------------
|
490 |
//VARIOS
|
491 |
|
492 |
/**
|
493 |
* Formats a double with an specified number of decimals.
|
494 |
* @param num
|
495 |
* Value to tail
|
496 |
* @param n
|
497 |
* Number of decimals
|
498 |
* @return
|
499 |
* The formatted double
|
500 |
*/
|
501 |
public static double format(double num, int n){ |
502 |
long m = (long)Math.pow(10, n); |
503 |
num *= m; |
504 |
long aux = ((long)num); |
505 |
num = (double)((double)aux / (double)m); |
506 |
return num;
|
507 |
} |
508 |
|
509 |
} |