TagBox::TagBox(ToolPanel *panel, wxWindowID id, const wxString& label, const wxPoint& pos, const wxSize& size, wxString boxname, wxString modpath) : wxComboBox(panel, id, label, wxDefaultPosition, size) { wxString filename, filepath; wxString readline, tag, text; TextFile opfile; bool check; path = modpath; name = boxname; diagbox = NULL; labelset = false; tag = ""; if(panel->mainwin) diagbox = panel->mainwin->diagbox; diagbox->Write("\nTagBox init " + name + "\n"); // tag history load if(name == "") { diagbox->Write("Tag file not set\n"); return; } filename = name + "tags.ini"; check = opfile.Open(path + "/Tags/" + filename); if(!check) { if(diagbox) diagbox->Write("No tag history\n"); return; } diagbox->Write("Reading tag history " + filename + "\n"); readline = opfile.ReadLine(); while(!readline.IsEmpty()) { //diagbox->Write("Readline " + readline + "\n"); readline = readline.AfterFirst(' '); readline.Trim(); tag = readline; Insert(tag, 0); //diagbox->Write("Insert " + tag + "\n"); readline = opfile.ReadLine(); } opfile.Close(); SetLabel(tag); diagbox->Write(name + " " + tag + "\n"); if(tag != "") labelset = true; }
void MainFrame::MainLoad() { long numdat; int i, check, boxindex; wxString filename, filepath; wxString readline, numstring; TextFile infile; wxPoint pos; wxSize size; //filepath = GetPath(); filepath = "Init//"; // Box Load filename = "mainbox.ini"; check = infile.Open(filepath + filename); if(!check) return; readline = infile.ReadLine(); //tofp.WriteLine(readline); while(!readline.IsEmpty()) { numstring = readline.BeforeFirst(' '); numstring.ToLong(&numdat); boxindex = numdat; if(boxindex >= toolset->numtools) break; pos.x = ReadNextData(&readline); pos.y = ReadNextData(&readline); size.x = ReadNextData(&readline); size.y = ReadNextData(&readline); if(toolset->box[boxindex]->servant) toolset->box[boxindex]->visible = (bool)ReadNextData(&readline); else toolset->box[boxindex]->visible = true; if(pos.x >= -5000 && pos.x < 5000 && pos.y >= -5000 && pos.y < 5000) toolset->box[boxindex]->mpos = pos; if(size.x >= 50 && size.x < 2000 && size.y >= 50 && size.y < 2000) toolset->box[boxindex]->boxsize = size; readline = infile.ReadLine(); // Read next line //tofp.WriteLine(readline); } infile.Close(); for(i=0; i<toolset->numtools; i++) { toolset->box[i]->ReSize(); toolset->box[i]->Show(toolset->box[i]->visible); } }
/** * Loads the user entered batchlist file into a private variable for later use * * @param file The batchlist file to load * * @history 2010-03-26 Sharmila Prasad - Remove the restriction of the number of * columns in the batchlist file to 10. * @throws Isis::IException::User - The batchlist does not contain any data */ void UserInterface::LoadBatchList(const QString file) { // Read in the batch list TextFile temp; try { temp.Open(file); } catch (IException &e) { QString msg = "The batchlist file [" + file + "] could not be opened"; throw IException(IException::User, msg, _FILEINFO_); } p_batchList.resize(temp.LineCount()); for(int i = 0; i < temp.LineCount(); i ++) { QString t; temp.GetLine(t); // Convert tabs to spaces but leave tabs inside quotes alone t = IString(t).Replace("\t", " ", true).ToQt(); t = IString(t).Compress().ToQt().trimmed(); // Allow " ," " , " or ", " as a valid single seperator t = IString(t).Replace(" ,", ",", true).ToQt(); t = IString(t).Replace(", ", ",", true).ToQt(); // Convert all spaces to "," the use "," as delimiter t = IString(t).Replace(" ", ",", true).ToQt(); int j = 0; QStringList tokens = t.split(","); foreach(QString token, tokens) { // removes quotes from tokens. NOTE: also removes escaped quotes. token = token.remove(QRegExp("[\"']")); p_batchList[i].push_back(token); j ++ ; } p_batchList[i].resize(j); // Every row in the batchlist must have the same number of columns if(i == 0) continue; if(p_batchList[i - 1].size() != p_batchList[i].size()) { QString msg = "The number of columns must be constant in batchlist"; throw IException(IException::User, msg, _FILEINFO_); } }
void ToolBox::OnClose(wxCloseEvent& event) { TextFile ofp; wxString text; ofp.Open("boxdiag.txt"); if(servant || child) { Show(false); ofp.WriteLine(text.Format("hide box %d, child %d", boxindex, child)); } else if(canclose) { ofp.WriteLine(text.Format("close box %d, mod boxes %d", boxindex, toolset->numtools)); //if(mod != NULL) mod->modtools.RemoveBox(boxindex); //mainwin->toolset.RemoveBox(boxindex); toolset->RemoveBox(boxindex); Destroy(); } ofp.Close(); }
void GraphBase::BaseLoad(wxString path, wxString tag, wxTextCtrl *textbox) { int i, index; TextFile infile; wxString readline, filename, filetag; wxString text, numstring, namestring, basestring; wxString gtag, gname; double numdat; GraphDat *graph; int version; filename = "gbase-" + tag + ".dat"; //if(!infile.Open(initpath + "/Graphs/" + filename)) return; if(!infile.Open(path + "/" + filename)) return; if(textbox) textbox->AppendText(text.Format("Loading %d graphs\n", numgraphs)); i = 0; readline = infile.ReadLine(); // Version check //fileversion = ParseLong(&vstring, 'v'); //textbox->AppendText(text.Format("Base file version %d\n", fileversion)); //if(fileversion < version) textbox->AppendText(text.Format("Create base index\n")); while(!readline.IsEmpty()) { if(readline.GetChar(0) == 'v') version = ParseLong(&readline, 'v'); // check file version for backwards compatability else version = 0; //textbox->AppendText(text.Format("Base file version %d\n", version)); //textbox->AppendText(text.Format("Readline %s\n", readline)); if(version >= 2) { // Modern, reference by tag gtag = ParseString(&readline, 'g'); graph = GetGraph(gtag); if(graph) graph->LoadDat(readline, version); } else { //GetGraphFromName(gname)->LoadDat(readline, version); // Should add code to chop off any tag first //int ndex = readline.Find("name"); //textbox->AppendText(text.Format("Base file version %d\n", version)); //textbox->AppendText(text.Format("Readline %s\n", readline)); namestring = readline.Mid(readline.Find("name")); //textbox->AppendText(text.Format("Name string %s\n", namestring)); gname = ParseString(&namestring, 'e'); gname.Replace("_", " "); if(textbox) textbox->AppendText(text.Format("gname %s\n", gname)); graph = GetGraphFromName(gname); if(graph) graph->LoadDat(readline, version); } //graphstore[i].LoadDat(readline, version); if(infile.End()) break; readline = infile.ReadLine(); i++; } infile.Close(); // Read graphbase entries /* while(!readline.IsEmpty()) { graphstore[i].diagbox = mainwin->diagbox; graphstore[i].LoadDat(readline, version); if(infile.End()) break; readline = infile.ReadLine(); i++; } infile.Close(); */ }
void HypoMain::OptionLoad() { long numdat; int check; wxString filename; wxString readline, numstring, tag; filename = "Init/hypoprefs.ini"; wxTextFile opfile(filename); if(!opfile.Exists()) { startmod = 13; numdraw = 3; ylabels = 5; diagnostic = 1; datsample = 1; basic = 0; } else { opfile.Open(); readline = opfile.GetFirstLine(); while(!readline.IsEmpty()) { tag = readline.BeforeFirst(' '); readline = readline.AfterFirst(' '); readline.Trim(); readline.ToLong(&numdat); prefstore[tag] = numdat; //if(diagnostic) ofp.WriteLine(text.Format("Model Param ID %d, Value %.4f\n", id, datval)); if(opfile.Eof()) return; readline = opfile.GetNextLine(); } opfile.Close(); startmod = prefstore["startmod"]; numdraw = prefstore["numdraw"]; viewheight = prefstore["viewheight"]; viewwidth = prefstore["viewwidth"]; ylabels = prefstore["ylabels"]; datsample = prefstore["datsample"]; basic = prefstore["basic"]; diagnostic = prefstore["diagnostic"]; } filename = "Init/hypopaths.ini"; TextFile infile; check = infile.Open(filename); if(!check) { datapath = "Data"; parampath = "Params"; outpath = ""; modpath = ""; return; } readline = infile.ReadLine(); datapath = readline.Trim(); readline = infile.ReadLine(); parampath = readline.Trim(); readline = infile.ReadLine(); outpath = readline.Trim(); readline = infile.ReadLine(); modpath = readline.Trim(); opfile.Close(); }
void IsisMain() { //Create a process to create the input cubes Process p; //Create the input cubes, matching sample/lines Cube *inCube = p.SetInputCube ("FROM"); Cube *latCube = p.SetInputCube("LATCUB", SpatialMatch); Cube *lonCube = p.SetInputCube("LONCUB", SpatialMatch); //A 1x1 brick to read in the latitude and longitude DN values from //the specified cubes Brick latBrick(1,1,1, latCube->PixelType()); Brick lonBrick(1,1,1, lonCube->PixelType()); UserInterface &ui = Application::GetUserInterface(); //Set the sample and line increments int sinc = (int)(inCube->Samples() * 0.10); if(ui.WasEntered("SINC")) { sinc = ui.GetInteger("SINC"); } int linc = (int)(inCube->Lines() * 0.10); if(ui.WasEntered("LINC")) { linc = ui.GetInteger("LINC"); } //Set the degree of the polynomial to use in our functions int degree = ui.GetInteger("DEGREE"); //We are using a polynomial with two variables PolynomialBivariate sampFunct(degree); PolynomialBivariate lineFunct(degree); //We will be solving the function using the least squares method LeastSquares sampSol(sampFunct); LeastSquares lineSol(lineFunct); //Setup the variables for solving the stereographic projection //x = cos(latitude) * sin(longitude - lon_center) //y = cos(lat_center) * sin(latitude) - sin(lat_center) * cos(latitude) * cos(longitude - lon_center) //Get the center lat and long from the input cubes double lat_center = latCube->Statistics()->Average() * PI/180.0; double lon_center = lonCube->Statistics()->Average() * PI/180.0; /** * Loop through lines and samples projecting the latitude and longitude at those * points to stereographic x and y and adding these points to the LeastSquares * matrix. */ for(int i = 1; i <= inCube->Lines(); i+= linc) { for(int j = 1; j <= inCube->Samples(); j+= sinc) { latBrick.SetBasePosition(j, i, 1); latCube->Read(latBrick); if(IsSpecial(latBrick.at(0))) continue; double lat = latBrick.at(0) * PI/180.0; lonBrick.SetBasePosition(j, i, 1); lonCube->Read(lonBrick); if(IsSpecial(lonBrick.at(0))) continue; double lon = lonBrick.at(0) * PI/180.0; //Project lat and lon to x and y using a stereographic projection double k = 2/(1 + sin(lat_center) * sin(lat) + cos(lat_center)*cos(lat)*cos(lon - lon_center)); double x = k * cos(lat) * sin(lon - lon_center); double y = k * (cos(lat_center) * sin(lat)) - (sin(lat_center) * cos(lat) * cos(lon - lon_center)); //Add x and y to the least squares matrix vector<double> data; data.push_back(x); data.push_back(y); sampSol.AddKnown(data, j); lineSol.AddKnown(data, i); //If the sample increment goes past the last sample in the line, we want to //always read the last sample.. if(j != inCube->Samples() && j + sinc > inCube->Samples()) { j = inCube->Samples() - sinc; } } //If the line increment goes past the last line in the cube, we want to //always read the last line.. if(i != inCube->Lines() && i + linc > inCube->Lines()) { i = inCube->Lines() - linc; } } //Solve the least squares functions using QR Decomposition sampSol.Solve(LeastSquares::QRD); lineSol.Solve(LeastSquares::QRD); //If the user wants to save the residuals to a file, create a file and write //the column titles to it. TextFile oFile; if(ui.WasEntered("RESIDUALS")) { oFile.Open(ui.GetFilename("RESIDUALS"), "overwrite"); oFile.PutLine("Sample,\tLine,\tX,\tY,\tSample Error,\tLine Error\n"); } //Gather the statistics for the residuals from the least squares solutions Statistics sampErr; Statistics lineErr; vector<double> sampResiduals = sampSol.Residuals(); vector<double> lineResiduals = lineSol.Residuals(); for(int i = 0; i < (int)sampResiduals.size(); i++) { sampErr.AddData(sampResiduals[i]); lineErr.AddData(lineResiduals[i]); } //If a residuals file was specified, write the previous data, and the errors to the file. if(ui.WasEntered("RESIDUALS")) { for(int i = 0; i < sampSol.Rows(); i++) { vector<double> data = sampSol.GetInput(i); iString tmp = ""; tmp += iString(sampSol.GetExpected(i)); tmp += ",\t"; tmp += iString(lineSol.GetExpected(i)); tmp += ",\t"; tmp += iString(data[0]); tmp += ",\t"; tmp += iString(data[1]); tmp += ",\t"; tmp += iString(sampResiduals[i]); tmp += ",\t"; tmp += iString(lineResiduals[i]); oFile.PutLine(tmp + "\n"); } } oFile.Close(); //Records the error to the log PvlGroup error( "Error" ); error += PvlKeyword( "Degree", degree ); error += PvlKeyword( "NumberOfPoints", (int)sampResiduals.size() ); error += PvlKeyword( "SampleMinimumError", sampErr.Minimum() ); error += PvlKeyword( "SampleAverageError", sampErr.Average() ); error += PvlKeyword( "SampleMaximumError", sampErr.Maximum() ); error += PvlKeyword( "SampleStdDeviationError", sampErr.StandardDeviation() ); error += PvlKeyword( "LineMinimumError", lineErr.Minimum() ); error += PvlKeyword( "LineAverageError", lineErr.Average() ); error += PvlKeyword( "LineMaximumError", lineErr.Maximum() ); error += PvlKeyword( "LineStdDeviationError", lineErr.StandardDeviation() ); Application::Log( error ); //Close the input cubes for cleanup p.EndProcess(); //If we want to warp the image, then continue, otherwise return if(!ui.GetBoolean("NOWARP")) { //Creates the mapping group Pvl mapFile; mapFile.Read(ui.GetFilename("MAP")); PvlGroup &mapGrp = mapFile.FindGroup("Mapping",Pvl::Traverse); //Reopen the lat and long cubes latCube = new Cube(); latCube->SetVirtualBands(ui.GetInputAttribute("LATCUB").Bands()); latCube->Open(ui.GetFilename("LATCUB")); lonCube = new Cube(); lonCube->SetVirtualBands(ui.GetInputAttribute("LONCUB").Bands()); lonCube->Open(ui.GetFilename("LONCUB")); PvlKeyword targetName; //If the user entered the target name if(ui.WasEntered("TARGET")) { targetName = PvlKeyword("TargetName", ui.GetString("TARGET")); } //Else read the target name from the input cube else { Pvl fromFile; fromFile.Read(ui.GetFilename("FROM")); targetName = fromFile.FindKeyword("TargetName", Pvl::Traverse); } mapGrp.AddKeyword(targetName, Pvl::Replace); PvlKeyword equRadius; PvlKeyword polRadius; //If the user entered the equatorial and polar radii if(ui.WasEntered("EQURADIUS") && ui.WasEntered("POLRADIUS")) { equRadius = PvlKeyword("EquatorialRadius", ui.GetDouble("EQURADIUS")); polRadius = PvlKeyword("PolarRadius", ui.GetDouble("POLRADIUS")); } //Else read them from the pck else { Filename pckFile("$base/kernels/pck/pck?????.tpc"); pckFile.HighestVersion(); string pckFilename = pckFile.Expanded(); furnsh_c(pckFilename.c_str()); string target = targetName[0]; SpiceInt code; SpiceBoolean found; bodn2c_c (target.c_str(), &code, &found); if (!found) { string msg = "Could not convert Target [" + target + "] to NAIF code"; throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); } SpiceInt n; SpiceDouble radii[3]; bodvar_c(code,"RADII",&n,radii); equRadius = PvlKeyword("EquatorialRadius", radii[0] * 1000); polRadius = PvlKeyword("PolarRadius", radii[2] * 1000); } mapGrp.AddKeyword(equRadius, Pvl::Replace); mapGrp.AddKeyword(polRadius, Pvl::Replace); //If the latitude type is not in the mapping group, copy it from the input if(!mapGrp.HasKeyword("LatitudeType")) { if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetocentric"), Pvl::Replace); } else { mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetographic"), Pvl::Replace); } } //If the longitude direction is not in the mapping group, copy it from the input if(!mapGrp.HasKeyword("LongitudeDirection")) { if(ui.GetString("LONDIR") == "POSITIVEEAST") { mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveEast"), Pvl::Replace); } else { mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"), Pvl::Replace); } } //If the longitude domain is not in the mapping group, assume it is 360 if(!mapGrp.HasKeyword("LongitudeDomain")) { mapGrp.AddKeyword(PvlKeyword("LongitudeDomain","360"), Pvl::Replace); } //If the default range is to be computed, use the input lat/long cubes to determine the range if(ui.GetString("DEFAULTRANGE") == "COMPUTE") { //NOTE - When computing the min/max longitude this application does not account for the //longitude seam if it exists. Since the min/max are calculated from the statistics of //the input longitude cube and then converted to the mapping group's domain they may be //invalid for cubes containing the longitude seam. Statistics *latStats = latCube->Statistics(); Statistics *lonStats = lonCube->Statistics(); double minLat = latStats->Minimum(); double maxLat = latStats->Maximum(); bool isOcentric = ((std::string)mapGrp.FindKeyword("LatitudeType")) == "Planetocentric"; if(isOcentric) { if(ui.GetString("LATTYPE") != "PLANETOCENTRIC") { minLat = Projection::ToPlanetocentric(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetocentric(maxLat, (double)equRadius, (double)polRadius); } } else { if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { minLat = Projection::ToPlanetographic(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetographic(maxLat, (double)equRadius, (double)polRadius); } } int lonDomain = (int)mapGrp.FindKeyword("LongitudeDomain"); double minLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Minimum()) : Projection::To180Domain(lonStats->Minimum()); double maxLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Maximum()) : Projection::To180Domain(lonStats->Maximum()); bool isPosEast = ((std::string)mapGrp.FindKeyword("LongitudeDirection")) == "PositiveEast"; if(isPosEast) { if(ui.GetString("LONDIR") != "POSITIVEEAST") { minLon = Projection::ToPositiveEast(minLon, lonDomain); maxLon = Projection::ToPositiveEast(maxLon, lonDomain); } } else { if(ui.GetString("LONDIR") == "POSITIVEEAST") { minLon = Projection::ToPositiveWest(minLon, lonDomain); maxLon = Projection::ToPositiveWest(maxLon, lonDomain); } } if(minLon > maxLon) { double temp = minLon; minLon = maxLon; maxLon = temp; } mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", minLat),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", maxLat),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", minLon),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", maxLon),Pvl::Replace); } //If the user decided to enter a ground range then override if (ui.WasEntered("MINLAT")) { mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")),Pvl::Replace); } if (ui.WasEntered("MAXLAT")) { mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")),Pvl::Replace); } if (ui.WasEntered("MINLON")) { mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")),Pvl::Replace); } if (ui.WasEntered("MAXLON")) { mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")),Pvl::Replace); } //If the pixel resolution is to be computed, compute the pixels/degree from the input if (ui.GetString("PIXRES") == "COMPUTE") { latBrick.SetBasePosition(1,1,1); latCube->Read(latBrick); lonBrick.SetBasePosition(1,1,1); lonCube->Read(lonBrick); //Read the lat and long at the upper left corner double a = latBrick.at(0) * PI/180.0; double c = lonBrick.at(0) * PI/180.0; latBrick.SetBasePosition(latCube->Samples(),latCube->Lines(),1); latCube->Read(latBrick); lonBrick.SetBasePosition(lonCube->Samples(),lonCube->Lines(),1); lonCube->Read(lonBrick); //Read the lat and long at the lower right corner double b = latBrick.at(0) * PI/180.0; double d = lonBrick.at(0) * PI/180.0; //Determine the angle between the two points double angle = acos(cos(a) * cos(b) * cos(c - d) + sin(a) * sin(b)); //double angle = acos((cos(a1) * cos(b1) * cos(b2)) + (cos(a1) * sin(b1) * cos(a2) * sin(b2)) + (sin(a1) * sin(a2))); angle *= 180/PI; //Determine the number of pixels between the two points double pixels = sqrt(pow(latCube->Samples() -1.0, 2.0) + pow(latCube->Lines() -1.0, 2.0)); //Add the scale in pixels/degree to the mapping group mapGrp.AddKeyword(PvlKeyword("Scale", pixels/angle, "pixels/degree"), Pvl::Replace); if (mapGrp.HasKeyword("PixelResolution")) { mapGrp.DeleteKeyword("PixelResolution"); } } // If the user decided to enter a resolution then override if (ui.GetString("PIXRES") == "MPP") { mapGrp.AddKeyword(PvlKeyword("PixelResolution", ui.GetDouble("RESOLUTION"), "meters/pixel"), Pvl::Replace); if (mapGrp.HasKeyword("Scale")) { mapGrp.DeleteKeyword("Scale"); } } else if (ui.GetString("PIXRES") == "PPD") { mapGrp.AddKeyword(PvlKeyword("Scale", ui.GetDouble("RESOLUTION"), "pixels/degree"), Pvl::Replace); if (mapGrp.HasKeyword("PixelResolution")) { mapGrp.DeleteKeyword("PixelResolution"); } } //Create a projection using the map file we created int samples,lines; Projection *outmap = ProjectionFactory::CreateForCube(mapFile,samples,lines,false); //Write the map file to the log Application::GuiLog(mapGrp); //Create a process rubber sheet ProcessRubberSheet r; //Set the input cube inCube = r.SetInputCube("FROM"); double tolerance = ui.GetDouble("TOLERANCE") * outmap->Resolution(); //Create a new transform object Transform *transform = new nocam2map (sampSol, lineSol, outmap, latCube, lonCube, ui.GetString("LATTYPE") == "PLANETOCENTRIC", ui.GetString("LONDIR") == "POSITIVEEAST", tolerance, ui.GetInteger("ITERATIONS"), inCube->Samples(), inCube->Lines(), samples, lines); //Allocate the output cube and add the mapping labels Cube *oCube = r.SetOutputCube ("TO", transform->OutputSamples(), transform->OutputLines(), inCube->Bands()); oCube->PutGroup(mapGrp); //Determine which interpolation to use Interpolator *interp = NULL; if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { interp = new Interpolator(Interpolator::NearestNeighborType); } else if (ui.GetString("INTERP") == "BILINEAR") { interp = new Interpolator(Interpolator::BiLinearType); } else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { interp = new Interpolator(Interpolator::CubicConvolutionType); } //Warp the cube r.StartProcess(*transform, *interp); r.EndProcess(); // add mapping to print.prt PvlGroup mapping = outmap->Mapping(); Application::Log(mapping); //Clean up delete latCube; delete lonCube; delete outmap; delete transform; delete interp; } }