diff --git a/IGNMap/Builds/LinuxMakefile/Makefile b/IGNMap/Builds/LinuxMakefile/Makefile index 73209cc..1be589c 100644 --- a/IGNMap/Builds/LinuxMakefile/Makefile +++ b/IGNMap/Builds/LinuxMakefile/Makefile @@ -250,6 +250,7 @@ OBJECTS_APP := \ $(JUCE_OBJDIR)/DtmLayersViewer_98c8b452.o \ $(JUCE_OBJDIR)/DtmShader_bfa70483.o \ $(JUCE_OBJDIR)/ExportImageDlg_2dc44e1.o \ + $(JUCE_OBJDIR)/ExportLasDlg_f653953e.o \ $(JUCE_OBJDIR)/GeoBase_343e9923.o \ $(JUCE_OBJDIR)/ImageLayersViewer_843f60d0.o \ $(JUCE_OBJDIR)/ImageOptionsViewer_66bba7be.o \ @@ -1251,6 +1252,11 @@ $(JUCE_OBJDIR)/ExportImageDlg_2dc44e1.o: ../../Source/ExportImageDlg.cpp @echo "Compiling ExportImageDlg.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/ExportLasDlg_f653953e.o: ../../Source/ExportLasDlg.cpp + -$(V_AT)mkdir -p $(@D) + @echo "Compiling ExportLasDlg.cpp" + $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" + $(JUCE_OBJDIR)/GeoBase_343e9923.o: ../../Source/GeoBase.cpp -$(V_AT)mkdir -p $(@D) @echo "Compiling GeoBase.cpp" diff --git a/IGNMap/Builds/LinuxMakefile/build/IGNMap b/IGNMap/Builds/LinuxMakefile/build/IGNMap index ae54eba..3ed79c3 100644 Binary files a/IGNMap/Builds/LinuxMakefile/build/IGNMap and b/IGNMap/Builds/LinuxMakefile/build/IGNMap differ diff --git a/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj b/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj index cd0fecd..410e4d5 100644 --- a/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj +++ b/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj @@ -329,6 +329,7 @@ COPY ..\..\Images\*.* .\x64\Release\App\Images + @@ -1901,6 +1902,7 @@ COPY ..\..\Images\*.* .\x64\Release\App\Images + diff --git a/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj.filters b/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj.filters index 4b62cd9..109d6cd 100644 --- a/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj.filters +++ b/IGNMap/Builds/VisualStudio2022/IGNMap_App.vcxproj.filters @@ -847,6 +847,9 @@ IGNMap\Source + + IGNMap\Source + IGNMap\Source @@ -2952,6 +2955,9 @@ IGNMap\Source + + IGNMap\Source + IGNMap\Source diff --git a/IGNMap/Builds/VisualStudio2022/icon.ico b/IGNMap/Builds/VisualStudio2022/icon.ico new file mode 100644 index 0000000..3b9d052 Binary files /dev/null and b/IGNMap/Builds/VisualStudio2022/icon.ico differ diff --git a/IGNMap/Builds/VisualStudio2022/x64/Release/App/IGNMap.exe b/IGNMap/Builds/VisualStudio2022/x64/Release/App/IGNMap.exe index 4e84728..e3f9d5d 100644 Binary files a/IGNMap/Builds/VisualStudio2022/x64/Release/App/IGNMap.exe and b/IGNMap/Builds/VisualStudio2022/x64/Release/App/IGNMap.exe differ diff --git a/IGNMap/IGNMap.jucer b/IGNMap/IGNMap.jucer index c635d6e..8bcbbf2 100644 --- a/IGNMap/IGNMap.jucer +++ b/IGNMap/IGNMap.jucer @@ -434,6 +434,9 @@ file="Source/ExportImageDlg.cpp"/> + + file_source_ID = 0; + m_Header->global_encoding = (1 << 0) | (1 << 4); // see LAS specification for details + m_Header->version_major = 1; + m_Header->version_minor = 4; + strncpy(m_Header->system_identifier, "Export LAS IGNMap", 32); + strncpy(m_Header->generating_software, "IGNMap v3", 32); + juce::Time time = juce::Time::getCurrentTime(); + m_Header->file_creation_day = time.getDayOfYear(); + m_Header->file_creation_year = time.getYear(); + m_Header->header_size = 375; + m_Header->offset_to_point_data = 375; + m_Header->point_data_format = 6; + m_Header->point_data_record_length = 30; + m_Header->number_of_point_records = 0; // legacy 32-bit counters should be zero for new point types > 5 + for (int i = 0; i < 5; i++) { + m_Header->number_of_points_by_return[i] = 0; // legacy 32-bit counters should be zero for new point types > 5 + } + m_Header->extended_number_of_point_records = 0; // a-priori unknown number of points + for (int i = 0; i < 15; i++) { + m_Header->extended_number_of_points_by_return[i] = 0; + } + m_Header->max_x = 0.0; // a-priori unknown bounding box + m_Header->min_x = 0.0; + m_Header->max_y = 0.0; + m_Header->min_y = 0.0; + m_Header->max_z = 0.0; + m_Header->min_z = 0.0; + + // Ajout de la projection + laszip_geokey_struct key_entries[5]; + + // projected coordinates + key_entries[0].key_id = 1024; // GTModelTypeGeoKey + key_entries[0].tiff_tag_location = 0; + key_entries[0].count = 1; + key_entries[0].value_offset = 1; // ModelTypeProjected + + // projection + key_entries[1].key_id = 3072; // ProjectedCSTypeGeoKey + key_entries[1].tiff_tag_location = 0; + key_entries[1].count = 1; + key_entries[1].value_offset = 2154; // Lambert 93 + + // horizontal units + key_entries[2].key_id = 3076; // ProjLinearUnitsGeoKey + key_entries[2].tiff_tag_location = 0; + key_entries[2].count = 1; + key_entries[2].value_offset = 9001; // meters + + // vertical units + key_entries[3].key_id = 4099; // VerticalUnitsGeoKey + key_entries[3].tiff_tag_location = 0; + key_entries[3].count = 1; + key_entries[3].value_offset = 9001; // meters + + // vertical datum + key_entries[4].key_id = 4096; // VerticalCSTypeGeoKey + key_entries[4].tiff_tag_location = 0; + key_entries[4].count = 1; + key_entries[4].value_offset = 5720; // IGN69 + + // add the geokeys (create or replace the appropriate VLR) + if (laszip_set_geokeys(m_Writer, 5, key_entries)) + return; + /* + if (laszip_add_vlr(m_Writer, "LASF_Projection", 2112, 0, "intentionally empty OGC WKT", 0)) + return; + if (laszip_add_vlr(m_Writer, "funny", 12345, 0, "just a funny VLR", 0)) + return;*/ + + laszip_BOOL compress = 0; + if (m_Compression) { + //laszip_BOOL request = 1; + //if (laszip_request_compatibility_mode(m_Writer, request)) + // return; + compress = 1; + } + + laszip_preserve_generating_software(m_Writer, 1); + if (laszip_open_writer(m_Writer, m_Filename.toStdString().c_str(), compress)) // Ouverture du Writer + return; + + // Pointeur pour ecrire les points + if (laszip_get_point_pointer(m_Writer, &m_Point)) + return; + + // Ecriture des points + m_Count = 0; + + for (uint32_t i = 0; i < m_GeoBase->NbClass(); i++) { + XGeoClass* C = m_GeoBase->Class(i); + if (C == nullptr) + continue; + if (!C->IsLAS()) + continue; + if (!C->Visible()) + continue; + if (!m_Frame.Intersect(C->Frame())) + continue; + + for (uint32_t j = 0; j < C->NbVector(); j++) { + GeoLAS* las = (GeoLAS*)C->Vector(j); + XFrame F = las->Frame(); + if (!m_Frame.Intersect(F)) + continue; + ExportLas(las); + if (threadShouldExit()) + return; + } + } + + // Fermeture du Writer + if (laszip_get_point_count(m_Writer, &m_Count)) + return; + + if (laszip_close_writer(m_Writer)) + return; + + if (laszip_destroy(m_Writer)) + return; + + +} + +//============================================================================== +// Export d'un fichier LAS +//============================================================================== +void LasExportThread::ExportLas(GeoLAS* las) +{ + laszip_I64 npoints = las->NbLasPoints(); + laszip_POINTER reader = las->GetReader(); + laszip_header* header = las->GetHeader(); + laszip_point* point = las->GetPoint(); + + laszip_seek_point(reader, 0); + double Xmin = (m_Frame.Xmin - header->x_offset) / header->x_scale_factor; + double Xmax = (m_Frame.Xmax - header->x_offset) / header->x_scale_factor; + double Ymin = (m_Frame.Ymin - header->y_offset) / header->y_scale_factor; + double Ymax = (m_Frame.Ymax - header->y_offset) / header->y_scale_factor; + double Zmin = (LasShader::Zmin() - header->z_offset) / header->z_scale_factor; + double Zmax = (LasShader::Zmax() - header->z_offset) / header->z_scale_factor; + + uint8_t classification; + bool classif_newtype = true; + if (header->version_minor < 4) classif_newtype = false; + LasShader shader; + laszip_F64 coordinates[3]; + for (laszip_I64 i = 0; i < npoints; i++) { + laszip_read_point(reader); + if (classif_newtype) + classification = point->extended_classification; + else + classification = point->classification; + if (!shader.ClassificationVisibility(classification)) continue; + if (point->X <= Xmin) continue; + if (point->X >= Xmax) continue; + if (point->Y <= Ymin) continue; + if (point->Y >= Ymax) continue; + if (point->Z < Zmin) continue; + if (point->Z > Zmax) continue; + + coordinates[0] = point->X * header->x_scale_factor + header->x_offset; + coordinates[1] = point->Y * header->y_scale_factor + header->y_offset; + coordinates[2] = point->Z * header->z_scale_factor + header->z_offset; + if (laszip_set_coordinates(m_Writer, coordinates)) + return; + + m_Point->intensity = point->intensity; + m_Point->extended_return_number = point->extended_return_number; + m_Point->extended_number_of_returns = point->extended_number_of_returns; + m_Point->classification = point->classification; // it must be set because it "fits" in 5 bits + m_Point->extended_classification = point->extended_classification; + m_Point->extended_scan_angle = point->extended_scan_angle; + m_Point->extended_scanner_channel = point->extended_scanner_channel; + m_Point->extended_classification_flags = point->extended_classification_flags; // overflag flag is set + m_Point->gps_time = point->gps_time; + + if (laszip_write_point(m_Writer)) + return; + if (laszip_update_inventory(m_Writer)) + return; + m_Count++; + } +} + + +//============================================================================== +// Constructeur +//============================================================================== +ExportLasDlg::ExportLasDlg(XGeoBase* base, double xmin, double ymin, double xmax, + double ymax) : m_ExportThread("ExportThread") +{ + m_Base = base; + + addAndMakeVisible(m_lblXmin); + m_lblXmin.setBounds(10, 50, 50, 24); + m_lblXmin.setText(juce::translate("Xmin : "), juce::NotificationType::dontSendNotification); + addAndMakeVisible(m_edtXmin); + m_edtXmin.setBounds(60, 50, 100, 24); + m_edtXmin.setText(juce::String(xmin, 2)); + + addAndMakeVisible(m_lblXmax); + m_lblXmax.setBounds(350, 50, 50, 24); + m_lblXmax.setText(juce::translate(" : Xmax"), juce::NotificationType::dontSendNotification); + addAndMakeVisible(m_edtXmax); + m_edtXmax.setBounds(240, 50, 100, 24); + m_edtXmax.setText(juce::String(xmax, 2)); + + addAndMakeVisible(m_lblYmax); + m_lblYmax.setBounds(100, 10, 50, 24); + m_lblYmax.setText(juce::translate("Ymax : "), juce::NotificationType::dontSendNotification); + addAndMakeVisible(m_edtYmax); + m_edtYmax.setBounds(150, 10, 100, 24); + m_edtYmax.setText(juce::String(ymax, 2)); + + addAndMakeVisible(m_lblYmin); + m_lblYmin.setBounds(260, 90, 50, 24); + m_lblYmin.setText(juce::translate(" : Ymin"), juce::NotificationType::dontSendNotification); + addAndMakeVisible(m_edtYmin); + m_edtYmin.setBounds(150, 90, 100, 24); + m_edtYmin.setText(juce::String(ymin, 2)); + + addAndMakeVisible(m_btnLaz); + m_btnLaz.setButtonText(juce::translate("LAZ Compression")); + m_btnLaz.setBounds(140, 130, 120, 24); + + addAndMakeVisible(m_btnExport); + m_btnExport.setButtonText(juce::translate("Export")); + m_btnExport.setBounds(160, 170, 80, 30); + m_btnExport.addListener(this); + + m_progressBar = new juce::ProgressBar(m_dProgress); + addAndMakeVisible(m_progressBar); + m_progressBar->setBounds(100, 210, 200, 30); + + addAndMakeVisible(m_edtFilename); + m_edtFilename.setBounds(10, 260, 380, 24); + m_edtFilename.setText(""); + m_edtFilename.setReadOnly(true); +} + +//============================================================================== +// Destructeur +//============================================================================== +ExportLasDlg::~ExportLasDlg() +{ + delete m_progressBar; + stopTimer(); + m_ExportThread.stopThread(5000); +} + +//============================================================================== +// Validation de l'export +//============================================================================== +void ExportLasDlg::buttonClicked(juce::Button* button) +{ + if (button != &m_btnExport) + return; + if (m_Base == nullptr) + return; + if (m_btnExport.getButtonText() == juce::translate("Cancel")) { // Annulation + stopTimer(); + m_ExportThread.signalThreadShouldExit(); + if (m_ExportThread.isThreadRunning()) + m_ExportThread.stopThread(-1); + m_dProgress = 0.; + m_btnExport.setButtonText(juce::translate("Export")); + juce::File file(m_strFilename); + file.deleteFile(); + return; + } + + m_btnExport.setButtonText(juce::translate("Cancel")); + + m_strFilename = m_edtFilename.getText(); + m_Frame.Xmin = m_edtXmin.getText().getDoubleValue(); + m_Frame.Xmax = m_edtXmax.getText().getDoubleValue(); + m_Frame.Ymin = m_edtYmin.getText().getDoubleValue(); + m_Frame.Ymax = m_edtYmax.getText().getDoubleValue(); + + m_dProgress = 0.; + + // Creation du fichier LAS + juce::String ext = "*.las"; + if (m_btnLaz.getToggleState()) + ext = "*.laz"; + m_strFilename = AppUtil::SaveFile("ExportLasFile", juce::translate("File to save"), ext); + if (m_strFilename.isEmpty()) + return; + + m_ExportThread.signalThreadShouldExit(); + if (m_ExportThread.isThreadRunning()) { + if (!m_ExportThread.stopThread(-1)) + return; + } + + // Lancement du thread d'export + m_ExportThread.SetGeoBase(m_Base); + m_ExportThread.SetExportFrame(m_Frame); + m_ExportThread.SetFilename(m_strFilename); + if (m_btnLaz.getToggleState()) + m_ExportThread.SetCompression(true); + m_ExportThread.startThread(); + + startTimerHz(10); +} + +//============================================================================== +// Callback du Timer +//============================================================================== +void ExportLasDlg::timerCallback() +{ + if (m_ExportThread.isThreadRunning()) { + m_dProgress++; + return; + } + m_dProgress = 1.; + stopTimer(); + m_btnExport.setButtonText(juce::translate("Export")); + juce::File file(m_strFilename); + file.revealToUser(); + juce::Component* parent = getParentComponent(); + if (parent != nullptr) + delete parent; + return; +} \ No newline at end of file diff --git a/IGNMap/Source/ExportLasDlg.h b/IGNMap/Source/ExportLasDlg.h new file mode 100644 index 0000000..60feefe --- /dev/null +++ b/IGNMap/Source/ExportLasDlg.h @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// ExportLasDlg.h +// ============== +// +// Dialogue d'options pour exporter les fichiers LAS/LAZ +// +// Auteur : F.Becirspahic - IGN / DSI / SIMV +// License : GNU AFFERO GENERAL PUBLIC LICENSE v3 +// Date de creation : 25/02/2024 +//----------------------------------------------------------------------------- + +#pragma once +#include +#include "GeoBase.h" + +class XGeoBase; + +//============================================================================== +// Thread pour l'export +//============================================================================== +class LasExportThread : public juce::Thread { +public: + LasExportThread(const juce::String& threadName, size_t threadStackSize = 0) : juce::Thread(threadName, threadStackSize) { m_GeoBase = nullptr; } + virtual ~LasExportThread() { ; } + + void SetExportFrame(const XFrame& F) { m_Frame = F; } + void SetGeoBase(XGeoBase* base) { m_GeoBase = base; } + void SetFilename(juce::String name) { m_Filename = name; } + void SetCompression(bool compression) { m_Compression = compression; } + + virtual void run() override; + +private: + XGeoBase* m_GeoBase; + XFrame m_Frame; // Cadre pour l'export + juce::String m_Filename; + bool m_Compression = false; + laszip_POINTER m_Writer = nullptr; + laszip_header* m_Header = nullptr; + laszip_point* m_Point = nullptr; + laszip_I64 m_Count = 0; + + void ExportLas(GeoLAS* las); +}; + +//============================================================================== +// Dialogue pour l'export +//============================================================================== +class ExportLasDlg : public juce::Component, public juce::Button::Listener, private juce::Timer { +public: + ExportLasDlg(XGeoBase* base, double xmin = 0., double ymin = 0., double xmax = 0., double ymax = 0.); + virtual ~ExportLasDlg(); + void buttonClicked(juce::Button*) override; + +private: + XGeoBase* m_Base; + juce::TextEditor m_edtXmin, m_edtYmin, m_edtXmax, m_edtYmax, m_edtFilename; + juce::Label m_lblXmin, m_lblYmin, m_lblXmax, m_lblYmax; + juce::TextButton m_btnExport; + juce::ToggleButton m_btnLaz; + + LasExportThread m_ExportThread; + juce::String m_strFilename; + XFrame m_Frame; + double m_dProgress = 0.; + juce::ProgressBar* m_progressBar; + + void timerCallback() override; +}; \ No newline at end of file diff --git a/IGNMap/Source/MainComponent.cpp b/IGNMap/Source/MainComponent.cpp index 9a5e0f8..7b59a8d 100644 --- a/IGNMap/Source/MainComponent.cpp +++ b/IGNMap/Source/MainComponent.cpp @@ -14,6 +14,7 @@ #include "OsmLayer.h" #include "WmtsLayer.h" #include "ExportImageDlg.h" +#include "ExportLasDlg.h" #include "../../XToolGeod/XGeoPref.h" #include "../../XToolImage/XTiffWriter.h" @@ -195,6 +196,7 @@ juce::PopupMenu MainComponent::getMenuForIndex(int menuIndex, const juce::String juce::PopupMenu ExportSubMenu; ExportSubMenu.addCommandItem(&m_CommandManager, CommandIDs::menuExportImage); + ExportSubMenu.addCommandItem(&m_CommandManager, CommandIDs::menuExportLas); menu.addSubMenu(juce::translate("Export"), ExportSubMenu); menu.addCommandItem(&m_CommandManager, CommandIDs::menuQuit); @@ -261,7 +263,7 @@ void MainComponent::getAllCommands(juce::Array& c) CommandIDs::menuImportVectorFile, CommandIDs::menuImportVectorFolder, CommandIDs::menuImportImageFile, CommandIDs::menuImportImageFolder, CommandIDs::menuImportDtmFile, CommandIDs::menuImportDtmFolder, CommandIDs::menuImportLasFile, CommandIDs::menuImportLasFolder, - CommandIDs::menuExportImage, + CommandIDs::menuExportImage, CommandIDs::menuExportLas, CommandIDs::menuZoomTotal, CommandIDs::menuZoomLevel, CommandIDs::menuTest, CommandIDs::menuShowSidePanel, CommandIDs::menuShowVectorLayers, CommandIDs::menuShowImageLayers, CommandIDs::menuShowDtmLayers, @@ -352,6 +354,9 @@ void MainComponent::getCommandInfo(juce::CommandID commandID, juce::ApplicationC case CommandIDs::menuExportImage: result.setInfo(juce::translate("Export image"), juce::translate("Export image"), "Menu", 0); break; + case CommandIDs::menuExportLas: + result.setInfo(juce::translate("Export LAS"), juce::translate("Export LAS"), "Menu", 0); + break; case CommandIDs::menuZoomTotal: result.setInfo(juce::translate("Zoom total"), juce::translate("Zoom total"), "Menu", 0); break; @@ -501,6 +506,9 @@ bool MainComponent::perform(const InvocationInfo& info) case CommandIDs::menuExportImage: ExportImage(); break; + case CommandIDs::menuExportLas: + ExportLas(); + break; case CommandIDs::menuZoomTotal: m_MapView.get()->ZoomWorld(); break; @@ -747,8 +755,8 @@ void MainComponent::NewWindow() //============================================================================== void MainComponent::AboutIGNMap() { - juce::String version = "0.0.2"; - juce::String info = "18/02/2024"; + juce::String version = "0.0.3"; + juce::String info = "28/02/2024"; juce::String message = "IGNMap 3 Version : " + version + "\n" + info + "\n"; message += "JUCE Version : " + juce::String(JUCE_MAJOR_VERSION) + "." + juce::String(JUCE_MINOR_VERSION) + "." + juce::String(JUCE_BUILDNUMBER); @@ -1011,7 +1019,7 @@ void MainComponent::ImportLasFolder() juce::String folderName = AppUtil::OpenFolder("LasFolderPath"); if (folderName.isEmpty()) return; - XGeoClass* C = ImportDataFolder(folderName, XGeoVector::LAS); + ImportDataFolder(folderName, XGeoVector::LAS); m_LasViewer.get()->SetBase(&m_GeoBase); m_MapView.get()->RenderMap(false, false, false, false, true, true); } @@ -1121,6 +1129,7 @@ bool MainComponent::AddWmtsServer(std::string server, std::string layer, std::st //============================================================================== bool MainComponent::ExportImage() { + m_MapView.get()->StopThread(); XFrame F = m_MapView.get()->GetSelectionFrame(); double gsd = m_MapView.get()->GetGsd(); ExportImageDlg* dlg = new ExportImageDlg(&m_GeoBase, XRint(F.Xmin), XRint(F.Ymin), XRint(F.Xmax), XRint(F.Ymax), XRint(gsd)); @@ -1140,6 +1149,31 @@ bool MainComponent::ExportImage() return true; } +//============================================================================== +// Export sous forme d'un nuage de points LAS +//============================================================================== +bool MainComponent::ExportLas() +{ + m_MapView.get()->StopThread(); + XFrame F = m_MapView.get()->GetSelectionFrame(); + double gsd = m_MapView.get()->GetGsd(); + ExportLasDlg* dlg = new ExportLasDlg(&m_GeoBase, XRint(F.Xmin), XRint(F.Ymin), XRint(F.Xmax), XRint(F.Ymax)); + juce::DialogWindow::LaunchOptions options; + options.content.setOwned(dlg); + + juce::Rectangle area(0, 0, 410, 300); + + options.content->setSize(area.getWidth(), area.getHeight()); + options.dialogTitle = juce::translate("Export LAS"); + options.dialogBackgroundColour = juce::Colour(0xff0e345a); + options.escapeKeyTriggersCloseButton = true; + options.useNativeTitleBar = false; + options.resizable = false; + + options.runModal(); + return true; +} + //============================================================================== // Chargement d'un fichier de traduction //============================================================================== diff --git a/IGNMap/Source/MainComponent.h b/IGNMap/Source/MainComponent.h index a39ee4c..6e8ba26 100644 --- a/IGNMap/Source/MainComponent.h +++ b/IGNMap/Source/MainComponent.h @@ -47,9 +47,9 @@ class MainComponent : public juce::Component, menuNew = 1, menuQuit, menuUndo, menuTranslate, menuTest, - menuImportVectorFolder, menuImportVectorFile, menuImportImageFolder, menuImportImageFile, + menuImportVectorFolder, menuImportVectorFile, menuImportImageFolder, menuImportImageFile, menuImportDtmFolder, menuImportDtmFile, menuImportLasFile, menuImportLasFolder, - menuExportImage, + menuExportImage, menuExportLas, menuZoomTotal, menuZoomLevel, menuScale1k, menuScale10k, menuScale25k, menuScale100k, menuScale250k, menuShowSidePanel, menuShow3DViewer, @@ -129,6 +129,7 @@ class MainComponent : public juce::Component, bool ImportLasFile(juce::String lasfile = ""); bool ExportImage(); + bool ExportLas(); bool AddOSMServer(); bool AddWmtsServer(); diff --git a/IGNMap/Source/MapThread.cpp b/IGNMap/Source/MapThread.cpp index 3c3e9fd..d078064 100644 --- a/IGNMap/Source/MapThread.cpp +++ b/IGNMap/Source/MapThread.cpp @@ -815,7 +815,7 @@ bool MapThread::DrawLas(GeoLAS* las) int W = (int)round(F.Width() / m_dGsd); int H = (int)round(F.Height() / m_dGsd); juce::Graphics g(m_Las); - g.setColour(juce::Colours::mediumvioletred); + g.setColour(juce::Colours::lightpink); g.fillRect((int)floor((F.Xmin - m_dX0) / m_dGsd), (int)floor((m_dY0 - F.Ymax) / m_dGsd), W, H); m_nNumObjects++; return true; diff --git a/XToolAlgo/XLasFile.cpp b/XToolAlgo/XLasFile.cpp index 483cec0..c654829 100644 --- a/XToolAlgo/XLasFile.cpp +++ b/XToolAlgo/XLasFile.cpp @@ -22,17 +22,18 @@ bool XLasFile::Open(std::string filename) m_strFilename = ""; if (laszip_create(&m_Reader)) return false; - laszip_BOOL compress; + laszip_BOOL compress = 0; if (laszip_open_reader(m_Reader, filename.c_str(), &compress)) { laszip_destroy(m_Reader); + m_Reader = nullptr; return false; } if (laszip_get_header_pointer(m_Reader, &m_Header)) { - laszip_destroy(m_Reader); + Close(); return false; } if (laszip_get_point_pointer(m_Reader, &m_Point)) { - laszip_destroy(m_Reader); + Close(); return false; } @@ -50,6 +51,9 @@ bool XLasFile::Close() laszip_close_reader(m_Reader); laszip_destroy(m_Reader); } + m_Reader = nullptr; + m_Header = nullptr; + m_Point = nullptr; m_strFilename = ""; return true; }