!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / CryDesigner / Util / SpotManager.cpp
blob9620e36f4098da655ad9fc43575eea1c92ff8773
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "Viewport.h"
5 #include "SpotManager.h"
6 #include "Tools/BaseTool.h"
7 #include "Core/Model.h"
8 #include "DesignerEditor.h"
9 #include "Grid.h"
10 #include "SurfaceInfoPicker.h"
12 namespace Designer
14 void SpotManager::DrawCurrentSpot(SDisplayContext& dc, const BrushMatrix34& worldTM) const
16 static const ColorB edgeCenterColor(100, 255, 100, 255);
17 static const ColorB polygonCenterColor(100, 255, 100, 255);
18 static const ColorB eitherPointColor(255, 100, 255, 255);
19 static const ColorB normalColor(100, 100, 100, 255);
20 static const ColorB edgeColor(100, 100, 255, 255);
21 static const ColorB startPointColor(255, 255, 100, 255);
23 if (m_CurrentSpot.m_PosState == eSpotPosState_Edge || m_CurrentSpot.m_PosState == eSpotPosState_OnVirtualLine)
24 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, edgeColor);
25 else if (m_CurrentSpot.m_PosState == eSpotPosState_CenterOfEdge)
26 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, edgeCenterColor);
27 else if (m_CurrentSpot.m_PosState == eSpotPosState_CenterOfPolygon)
28 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, polygonCenterColor);
29 else if (m_CurrentSpot.m_PosState == eSpotPosState_EitherPointOfEdge || m_CurrentSpot.IsAtEndPoint())
30 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, eitherPointColor);
31 else if (m_CurrentSpot.m_PosState == eSpotPosState_AtFirstSpot)
32 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, startPointColor);
33 else
34 DrawSpot(dc, worldTM, m_CurrentSpot.m_Pos, normalColor);
37 void SpotManager::DrawPolyline(SDisplayContext& dc) const
39 if (m_SpotList.empty())
40 return;
42 for (int i = 0, iSpotSize(m_SpotList.size() - 1); i < iSpotSize; ++i)
44 if (m_SpotList[i].m_bProcessed)
45 continue;
46 const BrushVec3& currPos(m_SpotList[i].m_Pos);
47 const BrushVec3& nextPos(m_SpotList[i + 1].m_Pos);
48 dc.DrawLine(currPos, nextPos);
52 bool SpotManager::AddPolygonToDesignerFromSpotList(Model* pModel, const SpotList& spotList)
54 if (pModel == NULL || spotList.empty())
55 return false;
57 SpotList copiedSpotList(spotList);
59 Spot firstSpot = copiedSpotList[0];
60 Spot secondSpot = copiedSpotList.size() >= 2 ? copiedSpotList[1] : copiedSpotList[0];
61 Spot lastSpot = copiedSpotList[copiedSpotList.size() - 1];
63 if (firstSpot.IsEquivalentPos(lastSpot))
65 SpotList spotListWithoutBeginning(copiedSpotList);
66 spotListWithoutBeginning.erase(spotListWithoutBeginning.begin());
67 CreatePolygonFromSpots(true, spotListWithoutBeginning);
69 else if (firstSpot.IsAtEndPoint() && lastSpot.IsAtEndPoint())
71 PolygonPtr pPolygon0 = firstSpot.m_pPolygon;
72 PolygonPtr pPolygon1 = lastSpot.m_pPolygon;
73 if (pPolygon0)
75 for (int i = 0, nSpotSize(copiedSpotList.size() - 1); i < nSpotSize; ++i)
77 if (firstSpot.m_PosState == eSpotPosState_FirstPointOfPolygon)
78 pPolygon0->AddEdge(BrushEdge3D(copiedSpotList[i + 1].m_Pos, copiedSpotList[i].m_Pos));
79 else if (firstSpot.m_PosState == eSpotPosState_LastPointOfPolygon)
80 pPolygon0->AddEdge(BrushEdge3D(copiedSpotList[i].m_Pos, copiedSpotList[i + 1].m_Pos));
82 if (pPolygon1 && pPolygon0 != pPolygon1)
84 if (pPolygon0->Concatenate(pPolygon1))
85 pModel->RemovePolygon(pPolygon1);
88 BrushVec3 firstVertex;
89 BrushVec3 lastVertex;
90 pPolygon0->GetFirstVertex(firstVertex);
91 pPolygon0->GetLastVertex(lastVertex);
93 if (!pPolygon0->IsOpen())
95 pModel->RemovePolygon(pPolygon0);
96 pPolygon0->ModifyOrientation();
97 pModel->AddSplitPolygon(pPolygon0);
99 else if (IsVertexOnEdgeInModel(pModel, pPolygon0->GetPlane(), firstVertex, pPolygon0) &&
100 IsVertexOnEdgeInModel(pModel, pPolygon0->GetPlane(), lastVertex, pPolygon0))
102 pModel->RemovePolygon(pPolygon0);
103 pModel->AddSplitPolygon(pPolygon0);
107 else if (firstSpot.IsAtEndPoint() || lastSpot.IsAtEndPoint())
109 if (!firstSpot.IsAtEndPoint())
111 std::swap(firstSpot, lastSpot);
112 int iSize(copiedSpotList.size());
113 for (int i = 0, iHalfSize(iSize / 2); i < iHalfSize; ++i)
114 std::swap(copiedSpotList[i], copiedSpotList[iSize - i - 1]);
117 PolygonPtr pPolygon0 = firstSpot.m_pPolygon;
118 if (!pPolygon0)
119 return true;
121 pModel->RemovePolygon(pPolygon0);
123 for (int i = 0, nSpotSize(copiedSpotList.size() - 1); i < nSpotSize; ++i)
125 if (firstSpot.m_PosState == eSpotPosState_FirstPointOfPolygon)
126 pPolygon0->AddEdge(BrushEdge3D(copiedSpotList[i + 1].m_Pos, copiedSpotList[i].m_Pos));
127 else if (firstSpot.m_PosState == eSpotPosState_LastPointOfPolygon)
128 pPolygon0->AddEdge(BrushEdge3D(copiedSpotList[i].m_Pos, copiedSpotList[i + 1].m_Pos));
131 if (!pPolygon0->IsOpen())
133 pModel->AddSplitPolygon(pPolygon0);
135 else
137 BrushVec3 firstVertex;
138 BrushVec3 lastVertex;
139 bool bOnlyAdd = false;
141 bool bFirstOnEdge =
142 pPolygon0->GetFirstVertex(firstVertex) &&
143 IsVertexOnEdgeInModel(pModel, pPolygon0->GetPlane(), firstVertex, pPolygon0);
144 bool bLastOnEdge =
145 pPolygon0->GetLastVertex(lastVertex) &&
146 IsVertexOnEdgeInModel(pModel, pPolygon0->GetPlane(), lastVertex, pPolygon0);
148 if (bFirstOnEdge && bLastOnEdge)
149 pModel->AddSplitPolygon(pPolygon0);
150 else
151 pModel->AddPolygon(pPolygon0);
154 else if (firstSpot.IsOnEdge() && lastSpot.IsOnEdge())
156 BrushPlane plane;
157 if (FindBestPlane(pModel, firstSpot, secondSpot, plane))
159 std::vector<BrushVec3> vList;
160 GenerateVertexListFromSpotList(copiedSpotList, vList);
161 PolygonPtr pOpenPolygon = new Polygon(vList, plane, 0, NULL, false);
162 pModel->AddSplitPolygon(pOpenPolygon);
165 else if (firstSpot.IsInPolygon() || lastSpot.IsInPolygon())
167 BrushPlane plane;
168 if (FindBestPlane(pModel, firstSpot, secondSpot, plane))
170 std::vector<BrushVec3> vList;
171 GenerateVertexListFromSpotList(copiedSpotList, vList);
172 PolygonPtr pPolygon = new Polygon(vList, plane, 0, NULL, false);
173 pModel->AddPolygon(pPolygon);
176 else if (firstSpot.m_PosState == eSpotPosState_OutsideDesigner && lastSpot.m_PosState == eSpotPosState_OutsideDesigner)
178 if (firstSpot.m_Plane.IsEquivalent(lastSpot.m_Plane))
180 std::vector<BrushVec3> vList;
181 GenerateVertexListFromSpotList(copiedSpotList, vList);
182 PolygonPtr pPolygon = new Polygon(vList, firstSpot.m_Plane, 0, NULL, false);
183 pModel->AddPolygon(pPolygon);
186 else
188 ResetAllSpots();
189 return false;
192 if (pModel)
193 pModel->ResetDB(eDBRF_ALL);
195 return true;
198 void SpotManager::GenerateVertexListFromSpotList(const SpotList& spotList, std::vector<BrushVec3>& outVList)
200 int iSpotSize(spotList.size());
201 outVList.reserve(iSpotSize);
202 for (int i = 0; i < iSpotSize; ++i)
203 outVList.push_back(spotList[i].m_Pos);
206 void SpotManager::RegisterSpotList(Model* pModel, const SpotList& spotList)
208 if (pModel == NULL)
209 return;
211 if (spotList.size() <= 1)
213 ResetAllSpots();
214 return;
217 std::vector<SpotList> splittedSpotList;
218 SplitSpotList(pModel, spotList, splittedSpotList);
220 if (!splittedSpotList.empty())
222 for (int i = 0, spotListCount(splittedSpotList.size()); i < spotListCount; ++i)
223 AddPolygonToDesignerFromSpotList(pModel, splittedSpotList[i]);
227 void SpotManager::SplitSpotList(Model* pModel, const SpotList& spotList, std::vector<SpotList>& outSpotLists)
229 if (pModel == NULL)
230 return;
232 SpotList partSpotList;
234 for (int k = 0, iSpotListCount(spotList.size()); k < iSpotListCount - 1; ++k)
236 const Spot& currentSpot = spotList[k];
237 const Spot& nextSpot = spotList[k + 1];
239 SpotPairList splittedSpotPairs;
240 SplitSpot(pModel, SpotPair(currentSpot, nextSpot), splittedSpotPairs);
242 if (splittedSpotPairs.empty())
243 continue;
245 std::map<BrushFloat, SpotPair> sortedSpotPairs;
246 for (int i = 0, iSpotPairCount(splittedSpotPairs.size()); i < iSpotPairCount; ++i)
248 BrushFloat fDistance = currentSpot.m_Pos.GetDistance(splittedSpotPairs[i].m_Spot[0].m_Pos);
249 sortedSpotPairs[fDistance] = splittedSpotPairs[i];
252 auto ii = sortedSpotPairs.begin();
253 for (; ii != sortedSpotPairs.end(); ++ii)
255 const SpotPair& spotPair = ii->second;
257 if (partSpotList.empty())
258 partSpotList.push_back(spotPair.m_Spot[0]);
260 partSpotList.push_back(spotPair.m_Spot[1]);
261 if (!spotPair.m_Spot[1].IsEquivalentPos(nextSpot))
263 outSpotLists.push_back(partSpotList);
264 partSpotList.clear();
268 if (!partSpotList.empty())
269 outSpotLists.push_back(partSpotList);
272 void SpotManager::SplitSpot(Model* pModel, const SpotPair& spotPair, SpotPairList& outSpotPairs)
274 if (pModel == NULL)
275 return;
277 bool bSubtracted = false;
278 BrushEdge3D inputEdge(spotPair.m_Spot[0].m_Pos, spotPair.m_Spot[1].m_Pos);
279 BrushEdge3D invInputEdge(spotPair.m_Spot[1].m_Pos, spotPair.m_Spot[0].m_Pos);
281 BrushPlane plane;
282 if (!FindBestPlane(pModel, spotPair.m_Spot[0], spotPair.m_Spot[1], plane))
283 return;
285 for (int i = 0, iPolygonCount(pModel->GetPolygonCount()); i < iPolygonCount; ++i)
287 PolygonPtr pPolygon = pModel->GetPolygon(i);
288 if (pPolygon == NULL)
289 continue;
291 if (!pPolygon->GetPlane().IsEquivalent(plane))
292 continue;
294 std::vector<BrushEdge3D> subtractedEdges;
295 bSubtracted = pPolygon->SubtractEdge(inputEdge, subtractedEdges);
297 if (!subtractedEdges.empty())
299 auto ii = subtractedEdges.begin();
300 for (; ii != subtractedEdges.end(); )
302 if ((*ii).IsEquivalent(inputEdge) || (*ii).IsEquivalent(invInputEdge))
303 ii = subtractedEdges.erase(ii);
304 else
305 ++ii;
307 if (subtractedEdges.empty())
308 bSubtracted = false;
311 if (subtractedEdges.empty())
313 if (bSubtracted)
314 break;
315 continue;
318 if (subtractedEdges.size() == 1)
320 auto ii = subtractedEdges.begin();
321 if (Comparison::IsEquivalent((*ii).m_v[0], (*ii).m_v[1]))
322 continue;
325 int iSubtractedEdgeCount(subtractedEdges.size());
327 for (int k = 0; k < iSubtractedEdgeCount; ++k)
329 BrushEdge3D subtractedEdge = subtractedEdges[k];
330 SpotPair subtractedSpotPair;
332 for (int a = 0; a < 2; ++a)
334 subtractedSpotPair.m_Spot[a].m_Pos = subtractedEdge.m_v[a];
336 if (pPolygon->HasPosition(subtractedEdge.m_v[a]))
338 subtractedSpotPair.m_Spot[a].m_PosState = eSpotPosState_EitherPointOfEdge;
339 subtractedSpotPair.m_Spot[a].m_pPolygon = pPolygon;
341 else if (pPolygon->IsPositionOnBoundary(subtractedEdge.m_v[a]))
343 subtractedSpotPair.m_Spot[a].m_PosState = eSpotPosState_Edge;
344 subtractedSpotPair.m_Spot[a].m_pPolygon = pPolygon;
348 SplitSpot(pModel, subtractedSpotPair, outSpotPairs);
350 break;
353 if (!bSubtracted)
354 outSpotPairs.push_back(spotPair);
357 bool SpotManager::FindSpotNearAxisAlignedLine(IDisplayViewport* pViewport, PolygonPtr pPolygon, const BrushMatrix34& worldTM, Spot& outSpot)
359 if (m_CurrentSpot.IsOnEdge() || !pPolygon->Include(m_CurrentSpot.m_Pos))
360 return false;
362 std::vector<BrushLine> axisAlignedLines;
363 if (!pPolygon->QueryAxisAlignedLines(axisAlignedLines))
364 return false;
366 BrushVec2 vCurrentPos2D = pPolygon->GetPlane().W2P(m_CurrentSpot.m_Pos);
367 for (int i = 0, iLineCount(axisAlignedLines.size()); i < iLineCount; ++i)
369 BrushVec2 vHitPos;
370 if (!axisAlignedLines[i].HitTest(vCurrentPos2D, vCurrentPos2D + axisAlignedLines[i].m_Normal, 0, &vHitPos))
371 continue;
373 BrushFloat fLength(0);
374 if (AreTwoPositionsClose(pPolygon->GetPlane().P2W(vHitPos), m_CurrentSpot.m_Pos, worldTM, pViewport, kLimitForMagnetic, &fLength))
376 outSpot.Reset();
377 outSpot.m_pPolygon = pPolygon;
378 outSpot.m_PosState = eSpotPosState_OnVirtualLine;
379 outSpot.m_Plane = pPolygon->GetPlane();
380 outSpot.m_Pos = outSpot.m_Plane.P2W(vHitPos);
381 return true;
385 return false;
388 bool SpotManager::FindNicestSpot(IDisplayViewport* pViewport, const std::vector<CandidateInfo>& candidates, const Model* pModel, const BrushMatrix34& worldTM, const BrushVec3& pickedPos, PolygonPtr pPickedPolygon, const BrushPlane& plane, Spot& outSpot) const
390 if (!pModel)
391 return false;
393 BrushFloat fMinimumLength(3e10f);
395 for (int i = 0; i < candidates.size(); ++i)
397 BrushFloat fLength(0);
398 if (!AreTwoPositionsClose(pickedPos, candidates[i].m_Pos, worldTM, pViewport, kLimitForMagnetic, &fLength))
399 continue;
401 if (fLength >= fMinimumLength)
402 continue;
404 fMinimumLength = fLength;
406 outSpot.m_Pos = candidates[i].m_Pos;
407 outSpot.m_PosState = candidates[i].m_SpotPosState;
408 if (pPickedPolygon)
410 outSpot.m_pPolygon = pPickedPolygon;
411 outSpot.m_Plane = pPickedPolygon->GetPlane();
413 else
415 outSpot.m_pPolygon = NULL;
416 outSpot.m_Plane = plane;
419 if (outSpot.m_PosState != eSpotPosState_EitherPointOfEdge)
420 continue;
422 bool bFirstPoint = false;
423 if (!pPickedPolygon || !pPickedPolygon->IsEndPoint(outSpot.m_Pos, &bFirstPoint))
424 continue;
426 if (bFirstPoint)
427 outSpot.m_PosState = eSpotPosState_FirstPointOfPolygon;
428 else
429 outSpot.m_PosState = eSpotPosState_LastPointOfPolygon;
432 return true;
435 bool SpotManager::FindSnappedSpot(const BrushMatrix34& worldTM, PolygonPtr pPickedPolygon, const BrushVec3& pickedPos, Spot& outSpot) const
437 bool bEnableSnap = IsSnapEnabled();
438 if (!bEnableSnap)
439 return false;
441 if (!pPickedPolygon || pPickedPolygon->IsOpen())
442 return false;
444 BrushPlane pickedPlane(pPickedPolygon->GetPlane());
445 BrushVec3 snappedPlanePos = Snap(pickedPos);
446 outSpot.m_Pos = pickedPlane.P2W(pickedPlane.W2P(snappedPlanePos));
447 outSpot.m_pPolygon = pPickedPolygon;
448 outSpot.m_Plane = pPickedPolygon->GetPlane();
449 return true;
452 bool SpotManager::UpdateCurrentSpotPosition(
453 Model* pModel,
454 const BrushMatrix34& worldTM,
455 const BrushPlane& plane,
456 IDisplayViewport* view,
457 CPoint point,
458 bool bKeepInitialPlane,
459 bool bSearchAllShelves)
461 if (pModel == NULL)
462 return false;
464 BrushPlane pickedPlane(plane);
465 BrushVec3 pickedPos(m_CurrentSpot.m_Pos);
466 bool bSuccessQuery(false);
467 PolygonPtr pPickedPolygon;
468 ShelfID nShelf = eShelf_Any;
470 ResetCurrentSpotWeakly();
472 if (!bSearchAllShelves)
474 if (bKeepInitialPlane)
475 bSuccessQuery = pModel->QueryPosition(pickedPlane, GetDesigner()->GetRay(), pickedPos, NULL, &pPickedPolygon);
476 else
477 bSuccessQuery = pModel->QueryPosition(GetDesigner()->GetRay(), pickedPos, &pickedPlane, NULL, &pPickedPolygon);
479 else
481 PolygonPtr pPolygons[2] = { NULL, NULL };
482 bool bSuccessShelfQuery[2] = { false, false };
483 MODEL_SHELF_RECONSTRUCTOR(pModel);
484 for (int i = eShelf_Base; i < cShelfMax; ++i)
486 pModel->SetShelf(static_cast<ShelfID>(i));
487 if (bKeepInitialPlane)
488 bSuccessShelfQuery[i] = pModel->QueryPosition(pickedPlane, GetDesigner()->GetRay(), pickedPos, NULL, &(pPolygons[i]));
489 else
490 bSuccessShelfQuery[i] = pModel->QueryPosition(GetDesigner()->GetRay(), pickedPos, &pickedPlane, NULL, &(pPolygons[i]));
493 BrushFloat ts[2] = { 3e10, 3e10 };
494 for (int i = 0; i < 2; ++i)
496 if (pPolygons[i])
497 pPolygons[i]->IsPassed(GetDesigner()->GetRay(), ts[i]);
500 if (ts[0] < ts[1])
502 pPickedPolygon = pPolygons[0];
503 bSuccessQuery = bSuccessShelfQuery[0];
504 nShelf = eShelf_Base;
506 else
508 pPickedPolygon = pPolygons[1];
509 bSuccessQuery = bSuccessShelfQuery[1];
510 nShelf = eShelf_Construction;
514 if (pPickedPolygon && pPickedPolygon->CheckFlags(ePolyFlag_Mirrored | ePolyFlag_Hidden))
516 m_CurrentSpot.m_pPolygon = NULL;
517 return false;
520 if (!bSuccessQuery || bKeepInitialPlane && !pPickedPolygon)
522 if (!bSuccessQuery)
524 if (!GetPosAndPlaneFromWorld(view, point, worldTM, pickedPos, pickedPlane))
525 return false;
527 m_CurrentSpot.m_pPolygon = NULL;
528 m_CurrentSpot.m_Pos = pickedPos;
529 m_CurrentSpot.m_PosState = eSpotPosState_OutsideDesigner;
530 m_CurrentSpot.m_Plane = pickedPlane;
532 Spot niceSpot(m_CurrentSpot);
533 std::vector<CandidateInfo> candidates;
534 if (GetSpotListCount() > 0)
535 candidates.push_back(CandidateInfo(GetSpot(0).m_Pos, eSpotPosState_AtFirstSpot));
537 std::vector<PolygonPtr> penetratedOpenPolygons;
538 pModel->QueryOpenPolygons(GetDesigner()->GetRay(), penetratedOpenPolygons);
539 PolygonPtr pConnectedPolygon = NULL;
540 for (int i = 0, iCount(penetratedOpenPolygons.size()); i < iCount; ++i)
542 if (GetSpotListCount() > 0 && !GetSpot(0).m_Plane.IsEquivalent(penetratedOpenPolygons[i]->GetPlane()))
543 continue;
544 std::vector<Vertex> vList;
545 penetratedOpenPolygons[i]->GetLinkedVertices(vList);
546 pConnectedPolygon = penetratedOpenPolygons[i];
547 for (int k = 0, iVCount(vList.size()); k < iVCount; ++k)
549 if (k == 0)
550 candidates.push_back(CandidateInfo(vList[k].pos, eSpotPosState_FirstPointOfPolygon));
551 else if (k == iVCount - 1)
552 candidates.push_back(CandidateInfo(vList[k].pos, eSpotPosState_LastPointOfPolygon));
553 else
554 candidates.push_back(CandidateInfo(vList[k].pos, eSpotPosState_EitherPointOfEdge));
555 if (k < iVCount - 1)
557 candidates.push_back(CandidateInfo((vList[k].pos + vList[k + 1].pos) * 0.5f, eSpotPosState_CenterOfEdge));
558 BrushEdge3D edge(vList[k].pos, vList[k + 1].pos);
559 BrushVec3 posOnEdge;
560 bool bInEdge = false;
561 if (edge.CalculateNearestVertex(pickedPos, posOnEdge, bInEdge) && bInEdge && AreTwoPositionsClose(pickedPos, posOnEdge, worldTM, view, kLimitForMagnetic))
563 if (!Comparison::IsEquivalent(posOnEdge, vList[k].pos) && !Comparison::IsEquivalent(posOnEdge, vList[k + 1].pos))
564 candidates.push_back(CandidateInfo(posOnEdge, eSpotPosState_Edge));
569 if (!candidates.empty() && FindNicestSpot(view, candidates, pModel, worldTM, pickedPos, pConnectedPolygon, plane, niceSpot))
570 m_CurrentSpot = niceSpot;
572 if (!m_CurrentSpot.m_pPolygon)
573 m_CurrentSpot.m_Pos = Snap(m_CurrentSpot.m_Pos);
574 return true;
577 m_CurrentSpot.m_pPolygon = pPickedPolygon;
579 bool bEnableSnap = IsSnapEnabled();
580 if (!m_bEnableMagnetic && !bEnableSnap)
582 if (bSuccessQuery)
584 m_CurrentSpot.m_Pos = pickedPos;
585 m_CurrentSpot.m_Plane = pickedPlane;
587 return true;
590 if (bEnableSnap && pPickedPolygon == NULL)
592 m_CurrentSpot.m_Plane = pickedPlane;
593 m_CurrentSpot.m_Pos = Snap(pickedPos);
594 m_CurrentSpot.m_pPolygon = NULL;
595 return true;
598 BrushVec3 nearestEdge[2];
599 BrushVec3 posOnEdge;
600 std::vector<QueryEdgeResult> queryResults;
601 std::vector<BrushEdge3D> queryEdges;
604 MODEL_SHELF_RECONSTRUCTOR(pModel);
605 if (nShelf != eShelf_Any)
606 pModel->SetShelf(nShelf);
607 bSuccessQuery = pModel->QueryNearestEdges(pickedPlane, GetDesigner()->GetRay(), pickedPos, posOnEdge, queryResults);
610 if (bKeepInitialPlane && !bSuccessQuery)
612 if (!bEnableSnap)
613 m_CurrentSpot.m_Pos = pickedPos;
614 m_CurrentSpot.m_Plane = pickedPlane;
615 return true;
618 if (!bSuccessQuery)
619 return false;
621 for (int i = 0, iQueryResultsCount(queryResults.size()); i < iQueryResultsCount; ++i)
622 queryEdges.push_back(queryResults[i].m_Edge);
624 if (m_bEnableMagnetic && AreTwoPositionsClose(pickedPos, posOnEdge, worldTM, view, kLimitForMagnetic))
626 m_CurrentSpot.m_Pos = posOnEdge;
627 m_CurrentSpot.m_PosState = eSpotPosState_Edge;
629 else if (!bEnableSnap)
631 m_CurrentSpot.m_Pos = pickedPos;
633 m_CurrentSpot.m_Plane = pickedPlane;
635 int nShortestIndex = FindShortestEdge(queryEdges);
636 pPickedPolygon = queryResults[nShortestIndex].m_pPolygon;
637 const BrushEdge3D& edge = queryEdges[nShortestIndex];
639 Spot niceSpot(m_CurrentSpot);
640 std::vector<CandidateInfo> candidates;
641 candidates.push_back(CandidateInfo(edge.m_v[0], eSpotPosState_EitherPointOfEdge));
642 candidates.push_back(CandidateInfo(edge.m_v[1], eSpotPosState_EitherPointOfEdge));
643 candidates.push_back(CandidateInfo((edge.m_v[0] + edge.m_v[1]) * 0.5f, eSpotPosState_CenterOfEdge));
644 if (GetSpotListCount() > 0)
645 candidates.push_back(CandidateInfo(GetSpot(0).m_Pos, eSpotPosState_AtFirstSpot));
646 BrushVec3 centerPolygonPos(m_CurrentSpot.m_Pos);
648 MODEL_SHELF_RECONSTRUCTOR(pModel);
649 if (nShelf != eShelf_Any)
650 pModel->SetShelf(nShelf);
651 if (pModel->QueryCenterOfPolygon(GetDesigner()->GetRay(), centerPolygonPos))
652 candidates.push_back(CandidateInfo(centerPolygonPos, eSpotPosState_CenterOfPolygon));
654 if (FindNicestSpot(view, candidates, pModel, worldTM, pickedPos, pPickedPolygon, plane, niceSpot))
655 m_CurrentSpot = niceSpot;
657 Spot snappedSpot;
658 if (FindSnappedSpot(worldTM, m_CurrentSpot.m_pPolygon, pickedPos, snappedSpot))
660 m_CurrentSpot = snappedSpot;
661 queryResults.clear();
662 MODEL_SHELF_RECONSTRUCTOR(pModel);
663 pModel->SetShelf(eShelf_Base);
664 pModel->QueryNearestEdges(pickedPlane, m_CurrentSpot.m_Pos, posOnEdge, queryResults);
665 if (Comparison::IsEquivalent(posOnEdge, m_CurrentSpot.m_Pos))
666 m_CurrentSpot.m_PosState = eSpotPosState_Edge;
667 else if (bSearchAllShelves)
669 pModel->SetShelf(eShelf_Construction);
670 pModel->QueryNearestEdges(pickedPlane, m_CurrentSpot.m_Pos, posOnEdge, queryResults);
671 if (Comparison::IsEquivalent(posOnEdge, m_CurrentSpot.m_Pos))
672 m_CurrentSpot.m_PosState = eSpotPosState_Edge;
674 return true;
677 Spot nearSpot(m_CurrentSpot);
678 if (FindSpotNearAxisAlignedLine(view, pPickedPolygon, worldTM, nearSpot))
679 m_CurrentSpot = nearSpot;
681 return bSuccessQuery;
684 void SpotManager::AddSpotToSpotList(const Spot& spot)
686 bool bExistSameSpot(false);
687 for (int i = 0, iSpotSize(GetSpotListCount()); i < iSpotSize; ++i)
689 if (GetSpot(i).IsEquivalentPos(spot) && !GetSpot(i).m_bProcessed)
691 bExistSameSpot = true;
692 break;
696 if (!bExistSameSpot)
697 m_SpotList.push_back(spot);
700 void SpotManager::ReplaceSpotList(const SpotList& spotList)
702 m_SpotList = spotList;
705 bool SpotManager::GetPlaneBeginEndPoints(const BrushPlane& plane, BrushVec2& outProjectedStartPt, BrushVec2& outProjectedEndPt) const
707 outProjectedStartPt = plane.W2P(GetStartSpotPos());
708 outProjectedEndPt = plane.W2P(GetCurrentSpotPos());
710 const BrushFloat SmallestPolygonSize(0.01f);
711 if (std::abs(outProjectedEndPt.x - outProjectedStartPt.x) < SmallestPolygonSize || std::abs(outProjectedEndPt.y - outProjectedStartPt.y) < SmallestPolygonSize)
712 return false;
714 const BrushVec2 vecMinimum(-1000.0f, -1000.0f);
715 const BrushVec2 vecMaximum(1000.0f, 1000.0f);
717 outProjectedStartPt.x = std::max(outProjectedStartPt.x, vecMinimum.x);
718 outProjectedStartPt.y = std::max(outProjectedStartPt.y, vecMinimum.y);
719 outProjectedEndPt.x = std::min(outProjectedEndPt.x, vecMaximum.x);
720 outProjectedEndPt.y = std::min(outProjectedEndPt.y, vecMaximum.y);
722 return true;
725 bool SpotManager::GetPosAndPlaneFromWorld(IDisplayViewport* view, const CPoint& point, const BrushMatrix34& worldTM, BrushVec3& outPos, BrushPlane& outPlane)
727 Vec3 vPickedPos;
728 if (!PickPosFromWorld(view, point, vPickedPos))
729 return false;
730 Matrix34 invTM = worldTM.GetInverted();
731 Vec3 p0 = invTM.TransformPoint(vPickedPos);
732 outPlane = BrushPlane(BrushVec3(0, 0, 1), -p0.Dot(BrushVec3(0, 0, 1)));
733 outPos = ToBrushVec3(p0);
734 return true;
737 bool SpotManager::FindBestPlane(Model* pModel, const Spot& s0, const Spot& s1, BrushPlane& outPlane)
739 if (s0.m_pPolygon && s0.m_pPolygon == s1.m_pPolygon)
741 outPlane = s0.m_pPolygon->GetPlane();
742 return true;
745 BrushPlane candidatePlanes[] = { s0.m_Plane, s1.m_Plane };
746 for (int i = 0, iCandidatePlaneCount(sizeof(candidatePlanes) / sizeof(*candidatePlanes)); i < iCandidatePlaneCount; ++i)
748 if (candidatePlanes[i].Normal().IsZero(kDesignerEpsilon))
749 continue;
750 BrushFloat d0 = candidatePlanes[i].Distance(s0.m_Pos);
751 BrushFloat d1 = candidatePlanes[i].Distance(s1.m_Pos);
752 if (std::abs(d0) < kDesignerEpsilon && std::abs(d1) < kDesignerEpsilon)
754 outPlane = candidatePlanes[i];
755 return true;
759 for (int i = 0, iPolygonCount(pModel->GetPolygonCount()); i < iPolygonCount; ++i)
761 const BrushPlane& plane = pModel->GetPolygon(i)->GetPlane();
762 BrushFloat d0 = plane.Distance(s0.m_Pos);
763 BrushFloat d1 = plane.Distance(s1.m_Pos);
764 if (std::abs(d0) < kDesignerEpsilon && std::abs(d1) < kDesignerEpsilon)
766 outPlane = plane;
767 return true;
771 DESIGNER_ASSERT(0);
772 return false;
775 bool SpotManager::IsSnapEnabled() const
777 if (!m_bBuiltInSnap)
778 return gSnappingPreferences.gridSnappingEnabled() | m_bBuiltInSnap;
779 return true;
782 BrushVec3 SpotManager::Snap(const BrushVec3& vPos) const
784 if (!m_bBuiltInSnap)
785 return gSnappingPreferences.Snap(vPos);
787 BrushVec3 snapped;
788 snapped.x = std::floor((vPos.x / m_BuiltInSnapSize) + (BrushFloat)0.5) * m_BuiltInSnapSize;
789 snapped.y = std::floor((vPos.y / m_BuiltInSnapSize) + (BrushFloat)0.5) * m_BuiltInSnapSize;
790 snapped.z = std::floor((vPos.z / m_BuiltInSnapSize) + (BrushFloat)0.5) * m_BuiltInSnapSize;
792 return snapped;
795 bool SpotManager::IsVertexOnEdgeInModel(Model* pModel, const BrushPlane& plane, const BrushVec3& vertex, PolygonPtr pExcludedPolygon) const
797 for (int i = 0, iPolygonSize(pModel->GetPolygonCount()); i < iPolygonSize; ++i)
799 PolygonPtr pPolygon = pModel->GetPolygon(i);
800 if (pPolygon == NULL)
801 continue;
802 if (pExcludedPolygon && pExcludedPolygon == pPolygon)
803 continue;
804 const BrushPlane& polygonPlane = pPolygon->GetPlane();
805 if (!plane.IsEquivalent(polygonPlane))
806 continue;
807 BrushEdge3D nearestEdge;
808 BrushVec3 hitPos;
809 if (!pPolygon->QueryNearestEdge(vertex, nearestEdge, hitPos))
810 continue;
811 if ((vertex - hitPos).GetLength() < kDesignerEpsilon)
812 return true;
814 return false;