1+ #include " CreateRailingsCommand.hpp"
2+ #include " ObjectState.hpp"
3+ #include " OnExit.hpp"
4+
5+
6+ GS::String CreateRailingsCommand::GetName () const
7+ {
8+ return " CreateRailings" ;
9+ }
10+
11+
12+ constexpr const char * RailingsParameterField = " railings" ;
13+ constexpr const char * LevelParameterField = " level" ;
14+ constexpr const char * PolygonCoordinatesParameterField = " polygonCoordinates" ;
15+ constexpr const char * HolesParameterField = " holes" ;
16+
17+
18+ GS::Optional<GS::UniString> CreateRailingsCommand::GetInputParametersSchema () const
19+ {
20+ return GS::UniString::Printf (R"( {
21+ "type": "object",
22+ "properties": {
23+ "%s": {
24+ "type": "array",
25+ "description": "The parameters of the new Railings.",
26+ "items": {
27+ "type": "object",
28+ "description" : "The parameters of the new Railing.",
29+ "properties" : {
30+ "%s": {
31+ "type": "number",
32+ "description" : "The Z coordinate value of the reference line of the railing."
33+ },
34+ "%s": {
35+ "type": "array",
36+ "description": "The 2D coordinates of the edge of the railing.",
37+ "items": {
38+ "type": "object",
39+ "description" : "Position of a 2D point.",
40+ "properties" : {
41+ "x": {
42+ "type": "number",
43+ "description" : "X value of the point."
44+ },
45+ "y" : {
46+ "type": "number",
47+ "description" : "Y value of the point."
48+ }
49+ },
50+ "additionalProperties": false,
51+ "required" : [
52+ "x",
53+ "y"
54+ ]
55+ }
56+ }
57+ },
58+ "additionalProperties": true,
59+ "required" : [
60+ "%s",
61+ "%s"
62+ ]
63+ }
64+ }
65+ },
66+ "additionalProperties": false,
67+ "required": [
68+ "%s"
69+ ]
70+ })" ,
71+ RailingsParameterField,
72+ LevelParameterField,
73+ PolygonCoordinatesParameterField,
74+ LevelParameterField,
75+ PolygonCoordinatesParameterField,
76+ RailingsParameterField);
77+ }
78+
79+
80+ static void AddPolyToMemo (const GS::Array<GS::ObjectState>& polygonCoordinates,
81+ const API_OverriddenAttribute& sideMat,
82+ Int32& iCoord,
83+ Int32& iPends,
84+ API_ElementMemo& memo)
85+ {
86+ Int32 iStart = iCoord;
87+ for (const GS::ObjectState& polygonCoordinate : polygonCoordinates) {
88+ (*memo.coords )[iCoord] = Utilities::Get2DCoordinateFromObjectState (polygonCoordinate);
89+ (*memo.edgeTrims )[iCoord].sideType = APIEdgeTrim_Vertical; // Only vertical trim is supported yet by my code
90+ memo.sideMaterials [iCoord] = sideMat;
91+ ++iCoord;
92+ }
93+ (*memo.coords )[iCoord] = (*memo.coords )[iStart];
94+ (*memo.pends )[iPends++] = iCoord;
95+ (*memo.edgeTrims )[iCoord].sideType = (*memo.edgeTrims )[iStart].sideType ;
96+ (*memo.edgeTrims )[iCoord].sideAngle = (*memo.edgeTrims )[iStart].sideAngle ;
97+ memo.sideMaterials [iCoord] = memo.sideMaterials [iStart];
98+ ++iCoord;
99+ }
100+
101+
102+ GS::ObjectState CreateRailingsCommand::Execute (const GS::ObjectState& parameters, GS::ProcessControl& /* processControl*/ ) const
103+ {
104+ GS::Array<GS::ObjectState> railings;
105+ parameters.Get (RailingsParameterField, railings);
106+
107+ GSIndex iRailing = 0 ;
108+ const APIErrCodes err = (APIErrCodes) ACAPI_CallUndoableCommand (" Create Railings" , [&] () -> GSErrCode {
109+ APIErrCodes err = (APIErrCodes) NoError;
110+ const GS::Array<GS::Pair<short , double >> storyLevels = Utilities::GetStoryLevels ();
111+ for (const GS::ObjectState& railing : railings) {
112+ if (!railing.Contains (LevelParameterField) ||
113+ !railing.Contains (PolygonCoordinatesParameterField)) {
114+ continue ;
115+ }
116+
117+ API_Element element = {};
118+ API_ElementMemo memo = {};
119+ const GS::OnExit guard ([&memo] () { ACAPI_DisposeElemMemoHdls (&memo); });
120+
121+ #ifdef ServerMainVers_2600
122+ element.header .type = API_RailingID;
123+ #else
124+ element.header .typeID = API_RailingID;
125+ #endif
126+ err = (APIErrCodes) ACAPI_Element_GetDefaults (&element, &memo);
127+
128+ railing.Get (LevelParameterField, element.railing .bottomOffset );
129+ element.header .floorInd = Utilities::GetFloorIndexAndOffset (element.railing .bottomOffset , storyLevels, element.railing .bottomOffset );
130+
131+ GS::Array<GS::ObjectState> polygonCoordinates;
132+ GS::Array<GS::ObjectState> holes;
133+ railing.Get (PolygonCoordinatesParameterField, polygonCoordinates);
134+ if (railing.Contains (HolesParameterField)) {
135+ railing.Get (HolesParameterField, holes);
136+ }
137+ API_Polygon poly = {};
138+ poly.nCoords = polygonCoordinates.GetSize () + 1 ;
139+ poly.nSubPolys = 1 ;
140+
141+ memo.coords = reinterpret_cast <API_Coord**> (BMAllocateHandle ((poly.nCoords + 1 ) * sizeof (API_Coord), ALLOCATE_CLEAR, 0 ));
142+ memo.edgeTrims = reinterpret_cast <API_EdgeTrim**> (BMAllocateHandle ((poly.nCoords + 1 ) * sizeof (API_EdgeTrim), ALLOCATE_CLEAR, 0 ));
143+ memo.sideMaterials = reinterpret_cast <API_OverriddenAttribute*> (BMAllocatePtr ((poly.nCoords + 1 ) * sizeof (API_OverriddenAttribute), ALLOCATE_CLEAR, 0 ));
144+ memo.pends = reinterpret_cast <Int32**> (BMAllocateHandle ((poly.nSubPolys + 1 ) * sizeof (Int32), ALLOCATE_CLEAR, 0 ));
145+
146+ element.railing .nVertices = poly.nCoords ;
147+
148+ Int32 iCoord = 1 ;
149+ Int32 iPends = 1 ;
150+ AddPolyToMemo (polygonCoordinates,
151+ API_OverriddenAttribute (),
152+ iCoord,
153+ iPends,
154+ memo);
155+
156+ err = (APIErrCodes) ACAPI_Element_Create (&element, &memo);
157+
158+ if (err != NoError) {
159+ break ;
160+ }
161+
162+ ++iRailing;
163+ }
164+
165+ return err;
166+ });
167+
168+ if (err != NoError) {
169+ const GS::UniString errorMsg = GS::UniString::Printf (" Failed to create railing #%d!" , iRailing);
170+ return CreateErrorResponse (err, errorMsg);
171+ }
172+
173+ return {};
174+ }
0 commit comments