Commit e156dbea authored by Andrey Filippov's avatar Andrey Filippov

combining processing, minor debugging and cleaning up

parent c430b2f4
......@@ -138,8 +138,9 @@ public class EyesisCorrectionParameters {
public String x3dSubdirSuffix= "";
// CLT 3d batch parameters
public boolean process_main_sources = false;
public boolean process_aux_sources = true;
public boolean process_main_sources = false; // not yet used
public boolean process_aux_sources = true; // not yet used
public int kml_sensors= 0xffffffff; // all sensors
public int rig_batch_adjust_main = 0;
public int rig_batch_adjust_aux = 0;
......@@ -305,6 +306,7 @@ public class EyesisCorrectionParameters {
cp.process_main_sources= this.process_main_sources;
cp.process_aux_sources= this.process_aux_sources;
cp.kml_sensors= this.kml_sensors;
cp.rig_batch_adjust_main= this.rig_batch_adjust_main;
cp.rig_batch_adjust_aux= this.rig_batch_adjust_aux;
cp.rig_batch_adjust_rig= this.rig_batch_adjust_rig;
......@@ -508,6 +510,8 @@ public class EyesisCorrectionParameters {
properties.setProperty(prefix+"process_main_sources", this.process_main_sources+"");
properties.setProperty(prefix+"process_aux_sources", this.process_aux_sources+"");
properties.setProperty(prefix+"kml_sensors", this.kml_sensors+"");
properties.setProperty(prefix+"rig_batch_adjust_main", this.rig_batch_adjust_main+"");
properties.setProperty(prefix+"rig_batch_adjust_aux", this.rig_batch_adjust_aux+"");
properties.setProperty(prefix+"rig_batch_adjust_rig", this.rig_batch_adjust_rig+"");
......@@ -693,6 +697,8 @@ public class EyesisCorrectionParameters {
if (properties.getProperty(prefix+"process_main_sources")!= null) this.process_main_sources=Boolean.parseBoolean(properties.getProperty(prefix+"process_main_sources"));
if (properties.getProperty(prefix+"process_aux_sources")!= null) this.process_aux_sources=Boolean.parseBoolean(properties.getProperty(prefix+"process_aux_sources"));
if (properties.getProperty(prefix+"kml_sensors")!=null) this.kml_sensors=Integer.parseInt(properties.getProperty(prefix+"kml_sensors"));
if (properties.getProperty(prefix+"rig_batch_adjust_main")!=null) this.rig_batch_adjust_main=Integer.parseInt(properties.getProperty(prefix+"rig_batch_adjust_main"));
if (properties.getProperty(prefix+"rig_batch_adjust_aux")!=null) this.rig_batch_adjust_aux=Integer.parseInt(properties.getProperty(prefix+"rig_batch_adjust_aux"));
if (properties.getProperty(prefix+"rig_batch_adjust_rig")!=null) this.rig_batch_adjust_rig=Integer.parseInt(properties.getProperty(prefix+"rig_batch_adjust_rig"));
......@@ -1086,6 +1092,8 @@ public class EyesisCorrectionParameters {
gd.addCheckbox ("Process main camera source images (false - ignore)", this.process_main_sources); // 20c
gd.addCheckbox ("Process AUX camera source images (false - ignore)", this.process_aux_sources); // 20d
gd.addNumericField("Bitmask of channels were to look for GPS data", this.kml_sensors, 0);
gd.addNumericField("Repeat main camera field adjustment (early, before rig)", this.rig_batch_adjust_main, 0);
gd.addNumericField("Repeat aux camera field adjustment (early, before rig)", this.rig_batch_adjust_aux, 0);
gd.addNumericField("Repeat 2-quad camera rig field adjustment (early, before late main/aux)", this.rig_batch_adjust_rig, 0);
......@@ -1226,6 +1234,8 @@ public class EyesisCorrectionParameters {
this.process_main_sources= gd.getNextBoolean(); // 20c
this.process_aux_sources= gd.getNextBoolean(); // 20d
this.kml_sensors = (int) gd.getNextNumber();
this.rig_batch_adjust_main = (int) gd.getNextNumber();
this.rig_batch_adjust_aux = (int) gd.getNextNumber();
this.rig_batch_adjust_rig = (int) gd.getNextNumber();
......@@ -1289,7 +1299,7 @@ public class EyesisCorrectionParameters {
return (this.sourcePaths!=null)?this.sourcePaths:empty;
}
public int getChannelFromTiff(String path, String suffix){
public static int getChannelFromTiff(String path, String suffix){
int indexSuffix=path.length()-suffix.length();
int indexLastDash=indexSuffix-1; // in jp4 it will be underscore, not dash? Or should we change that?
while ((indexLastDash>0) &&
......
......@@ -838,6 +838,10 @@ public class GpuQuad{ // quad camera description
}
float [] fbayer = new float [bayer_data[0][0].length];
for (int ncam = 0; ncam < bayer_data.length; ncam++) {
if (bayer_data[ncam][0] == null) {
System.out.println("BUG!! bayer_data["+ncam+"][0] == null");
continue;
}
for (int i = 0; i < bayer_data[ncam][0].length; i++) {
fbayer[i] = (float) (bayer_data[ncam][0][i]); // + bayer_data[ncam][1][i] + bayer_data[ncam][2][i]);
for (int j = 1; j < bayer_data[ncam].length; j++) {
......
......@@ -649,19 +649,20 @@ public class ImagejJp4Tiff {
return center;
}
System.out.println ("Discontinuities remain, will fix by clusters");
fixByClusters(
boolean OK = fixByClusters(
width,
height,
FIXCH6_BIT, // int bad_bit,
idata, // int [] data)
(dbg_img != null)); // boolean debug)
System.out.println ("FixByClusters -> "+OK);
for (int i = 0; i < idata.length; i++) {
pixels[i+640] = idata[i];
}
return center;
}
public boolean fixByClusters(
public static boolean fixByClusters(
int width,
int height,
int bad_bit,
......@@ -733,6 +734,9 @@ public class ImagejJp4Tiff {
}
if (ndir == 1) {
indx++;
if (indx >= clusters.length) { // start from the beginning
indx -= clusters.length;
}
}
}
if (ntry >= (2*clusters.length)) {
......
......@@ -2467,6 +2467,9 @@ public class ImageDtt extends ImageDttCPU {
final boolean use_partial, // find motion vectors for individual pairs, false - for sum only
final double centroid_radius, // 0 - use all tile, >0 - cosine window around local max
final int n_recenter, // when cosine window, re-center window this many times
final double td_weight, // mix correlations accumulated in TD with
final double pd_weight, // correlations (post) accumulated in PD
final boolean td_nopd_only, // only use TD accumulated data if no safe PD is available for the tile.
final double min_str, // = 0.25;
final double min_str_sum, // = 0.8; // 5;
final int min_neibs, // 2; // minimal number of strong neighbors (> min_str)
......@@ -2658,26 +2661,60 @@ public class ImageDtt extends ImageDttCPU {
}
}
// now calculate only for composite
double [] mv = Correlation2d.getMaxXYCm(
double [] mv_pd = new double [3];
double [] mv_td = new double [3];
if (pd_weight > 0.0) {
mv_pd = Correlation2d.getMaxXYCm(
corrs[corrs.length-1], // double [] data,
corr_size, // int data_width, // = 2 * transform_size - 1;
centroid_radius, // double radius, // 0 - all same weight, > 0 cosine(PI/2*sqrt(dx^2+dy^2)/rad)
n_recenter, // int refine, // re-center window around new maximum. 0 -no refines (single-pass)
false); // boolean debug)
if (mv != null) {
if (mv[2] < min_str) {
mv = null;
} else {
mv[2] -= min_str;
if (mv_pd != null) {
if (mv_pd[2] < min_str) {
mv_pd = null;
} else {
mv_pd[2] -= min_str;
}
}
}
if (mv != null) {
if (pXpYD == null) {
coord_motion[0][nTile] = mv;
} else {
if (pXpYD[nTile] != null) { // seems always
coord_motion[0][nTile] = pXpYD[nTile].clone();
coord_motion[1][nTile] = mv;
if (td_weight > 0.0) {
mv_td = Correlation2d.getMaxXYCm(
corrs[corrs.length-2], // double [] data,
corr_size, // int data_width, // = 2 * transform_size - 1;
centroid_radius, // double radius, // 0 - all same weight, > 0 cosine(PI/2*sqrt(dx^2+dy^2)/rad)
n_recenter, // int refine, // re-center window around new maximum. 0 -no refines (single-pass)
false); // boolean debug)
if (mv_td != null) {
if (mv_td[2] < min_str_sum) {
mv_td = null;
} else {
mv_td[2] -= min_str_sum;
}
}
}
if ((mv_td != null) || (mv_pd != null)) {
double [] mv = new double[3];
if (mv_pd != null) {
mv = mv_pd;
mv[2] *= pd_weight;
if ((mv_td != null) && !td_nopd_only) { // mix
mv[0] = (mv[0] * pd_weight + mv_td[0] * td_weight)/ (pd_weight + td_weight);
mv[1] = (mv[1] * pd_weight + mv_td[1] * td_weight)/ (pd_weight + td_weight);
mv[2] += mv_td[2] * td_weight;
} // mix
} else { // (mv_pd == null) && (mv_td != null) below
mv = mv_td;
mv[2] *= td_weight;
}
if (mv != null) {
if (pXpYD == null) {
coord_motion[0][nTile] = mv;
} else {
if (pXpYD[nTile] != null) { // seems always
coord_motion[0][nTile] = pXpYD[nTile].clone();
coord_motion[1][nTile] = mv;
}
}
}
}
......
......@@ -620,7 +620,7 @@ public class IntersceneLma {
pure_weight = s_pure/full_weight;
final double s = 1.0/asum_weight.sum();
if (Double.isNaN(s)) {
System.out.println("normalizeWeights(): s == NaN");
System.out.println("normalizeWeights(): s == NaN : 1");
}
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
......@@ -673,7 +673,7 @@ public class IntersceneLma {
pure_weight = sum_weight_pure/full_weight;
final double s = 1.0/full_weight;
if (Double.isNaN(s)) {
System.out.println("normalizeWeights(): s == NaN");
System.out.println("normalizeWeights(): s == NaN : 2");
}
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
......
......@@ -50,6 +50,12 @@ public class IntersceneMatchParameters {
public double centroid_radius = 4.0; //
public int n_recenter = 2; // when cosine window, re-center window this many times
// filtering motion vectors
// TD accumulation of the inter-scene correlations demonstrated artifacts (horizontally offset by 8 pixels
// false maximum that is sharper than the real one. Still not understood - maybe float precision related.
public double td_weight = 0.5; // mix correlations accumulated in TD with
public double pd_weight = 0.5; // correlations (post) accumulated in PD
public boolean td_nopd_only = true; // only use TD accumulated data if no safe PD is available for the tile.
public double min_str = 0.25; // minimal correlation strength for all but TD-accumulated layer
public double min_str_sum = 0.8; // minimal correlation strength for TD-accumulated layer
public int min_neibs = 2; // minimal number of strong neighbors (> min_str)
......@@ -131,6 +137,14 @@ public class IntersceneMatchParameters {
"Calculate centroids after multiplication by a half-cosine window. All correlation data farther than this value from the center is ignored");
gd.addNumericField("Refine centroids", this.n_recenter, 0,5,"",
"Repeat centroids after moving the window center to the new centroid location this many times (0 - calculate once)");
gd.addMessage ("Mixing TD and PD accumulation of 2d correlations");
gd.addNumericField("TD-accumulated weight", this.td_weight, 5,7,"",
"Mix argmax from TD-accumulated correlation.");
gd.addNumericField("PD-accumulated weight", this.pd_weight, 5,7,"",
"Mix argmax from PD-accumulated correlation.");
gd.addCheckbox ("TD when no PD only", this.td_nopd_only,
"Use argmax from TD only if PD data is not available for this tile.");
gd.addMessage ("Filtering motion vectors");
gd.addNumericField("Minimal correlation strength (non-sum)", this.min_str, 5,7,"",
......@@ -223,6 +237,11 @@ public class IntersceneMatchParameters {
this.run_poly = gd.getNextBoolean();
this.centroid_radius = gd.getNextNumber();
this.n_recenter = (int) gd.getNextNumber();
this.td_weight = gd.getNextNumber();
this.pd_weight = gd.getNextNumber();
this.td_nopd_only = gd.getNextBoolean();
this.min_str = gd.getNextNumber();
this.min_str_sum = gd.getNextNumber();
this.min_neibs = (int) gd.getNextNumber();
......@@ -275,6 +294,11 @@ public class IntersceneMatchParameters {
properties.setProperty(prefix+"run_poly", this.run_poly+""); // boolean
properties.setProperty(prefix+"centroid_radius", this.centroid_radius+""); // double
properties.setProperty(prefix+"n_recenter", this.n_recenter+""); // int
properties.setProperty(prefix+"td_weight", this.td_weight+""); // double
properties.setProperty(prefix+"pd_weight", this.pd_weight+""); // double
properties.setProperty(prefix+"td_nopd_only", this.td_nopd_only+""); // boolean
properties.setProperty(prefix+"min_str", this.min_str+""); // double
properties.setProperty(prefix+"min_str_sum", this.min_str_sum+""); // double
properties.setProperty(prefix+"min_neibs", this.min_neibs+""); // int
......@@ -323,6 +347,11 @@ public class IntersceneMatchParameters {
if (properties.getProperty(prefix+"run_poly")!=null) this.run_poly=Boolean.parseBoolean(properties.getProperty(prefix+"run_poly"));
if (properties.getProperty(prefix+"centroid_radius")!=null) this.centroid_radius=Double.parseDouble(properties.getProperty(prefix+"centroid_radius"));
if (properties.getProperty(prefix+"n_recenter")!=null) this.n_recenter=Integer.parseInt(properties.getProperty(prefix+"n_recenter"));
if (properties.getProperty(prefix+"td_weight")!=null) this.td_weight=Double.parseDouble(properties.getProperty(prefix+"td_weight"));
if (properties.getProperty(prefix+"pd_weight")!=null) this.pd_weight=Double.parseDouble(properties.getProperty(prefix+"pd_weight"));
if (properties.getProperty(prefix+"td_nopd_only")!=null) this.td_nopd_only=Boolean.parseBoolean(properties.getProperty(prefix+"td_nopd_only"));
if (properties.getProperty(prefix+"min_str")!=null) this.min_str=Double.parseDouble(properties.getProperty(prefix+"min_str"));
if (properties.getProperty(prefix+"min_str_sum")!=null) this.min_str_sum=Double.parseDouble(properties.getProperty(prefix+"min_str_sum"));
if (properties.getProperty(prefix+"min_neibs")!=null) this.min_neibs=Integer.parseInt(properties.getProperty(prefix+"min_neibs"));
......@@ -373,6 +402,11 @@ public class IntersceneMatchParameters {
imp.run_poly = this.run_poly;
imp.centroid_radius = this.centroid_radius;
imp.n_recenter = this.n_recenter;
imp.td_weight = this.td_weight;
imp.pd_weight = this.pd_weight;
imp.td_nopd_only = this.td_nopd_only;
imp.min_str = this.min_str;
imp.min_str_sum = this.min_str_sum;
imp.min_neibs = this.min_neibs;
......
......@@ -3907,7 +3907,7 @@ public class OpticalFlow {
null, // QuadCLT quadCLT_aux,
clt_parameters, // EyesisCorrectionParameters.DCTParameters dct_parameters,
true, // boolean skip_existing,
false, // boolean search_KML,
true, // false, // boolean search_KML,
debugLevel);
quadCLTs[ref_index] = (QuadCLT) quadCLT_main.spawnNoModelQuadCLT( // will conditionImageSet
set_channels[ref_index].set_name,
......@@ -3971,7 +3971,7 @@ public class OpticalFlow {
null, // QuadCLT quadCLT_aux,
clt_parameters, // EyesisCorrectionParameters.DCTParameters dct_parameters,
true, // boolean skip_existing,
false, // boolean search_KML,
true, // false, // boolean search_KML,
debugLevel);
} // split cycles to remove output clutter
} // if (build_ref_dsi) {
......@@ -4061,6 +4061,9 @@ public class OpticalFlow {
quadCLTs[ref_index].getImageName() + "/" + scene_QuadClt.getImageName()+
" Done. RMS="+lma_rms[0]+", maximal so far was "+maximal_series_rms);
}
if (scene_index == 25) {
System.out.println("scene_index == 25");
}
/*
if (delete_scene_asap) {
scenes[i+1] = null;
......@@ -9666,7 +9669,7 @@ public double[][] correlateIntersceneDebug( // only uses GPU and quad
final float [][][] fclt_corr = ((accum_2d_corr != null) || show_2d_correlations) ?
(new float [tilesX * tilesY][][]) : null;
if (debug_level > 1) {
System.out.println("interCorrPair(): "+IntersceneLma.printNameV3("ATR",scene_atr)+
System.out.println("interCorrPair(): "+IntersceneLma.printNameV3("ATR",scene_atr)+
" "+IntersceneLma.printNameV3("XYZ",scene_xyz));
}
ImageDtt image_dtt;
......@@ -9682,10 +9685,11 @@ public double[][] correlateIntersceneDebug( // only uses GPU and quad
if (ref_scene.getGPU() != null) {
ref_scene.getGPU().setGpu_debug_level(debug_level - 4); // monitor GPU ops >=-1
}
final double disparity_corr = 0.00; // (z_correction == 0) ? 0.0 : geometryCorrection.getDisparityFromZ(1.0/z_correction);
double [][] dsrbg_ref= ref_scene.getDSRBG();
final double disparity_corr = 0.0; // (z_correction == 0) ? 0.0 : geometryCorrection.getDisparityFromZ(1.0/z_correction);
// double [][] dsrbg_ref= ref_scene.getDSRBG();
double [][] dls= ref_scene.getDLS();
double [][] ref_pXpYD = transformToScenePxPyD( // full size - [tilesX*tilesY], some nulls
dsrbg_ref[0], // final double [] disparity_ref, // invalid tiles - NaN in disparity (maybe it should not be masked by margins?)
dls[0], // final double [] disparity_ref, // invalid tiles - NaN in disparity (maybe it should not be masked by margins?)
ZERO3, // final double [] scene_xyz, // camera center in world coordinates
ZERO3, // final double [] scene_atr, // camera orientation relative to world frame
ref_scene, // final QuadCLT scene_QuadClt,
......@@ -9713,7 +9717,7 @@ public double[][] correlateIntersceneDebug( // only uses GPU and quad
//setupERS() will be inside transformToScenePxPyD()
*/
double [][] scene_pXpYD = transformToScenePxPyD( // will be null for disparity == NaN, total size - tilesX*tilesY
dsrbg_ref[0], // final double [] disparity_ref, // invalid tiles - NaN in disparity (maybe it should not be masked by margins?)
dls[0], // final double [] disparity_ref, // invalid tiles - NaN in disparity (maybe it should not be masked by margins?)
scene_xyz, // final double [] scene_xyz, // camera center in world coordinates
scene_atr, // final double [] scene_atr, // camera orientation relative to world frame
scene, // final QuadCLT scene_QuadClt,
......@@ -9804,6 +9808,9 @@ public double[][] correlateIntersceneDebug( // only uses GPU and quad
clt_parameters.imp.use_partial, // final boolean use_partial, // find motion vectors for individual pairs, false - for sum only
clt_parameters.imp.centroid_radius,// final double centroid_radius, // 0 - use all tile, >0 - cosine window around local max
clt_parameters.imp.n_recenter, // final int n_recenter, // when cosine window, re-center window this many times
clt_parameters.imp.td_weight, // final double td_weight, // mix correlations accumulated in TD with
clt_parameters.imp.pd_weight, // final double pd_weight, // correlations (post) accumulated in PD
clt_parameters.imp.td_nopd_only, // final boolean td_nopd_only, // only use TD accumulated data if no safe PD is available for the tile.
clt_parameters.imp.min_str, // final double min_str, // = 0.25;
clt_parameters.imp.min_str_sum, // final double min_str_sum, // = 0.8; // 5;
clt_parameters.imp.min_neibs, // final int min_neibs, // 2; // minimal number of strong neighbors (> min_str)
......
......@@ -14214,9 +14214,42 @@ public class QuadCLTCPU {
if (imp.getProperty("ALTITUDE") != null) gps_lla[2] =Double.parseDouble((String) imp.getProperty("ALTITUDE"));
return true;
}
if (imp.getProperty("STD_GPS_Latitude") != null) {
gps_lla = new double[3];
for (int i = 0; i < 3; i++) {
gps_lla[i] = Double.NaN;
}
if (imp.getProperty("STD_GPS_Latitude") != null) gps_lla[0] =parseDegreeMinSec((String) imp.getProperty("STD_GPS_Latitude"));
if (imp.getProperty("STD_GPS_Longitude") != null) gps_lla[1] =parseDegreeMinSec((String) imp.getProperty("STD_GPS_Longitude"));
if (imp.getProperty("STD_GPS_Altitude") != null) gps_lla[2] =parseStringToEndString((String) imp.getProperty("STD_GPS_Altitude"),"m");
return true;
}
return false; // not used in lwir
}
static double parseDegreeMinSec(String s) {
int indx_degree = s.indexOf("\u00B0");
int indx_minute = s.indexOf("\u2032");
if (indx_minute < 0) {
indx_minute = s.indexOf("'");
}
int indx_second = s.indexOf("\u2033");
if (indx_second < 0) {
indx_second = s.indexOf("\"");
}
double degrees = Double.parseDouble(s.substring(0,indx_degree));
double min_sec = Double.parseDouble(s.substring(indx_degree+1, indx_minute))/60.0 +
Double.parseDouble(s.substring(indx_minute+1, indx_second))/3600.0;
if (degrees < 0) {
return degrees - min_sec;
} else {
return degrees + min_sec;
}
}
static double parseStringToEndString(String s, String end_string) {
int indx_end = s.indexOf(end_string);
return Double.parseDouble(s.substring(0, indx_end));
}
public boolean writeKml( // USED in lwir
String image_name,
......@@ -14227,12 +14260,18 @@ public class QuadCLTCPU {
}
String [] sourceFiles_main=correctionsParameters.getSourcePaths();
SetChannels [] set_channels = setChannels(image_name,debugLevel); // only for specified image timestamp
int kml_sensors = correctionsParameters.kml_sensors;
ArrayList<String> path_list = new ArrayList<String>();
for (int i = 0; i < set_channels.length; i++) {
for (int fn:set_channels[i].file_number) {
path_list.add(sourceFiles_main[fn]);
for (int nchn = 0; nchn < set_channels[i].file_number.length; nchn++) {
if ((kml_sensors & (1 << nchn)) != 0) {
path_list.add(sourceFiles_main[set_channels[i].file_number[nchn]]);
}
}
/// for (int fn:set_channels[i].file_number) {
/// path_list.add(sourceFiles_main[fn]);
/// }
}
for (String fname:path_list) {
System.out.println("writeKml(): "+fname);
......
......@@ -3137,6 +3137,11 @@ if (debugLevel > -100) return true; // temporarily !
return;
}
}
if (search_KML && (set_channels_main !=null)) { // TODO: make it look in both MAIN and AUX. Look in only the same scene?
quadCLT_main.writeKml(
set_name,
debugLevel ); // also generated with x3d model
}
for (String fname:path_list) {
if (fname.contains(set_name)) { // only files containing set name // TODO:improve
File file = new File(fname);
......@@ -3152,11 +3157,6 @@ if (debugLevel > -100) return true; // temporarily !
}
}
}
if (search_KML && (set_channels_main !=null)) { // TODO: make it look in both MAIN and AUX. Look in only the same scene?
quadCLT_main.writeKml(
set_name,
debugLevel ); // also generated with x3d model
}
System.out.println("jp4_copy_path = "+jp4_copy_path);
// System.out.println("Do something useful here");
}
......
......@@ -284,6 +284,7 @@ public class X3dOutput {
addTextElement(kmlDoc, el_Camera, "heading", String.format("%f",0.0));
addTextElement(kmlDoc, el_Camera, "tilt", String.format("%f",90.0));
addTextElement(kmlDoc, el_Camera, "roll", String.format("%f",0.0));
addTextElement(kmlDoc, el_Camera, "altitudeMode", "clampToGround");
if (icon_path != null) {
Element el_Icon = addElement(kmlDoc, el_PhotoOverlay, "Icon");
addTextElement(kmlDoc, el_Icon, "href", icon_path);
......@@ -296,6 +297,7 @@ public class X3dOutput {
addTextElement(kmlDoc, el_OriginalData, "heading", String.format("%f",0.0));
addTextElement(kmlDoc, el_OriginalData, "tilt", String.format("%f",90.0));
addTextElement(kmlDoc, el_OriginalData, "roll", String.format("%f",0.0));
addTextElement(kmlDoc, el_OriginalData, "altitudeMode", "clampToGround");
try {
// write the content into xml file
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment