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