载入中...
搜索中...
未找到
Ghost.cpp
浏览该文件的文档.
1#include "building/Ghost.h"
6
7#include <limits>
8
9namespace eve::building {
10
11void Ghost::destroy() { delete this; }
12
13void Ghost::setBuildingId(const std::string &id) {
14 buildingId_ = id;
15 placementKind_ = "cell";
16 valid_ = false;
17 reason_.clear();
18 surfacePatchStale_ = false;
19 surfaceHitMissing_ = false;
20 surfaceId_.clear();
21 surfaceRevision_ = 0;
22 surfaceNormalX_ = 0.f;
23 surfaceNormalY_ = 1.f;
24 surfaceNormalZ_ = 0.f;
25 surfaceTangentX_ = 1.f;
26 surfaceTangentY_ = 0.f;
27 surfaceTangentZ_ = 0.f;
28 surfaceSampleCount_ = 0;
29 surfaceMaxSlopeDegrees_ = 0.f;
30 surfaceHeightDelta_ = 0.f;
31}
32
33void Ghost::setCell(int cellX, int cellY) {
34 placementKind_ = "cell";
35 cellX_ = cellX;
36 cellY_ = cellY;
37 valid_ = false;
38 reason_.clear();
39 surfacePatchStale_ = false;
40 surfaceHitMissing_ = false;
41 surfaceId_.clear();
42 surfaceRevision_ = 0;
43 surfaceNormalX_ = 0.f;
44 surfaceNormalY_ = 1.f;
45 surfaceNormalZ_ = 0.f;
46 surfaceTangentX_ = 1.f;
47 surfaceTangentY_ = 0.f;
48 surfaceTangentZ_ = 0.f;
49 surfaceSampleCount_ = 0;
50 surfaceMaxSlopeDegrees_ = 0.f;
51 surfaceHeightDelta_ = 0.f;
52}
53
54void Ghost::setWorld(float worldX, float worldY) {
55 placementKind_ = "cell";
56 worldX_ = worldX;
57 worldY_ = worldY;
58 valid_ = false;
59 reason_.clear();
60 surfacePatchStale_ = false;
61 surfaceHitMissing_ = false;
62 surfaceId_.clear();
63 surfaceRevision_ = 0;
64 surfaceNormalX_ = 0.f;
65 surfaceNormalY_ = 1.f;
66 surfaceNormalZ_ = 0.f;
67 surfaceTangentX_ = 1.f;
68 surfaceTangentY_ = 0.f;
69 surfaceTangentZ_ = 0.f;
70 surfaceSampleCount_ = 0;
71 surfaceMaxSlopeDegrees_ = 0.f;
72 surfaceHeightDelta_ = 0.f;
73}
74
76 elevation_ = elevation;
77 valid_ = false;
78 reason_.clear();
79 surfacePatchStale_ = false;
80 surfaceHitMissing_ = false;
81 surfaceId_.clear();
82 surfaceRevision_ = 0;
83 surfaceNormalX_ = 0.f;
84 surfaceNormalY_ = 1.f;
85 surfaceNormalZ_ = 0.f;
86 surfaceTangentX_ = 1.f;
87 surfaceTangentY_ = 0.f;
88 surfaceTangentZ_ = 0.f;
89 surfaceSampleCount_ = 0;
90 surfaceMaxSlopeDegrees_ = 0.f;
91 surfaceHeightDelta_ = 0.f;
92}
93
94void Ghost::setRotationDeg(float deg) {
95 rotationDeg_ = deg;
96 if (!surfaceId_.empty()) surfacePatchStale_ = true;
97 valid_ = false;
98 if (!surfaceHitMissing_) reason_.clear();
99}
100
101void Ghost::rotateBy(float deltaDeg) {
102 setRotationDeg(rotationDeg_ + deltaDeg);
103}
104
105void Ghost::setFromWorld(PlacementWorld *world, float worldX, float worldY) {
106 if (!world) return;
107 placementKind_ = "cell";
108 const SnapResult s = PlacementSystem::snap(*world, buildingId_, worldX, worldY);
109 cellX_ = s.cellX;
110 cellY_ = s.cellY;
111 worldX_ = s.worldX;
112 worldY_ = s.worldY;
113 elevation_ = s.elevation;
114 valid_ = false;
115 reason_.clear();
116 surfacePatchStale_ = false;
117 surfaceHitMissing_ = false;
118 surfaceId_.clear();
119 surfaceRevision_ = 0;
120 surfaceNormalX_ = 0.f;
121 surfaceNormalY_ = 1.f;
122 surfaceNormalZ_ = 0.f;
123 surfaceTangentX_ = 1.f;
124 surfaceTangentY_ = 0.f;
125 surfaceTangentZ_ = 0.f;
126 surfaceSampleCount_ = 0;
127 surfaceMaxSlopeDegrees_ = 0.f;
128 surfaceHeightDelta_ = 0.f;
129}
130
131void Ghost::setFromWorld3D(PlacementWorld *world, float worldX, float worldY, float worldZ) {
132 if (!world) return;
133 placementKind_ = "cell";
134 const SnapResult s = PlacementSystem::snap3D(*world, buildingId_, worldX, worldY, worldZ);
135 cellX_ = s.cellX;
136 cellY_ = s.cellY;
137 worldX_ = s.worldX;
138 worldY_ = s.worldY;
139 elevation_ = s.elevation;
140 valid_ = false;
141 reason_.clear();
142 surfacePatchStale_ = false;
143 surfaceHitMissing_ = false;
144 surfaceId_.clear();
145 surfaceRevision_ = 0;
146 surfaceNormalX_ = 0.f;
147 surfaceNormalY_ = 1.f;
148 surfaceNormalZ_ = 0.f;
149 surfaceTangentX_ = 1.f;
150 surfaceTangentY_ = 0.f;
151 surfaceTangentZ_ = 0.f;
152 surfaceSampleCount_ = 0;
153 surfaceMaxSlopeDegrees_ = 0.f;
154 surfaceHeightDelta_ = 0.f;
155}
156
157std::string Ghost::getEdgeAxis() const {
158 if (placementKind_ != "edge") return {};
159 return edge_.axis == EdgeAxis::Horizontal ? "horizontal" : "vertical";
160}
161
162void Ghost::setEdge(PlacementWorld *world, int cellX, int cellY, const std::string &direction) {
163 if (!world) return;
164 auto result = PlacementSystem::canonicalEdge(cellX, cellY, direction);
165 if (!result.ok()) {
166 placementKind_ = "edge";
167 valid_ = false;
168 reason_ = "invalid_edge_direction";
169 return;
170 }
171 placementKind_ = "edge";
172 edge_ = std::move(result).takeValue();
173 cellX_ = edge_.x;
174 cellY_ = edge_.y;
175 float ax = 0.f, ay = 0.f, bx = 0.f, by = 0.f;
176 world->cellToWorldPlane(edge_.x, edge_.y, ax, ay);
177 world->cellToWorldPlane(edge_.x + (edge_.axis == EdgeAxis::Horizontal ? 1 : 0),
178 edge_.y + (edge_.axis == EdgeAxis::Vertical ? 1 : 0), bx, by);
179 worldX_ = (ax + bx) * 0.5f;
180 worldY_ = (ay + by) * 0.5f;
181 rotationDeg_ = edge_.axis == EdgeAxis::Horizontal ? 0.f : 90.f;
182 surfacePatchStale_ = false;
183 surfaceHitMissing_ = false;
184 surfaceId_.clear();
185 surfaceRevision_ = 0;
186 valid_ = false;
187 reason_.clear();
188}
189
190void Ghost::setCorner(PlacementWorld *world, int vertexX, int vertexY) {
191 if (!world) return;
192 placementKind_ = "corner";
193 corner_ = CornerAddress{vertexX, vertexY};
194 cellX_ = vertexX;
195 cellY_ = vertexY;
196 world->cellToWorldPlane(vertexX, vertexY, worldX_, worldY_);
197 rotationDeg_ = PlacementSystem::normalizeRotation(buildingId_, rotationDeg_);
198 surfacePatchStale_ = false;
199 surfaceHitMissing_ = false;
200 surfaceId_.clear();
201 surfaceRevision_ = 0;
202 surfaceSampleCount_ = 0;
203 valid_ = false;
204 reason_.clear();
205}
206
207void Ghost::setFree(PlacementWorld *world, float worldX, float worldY, float elevation) {
208 if (!world) return;
209 placementKind_ = "free";
210 worldX_ = worldX;
211 worldY_ = worldY;
212 elevation_ = elevation;
213 grid::worldToCell(world->getGrid(), worldX, worldY, cellX_, cellY_, world->getWidth(),
214 world->getHeight());
215 rotationDeg_ = PlacementSystem::normalizeRotation(buildingId_, rotationDeg_);
216 surfacePatchStale_ = false;
217 surfaceHitMissing_ = false;
218 surfaceId_.clear();
219 surfaceRevision_ = 0;
220 surfaceSampleCount_ = 0;
221 valid_ = false;
222 reason_.clear();
223}
224
225void Ghost::setFromSurface(PlacementWorld *world, const std::string &surface, float x, float y) {
226 if (!world) return;
227 surfaceProviderName_ = surface;
228 surfaceInputX_ = x;
229 surfaceInputY_ = y;
230 auto result = PlacementSystem::sampleSurfacePatch(*world, buildingId_, surface, x, y,
231 rotationDeg_);
232 if (!result.ok()) {
233 surfaceId_.clear();
234 surfaceRevision_ = 0;
235 surfaceNormalX_ = 0.f;
236 surfaceNormalY_ = 1.f;
237 surfaceNormalZ_ = 0.f;
238 surfaceTangentX_ = 1.f;
239 surfaceTangentY_ = 0.f;
240 surfaceTangentZ_ = 0.f;
241 surfaceSampleCount_ = 0;
242 surfaceMaxSlopeDegrees_ = 0.f;
243 surfaceHeightDelta_ = 0.f;
244 surfacePatchStale_ = false;
245 surfaceHitMissing_ = true;
246 valid_ = false;
247 reason_ = result.code() == eve::StatusCode::NotFound ? "no_surface_hit"
248 : "invalid_surface_hit";
249 return;
250 }
251 PlacementSystem::SurfacePatch patch = std::move(result).takeValue();
253 setFromWorld3D(world, hit.worldX, hit.worldY, hit.worldZ);
254 const BuildingDefinition *definition = BuildingRegistry::find(buildingId_);
255 if (definition && definition->placementKind == "free") placementKind_ = "free";
256 surfaceId_ = std::move(hit.surfaceId);
257 surfaceRevision_ = hit.surfaceRevision;
258 surfaceNormalX_ = hit.normalX;
259 surfaceNormalY_ = hit.normalY;
260 surfaceNormalZ_ = hit.normalZ;
261 surfaceTangentX_ = hit.tangentX;
262 surfaceTangentY_ = hit.tangentY;
263 surfaceTangentZ_ = hit.tangentZ;
264 surfaceSampleCount_ = static_cast<int>(patch.samples.size());
265 surfaceMaxSlopeDegrees_ = patch.maxSlopeDegrees;
266 surfaceHeightDelta_ = patch.heightDelta;
267 surfacePatchStale_ = false;
268}
269
271 if (!world) {
272 valid_ = false;
273 reason_ = "no_world";
274 return false;
275 }
276 if (surfaceHitMissing_) return false;
277 if (surfacePatchStale_) {
278 setFromSurface(world, surfaceProviderName_, surfaceInputX_, surfaceInputY_);
279 if (surfaceHitMissing_) return false;
280 }
281 const BuildingDefinition *definition = BuildingRegistry::find(buildingId_);
282 if (definition && definition->placementKind == "edge") {
283 if (placementKind_ != "edge") {
284 valid_ = false;
285 reason_ = "edge_requires_edge_address";
286 return false;
287 }
288 const char *direction = edge_.axis == EdgeAxis::Horizontal ? "north" : "west";
289 valid_ = PlacementSystem::canPlaceEdge(world, buildingId_, edge_.x, edge_.y, direction, 0,
290 &reason_);
291 return valid_;
292 }
293 if (definition && definition->placementKind == "corner") {
294 if (placementKind_ != "corner") {
295 valid_ = false;
296 reason_ = "corner_requires_corner_address";
297 return false;
298 }
299 valid_ = PlacementSystem::canPlaceCorner(world, buildingId_, corner_.x, corner_.y, 0,
300 &reason_);
301 return valid_;
302 }
303 if (definition && definition->placementKind == "free") {
304 if (placementKind_ != "free") {
305 valid_ = false;
306 reason_ = "free_requires_free_address";
307 return false;
308 }
310 world, buildingId_, worldX_, worldY_, 0, &reason_,
311 std::numeric_limits<int>::min(), rotationDeg_);
312 if (valid_ && surfaceMaxSlopeDegrees_ > definition->maxSurfaceSlopeDegrees) {
313 valid_ = false;
314 reason_ = "surface_slope";
315 }
316 if (valid_ && definition->maxSurfaceHeightDelta >= 0.f &&
317 surfaceHeightDelta_ > definition->maxSurfaceHeightDelta) {
318 valid_ = false;
319 reason_ = "surface_height_delta";
320 }
321 return valid_;
322 }
323 rotationDeg_ = PlacementSystem::normalizeRotation(buildingId_, rotationDeg_);
324 PlacementQuery query;
325 query.buildingId = buildingId_;
326 query.cellX = cellX_;
327 query.cellY = cellY_;
328 query.worldX = worldX_;
329 query.worldY = worldY_;
330 query.elevation = elevation_;
331 query.rotationDeg = rotationDeg_;
332 query.surfaceId = surfaceId_;
333 query.surfaceRevision = surfaceRevision_;
334 query.surfaceNormalX = surfaceNormalX_;
335 query.surfaceNormalY = surfaceNormalY_;
336 query.surfaceNormalZ = surfaceNormalZ_;
337 query.surfaceSampleCount = surfaceSampleCount_;
338 query.surfaceMaxSlopeDegrees = surfaceMaxSlopeDegrees_;
339 query.surfaceHeightDelta = surfaceHeightDelta_;
340 std::string reason;
341 valid_ = PlacementSystem::canPlaceQuery(world, query, &reason);
342 reason_ = reason;
343 return valid_;
344}
345
346} // namespace eve::building
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
int ax
Definition CaveMesh.cpp:113
int ay
Definition CaveMesh.cpp:113
int bx
Definition CaveMesh.cpp:114
int by
Definition CaveMesh.cpp:114
Pure cell/world projection helpers for GridConfig.
float elevation
World3D * world
std::string id
Definition PlayHost.cpp:108
bool hit
RoadLaneDirection direction
static const BuildingDefinition * find(const std::string &id)
Finds .
void setFree(PlacementWorld *world, float worldX, float worldY, float elevation=0.f)
Set an exact unsnapped world-plane anchor for a free-domain definition.
Definition Ghost.cpp:207
void setFromWorld(PlacementWorld *world, float worldX, float worldY)
按世界吸附模式,从世界坐标刷新格子与世界位姿。
Definition Ghost.cpp:105
void setRotationDeg(float deg)
Sets the rotation deg.
Definition Ghost.cpp:94
void setElevation(float elevation)
Sets the elevation.
Definition Ghost.cpp:75
bool validate(PlacementWorld *world)
对当前姿态做校验,写入 valid_/reason_。
Definition Ghost.cpp:270
void setFromWorld3D(PlacementWorld *world, float worldX, float worldY, float worldZ)
Sets the from world 3 d.
Definition Ghost.cpp:131
void setCorner(PlacementWorld *world, int vertexX, int vertexY)
Snap this ghost to one canonical grid vertex.
Definition Ghost.cpp:190
std::string getEdgeAxis() const
Canonical edge axis (horizontal/vertical), empty for cell ghosts.
Definition Ghost.cpp:157
void setEdge(PlacementWorld *world, int cellX, int cellY, const std::string &direction)
Snap this ghost to a canonicalized cell edge and its exact midpoint pose.
Definition Ghost.cpp:162
void setWorld(float worldX, float worldY)
Sets the world.
Definition Ghost.cpp:54
void rotateBy(float deltaDeg)
Rotate by.
Definition Ghost.cpp:101
void setCell(int cellX, int cellY)
Sets the cell.
Definition Ghost.cpp:33
void setFromSurface(PlacementWorld *world, const std::string &surface, float x, float y)
Sets the from surface.
Definition Ghost.cpp:225
void setBuildingId(const std::string &id)
Sets the building id.
Definition Ghost.cpp:13
void destroy()
Destroys .
Definition Ghost.cpp:11
static SnapResult snap(const PlacementWorld &world, const std::string &buildingId, float worldX, float worldY)
static SnapResult snap3D(const PlacementWorld &world, const std::string &buildingId, float worldX, float worldY, float worldZ)
static bool canPlaceFree(PlacementWorld *world, const std::string &buildingId, float worldX, float worldY, int excludeInstanceId=0, std::string *reason=nullptr, int level=std::numeric_limits< int >::min(), float rotationDeg=0.f)
Validate an exact free-domain world-plane anchor and circular or oriented-box footprint.
static float normalizeRotation(const std::string &buildingId, float rotationDeg)
规范化旋转角(cardinal → 0/90/180/270;none → 0)。
static bool canPlaceCorner(PlacementWorld *world, const std::string &buildingId, int vertexX, int vertexY, int excludeInstanceId=0, std::string *reason=nullptr, int level=std::numeric_limits< int >::min())
Validate a corner-domain placement at one canonical grid vertex.
static eve::Result< SurfacePatch > sampleSurfacePatch(const PlacementWorld &world, const std::string &buildingId, const std::string &surfaceName, float x, float y, float rotationDegrees=0.f)
Sample the occupied cells of a rotated footprint relative to an exact anchor hit.
static eve::Result< EdgeAddress > canonicalEdge(int cellX, int cellY, const std::string &direction)
Normalize a cell-relative cardinal direction to a unique edge address.
static bool canPlaceEdge(PlacementWorld *world, const std::string &buildingId, int cellX, int cellY, const std::string &direction, int excludeInstanceId=0, std::string *reason=nullptr, int level=std::numeric_limits< int >::min())
Validate an edge-domain placement without mutating the world.
格子型建筑放置世界(脚本可直接操作)。
建筑放置模块入口:定义 / 放置世界 / 鬼影 / 变更事件的脚本绑定点。 设计文档:docs/dev/建筑放置系统设计.md
Definition Building.cpp:7
void worldToCell(const GridConfig &cfg, float px, float py, int &cx, int &cy, int mapW, int mapH)
Maps planar coordinates to the nearest cell. Staggered/hex layouts use a bounded nearest-neighbor sea...
建筑模板(进程级注册表中的定义)。
Canonical address of one logical grid vertex used by corner objects.
校验上下文:传给可插拔规则。
One sampled point and orthonormal frame on a placement surface.
Surface samples and continuity metrics for one rotated building footprint.
std::vector< SurfacePatchSample > samples