1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "Group.h"
21 
22 #include "Hit.h"
23 #include "Model/BoundsContainsNodeVisitor.h"
24 #include "Model/BoundsIntersectsNodeVisitor.h"
25 #include "Model/Brush.h"
26 #include "Model/ComputeNodeBoundsVisitor.h"
27 #include "Model/Entity.h"
28 #include "Model/FindContainerVisitor.h"
29 #include "Model/FindGroupVisitor.h"
30 #include "Model/FindLayerVisitor.h"
31 #include "Model/GroupSnapshot.h"
32 #include "Model/IntersectNodeWithRayVisitor.h"
33 #include "Model/IssueGenerator.h"
34 #include "Model/NodeVisitor.h"
35 #include "Model/PickResult.h"
36 #include "Model/TransformObjectVisitor.h"
37 
38 namespace TrenchBroom {
39     namespace Model {
40         const Hit::HitType Group::GroupHit = Hit::freeHitType();
41 
Group(const String & name)42         Group::Group(const String& name) :
43         m_name(name),
44         m_editState(Edit_Closed),
45         m_boundsValid(false) {}
46 
setName(const String & name)47         void Group::setName(const String& name) {
48             m_name = name;
49         }
50 
opened() const51         bool Group::opened() const {
52             return m_editState == Edit_Open;
53         }
54 
open()55         void Group::open() {
56             assert(m_editState == Edit_Closed);
57             setEditState(Edit_Open);
58             openAncestors();
59         }
60 
close()61         void Group::close() {
62             assert(m_editState == Edit_Open);
63             setEditState(Edit_Closed);
64             closeAncestors();
65         }
66 
setEditState(const EditState editState)67         void Group::setEditState(const EditState editState) {
68             m_editState = editState;
69         }
70 
71         class Group::SetEditStateVisitor : public NodeVisitor {
72         private:
73             EditState m_editState;
74         public:
SetEditStateVisitor(const EditState editState)75             SetEditStateVisitor(const EditState editState) : m_editState(editState) {}
76         private:
doVisit(World * world)77             void doVisit(World* world)   {}
doVisit(Layer * layer)78             void doVisit(Layer* layer)   {}
doVisit(Group * group)79             void doVisit(Group* group)   { group->setEditState(m_editState); }
doVisit(Entity * entity)80             void doVisit(Entity* entity) {}
doVisit(Brush * brush)81             void doVisit(Brush* brush)   {}
82         };
83 
openAncestors()84         void Group::openAncestors() {
85             SetEditStateVisitor visitor(Edit_DescendantOpen);
86             escalate(visitor);
87         }
88 
closeAncestors()89         void Group::closeAncestors() {
90             SetEditStateVisitor visitor(Edit_Closed);
91             escalate(visitor);
92         }
93 
hasOpenedDescendant() const94         bool Group::hasOpenedDescendant() const {
95             return m_editState == Edit_DescendantOpen;
96         }
97 
doGetName() const98         const String& Group::doGetName() const {
99             return m_name;
100         }
101 
doGetBounds() const102         const BBox3& Group::doGetBounds() const {
103             if (!m_boundsValid)
104                 validateBounds();
105             return m_bounds;
106         }
107 
doClone(const BBox3 & worldBounds) const108         Node* Group::doClone(const BBox3& worldBounds) const {
109             Group* group = new Group(m_name);
110             cloneAttributes(group);
111             return group;
112         }
113 
doTakeSnapshot()114         NodeSnapshot* Group::doTakeSnapshot() {
115             return new GroupSnapshot(this);
116         }
117 
118         class CanAddChildToGroup : public ConstNodeVisitor, public NodeQuery<bool> {
119         private:
doVisit(const World * world)120             void doVisit(const World* world)   { setResult(false); }
doVisit(const Layer * layer)121             void doVisit(const Layer* layer)   { setResult(false); }
doVisit(const Group * group)122             void doVisit(const Group* group)   { setResult(true); }
doVisit(const Entity * entity)123             void doVisit(const Entity* entity) { setResult(true); }
doVisit(const Brush * brush)124             void doVisit(const Brush* brush)   { setResult(true); }
125         };
126 
doCanAddChild(const Node * child) const127         bool Group::doCanAddChild(const Node* child) const {
128             CanAddChildToGroup visitor;
129             child->accept(visitor);
130             return visitor.result();
131         }
132 
doCanRemoveChild(const Node * child) const133         bool Group::doCanRemoveChild(const Node* child) const {
134             return true;
135         }
136 
doRemoveIfEmpty() const137         bool Group::doRemoveIfEmpty() const {
138             return true;
139         }
140 
doChildWasAdded(Node * node)141         void Group::doChildWasAdded(Node* node) {
142             nodeBoundsDidChange();
143         }
144 
doChildWasRemoved(Node * node)145         void Group::doChildWasRemoved(Node* node) {
146             nodeBoundsDidChange();
147         }
148 
doNodeBoundsDidChange()149         void Group::doNodeBoundsDidChange() {
150             invalidateBounds();
151         }
152 
doChildBoundsDidChange(Node * node)153         void Group::doChildBoundsDidChange(Node* node) {
154             nodeBoundsDidChange();
155         }
156 
doShouldPropagateDescendantEvents() const157         bool Group::doShouldPropagateDescendantEvents() const {
158             return false;
159         }
160 
doSelectable() const161         bool Group::doSelectable() const {
162             return true;
163         }
164 
doPick(const Ray3 & ray,PickResult & pickResult) const165         void Group::doPick(const Ray3& ray, PickResult& pickResult) const {
166             if (!opened() && !hasOpenedDescendant()) {
167                 const FloatType distance = intersectWithRay(ray);
168                 if (!Math::isnan(distance)) {
169                     const Vec3 hitPoint = ray.pointAtDistance(distance);
170                     pickResult.addHit(Hit(GroupHit, distance, hitPoint, this));
171                 }
172             }
173 
174             const NodeList& children = Node::children();
175             NodeList::const_iterator it, end;
176             for (it = children.begin(), end = children.end(); it != end; ++it) {
177                 const Node* child = *it;
178                 child->pick(ray, pickResult);
179             }
180         }
181 
doFindNodesContaining(const Vec3 & point,NodeList & result)182         void Group::doFindNodesContaining(const Vec3& point, NodeList& result) {
183             if (bounds().contains(point))
184                 result.push_back(this);
185 
186             const NodeList& children = Node::children();
187             NodeList::const_iterator it, end;
188             for (it = children.begin(), end = children.end(); it != end; ++it) {
189                 Node* child = *it;
190                 child->findNodesContaining(point, result);
191             }
192         }
193 
doIntersectWithRay(const Ray3 & ray) const194         FloatType Group::doIntersectWithRay(const Ray3& ray) const {
195             const BBox3& myBounds = bounds();
196             if (!myBounds.contains(ray.origin) && Math::isnan(myBounds.intersectWithRay(ray)))
197                 return Math::nan<FloatType>();
198 
199             IntersectNodeWithRayVisitor visitor(ray);
200             iterate(visitor);
201             if (!visitor.hasResult())
202                 return Math::nan<FloatType>();
203             return visitor.result();
204         }
205 
doGenerateIssues(const IssueGenerator * generator,IssueList & issues)206         void Group::doGenerateIssues(const IssueGenerator* generator, IssueList& issues) {
207             generator->generate(this, issues);
208         }
209 
doAccept(NodeVisitor & visitor)210         void Group::doAccept(NodeVisitor& visitor) {
211             visitor.visit(this);
212         }
213 
doAccept(ConstNodeVisitor & visitor) const214         void Group::doAccept(ConstNodeVisitor& visitor) const {
215             visitor.visit(this);
216         }
217 
doGetContainer() const218         Node* Group::doGetContainer() const {
219             FindContainerVisitor visitor;
220             escalate(visitor);
221             return visitor.hasResult() ? visitor.result() : NULL;
222         }
223 
doGetLayer() const224         Layer* Group::doGetLayer() const {
225             FindLayerVisitor visitor;
226             escalate(visitor);
227             return visitor.hasResult() ? visitor.result() : NULL;
228         }
229 
doGetGroup() const230         Group* Group::doGetGroup() const {
231             FindGroupVisitor visitor(false);
232             escalate(visitor);
233             return visitor.hasResult() ? visitor.result() : NULL;
234         }
235 
doTransform(const Mat4x4 & transformation,const bool lockTextures,const BBox3 & worldBounds)236         void Group::doTransform(const Mat4x4& transformation, const bool lockTextures, const BBox3& worldBounds) {
237             TransformObjectVisitor visitor(transformation, lockTextures, worldBounds);
238             iterate(visitor);
239         }
240 
doContains(const Node * node) const241         bool Group::doContains(const Node* node) const {
242             BoundsContainsNodeVisitor contains(bounds());
243             node->accept(contains);
244             assert(contains.hasResult());
245             return contains.result();
246         }
247 
doIntersects(const Node * node) const248         bool Group::doIntersects(const Node* node) const {
249             BoundsIntersectsNodeVisitor intersects(bounds());
250             node->accept(intersects);
251             assert(intersects.hasResult());
252             return intersects.result();
253         }
254 
invalidateBounds()255         void Group::invalidateBounds() {
256             m_boundsValid = false;
257         }
258 
validateBounds() const259         void Group::validateBounds() const {
260             ComputeNodeBoundsVisitor visitor(BBox3(0.0));
261             iterate(visitor);
262             m_bounds = visitor.bounds();
263             m_boundsValid = true;
264         }
265     }
266 }
267