Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / native_client_sdk / src / examples / demo / flock / goose.cc
blobf706134c654b0b2a5b197a896d20e0c6d2dbbb06
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "goose.h"
7 namespace {
8 // The maximum speed of a goose. Measured in meters/second.
9 const double kMaxSpeed = 2.0;
11 // The maximum force that can be applied to turn a goose when computing the
12 // aligment. Measured in meters/second/second.
13 const double kMaxTurningForce = 0.05;
15 // The neighbour radius of a goose. Only geese within this radius will affect
16 // the flocking computations of this goose. Measured in pixels.
17 const double kNeighbourRadius = 64.0;
19 // The minimum distance that a goose can be from this goose. If another goose
20 // comes within this distance of this goose, the flocking algorithm tries to
21 // move the geese apart. Measured in pixels.
22 const double kPersonalSpace = 32.0;
24 // The distance at which attractors have effect on a goose's direction.
25 const double kAttractorRadius = 320.0;
27 // The goose will try to turn towards geese within this distance (computed
28 // during the cohesion phase). Measured in pixels.
29 const double kMaxTurningDistance = 100.0;
31 // The weights used when computing the weighted sum the three flocking
32 // components.
33 const double kSeparationWeight = 2.0;
34 const double kAlignmentWeight = 1.0;
35 const double kCohesionWeight = 1.0;
37 } // namespace
40 Goose::Goose() : location_(0, 0), velocity_(0, 0) {
43 Goose::Goose(const Vector2& location, const Vector2& velocity)
44 : location_(location),
45 velocity_(velocity) {
48 void Goose::SimulationTick(const std::vector<Goose>& geese,
49 const std::vector<Vector2>& attractors,
50 const pp::Rect& flock_box) {
52 Vector2 acceleration = DesiredVector(geese, attractors);
53 velocity_.Add(acceleration);
55 // Limit the velocity to a maximum speed.
56 velocity_.Clamp(kMaxSpeed);
58 location_.Add(velocity_);
60 // Wrap the goose location to the flock box.
61 if (!flock_box.IsEmpty()) {
62 while (location_.x() < flock_box.x())
63 location_.set_x(location_.x() + flock_box.width());
65 while (location_.x() >= flock_box.right())
66 location_.set_x(location_.x() - flock_box.width());
68 while (location_.y() < flock_box.y())
69 location_.set_y(location_.y() + flock_box.height());
71 while (location_.y() >= flock_box.bottom())
72 location_.set_y(location_.y() - flock_box.height());
76 Vector2 Goose::DesiredVector(const std::vector<Goose>& geese,
77 const std::vector<Vector2>& attractors) {
78 // Loop over all the neighbouring geese in the flock, accumulating
79 // the separation mean, the alignment mean and the cohesion mean.
80 int32_t separation_count = 0;
81 Vector2 separation;
82 int32_t align_count = 0;
83 Vector2 alignment;
84 int32_t cohesion_count = 0;
85 Vector2 cohesion;
87 for (std::vector<Goose>::const_iterator goose_it = geese.begin();
88 goose_it < geese.end();
89 ++goose_it) {
90 const Goose& goose = *goose_it;
92 // Compute the distance from this goose to its neighbour.
93 Vector2 goose_delta = Vector2::Difference(
94 location_, goose.location());
95 double distance = goose_delta.Magnitude();
97 separation_count = AccumulateSeparation(
98 distance, goose_delta, &separation, separation_count);
100 align_count = AccumulateAlignment(
101 distance, goose, &alignment, align_count);
102 cohesion_count = AccumulateCohesion(
103 distance, goose, &cohesion, cohesion_count);
106 // Compute the means and create a weighted sum. This becomes the goose's new
107 // acceleration.
108 if (separation_count > 0) {
109 separation.Scale(1.0 / static_cast<double>(separation_count));
111 if (align_count > 0) {
112 alignment.Scale(1.0 / static_cast<double>(align_count));
113 // Limit the effect that alignment has on the final acceleration. The
114 // alignment component can overpower the others if there is a big
115 // difference between this goose's velocity and its neighbours'.
116 alignment.Clamp(kMaxTurningForce);
119 // Compute the effect of the attractors and blend this in with the flock
120 // cohesion component. An attractor has to be within kAttractorRadius to
121 // effect the heading of a goose.
122 for (size_t i = 0; i < attractors.size(); ++i) {
123 Vector2 attractor_direction = Vector2::Difference(
124 attractors[i], location_);
125 double distance = attractor_direction.Magnitude();
126 if (distance < kAttractorRadius) {
127 attractor_direction.Scale(1000); // Each attractor acts like 1000 geese.
128 cohesion.Add(attractor_direction);
129 cohesion_count++;
133 // If there is a non-0 cohesion component, steer the goose so that it tries
134 // to follow the flock.
135 if (cohesion_count > 0) {
136 cohesion.Scale(1.0 / static_cast<double>(cohesion_count));
137 cohesion = TurnTowardsTarget(cohesion);
139 // Compute the weighted sum.
140 separation.Scale(kSeparationWeight);
141 alignment.Scale(kAlignmentWeight);
142 cohesion.Scale(kCohesionWeight);
143 Vector2 weighted_sum = cohesion;
144 weighted_sum.Add(alignment);
145 weighted_sum.Add(separation);
146 return weighted_sum;
149 Vector2 Goose::TurnTowardsTarget(const Vector2& target) {
150 Vector2 desired_direction = Vector2::Difference(target, location_);
151 double distance = desired_direction.Magnitude();
152 Vector2 new_direction;
153 if (distance > 0.0) {
154 desired_direction.Normalize();
155 // If the target is within the turning affinity distance, then make the
156 // desired direction based on distance to the target. Otherwise, base
157 // the desired direction on MAX_SPEED.
158 if (distance < kMaxTurningDistance) {
159 // Some pretty arbitrary dampening.
160 desired_direction.Scale(kMaxSpeed * distance / 100.0);
161 } else {
162 desired_direction.Scale(kMaxSpeed);
164 new_direction = Vector2::Difference(desired_direction, velocity_);
165 new_direction.Clamp(kMaxTurningForce);
167 return new_direction;
170 int32_t Goose::AccumulateSeparation(double distance,
171 const Vector2& goose_delta,
172 Vector2* separation, /* inout */
173 int32_t separation_count) {
174 if (distance > 0.0 && distance < kPersonalSpace) {
175 Vector2 weighted_direction = goose_delta;
176 weighted_direction.Normalize();
177 weighted_direction.Scale(1.0 / distance);
178 separation->Add(weighted_direction);
179 separation_count++;
181 return separation_count;
184 int32_t Goose::AccumulateAlignment(double distance,
185 const Goose& goose,
186 Vector2* alignment, /* inout */
187 int32_t align_count) {
188 if (distance > 0.0 && distance < kNeighbourRadius) {
189 alignment->Add(goose.velocity());
190 align_count++;
192 return align_count;
195 int32_t Goose::AccumulateCohesion(double distance,
196 const Goose& goose,
197 Vector2* cohesion, /* inout */
198 int32_t cohesion_count) {
199 if (distance > 0.0 && distance < kNeighbourRadius) {
200 cohesion->Add(goose.location());
201 cohesion_count++;
203 return cohesion_count;