1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
5 #include "SpotManager.h"
6 #include "Tools/BaseTool.h"
7 #include "Core/Model.h"
8 #include "DesignerEditor.h"
10 #include "SurfaceInfoPicker.h"
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
);
34 DrawSpot(dc
, worldTM
, m_CurrentSpot
.m_Pos
, normalColor
);
37 void SpotManager::DrawPolyline(SDisplayContext
& dc
) const
39 if (m_SpotList
.empty())
42 for (int i
= 0, iSpotSize(m_SpotList
.size() - 1); i
< iSpotSize
; ++i
)
44 if (m_SpotList
[i
].m_bProcessed
)
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())
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
;
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
;
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
;
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
);
137 BrushVec3 firstVertex
;
138 BrushVec3 lastVertex
;
139 bool bOnlyAdd
= false;
142 pPolygon0
->GetFirstVertex(firstVertex
) &&
143 IsVertexOnEdgeInModel(pModel
, pPolygon0
->GetPlane(), firstVertex
, pPolygon0
);
145 pPolygon0
->GetLastVertex(lastVertex
) &&
146 IsVertexOnEdgeInModel(pModel
, pPolygon0
->GetPlane(), lastVertex
, pPolygon0
);
148 if (bFirstOnEdge
&& bLastOnEdge
)
149 pModel
->AddSplitPolygon(pPolygon0
);
151 pModel
->AddPolygon(pPolygon0
);
154 else if (firstSpot
.IsOnEdge() && lastSpot
.IsOnEdge())
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())
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
);
193 pModel
->ResetDB(eDBRF_ALL
);
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
)
211 if (spotList
.size() <= 1)
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
)
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())
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
)
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
);
282 if (!FindBestPlane(pModel
, spotPair
.m_Spot
[0], spotPair
.m_Spot
[1], plane
))
285 for (int i
= 0, iPolygonCount(pModel
->GetPolygonCount()); i
< iPolygonCount
; ++i
)
287 PolygonPtr pPolygon
= pModel
->GetPolygon(i
);
288 if (pPolygon
== NULL
)
291 if (!pPolygon
->GetPlane().IsEquivalent(plane
))
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
);
307 if (subtractedEdges
.empty())
311 if (subtractedEdges
.empty())
318 if (subtractedEdges
.size() == 1)
320 auto ii
= subtractedEdges
.begin();
321 if (Comparison::IsEquivalent((*ii
).m_v
[0], (*ii
).m_v
[1]))
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
);
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
))
362 std::vector
<BrushLine
> axisAlignedLines
;
363 if (!pPolygon
->QueryAxisAlignedLines(axisAlignedLines
))
366 BrushVec2 vCurrentPos2D
= pPolygon
->GetPlane().W2P(m_CurrentSpot
.m_Pos
);
367 for (int i
= 0, iLineCount(axisAlignedLines
.size()); i
< iLineCount
; ++i
)
370 if (!axisAlignedLines
[i
].HitTest(vCurrentPos2D
, vCurrentPos2D
+ axisAlignedLines
[i
].m_Normal
, 0, &vHitPos
))
373 BrushFloat
fLength(0);
374 if (AreTwoPositionsClose(pPolygon
->GetPlane().P2W(vHitPos
), m_CurrentSpot
.m_Pos
, worldTM
, pViewport
, kLimitForMagnetic
, &fLength
))
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
);
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
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
))
401 if (fLength
>= fMinimumLength
)
404 fMinimumLength
= fLength
;
406 outSpot
.m_Pos
= candidates
[i
].m_Pos
;
407 outSpot
.m_PosState
= candidates
[i
].m_SpotPosState
;
410 outSpot
.m_pPolygon
= pPickedPolygon
;
411 outSpot
.m_Plane
= pPickedPolygon
->GetPlane();
415 outSpot
.m_pPolygon
= NULL
;
416 outSpot
.m_Plane
= plane
;
419 if (outSpot
.m_PosState
!= eSpotPosState_EitherPointOfEdge
)
422 bool bFirstPoint
= false;
423 if (!pPickedPolygon
|| !pPickedPolygon
->IsEndPoint(outSpot
.m_Pos
, &bFirstPoint
))
427 outSpot
.m_PosState
= eSpotPosState_FirstPointOfPolygon
;
429 outSpot
.m_PosState
= eSpotPosState_LastPointOfPolygon
;
435 bool SpotManager::FindSnappedSpot(const BrushMatrix34
& worldTM
, PolygonPtr pPickedPolygon
, const BrushVec3
& pickedPos
, Spot
& outSpot
) const
437 bool bEnableSnap
= IsSnapEnabled();
441 if (!pPickedPolygon
|| pPickedPolygon
->IsOpen())
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();
452 bool SpotManager::UpdateCurrentSpotPosition(
454 const BrushMatrix34
& worldTM
,
455 const BrushPlane
& plane
,
456 IDisplayViewport
* view
,
458 bool bKeepInitialPlane
,
459 bool bSearchAllShelves
)
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
);
477 bSuccessQuery
= pModel
->QueryPosition(GetDesigner()->GetRay(), pickedPos
, &pickedPlane
, NULL
, &pPickedPolygon
);
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
]));
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
)
497 pPolygons
[i
]->IsPassed(GetDesigner()->GetRay(), ts
[i
]);
502 pPickedPolygon
= pPolygons
[0];
503 bSuccessQuery
= bSuccessShelfQuery
[0];
504 nShelf
= eShelf_Base
;
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
;
520 if (!bSuccessQuery
|| bKeepInitialPlane
&& !pPickedPolygon
)
524 if (!GetPosAndPlaneFromWorld(view
, point
, worldTM
, pickedPos
, pickedPlane
))
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()))
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
)
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
));
554 candidates
.push_back(CandidateInfo(vList
[k
].pos
, eSpotPosState_EitherPointOfEdge
));
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
);
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
);
577 m_CurrentSpot
.m_pPolygon
= pPickedPolygon
;
579 bool bEnableSnap
= IsSnapEnabled();
580 if (!m_bEnableMagnetic
&& !bEnableSnap
)
584 m_CurrentSpot
.m_Pos
= pickedPos
;
585 m_CurrentSpot
.m_Plane
= pickedPlane
;
590 if (bEnableSnap
&& pPickedPolygon
== NULL
)
592 m_CurrentSpot
.m_Plane
= pickedPlane
;
593 m_CurrentSpot
.m_Pos
= Snap(pickedPos
);
594 m_CurrentSpot
.m_pPolygon
= NULL
;
598 BrushVec3 nearestEdge
[2];
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
)
613 m_CurrentSpot
.m_Pos
= pickedPos
;
614 m_CurrentSpot
.m_Plane
= pickedPlane
;
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
;
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
;
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;
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
)
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
);
725 bool SpotManager::GetPosAndPlaneFromWorld(IDisplayViewport
* view
, const CPoint
& point
, const BrushMatrix34
& worldTM
, BrushVec3
& outPos
, BrushPlane
& outPlane
)
728 if (!PickPosFromWorld(view
, point
, vPickedPos
))
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
);
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();
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
))
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
];
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
)
775 bool SpotManager::IsSnapEnabled() const
778 return gSnappingPreferences
.gridSnappingEnabled() | m_bBuiltInSnap
;
782 BrushVec3
SpotManager::Snap(const BrushVec3
& vPos
) const
785 return gSnappingPreferences
.Snap(vPos
);
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
;
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
)
802 if (pExcludedPolygon
&& pExcludedPolygon
== pPolygon
)
804 const BrushPlane
& polygonPlane
= pPolygon
->GetPlane();
805 if (!plane
.IsEquivalent(polygonPlane
))
807 BrushEdge3D nearestEdge
;
809 if (!pPolygon
->QueryNearestEdge(vertex
, nearestEdge
, hitPos
))
811 if ((vertex
- hitPos
).GetLength() < kDesignerEpsilon
)