CC中有两个地方使用了文件保存,一个是MainWindow,另一个是ccCommandLineParser。
MainWindow的保存按钮关联的槽是doActionSaveFile()方法,实现了点云和Mesh的保存。
1 void MainWindow::doActionSaveFile() 2 { 3 size_t selNum = m_selectedEntities.size(); 4 if (selNum == 0) 5 return; 6 7 ccHObject clouds("clouds"); 8 ccHObject meshes("meshes"); 9 ccHObject images("images"); 10 ccHObject polylines("polylines"); 11 ccHObject other("other"); 12 ccHObject otherSerializable("serializable"); 13 ccHObject::Container entitiesToDispatch; 14 entitiesToDispatch.insert(entitiesToDispatch.begin(),m_selectedEntities.begin(),m_selectedEntities.end()); 15 ccHObject entitiesToSave; 16 while (!entitiesToDispatch.empty()) 17 { 18 ccHObject* child = entitiesToDispatch.back(); 19 entitiesToDispatch.pop_back(); 20 21 if (child->isA(CC_TYPES::HIERARCHY_OBJECT)) 22 { 23 for (unsigned j=0; j<child->getChildrenNumber(); ++j) 24 entitiesToDispatch.push_back(child->getChild(j)); 25 } 26 else 27 { 28 //we put the entity in the container corresponding to its type 29 ccHObject* dest = 0; 30 if (child->isA(CC_TYPES::POINT_CLOUD)) 31 dest = &clouds; 32 else if (child->isKindOf(CC_TYPES::MESH)) 33 dest = &meshes; 34 else if (child->isKindOf(CC_TYPES::IMAGE)) 35 dest = &images; 36 else if (child->isKindOf(CC_TYPES::POLY_LINE)) 37 dest = &polylines; 38 else if (child->isSerializable()) 39 dest = &otherSerializable; 40 else 41 dest = &other; 42 43 assert(dest); 44 45 //we don't want double insertions if the user has clicked both the father and child 46 if (!dest->find(child->getUniqueID())) 47 { 48 dest->addChild(child,ccHObject::DP_NONE); 49 entitiesToSave.addChild(child,ccHObject::DP_NONE); 50 } 51 } 52 } 53 54 bool hasCloud = (clouds.getChildrenNumber() != 0); 55 bool hasMesh = (meshes.getChildrenNumber() != 0); 56 bool hasImages = (images.getChildrenNumber() != 0); 57 bool hasPolylines = (polylines.getChildrenNumber() != 0); 58 bool hasSerializable = (otherSerializable.getChildrenNumber() != 0); 59 bool hasOther = (other.getChildrenNumber() != 0); 60 61 int stdSaveTypes = static_cast<int>(hasCloud) 62 + static_cast<int>(hasMesh) 63 + static_cast<int>(hasImages) 64 + static_cast<int>(hasPolylines) 65 + static_cast<int>(hasSerializable); 66 if (stdSaveTypes == 0) 67 { 68 ccConsole::Error("Can't save selected entity(ies) this way!"); 69 return; 70 } 71 72 //we set up the right file filters, depending on the selected 73 //entities type (cloud, mesh, etc.). 74 QStringList fileFilters; 75 { 76 const FileIOFilter::FilterContainer& filters = FileIOFilter::GetFilters(); 77 for (size_t i=0; i<filters.size(); ++i) 78 { 79 bool atLeastOneExclusive = false; 80 81 //current I/O filter 82 const FileIOFilter::Shared filter = filters[i]; 83 84 //does this filter can export one or several clouds? 85 bool canExportClouds = true; 86 if (hasCloud) 87 { 88 bool isExclusive = true; 89 bool multiple = false; 90 canExportClouds = ( filter->canSave(CC_TYPES::POINT_CLOUD,multiple,isExclusive) 91 && (multiple || clouds.getChildrenNumber() == 1) ); 92 atLeastOneExclusive |= isExclusive; 93 } 94 95 //does this filter can export one or several meshes? 96 bool canExportMeshes = true; 97 if (hasMesh) 98 { 99 bool isExclusive = true; 100 bool multiple = false; 101 canExportMeshes = ( filter->canSave(CC_TYPES::MESH,multiple,isExclusive) 102 && (multiple || meshes.getChildrenNumber() == 1) ); 103 atLeastOneExclusive |= isExclusive; 104 } 105 106 //does this filter can export one or several polylines? 107 bool canExportPolylines = true; 108 if (hasPolylines) 109 { 110 bool isExclusive = true; 111 bool multiple = false; 112 canExportPolylines = ( filter->canSave(CC_TYPES::POLY_LINE,multiple,isExclusive) 113 && (multiple || polylines.getChildrenNumber() == 1) ); 114 atLeastOneExclusive |= isExclusive; 115 } 116 117 //does this filter can export one or several images? 118 bool canExportImages = true; 119 if (hasImages) 120 { 121 bool isExclusive = true; 122 bool multiple = false; 123 canExportImages = ( filter->canSave(CC_TYPES::IMAGE,multiple,isExclusive) 124 && (multiple || images.getChildrenNumber() == 1) ); 125 atLeastOneExclusive |= isExclusive; 126 } 127 128 //does this filter can export one or several other serializable entities? 129 bool canExportSerializables = true; 130 if (hasSerializable) 131 { 132 //check if all entities have the same type 133 { 134 CC_CLASS_ENUM firstClassID = otherSerializable.getChild(0)->getUniqueID(); 135 for (unsigned j=1; j<otherSerializable.getChildrenNumber(); ++j) 136 { 137 if (otherSerializable.getChild(j)->getUniqueID() != firstClassID) 138 { 139 //we add a virtual second 'stdSaveType' so as to properly handle exlusivity 140 ++stdSaveTypes; 141 break; 142 } 143 } 144 } 145 146 for (unsigned j=0; j<otherSerializable.getChildrenNumber(); ++j) 147 { 148 ccHObject* child = otherSerializable.getChild(j); 149 bool isExclusive = true; 150 bool multiple = false; 151 canExportSerializables &= ( filter->canSave(child->getUniqueID(),multiple,isExclusive) 152 && (multiple || otherSerializable.getChildrenNumber() == 1) ); 153 atLeastOneExclusive |= isExclusive; 154 } 155 } 156 157 bool useThisFilter = canExportClouds 158 && canExportMeshes 159 && canExportImages 160 && canExportPolylines 161 && canExportSerializables 162 && (!atLeastOneExclusive || stdSaveTypes == 1); 163 164 if (useThisFilter) 165 { 166 QStringList ff = filter->getFileFilters(false); 167 for (int j=0; j<ff.size(); ++j) 168 fileFilters.append(ff[j]); 169 } 170 } 171 } 172 173 //persistent settings 174 QSettings settings; 175 settings.beginGroup(ccPS::SaveFile()); 176 177 //default filter 178 QString selectedFilter = fileFilters.first(); 179 if (hasCloud) 180 selectedFilter = settings.value(ccPS::SelectedOutputFilterCloud(),selectedFilter).toString(); 181 else if (hasMesh) 182 selectedFilter = settings.value(ccPS::SelectedOutputFilterMesh(), selectedFilter).toString(); 183 else if (hasImages) 184 selectedFilter = settings.value(ccPS::SelectedOutputFilterImage(), selectedFilter).toString(); 185 else if (hasPolylines) 186 selectedFilter = settings.value(ccPS::SelectedOutputFilterPoly(), selectedFilter).toString(); 187 188 //default output path (+ filename) 189 QString currentPath = settings.value(ccPS::CurrentPath(),QApplication::applicationDirPath()).toString(); 190 QString fullPathName = currentPath; 191 if (selNum == 1) 192 { 193 //hierarchy objects have generally as name: 'filename.ext (fullpath)' 194 //so we must only take the first part! (otherwise this type of name 195 //with a path inside perturbs the QFileDialog a lot ;)) 196 QString defaultFileName(m_selectedEntities.front()->getName()); 197 if (m_selectedEntities.front()->isA(CC_TYPES::HIERARCHY_OBJECT)) 198 { 199 QStringList parts = defaultFileName.split(' ',QString::SkipEmptyParts); 200 if (parts.size() > 0) 201 defaultFileName = parts[0]; 202 } 203 204 //we remove the extension 205 defaultFileName = QFileInfo(defaultFileName).baseName(); 206 207 if (!IsValidFileName(defaultFileName)) 208 { 209 ccLog::Warning("[I/O] First entity's name would make an invalid filename! Can't use it..."); 210 defaultFileName = "project"; 211 } 212 213 fullPathName += QString("/") + defaultFileName; 214 } 215 216 //ask the user for the output filename 217 QString selectedFilename = QFileDialog::getSaveFileName(this, 218 "Save file", 219 fullPathName, 220 fileFilters.join(s_fileFilterSeparator), 221 &selectedFilter); 222 223 if (selectedFilename.isEmpty()) 224 { 225 //process cancelled by the user 226 return; 227 } 228 229 //ignored items 230 if (hasOther) 231 { 232 ccConsole::Warning("[I/O] The following selected entites won't be saved:"); 233 for (unsigned i=0; i<other.getChildrenNumber(); ++i) 234 ccConsole::Warning(QString("\t- %1s").arg(other.getChild(i)->getName())); 235 } 236 237 CC_FILE_ERROR result = CC_FERR_NO_ERROR; 238 FileIOFilter::SaveParameters parameters; 239 { 240 parameters.alwaysDisplaySaveDialog = true; 241 parameters.parentWidget = this; 242 } 243 244 //specific case: BIN format 245 if (selectedFilter == BinFilter::GetFileFilter()) 246 { 247 if (selNum == 1) 248 { 249 result = FileIOFilter::SaveToFile(m_selectedEntities.front(),selectedFilename,parameters,selectedFilter); 250 } 251 else 252 { 253 //we'll regroup all selected entities in a temporary group 254 ccHObject tempContainer; 255 ConvertToGroup(m_selectedEntities,tempContainer,ccHObject::DP_NONE); 256 if (tempContainer.getChildrenNumber()) 257 { 258 result = FileIOFilter::SaveToFile(&tempContainer,selectedFilename,parameters,selectedFilter); 259 } 260 else 261 { 262 ccLog::Warning("[I/O] None of the selected entities can be saved this way..."); 263 result = CC_FERR_NO_SAVE; 264 } 265 } 266 } 267 else if (entitiesToSave.getChildrenNumber() != 0) 268 { 269 //ignored items 270 /*if (hasSerializable) 271 { 272 if (!hasOther) 273 ccConsole::Warning("[I/O] The following selected entites won't be saved:"); //display this warning only if not already done 274 for (unsigned i=0; i<otherSerializable.getChildrenNumber(); ++i) 275 ccConsole::Warning(QString("\t- %1").arg(otherSerializable.getChild(i)->getName())); 276 } 277 //*/ 278 279 result = FileIOFilter::SaveToFile( entitiesToSave.getChildrenNumber() > 1 ? &entitiesToSave : entitiesToSave.getChild(0), 280 selectedFilename, 281 parameters, 282 selectedFilter); 283 } 284 285 //update default filters 286 if (hasCloud) 287 settings.setValue(ccPS::SelectedOutputFilterCloud(),selectedFilter); 288 if (hasMesh) 289 settings.setValue(ccPS::SelectedOutputFilterMesh(), selectedFilter); 290 if (hasImages) 291 settings.setValue(ccPS::SelectedOutputFilterImage(),selectedFilter); 292 if (hasPolylines) 293 settings.setValue(ccPS::SelectedOutputFilterPoly(), selectedFilter); 294 295 //we update current file path 296 currentPath = QFileInfo(selectedFilename).absolutePath(); 297 settings.setValue(ccPS::CurrentPath(),currentPath); 298 settings.endGroup(); 299 }