Hello community,
with my ObjectARX application, I'd like to update the path of a point cloud reference (RCS) and reload the view to reflect this change.
I got the right object from the ACAD_POINTCLOUD_EX_DICT dictionary, and tried to update its file name by calling AcDbPointCloudDefEx::setSourceFileName() and AcDbPointCloudDefEx::setActiveFileName().
However, the view in the XREF manager did not refresh entirely. The path under "Saved Path" is correct, but the property "Found At" still points to the old location. Please see the attached screenshot which illustrates this problem.
This is the code I used to update the file path:
AcDbDictionary* pNamedObjectsDictionary = nullptr; Acad::ErrorStatus es = pDb->getNamedObjectsDictionary(pNamedObjectsDictionary, AcDb::kForRead); AcDbDictionary* pPointCloudsDictionary = nullptr; es = pNamedObjectsDictionary->getAt(_T("ACAD_POINTCLOUD_EX_DICT"), (AcDbObject*&)pPointCloudsDictionary, AcDb::kForRead); AcDbDictionaryIterator* pIt = pPointCloudsDictionary->newIterator(); for (; !pIt->done(); pIt->next()) { AcDbPointCloudDefEx* pPointCloudDef = nullptr; es = acdbOpenObject(pPointCloudDef, pIt->objectId(), AcDb::kForWrite); const TCHAR* pSourceFile = pPointCloudDef->sourceFileName(); const TCHAR* pActiveFileName = pPointCloudDef->activeFileName();
/* Check pSourceFile if we got the desired file omitted.
Please assume we found the right file. */ // now update the path pPointCloudDef->setSourceFileName(strNewFileName); pPointCloudDef->setActiveFileName(strNewFileName); }
(Various checks and error handling have been omitted due to readability)
Is there any way, I can force reload both paths programmatically? I have already tried to "reload" the point cloud with AcDbPointCloudDefEx::unload() and AcDbPointCloudDefEx::load(), but the result did not change.
It would be nice if someone could give me a hint.
Kind regards,
Bettina
Solved! Go to Solution.
Solved by thierry_prince. Go to Solution.
Solved by thierry_prince. Go to Solution.
Hi Bettina,
When you tried AcDbPointCloudDefEx::unload() and AcDbPointCloudDefEx::load(), which sequence do you use ?
I never have to work with the AcDbPointCloudDefEx class except to get informations about the point clouds, but if needed I would try :
1. Unload the point cloud with AcDbPointCloudDefEx::unload() that conserve the dictionary entry
2. Set the new file pathes AcDbPointCloudDefEx::setSourceFileName() and setActiveFileName()
3. Load the new file with AcDbPointCloudDefEx::load()
If you do the same process, I have no other idea at this time.
Cheers,
Thierry
Hi Thierry,
thanks for your reply.
At first, I updated the point cloud in the following sequence:
1. Set the new file paths
2. Unload the AcDbPointCloudDefEx
3. Load the AcDbPointCloudDefEx again
Afterwards, I tried your suggestion, and unloaded the object first, then updated both file paths and loaded the AcDbPointCloudDefEx again at the end.
However, the path stored in "Found At" didn't change.
What surprises me is that the path does not change either when I select "Reload" from the XREF Manager context menu. I need to execute "Select New Path..." and search the new file manually to get the second file path to update correctly...
Is this worth a bug report?
Kind regards,
Bettina
Hi Bettina,
Try this code, it works nice for me with AutoCAD 2015 & 2018 :
// Point cloud selection AcDbObjectId cloudId; //... // If ID is correct Acad::ErrorStatus es; AcDbObjectId defId; if (cloudId.isValid()) { // Get associated dictionary ID AcDbObjectPointer<AcDbPointCloudEx> pPCloud(cloudId, AcDb::kForRead); if ((es = pPCloud.openStatus()) == Acad::eOk) defId = pPCloud->pointCloudDefExId(); if (!defId.isValid()) return; } // Ask for a new point cloud file CFileDialog file(TRUE,
_T("rcp"),
NULL,
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
_T("Recap project file (*.rcp)|*.rcp|Recap scan file (*.rcs)|*.rcs||"),
acedGetAcadFrame()); file.m_ofn.lpstrTitle = _T("New point cloud file"); if (file.DoModal() != IDOK) return; // Get new file path CString sFilePath = file.GetPathName(); // Unload point cloud then load the new file AcDbObjectPointer<AcDbPointCloudDefEx> pPCDef(defId, AcDb::kForWrite); if ((es = pPCDef.openStatus()) == Acad::eOk) { es = pPCDef->unload(); es = pPCDef->setSourceFileName(sFileName); es = pPCDef->setActiveFileName(sFileName); es = pPCDef->load(); es = pPCDef.close(); // Force point cloud graphics update and zoom to extents AcDbObjectPointer<AcDbPointCloudEx> pPCloud(cloudId, AcDb::kForWrite); if ((es = pPCloud.openStatus()) == Acad::eOk) { pPCloud->recordGraphicsModified(true); pPCloud.close(); acedCommandS(RTSTR, _T("_.ZOOM"), RTSTR, _T("_EX"), 0); } }
I hope it helps you.
Cheers,
Thierry
Hi Bettina,
Yes, you should query for all AcDbPointCloudEx entities in the database and then match by pointCloudDefExId(), because more than one point cloud can refer to an AcDbPointCloudDefEx, as mentioned in the ObjectARX documentation :
The AcDbPointCloudDefEx object (or "point cloud extension definition object") controls the actual point cloud data associated with one or more AcDbPointCloudEx entities (or "point cloud extension entity"). These objects link the .rcp/.rcs file to the dwg file, similar to how Xrefs work.
The relationship between the AcDbPointCloudDefEx and AcDbPointCloudEx classes is much like the relationship between an AutoCAD block definition object and a block reference entity. (...)
You can for example select all point cloud objects with the acedSSGet() function, like :
struct resbuf *pFilter = acutBuildList(RTDXF0, _T("AcDbPointCloudEx"), 0); ads_name selectionSet; if ((acedSSGet(_T("_X"), NULL, NULL, pFilter, selectionSet) == RTNORM) { AcDbObjectIdArray objIds; if (acedGetCurrentSelectionSet(objIds) == Acad::eOk) { // Associate point clouds and def's //... }
acedSSFree(selectionSet); } acutRelRb(pFilter);
Cheers,
Thierry
Can't find what you're looking for? Ask the community or share your knowledge.