ObjectARX
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to correctly reload a Point Cloud via ObjectARX ?

6 REPLIES 6
SOLVED
Reply
Message 1 of 7
cdnbake
1601 Views, 6 Replies

How to correctly reload a Point Cloud via ObjectARX ?

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.

 

screenshot-point-cloud-paths.png

 

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

Bettina Kutsche
CIDEON
take the value perspective.
6 REPLIES 6
Message 2 of 7
thierry_prince
in reply to: cdnbake

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

Message 3 of 7
cdnbake
in reply to: thierry_prince

Hi Thierry, 

thanks for your reply. Smiley Happy

 

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...

 

screenshot-point-cloud-paths-02.png

 

Is this worth a bug report?

 

Kind regards, 

Bettina 

Bettina Kutsche
CIDEON
take the value perspective.
Message 4 of 7
thierry_prince
in reply to: cdnbake

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

 

 

Message 5 of 7
cdnbake
in reply to: thierry_prince

Hi Thierry,
wow thanks for that code snippet! 🙂

Is there any way to find the corresponding AcDbPointCloudEx if I only have the AcDbPointCloudDefEx? Because I am iterating the dictionary and search for a AcDbPointCloudDefEx by matching the file name. Unfortunately, the old filename is the only identifier I currently have...
Although there is the method AcDbPointCloudEx::pointCloudDefExId(), I do not see a possibility for the other way around.

Any ideas? Is it possible to query for all AcDbPointCloudEx entities in the database and then match by pointCloudDefExId() ?

Kind regards,
Bettina
Bettina Kutsche
CIDEON
take the value perspective.
Message 6 of 7
thierry_prince
in reply to: cdnbake

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

 

 

Message 7 of 7
cdnbake
in reply to: thierry_prince

Hi Thierry,
thanks for your great suggestions, it seems to work just fine now. 🙂

Thank you very much for your help!

Kind regards,
Bettina
Bettina Kutsche
CIDEON
take the value perspective.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report