SOLVED!
Get Facade Panels in Order?
Anonymous
Not applicable
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-12-11
09:51 AM
- last edited on
2022-10-04
04:52 PM
by
Daniel Kassai
2018-12-11
09:51 AM
Hello Archicad community,
Based on the grid mesh I can get each facade panel's dimensions and convert it into a wall (attachment 1 is the input, attachment 2 the output), however, the panels I get do not seem to be in any particular order (attachment 2). If I loop over the panels I get from "memo.cWallPanels" (API_CWPanelType) and build a wall based on the panel's material (glass or opaque) the order is not the same (and there also does not seem to be any other order which I could correlate).
Is there any way I could retrieve the panels in such a way that I know their position in the grid mesh and assign the correct material accordingly?
Thanks,
- Dan
Based on the grid mesh I can get each facade panel's dimensions and convert it into a wall (attachment 1 is the input, attachment 2 the output), however, the panels I get do not seem to be in any particular order (attachment 2). If I loop over the panels I get from "memo.cWallPanels" (API_CWPanelType) and build a wall based on the panel's material (glass or opaque) the order is not the same (and there also does not seem to be any other order which I could correlate).
Is there any way I could retrieve the panels in such a way that I know their position in the grid mesh and assign the correct material accordingly?
Thanks,
- Dan
Solved! Go to Solution.
Labels:
- Labels:
-
Add-On (C++)
1 ACCEPTED SOLUTION
Accepted Solutions
Solution

Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-12-13 04:50 PM
2018-12-13
04:50 PM
In theory it's possible to get the panels in order, but unfortunately two bugs in the API prevent us to do that:
- cWallPanelGridIDTable member of the API_ElementMemo is always nullptr. That member should contain the information about the positions of the panels in the grid.
- API_CWPanelType structure does not contain the ID of the segment, so if the curtain wall has multiple segments then the panels cannot be sorted correctly (because each segment has individual grid and a gridCellID is not unique).
I added these bugs to our bug database.
The first will be fixed in an upcoming update for AC22 (buildnum higher than 5500).
The second one needs API interface modification: the filler_1[0] member of the API_CWPanelType structure will be reused, that will contain the index of the segment which contains the panel. I hope that modification can be done also in an upcoming update for AC22 (buildnum higher than 5500).
I will notify again you when the modifications were successfully done. After that you can use the following code to get the sorted panels:
GS::Array<API_CWPanelType> GetCurtainWallPanelsInOrder (const API_Guid& cwGuid) { GS::Array<API_CWPanelType> result; API_Element cwElement; BNZeroMemory (&cwElement, sizeof (API_Element)); cwElement.header.guid = cwGuid; GSErrCode err = ACAPI_Element_Get (&cwElement); if (err == NoError) { API_ElementMemo cwMemo; BNZeroMemory (&cwMemo, sizeof (API_ElementMemo)); err = ACAPI_Element_GetMemo (cwElement.header.guid, &cwMemo, APIMemoMask_CWallSegments | APIMemoMask_CWallPanels); if (err == NoError && cwMemo.cWallSegments != nullptr && cwMemo.cWallPanelGridIDTable != nullptr) { GS::HashTable<API_Guid, API_CWPanelType> cwPanelTable; for (UIndex ii = 0; ii < cwElement.curtainWall.nPanels; ++ii) { const API_CWPanelType& cwPanel = cwMemo.cWallPanels[ii]; cwPanelTable.Add (cwPanel.head.guid, cwPanel); } using CWPanelSegmentGridID = GS::Pair<UInt32, API_GridElemID>; GS::Array<CWPanelSegmentGridID> segmentGridIDs; GS::HashTable<CWPanelSegmentGridID, GS::Array<API_CWPanelType>> reversedCWPanelGridIDTable; for (auto it = cwMemo.cWallPanelGridIDTable->EnumeratePairs (); it != nullptr; ++it) { const API_CWPanelType& cwPanel = cwPanelTable[*it->key]; const GS::Array<API_GridElemID>& cwPanelGridIDs = *it->value; for (auto it = cwPanelGridIDs.Enumerate (); it != nullptr; ++it) { const API_GridElemID& gridID = *it; CWPanelSegmentGridID segmentGridID (cwPanel.filler_1[0]/*cwPanel.segmentID*/, gridID); if (reversedCWPanelGridIDTable.ContainsKey (segmentGridID)) reversedCWPanelGridIDTable[segmentGridID].Push (cwPanel); else reversedCWPanelGridIDTable.Add (segmentGridID, { cwPanel }); segmentGridIDs.Push (segmentGridID); } } GS::Sort (segmentGridIDs.Begin (), segmentGridIDs.End (), [](const auto& lhs, const auto& rhs) { if (lhs.first == rhs.first) return lhs.second < rhs.second; return lhs.first < rhs.first; }); for (auto it = segmentGridIDs.Enumerate (); it != nullptr; ++it) { const CWPanelSegmentGridID& segmentGridID = *it; result.Append (reversedCWPanelGridIDTable[segmentGridID]); } } ACAPI_DisposeElemMemoHdls (&cwMemo); } return result; }
3 REPLIES 3

Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-12-13 12:10 PM
2018-12-13
12:10 PM
Hi Dan,
You're right, it's not trivial to get the panels in order. But it's not impossible
I'm preparing an example code for you now. I will post it soon.
Regards,
Tibor
You're right, it's not trivial to get the panels in order. But it's not impossible

I'm preparing an example code for you now. I will post it soon.
Regards,
Tibor
Solution

Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-12-13 04:50 PM
2018-12-13
04:50 PM
In theory it's possible to get the panels in order, but unfortunately two bugs in the API prevent us to do that:
- cWallPanelGridIDTable member of the API_ElementMemo is always nullptr. That member should contain the information about the positions of the panels in the grid.
- API_CWPanelType structure does not contain the ID of the segment, so if the curtain wall has multiple segments then the panels cannot be sorted correctly (because each segment has individual grid and a gridCellID is not unique).
I added these bugs to our bug database.
The first will be fixed in an upcoming update for AC22 (buildnum higher than 5500).
The second one needs API interface modification: the filler_1[0] member of the API_CWPanelType structure will be reused, that will contain the index of the segment which contains the panel. I hope that modification can be done also in an upcoming update for AC22 (buildnum higher than 5500).
I will notify again you when the modifications were successfully done. After that you can use the following code to get the sorted panels:
GS::Array<API_CWPanelType> GetCurtainWallPanelsInOrder (const API_Guid& cwGuid) { GS::Array<API_CWPanelType> result; API_Element cwElement; BNZeroMemory (&cwElement, sizeof (API_Element)); cwElement.header.guid = cwGuid; GSErrCode err = ACAPI_Element_Get (&cwElement); if (err == NoError) { API_ElementMemo cwMemo; BNZeroMemory (&cwMemo, sizeof (API_ElementMemo)); err = ACAPI_Element_GetMemo (cwElement.header.guid, &cwMemo, APIMemoMask_CWallSegments | APIMemoMask_CWallPanels); if (err == NoError && cwMemo.cWallSegments != nullptr && cwMemo.cWallPanelGridIDTable != nullptr) { GS::HashTable<API_Guid, API_CWPanelType> cwPanelTable; for (UIndex ii = 0; ii < cwElement.curtainWall.nPanels; ++ii) { const API_CWPanelType& cwPanel = cwMemo.cWallPanels[ii]; cwPanelTable.Add (cwPanel.head.guid, cwPanel); } using CWPanelSegmentGridID = GS::Pair<UInt32, API_GridElemID>; GS::Array<CWPanelSegmentGridID> segmentGridIDs; GS::HashTable<CWPanelSegmentGridID, GS::Array<API_CWPanelType>> reversedCWPanelGridIDTable; for (auto it = cwMemo.cWallPanelGridIDTable->EnumeratePairs (); it != nullptr; ++it) { const API_CWPanelType& cwPanel = cwPanelTable[*it->key]; const GS::Array<API_GridElemID>& cwPanelGridIDs = *it->value; for (auto it = cwPanelGridIDs.Enumerate (); it != nullptr; ++it) { const API_GridElemID& gridID = *it; CWPanelSegmentGridID segmentGridID (cwPanel.filler_1[0]/*cwPanel.segmentID*/, gridID); if (reversedCWPanelGridIDTable.ContainsKey (segmentGridID)) reversedCWPanelGridIDTable[segmentGridID].Push (cwPanel); else reversedCWPanelGridIDTable.Add (segmentGridID, { cwPanel }); segmentGridIDs.Push (segmentGridID); } } GS::Sort (segmentGridIDs.Begin (), segmentGridIDs.End (), [](const auto& lhs, const auto& rhs) { if (lhs.first == rhs.first) return lhs.second < rhs.second; return lhs.first < rhs.first; }); for (auto it = segmentGridIDs.Enumerate (); it != nullptr; ++it) { const CWPanelSegmentGridID& segmentGridID = *it; result.Append (reversedCWPanelGridIDTable[segmentGridID]); } } ACAPI_DisposeElemMemoHdls (&cwMemo); } return result; }
Anonymous
Not applicable
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2018-12-13 05:12 PM
2018-12-13
05:12 PM
Interesting... I already stumbled upon cWallPanelGridIDTable in the code, but could not click on it in the docs and so didn't know how to use it - I guess this is related to the nullptr issue you mentioned.
Thanks a lot for the code already, it will be very useful as soon as I can use it
Have a great weekend!
- Dan
Thanks a lot for the code already, it will be very useful as soon as I can use it

Have a great weekend!
- Dan