1 /******************************************************************************
2
3 This source file is part of the Avogadro project.
4
5 Copyright 2013 Kitware, Inc.
6
7 This source code is released under the New BSD License, (the "License").
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14
15 ******************************************************************************/
16
17 #include "geometryvisitor.h"
18
19 #include "ambientocclusionspheregeometry.h"
20 #include "linestripgeometry.h"
21 #include "spheregeometry.h"
22
23 namespace Avogadro {
24 namespace Rendering {
25
GeometryVisitor()26 GeometryVisitor::GeometryVisitor()
27 : m_center(Vector3f::Zero()), m_radius(0.0f), m_dirty(false)
28 {
29 }
30
~GeometryVisitor()31 GeometryVisitor::~GeometryVisitor()
32 {
33 }
34
visit(Drawable &)35 void GeometryVisitor::visit(Drawable&)
36 {
37 }
38
visit(SphereGeometry & geometry)39 void GeometryVisitor::visit(SphereGeometry& geometry)
40 {
41 const Core::Array<SphereColor>& spheres = geometry.spheres();
42 if (!spheres.size())
43 return;
44
45 m_dirty = true;
46
47 Vector3f tmpCenter(Vector3f::Zero());
48 // First find the center of the sphere geometry.
49 std::vector<SphereColor>::const_iterator it = spheres.begin();
50 for (; it != spheres.end(); ++it)
51 tmpCenter += it->center;
52 tmpCenter /= static_cast<float>(spheres.size());
53
54 // Now find its radius.
55 float tmpRadius(0.0f);
56 if (spheres.size() > 1) {
57 for (it = spheres.begin(); it != spheres.end(); ++it) {
58 float distance = (it->center - tmpCenter).squaredNorm();
59 if (distance > tmpRadius)
60 tmpRadius = distance;
61 }
62 }
63 tmpRadius = std::sqrt(tmpRadius);
64 m_centers.push_back(tmpCenter);
65 m_radii.push_back(tmpRadius);
66 }
67
visit(AmbientOcclusionSphereGeometry & geometry)68 void GeometryVisitor::visit(AmbientOcclusionSphereGeometry& geometry)
69 {
70 const Core::Array<SphereColor>& spheres = geometry.spheres();
71 if (!spheres.size())
72 return;
73
74 m_dirty = true;
75
76 Vector3f tmpCenter(Vector3f::Zero());
77 // First find the center of the sphere geometry.
78 std::vector<SphereColor>::const_iterator it = spheres.begin();
79 for (; it != spheres.end(); ++it)
80 tmpCenter += it->center;
81 tmpCenter /= static_cast<float>(spheres.size());
82
83 // Now find its radius.
84 float tmpRadius(0.0f);
85 if (spheres.size() > 1) {
86 for (it = spheres.begin(); it != spheres.end(); ++it) {
87 float distance = (it->center - tmpCenter).squaredNorm();
88 if (distance > tmpRadius)
89 tmpRadius = distance;
90 }
91 }
92 tmpRadius = std::sqrt(tmpRadius);
93 m_centers.push_back(tmpCenter);
94 m_radii.push_back(tmpRadius);
95 }
96
visit(LineStripGeometry & lsg)97 void GeometryVisitor::visit(LineStripGeometry& lsg)
98 {
99 typedef Core::Array<LineStripGeometry::PackedVertex> VertexArray;
100 const VertexArray verts(lsg.vertices());
101 if (!verts.size())
102 return;
103
104 m_dirty = true;
105
106 Vector3f tmpCenter(Vector3f::Zero());
107 for (VertexArray::const_iterator it = verts.begin(), itEnd = verts.end();
108 it != itEnd; ++it) {
109 tmpCenter += it->vertex;
110 }
111 tmpCenter /= static_cast<float>(verts.size());
112
113 float tmpRadius(0.f);
114 for (VertexArray::const_iterator it = verts.begin(), itEnd = verts.end();
115 it != itEnd; ++it) {
116 float distance = (it->vertex - tmpCenter).squaredNorm();
117 if (distance > tmpRadius)
118 tmpRadius = distance;
119 }
120
121 m_centers.push_back(tmpCenter);
122 m_radii.push_back(std::sqrt(tmpRadius));
123 }
124
clear()125 void GeometryVisitor::clear()
126 {
127 m_center = Vector3f::Zero();
128 m_radius = 0.0f;
129 m_dirty = false;
130 m_centers.clear();
131 m_radii.clear();
132 }
133
center()134 Vector3f GeometryVisitor::center()
135 {
136 average();
137 return m_center;
138 }
139
radius()140 float GeometryVisitor::radius()
141 {
142 average();
143 return m_radius;
144 }
145
average()146 void GeometryVisitor::average()
147 {
148 if (!m_dirty)
149 return;
150
151 // Find the average position of the center, then the minimal enclosing radius.
152 m_dirty = false;
153 if (m_centers.size() == 1) {
154 m_center = m_centers[0];
155 m_radius = m_radii[0];
156 } else {
157 m_center = Vector3f::Zero();
158 std::vector<Vector3f>::const_iterator cit;
159 for (cit = m_centers.begin(); cit != m_centers.end(); ++cit)
160 m_center += *cit;
161 m_center /= static_cast<float>(m_centers.size());
162 // Now find the smallest enclosing radius for the new center.
163 m_radius = 0.0f;
164 std::vector<float>::const_iterator rit;
165 for (cit = m_centers.begin(), rit = m_radii.begin();
166 cit != m_centers.end() && rit != m_radii.end(); ++cit, ++rit) {
167 float distance = (m_center - (*cit)).norm() + (*rit);
168 if (distance > m_radius)
169 m_radius = distance;
170 }
171 }
172 }
173
174 } // End namespace Rendering
175 } // End namespace Avogadro
176