## root / src / layout / forcedirectedparameters.h @ 81ad8b66

History | View | Annotate | Download (25.2 KB)

1 | 01873262 | Georg Kunz | ```
//=========================================================================
``` |
---|---|---|---|

2 | ```
// FORCEDIRECTEDPARAMETERS.H - part of
``` |
||

3 | ```
// OMNeT++/OMNEST
``` |
||

4 | ```
// Discrete System Simulation in C++
``` |
||

5 | ```
//
``` |
||

6 | ```
// Author: Levente Meszaros
``` |
||

7 | ```
//
``` |
||

8 | ```
//=========================================================================
``` |
||

9 | |||

10 | ```
/*--------------------------------------------------------------*
``` |
||

11 | ```
Copyright (C) 2006-2008 OpenSim Ltd.
``` |
||

12 | |||

13 | ```
This file is distributed WITHOUT ANY WARRANTY. See the file
``` |
||

14 | ```
`license' for details on this and other legal matters.
``` |
||

15 | ```
*--------------------------------------------------------------*/
``` |
||

16 | |||

17 | ```
#ifndef __FORCEDIRECTEDPARAMETERS_H_
``` |
||

18 | ```
#define __FORCEDIRECTEDPARAMETERS_H_
``` |
||

19 | |||

20 | #include <math.h> |
||

21 | #include "geometry.h" |
||

22 | #include "forcedirectedparametersbase.h" |
||

23 | #include "forcedirectedembedding.h" |
||

24 | |||

25 | NAMESPACE_BEGIN |
||

26 | |||

27 | inline double signum(double val) { |
||

28 | return val < 0 ? -1 : val == 0 ? 0 : 1; |
||

29 | } |
||

30 | |||

31 | ```
/**
``` |
||

32 | ```
* Represents a freely positioned two dimensional body with a finite mass and charge.
``` |
||

33 | ```
* The actual position of the body is stored in the corresponding variable. This allows
``` |
||

34 | ```
* having multiple bodies sharing the same variable which is important for relatively positioned
``` |
||

35 | ```
* bodies.
``` |
||

36 | ```
*/
``` |
||

37 | class Body : public IBody { |
||

38 | ```
protected:
``` |
||

39 | Variable *variable; |
||

40 | |||

41 | ```
double mass;
``` |
||

42 | |||

43 | ```
double charge;
``` |
||

44 | |||

45 | Rs size; |
||

46 | |||

47 | ```
private:
``` |
||

48 | void constructor(Variable *variable, double mass, double charge, const Rs& size) { |
||

49 | this->variable = variable; |
||

50 | this->mass = mass; |
||

51 | this->charge = charge; |
||

52 | this->size = size; |
||

53 | } |
||

54 | |||

55 | ```
public:
``` |
||

56 | Body(Variable *variable) { |
||

57 | constructor(variable, -1, -1, Rs::getNil()); |
||

58 | } |
||

59 | |||

60 | ```
Body(Variable *variable, const Rs& size) {
``` |
||

61 | constructor(variable, -1, -1, size); |
||

62 | } |
||

63 | |||

64 | Body(Variable *variable, double mass, double charge, const Rs& size) { |
||

65 | constructor(variable, mass, charge, size); |
||

66 | } |
||

67 | |||

68 | ```
virtual void reinitialize() {
``` |
||

69 | IBody::reinitialize(); |
||

70 | if (mass == -1) |
||

71 | mass = embedding->parameters.defaultBodyMass; |
||

72 | if (charge == -1) |
||

73 | charge = embedding->parameters.defaultBodyCharge; |
||

74 | ```
if (size.isNil())
``` |
||

75 | size = embedding->parameters.defaultBodySize; |
||

76 | } |
||

77 | |||

78 | virtual const char *getClassName() { |
||

79 | return "Body"; |
||

80 | } |
||

81 | |||

82 | ```
/**
``` |
||

83 | ```
* Center of the body.
``` |
||

84 | ```
*/
``` |
||

85 | ```
virtual const Pt& getPosition() {
``` |
||

86 | ```
return variable->getPosition();
``` |
||

87 | } |
||

88 | |||

89 | virtual Variable *getVariable() { |
||

90 | ```
return variable;
``` |
||

91 | } |
||

92 | |||

93 | ```
virtual double getMass() {
``` |
||

94 | ```
return mass;
``` |
||

95 | } |
||

96 | |||

97 | ```
virtual double getCharge() {
``` |
||

98 | ```
return charge;
``` |
||

99 | } |
||

100 | |||

101 | ```
virtual const Rs& getSize() {
``` |
||

102 | ```
return size;
``` |
||

103 | } |
||

104 | }; |
||

105 | |||

106 | ```
/**
``` |
||

107 | ```
* A body which is relatively positioned to something. The anchor may be a variable or another body.
``` |
||

108 | ```
*/
``` |
||

109 | class RelativelyPositionedBody : public Body { |
||

110 | ```
protected:
``` |
||

111 | Pt relativePosition; |
||

112 | |||

113 | Variable *anchor; |
||

114 | |||

115 | Pt position; |
||

116 | |||

117 | ```
private:
``` |
||

118 | void constructor(Variable *anchor, const Pt& relativePosition) { |
||

119 | this->anchor = anchor; |
||

120 | this->relativePosition = relativePosition; |
||

121 | } |
||

122 | |||

123 | ```
public:
``` |
||

124 | ```
RelativelyPositionedBody(Variable *variable, const Pt& relativePosition) : Body(variable) {
``` |
||

125 | constructor(variable, relativePosition); |
||

126 | } |
||

127 | |||

128 | RelativelyPositionedBody(Variable *variable, const Pt& relativePosition, const Rs& size) : Body(variable, size) { |
||

129 | constructor(variable, relativePosition); |
||

130 | } |
||

131 | |||

132 | virtual const char *getClassName() { |
||

133 | return "RelativelyPositionedBody"; |
||

134 | } |
||

135 | |||

136 | ```
/**
``` |
||

137 | ```
* Center of the body.
``` |
||

138 | ```
*/
``` |
||

139 | ```
virtual const Pt& getPosition() {
``` |
||

140 | ```
return position.assign(anchor->getPosition()).add(relativePosition);
``` |
||

141 | } |
||

142 | }; |
||

143 | |||

144 | ```
/**
``` |
||

145 | ```
* Represents a body which has infinite size in one dimension and zero size in the other dimension.
``` |
||

146 | ```
*/
``` |
||

147 | class WallBody : public Body { |
||

148 | ```
private:
``` |
||

149 | ```
bool horizontal;
``` |
||

150 | |||

151 | ```
public:
``` |
||

152 | WallBody(bool horizontal, double position, bool fixed = false) : Body(NULL) { |
||

153 | this->horizontal = horizontal; |
||

154 | |||

155 | ```
if (horizontal)
``` |
||

156 | ```
size = Rs(POSITIVE_INFINITY, 0);
``` |
||

157 | ```
else
``` |
||

158 | ```
size = Rs(0, POSITIVE_INFINITY);
``` |
||

159 | } |
||

160 | |||

161 | void setPosition(double position) { |
||

162 | getVariable()->assignPosition(Pt(horizontal ? NaN : position, horizontal ? position : NaN, NaN)); |
||

163 | } |
||

164 | |||

165 | ```
void setVariable(Variable *variable) {
``` |
||

166 | Assert(!this->variable); |
||

167 | this->variable = variable; |
||

168 | } |
||

169 | |||

170 | virtual const char *getClassName() { |
||

171 | return "WallBody"; |
||

172 | } |
||

173 | }; |
||

174 | |||

175 | class AbstractForceProvider : public IForceProvider { |
||

176 | ```
protected:
``` |
||

177 | ```
double maxForce;
``` |
||

178 | |||

179 | ```
int slippery;
``` |
||

180 | |||

181 | ```
int pointLikeDistance;
``` |
||

182 | |||

183 | ```
private:
``` |
||

184 | void constructor(double maxForce, int pointLikeDistance, int slippery) { |
||

185 | this->maxForce = maxForce; |
||

186 | this->pointLikeDistance = pointLikeDistance; |
||

187 | this->slippery = slippery; |
||

188 | } |
||

189 | |||

190 | ```
public:
``` |
||

191 | AbstractForceProvider() { |
||

192 | constructor(-1, -1, -1); |
||

193 | } |
||

194 | |||

195 | ```
AbstractForceProvider(int slippery) {
``` |
||

196 | constructor(-1, -1, slippery); |
||

197 | } |
||

198 | |||

199 | AbstractForceProvider(double maxForce, int slippery) { |
||

200 | ```
constructor(maxForce, -1, slippery);
``` |
||

201 | } |
||

202 | |||

203 | ```
virtual void reinitialize() {
``` |
||

204 | IForceProvider::reinitialize(); |
||

205 | if (maxForce == -1) |
||

206 | maxForce = embedding->parameters.defaultMaxForce; |
||

207 | if (slippery == -1) |
||

208 | slippery = embedding->parameters.defaultSlippery; |
||

209 | if (pointLikeDistance == -1) |
||

210 | pointLikeDistance = embedding->parameters.defaultPointLikeDistance; |
||

211 | } |
||

212 | |||

213 | ```
protected:
``` |
||

214 | ```
double getMaxForce() {
``` |
||

215 | ```
return maxForce;
``` |
||

216 | } |
||

217 | |||

218 | double getValidForce(double force) { |
||

219 | ```
Assert(force >= 0);
``` |
||

220 | ```
return std::min(maxForce, force);
``` |
||

221 | } |
||

222 | |||

223 | double getValidSignedForce(double force) { |
||

224 | if (force < 0) |
||

225 | ```
return -getValidForce(fabs(force));
``` |
||

226 | ```
else
``` |
||

227 | ```
return getValidForce(fabs(force));
``` |
||

228 | } |
||

229 | |||

230 | ```
Pt getDistanceAndVector(IBody *body1, IBody *body2, double &distance) {
``` |
||

231 | ```
if (slippery)
``` |
||

232 | ```
return getSlipperyDistanceAndVector(body1, body2, distance);
``` |
||

233 | ```
else
``` |
||

234 | ```
return getStandardDistanceAndVector(body1, body2, distance);
``` |
||

235 | } |
||

236 | |||

237 | ```
Pt getStandardDistanceAndVector(IBody *body1, IBody *body2, double &distance) {
``` |
||

238 | ```
const Pt& pt1 = body1->getPosition();
``` |
||

239 | ```
const Pt& pt2 = body2->getPosition();
``` |
||

240 | Pt vector = Pt(pt1).subtract(pt2); |
||

241 | distance = vector.getLength(); |
||

242 | vector.divide(distance); |
||

243 | |||

244 | ```
if (!pointLikeDistance) {
``` |
||

245 | ```
const Rs& rs1 = body1->getSize();
``` |
||

246 | ```
const Rs& rs2 = body2->getSize();
``` |
||

247 | ```
double dx = fabs(pt1.x - pt2.x);
``` |
||

248 | ```
double dy = fabs(pt1.y - pt2.y);
``` |
||

249 | double dHalf = vector.getBasePlaneProjectionLength() / 2; |
||

250 | ```
double d1 = dHalf * std::min(rs1.width / dx, rs1.height / dy);
``` |
||

251 | ```
double d2 = dHalf * std::min(rs2.width / dx, rs2.height / dy);
``` |
||

252 | |||

253 | distance = std::max(0.0, distance - d1 - d2); |
||

254 | } |
||

255 | |||

256 | ```
return vector;
``` |
||

257 | } |
||

258 | |||

259 | ```
Pt getStandardHorizontalDistanceAndVector(IBody *body1, IBody *body2, double &distance) {
``` |
||

260 | distance = body1->getPosition().x - body2->getPosition().x; |
||

261 | Pt vector = Pt(signum(distance), 0, 0); |
||

262 | distance = fabs(distance); |
||

263 | |||

264 | ```
if (!pointLikeDistance)
``` |
||

265 | distance = std::max(0.0, distance - body1->getSize().width - body2->getSize().width); |
||

266 | |||

267 | ```
return vector;
``` |
||

268 | } |
||

269 | |||

270 | ```
Pt getStandardVerticalDistanceAndVector(IBody *body1, IBody *body2, double &distance) {
``` |
||

271 | distance = body1->getPosition().y - body2->getPosition().y; |
||

272 | Pt vector = Pt(0, signum(distance), 0); |
||

273 | distance = fabs(distance); |
||

274 | |||

275 | ```
if (!pointLikeDistance)
``` |
||

276 | distance = std::max(0.0, distance - body1->getSize().height - body2->getSize().height); |
||

277 | |||

278 | ```
return vector;
``` |
||

279 | } |
||

280 | |||

281 | ```
Pt getSlipperyDistanceAndVector(IBody *body1, IBody *body2, double &distance) {
``` |
||

282 | Rc rc1 = Rc::getRcFromCenterSize(body1->getPosition(), body1->getSize()); |
||

283 | Rc rc2 = Rc::getRcFromCenterSize(body2->getPosition(), body2->getSize()); |
||

284 | Ln ln = rc1.getBasePlaneProjectionDistance(rc2, distance); |
||

285 | Pt vector = ln.begin; |
||

286 | vector.subtract(ln.end); |
||

287 | vector.setNaNToZero(); |
||

288 | vector.normalize(); |
||

289 | ```
return vector;
``` |
||

290 | } |
||

291 | }; |
||

292 | |||

293 | ```
/**
``` |
||

294 | ```
* A repulsive force which decreases in a quadratic way propoportional to the distance of the bodies.
``` |
||

295 | ```
* Abstract base class for electric repulsive forces.
``` |
||

296 | ```
*/
``` |
||

297 | class AbstractElectricRepulsion : public AbstractForceProvider { |
||

298 | ```
protected:
``` |
||

299 | IBody *charge1; |
||

300 | |||

301 | IBody *charge2; |
||

302 | |||

303 | ```
double linearityDistance;
``` |
||

304 | |||

305 | ```
double maxDistance;
``` |
||

306 | |||

307 | ```
private:
``` |
||

308 | void constructor(IBody *charge1, IBody *charge2, double linearityDistance, double maxDistance) { |
||

309 | this->charge1 = charge1; |
||

310 | this->charge2 = charge2; |
||

311 | this->linearityDistance = linearityDistance; |
||

312 | this->maxDistance = maxDistance; |
||

313 | } |
||

314 | |||

315 | ```
public:
``` |
||

316 | ```
AbstractElectricRepulsion(IBody *charge1, IBody *charge2) : AbstractForceProvider(-1) {
``` |
||

317 | constructor(charge1, charge2, -1, -1); |
||

318 | } |
||

319 | |||

320 | AbstractElectricRepulsion(IBody *charge1, IBody *charge2, double linearityDistance, double maxDistance, int slippery = -1) : AbstractForceProvider(slippery) { |
||

321 | constructor(charge1, charge2, linearityDistance, maxDistance); |
||

322 | } |
||

323 | |||

324 | ```
virtual void reinitialize() {
``` |
||

325 | AbstractForceProvider::reinitialize(); |
||

326 | if (linearityDistance == -1) |
||

327 | linearityDistance = embedding->parameters.defaultElectricRepulsionLinearityDistance; |
||

328 | if (maxDistance == -1) |
||

329 | maxDistance = embedding->parameters.defaultElectricRepulsionMaxDistance; |
||

330 | } |
||

331 | |||

332 | virtual IBody *getCharge1() { |
||

333 | ```
return charge1;
``` |
||

334 | } |
||

335 | |||

336 | virtual IBody *getCharge2() { |
||

337 | ```
return charge2;
``` |
||

338 | } |
||

339 | |||

340 | ```
virtual double getDistance() {
``` |
||

341 | ```
double distance;
``` |
||

342 | getDistanceAndVector(distance); |
||

343 | ```
return distance;
``` |
||

344 | } |
||

345 | |||

346 | ```
virtual void applyForces() {
``` |
||

347 | ```
double distance;
``` |
||

348 | Pt force = getDistanceAndVector(distance); |
||

349 | ```
Assert(distance >= 0);
``` |
||

350 | |||

351 | ```
double power;
``` |
||

352 | if (distance == 0) |
||

353 | power = maxForce; |
||

354 | ```
else
``` |
||

355 | power = getValidForce(embedding->parameters.electricRepulsionCoefficient * charge1->getCharge() * charge2->getCharge() / distance / distance); |
||

356 | |||

357 | if (linearityDistance != -1 && distance > linearityDistance) |
||

358 | power *= 1 - std::min(1.0, (distance - linearityDistance) / (maxDistance - linearityDistance)); |
||

359 | |||

360 | force.multiply(power); |
||

361 | |||

362 | charge1->getVariable()->addForce(force); |
||

363 | charge2->getVariable()->subtractForce(force); |
||

364 | } |
||

365 | |||

366 | ```
virtual double getPotentialEnergy() {
``` |
||

367 | ```
return embedding->parameters.electricRepulsionCoefficient * charge1->getCharge() * charge2->getCharge() / getDistance();
``` |
||

368 | } |
||

369 | |||

370 | ```
protected:
``` |
||

371 | virtual Pt getDistanceAndVector(double &distance) = 0; |
||

372 | }; |
||

373 | |||

374 | ```
/**
``` |
||

375 | ```
* Standard electric repulsion. Slippery mode means the distance will be calculated between the two
``` |
||

376 | ```
* rectangles instead of the two center points.
``` |
||

377 | ```
*/
``` |
||

378 | class ElectricRepulsion : public AbstractElectricRepulsion { |
||

379 | ```
public:
``` |
||

380 | ElectricRepulsion(IBody *charge1, IBody *charge2, double linearityDistance = -1, double maxDistance = -1, int slippery = -1) : AbstractElectricRepulsion(charge1, charge2, linearityDistance, maxDistance, slippery) { |
||

381 | } |
||

382 | |||

383 | virtual const char *getClassName() { |
||

384 | return "ElectricRepulsion"; |
||

385 | } |
||

386 | |||

387 | ```
protected:
``` |
||

388 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

389 | ```
return AbstractForceProvider::getDistanceAndVector(charge1, charge2, distance);
``` |
||

390 | } |
||

391 | }; |
||

392 | |||

393 | class VerticalElectricRepulsion : public AbstractElectricRepulsion { |
||

394 | ```
public:
``` |
||

395 | VerticalElectricRepulsion(IBody *charge1, IBody *charge2) : AbstractElectricRepulsion(charge1, charge2) { |
||

396 | } |
||

397 | |||

398 | virtual const char *getClassName() { |
||

399 | return "VerticalElectricRepulsion"; |
||

400 | } |
||

401 | |||

402 | ```
protected:
``` |
||

403 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

404 | ```
return getStandardVerticalDistanceAndVector(charge1, charge2, distance);
``` |
||

405 | } |
||

406 | }; |
||

407 | |||

408 | class HorizontalElectricRepulsion : public AbstractElectricRepulsion { |
||

409 | ```
public:
``` |
||

410 | HorizontalElectricRepulsion(IBody *charge1, IBody *charge2) : AbstractElectricRepulsion(charge1, charge2) { |
||

411 | } |
||

412 | |||

413 | virtual const char *getClassName() { |
||

414 | return "HorizontalElectricRepulsion"; |
||

415 | } |
||

416 | |||

417 | ```
protected:
``` |
||

418 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

419 | ```
return getStandardHorizontalDistanceAndVector(charge1, charge2, distance);
``` |
||

420 | } |
||

421 | }; |
||

422 | |||

423 | ```
/**
``` |
||

424 | ```
* An attractive force which increases in a linear way proportional to the distance of the bodies.
``` |
||

425 | ```
* Abstract base class for spring attractive forces.
``` |
||

426 | ```
*/
``` |
||

427 | class AbstractSpring : public AbstractForceProvider { |
||

428 | friend class LeastExpandedSpring; |
||

429 | |||

430 | ```
protected:
``` |
||

431 | IBody *body1; |
||

432 | |||

433 | IBody *body2; |
||

434 | |||

435 | ```
double springCoefficient;
``` |
||

436 | |||

437 | ```
double reposeLength;
``` |
||

438 | |||

439 | ```
private:
``` |
||

440 | void constructor(IBody *body1, IBody *body2, double springCoefficient, double reposeLength) { |
||

441 | this->body1 = body1; |
||

442 | this->body2 = body2; |
||

443 | this->springCoefficient = springCoefficient; |
||

444 | this->reposeLength = reposeLength; |
||

445 | } |
||

446 | |||

447 | ```
public:
``` |
||

448 | ```
AbstractSpring(IBody *body1, IBody *body2) : AbstractForceProvider(-1) {
``` |
||

449 | constructor(body1, body2, -1, -1); |
||

450 | } |
||

451 | |||

452 | AbstractSpring(IBody *body1, IBody *body2, double springCoefficient, double reposeLength, int slippery) : AbstractForceProvider(slippery) { |
||

453 | constructor(body1, body2, springCoefficient, reposeLength); |
||

454 | } |
||

455 | |||

456 | ```
virtual void reinitialize() {
``` |
||

457 | AbstractForceProvider::reinitialize(); |
||

458 | if (springCoefficient == -1) |
||

459 | springCoefficient = embedding->parameters.defaultSpringCoefficient; |
||

460 | if (reposeLength == -1) |
||

461 | reposeLength = embedding->parameters.defaultSpringReposeLength; |
||

462 | } |
||

463 | |||

464 | ```
virtual double getSpringCoefficient() {
``` |
||

465 | ```
return springCoefficient;
``` |
||

466 | } |
||

467 | |||

468 | ```
double getReposeLength() {
``` |
||

469 | ```
return reposeLength;
``` |
||

470 | } |
||

471 | |||

472 | virtual IBody *getBody1() { |
||

473 | ```
return body1;
``` |
||

474 | } |
||

475 | |||

476 | virtual IBody *getBody2() { |
||

477 | ```
return body2;
``` |
||

478 | } |
||

479 | |||

480 | ```
virtual double getDistance() {
``` |
||

481 | ```
double distance;
``` |
||

482 | getDistanceAndVector(distance); |
||

483 | ```
return distance;
``` |
||

484 | } |
||

485 | |||

486 | ```
virtual void applyForces() {
``` |
||

487 | ```
double distance;
``` |
||

488 | Pt force = getDistanceAndVector(distance); |
||

489 | ```
Assert(distance >= 0);
``` |
||

490 | ```
double expansion = distance - reposeLength;
``` |
||

491 | ```
double power = getValidSignedForce(getSpringCoefficient() * expansion);
``` |
||

492 | |||

493 | force.multiply(power); |
||

494 | |||

495 | ```
if (body1)
``` |
||

496 | body1->getVariable()->subtractForce(force); |
||

497 | |||

498 | ```
if (body2)
``` |
||

499 | body2->getVariable()->addForce(force); |
||

500 | } |
||

501 | |||

502 | ```
virtual double getPotentialEnergy() {
``` |
||

503 | ```
double expansion = getDistance() - reposeLength;
``` |
||

504 | return getSpringCoefficient() * expansion * expansion / 2; |
||

505 | } |
||

506 | |||

507 | ```
protected:
``` |
||

508 | virtual Pt getDistanceAndVector(double &distance) = 0; |
||

509 | }; |
||

510 | |||

511 | ```
/**
``` |
||

512 | ```
* Standard spring attraction. Slippery mode means the distance will be calculated between the two
``` |
||

513 | ```
* rectangles instead of the two center points.
``` |
||

514 | ```
*/
``` |
||

515 | class Spring : public AbstractSpring { |
||

516 | ```
public:
``` |
||

517 | Spring(IBody *body1, IBody *body2) : AbstractSpring(body1, body2) { |
||

518 | } |
||

519 | |||

520 | Spring(IBody *body1, IBody *body2, double springCoefficient, double reposeLength, int slippery = -1) |
||

521 | : AbstractSpring(body1, body2, springCoefficient, reposeLength, slippery) { |
||

522 | } |
||

523 | |||

524 | virtual const char *getClassName() { |
||

525 | return "Spring"; |
||

526 | } |
||

527 | |||

528 | ```
protected:
``` |
||

529 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

530 | ```
return AbstractForceProvider::getDistanceAndVector(body1, body2, distance);
``` |
||

531 | } |
||

532 | }; |
||

533 | |||

534 | class VerticalSpring : public AbstractSpring { |
||

535 | ```
public:
``` |
||

536 | VerticalSpring(IBody *body1, IBody *body2) : AbstractSpring(body1, body2) { |
||

537 | } |
||

538 | |||

539 | VerticalSpring(IBody *body1, IBody *body2, double springCoefficient, double reposeLength) : AbstractSpring(body1, body2, springCoefficient, reposeLength, -1){ |
||

540 | } |
||

541 | |||

542 | virtual const char *getClassName() { |
||

543 | return "VerticalSpring"; |
||

544 | } |
||

545 | |||

546 | ```
protected:
``` |
||

547 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

548 | ```
return getStandardVerticalDistanceAndVector(body1, body2, distance);
``` |
||

549 | } |
||

550 | }; |
||

551 | |||

552 | class HorizonalSpring : public AbstractSpring { |
||

553 | ```
public:
``` |
||

554 | HorizonalSpring(IBody *body1, IBody *body2) : AbstractSpring(body1, body2) { |
||

555 | } |
||

556 | |||

557 | HorizonalSpring(IBody *body1, IBody *body2, double springCoefficient, double reposeLength) : AbstractSpring(body1, body2, springCoefficient, reposeLength, -1) { |
||

558 | } |
||

559 | |||

560 | virtual const char *getClassName() { |
||

561 | return "HorizonalSpring"; |
||

562 | } |
||

563 | |||

564 | ```
protected:
``` |
||

565 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

566 | ```
return getStandardHorizontalDistanceAndVector(body1, body2, distance);
``` |
||

567 | } |
||

568 | }; |
||

569 | |||

570 | class LeastExpandedSpring : public AbstractForceProvider { |
||

571 | ```
private:
``` |
||

572 | std::vector<AbstractSpring *> springs; |
||

573 | |||

574 | ```
public:
``` |
||

575 | LeastExpandedSpring(std::vector<AbstractSpring *> springs) { |
||

576 | this->springs = springs; |
||

577 | } |
||

578 | |||

579 | ~LeastExpandedSpring() { |
||

580 | ```
for (std::vector<AbstractSpring *>::iterator it = springs.begin(); it != springs.end(); it++)
``` |
||

581 | delete *it; |
||

582 | } |
||

583 | |||

584 | ```
virtual void setForceDirectedEmbedding(ForceDirectedEmbedding *embedding) {
``` |
||

585 | AbstractForceProvider::setForceDirectedEmbedding(embedding); |
||

586 | ```
for (std::vector<AbstractSpring *>::iterator it = springs.begin(); it != springs.end(); it++)
``` |
||

587 | (*it)->setForceDirectedEmbedding(embedding); |
||

588 | } |
||

589 | |||

590 | ```
virtual void reinitialize() {
``` |
||

591 | AbstractForceProvider::reinitialize(); |
||

592 | ```
for (std::vector<AbstractSpring *>::iterator it = springs.begin(); it != springs.end(); it++)
``` |
||

593 | (*it)->reinitialize(); |
||

594 | } |
||

595 | |||

596 | AbstractSpring *findLeastExpandedSpring() { |
||

597 | AbstractSpring *leastExpandedSpring; |
||

598 | ```
double leastExpansion = POSITIVE_INFINITY;
``` |
||

599 | |||

600 | ```
for (std::vector<AbstractSpring *>::iterator it = springs.begin(); it != springs.end(); it++) {
``` |
||

601 | AbstractSpring *spring = *it; |
||

602 | ```
double distance;
``` |
||

603 | Pt vector = spring->getDistanceAndVector(distance); |
||

604 | ```
double expansion = fabs(distance - spring->getReposeLength());
``` |
||

605 | |||

606 | ```
if (expansion < leastExpansion) {
``` |
||

607 | leastExpansion = expansion; |
||

608 | leastExpandedSpring = spring; |
||

609 | } |
||

610 | } |
||

611 | |||

612 | ```
return leastExpandedSpring;
``` |
||

613 | } |
||

614 | |||

615 | ```
virtual void applyForces() {
``` |
||

616 | findLeastExpandedSpring()->applyForces(); |
||

617 | } |
||

618 | |||

619 | ```
virtual double getPotentialEnergy() {
``` |
||

620 | ```
return findLeastExpandedSpring()->getPotentialEnergy();
``` |
||

621 | } |
||

622 | |||

623 | virtual const char *getClassName() { |
||

624 | return "LeastExpandedSpring"; |
||

625 | } |
||

626 | }; |
||

627 | |||

628 | ```
/**
``` |
||

629 | ```
* This constraint is like a spring between a body and the base plane (z = 0).
``` |
||

630 | ```
* The spring coefficient increases by time proportional to the relax factor.
``` |
||

631 | ```
* This allows nodes to move in the third dimension in the beginning of the calculation
``` |
||

632 | ```
* while it forces to them to move to the base plane as time goes by.
``` |
||

633 | ```
*/
``` |
||

634 | class BasePlaneSpring : public AbstractSpring { |
||

635 | ```
public:
``` |
||

636 | ```
BasePlaneSpring(IBody *body) : AbstractSpring(body, NULL) {
``` |
||

637 | } |
||

638 | |||

639 | BasePlaneSpring(IBody *body, double springCoefficient, double reposeLength) : AbstractSpring(body, NULL, springCoefficient, reposeLength, -1) { |
||

640 | } |
||

641 | |||

642 | ```
virtual double getSpringCoefficient() {
``` |
||

643 | ```
return springCoefficient * embedding->relaxFactor;
``` |
||

644 | } |
||

645 | |||

646 | virtual const char *getClassName() { |
||

647 | return "BasePlaneSpring"; |
||

648 | } |
||

649 | |||

650 | ```
protected:
``` |
||

651 | ```
virtual Pt getDistanceAndVector(double &distance) {
``` |
||

652 | Pt vector(0, 0, body1->getPosition().z); |
||

653 | distance = fabs(vector.z); |
||

654 | ```
return vector;
``` |
||

655 | } |
||

656 | }; |
||

657 | |||

658 | ```
/**
``` |
||

659 | ```
* Base class for velocity based kinetic energy reducers.
``` |
||

660 | ```
*/
``` |
||

661 | class AbstractVelocityBasedForceProvider : public AbstractForceProvider { |
||

662 | ```
public:
``` |
||

663 | virtual double getPower(Variable *variable, double vlen) = 0; |
||

664 | |||

665 | ```
virtual void applyForces() {
``` |
||

666 | ```
const std::vector<Variable *>& variables = embedding->getVariables();
``` |
||

667 | |||

668 | ```
for (std::vector<Variable *>::const_iterator it = variables.begin(); it != variables.end(); it++) {
``` |
||

669 | Variable *variable = *it; |
||

670 | Pt vector(variable->getVelocity()); |
||

671 | vector.multiply(-getPower(variable, vector.getLength())); |
||

672 | |||

673 | variable->addForce(vector); |
||

674 | } |
||

675 | } |
||

676 | |||

677 | ```
virtual double getPotentialEnergy() {
``` |
||

678 | return 0; |
||

679 | } |
||

680 | }; |
||

681 | |||

682 | ```
/**
``` |
||

683 | ```
* Reduces kinetic energy during the calculation.
``` |
||

684 | ```
*/
``` |
||

685 | class Friction : public AbstractVelocityBasedForceProvider { |
||

686 | ```
public:
``` |
||

687 | virtual double getPower(Variable *variable, double vlen) { |
||

688 | return std::max(embedding->parameters.frictionCoefficient * 0.01, vlen / embedding->updatedTimeStep) * variable->getMass(); |
||

689 | } |
||

690 | |||

691 | virtual const char *getClassName() { |
||

692 | return "Friction"; |
||

693 | } |
||

694 | }; |
||

695 | |||

696 | ```
/**
``` |
||

697 | ```
* Reduces kinetic energy during the calculation.
``` |
||

698 | ```
*/
``` |
||

699 | class Drag : public AbstractVelocityBasedForceProvider { |
||

700 | ```
public:
``` |
||

701 | virtual double getPower(Variable *variable, double vlen) { |
||

702 | ```
return embedding->parameters.frictionCoefficient * vlen;
``` |
||

703 | } |
||

704 | |||

705 | virtual const char *getClassName() { |
||

706 | return "Drag"; |
||

707 | } |
||

708 | }; |
||

709 | |||

710 | ```
/**
``` |
||

711 | ```
* Abstract base class for position constraints applied to a single body. These constraints are
``` |
||

712 | ```
* more expensive to calculate with than the constrained variables and the final position will not
``` |
||

713 | ```
* exactly satisfy the constraint.
``` |
||

714 | ```
*/
``` |
||

715 | class BodyConstraint : public AbstractForceProvider { |
||

716 | ```
protected:
``` |
||

717 | IBody *body; |
||

718 | |||

719 | ```
public:
``` |
||

720 | BodyConstraint(IBody *body) { |
||

721 | this->body = body; |
||

722 | } |
||

723 | |||

724 | virtual IBody *getBody() { |
||

725 | ```
return body;
``` |
||

726 | } |
||

727 | |||

728 | virtual void applyForces() = 0; |
||

729 | |||

730 | virtual double getPotentialEnergy() = 0; |
||

731 | }; |
||

732 | |||

733 | ```
/**
``` |
||

734 | ```
* This constraint is like a spring between a body and a fixed point.
``` |
||

735 | ```
*/
``` |
||

736 | class PointConstraint : public BodyConstraint { |
||

737 | ```
protected:
``` |
||

738 | Pt constraint; |
||

739 | |||

740 | ```
double coefficient;
``` |
||

741 | |||

742 | ```
public:
``` |
||

743 | ```
PointConstraint(IBody *body, double coefficient, Pt constraint) : BodyConstraint(body) {
``` |
||

744 | this->coefficient = coefficient; |
||

745 | this->constraint = constraint; |
||

746 | } |
||

747 | |||

748 | ```
virtual void applyForces() {
``` |
||

749 | Pt vector(constraint); |
||

750 | vector.subtract(body->getPosition()); |
||

751 | ```
double power = coefficient * vector.getLength();
``` |
||

752 | vector.multiply(power); |
||

753 | |||

754 | body->getVariable()->addForce(vector); |
||

755 | } |
||

756 | |||

757 | virtual const char *getClassName() { |
||

758 | return "PointConstraint"; |
||

759 | } |
||

760 | }; |
||

761 | |||

762 | ```
/**
``` |
||

763 | ```
* This constraint is like a spring between a body and a fixed line, the end connected to the line is slippery.
``` |
||

764 | ```
*/
``` |
||

765 | class LineConstraint : public BodyConstraint { |
||

766 | ```
protected:
``` |
||

767 | Ln constraint; |
||

768 | |||

769 | ```
double coefficient;
``` |
||

770 | |||

771 | ```
public:
``` |
||

772 | ```
LineConstraint(IBody *body, double coefficient, Ln constraint) : BodyConstraint(body) {
``` |
||

773 | this->coefficient = coefficient; |
||

774 | this->constraint = constraint; |
||

775 | } |
||

776 | |||

777 | ```
virtual void applyForces() {
``` |
||

778 | ```
const Pt& position = body->getPosition();
``` |
||

779 | Pt force(constraint.getClosestPoint(position)); |
||

780 | force.subtract(position); |
||

781 | force.multiply(coefficient * force.getLength()); |
||

782 | |||

783 | body->getVariable()->addForce(force); |
||

784 | } |
||

785 | |||

786 | virtual const char *getClassName() { |
||

787 | return "LineConstraint"; |
||

788 | } |
||

789 | }; |
||

790 | |||

791 | ```
/**
``` |
||

792 | ```
* This constraint is like a spring between a body and a fixed circle, the end connected to the circle is slippery.
``` |
||

793 | ```
*/
``` |
||

794 | class CircleConstraint : public BodyConstraint { |
||

795 | ```
protected:
``` |
||

796 | Cc constraint; |
||

797 | |||

798 | ```
protected:
``` |
||

799 | ```
double coefficient;
``` |
||

800 | |||

801 | ```
public:
``` |
||

802 | ```
CircleConstraint(IBody *body, double coefficient, Cc constraint) : BodyConstraint(body) {
``` |
||

803 | this->coefficient = coefficient; |
||

804 | this->constraint = constraint; |
||

805 | } |
||

806 | |||

807 | ```
virtual void applyForces() {
``` |
||

808 | ```
const Pt& position = body->getPosition();
``` |
||

809 | Pt vector(constraint.origin); |
||

810 | vector.subtract(position); |
||

811 | vector.multiply(coefficient * (constraint.origin.getDistance(position) - constraint.radius)); |
||

812 | |||

813 | body->getVariable()->addForce(vector); |
||

814 | } |
||

815 | |||

816 | virtual const char *getClassName() { |
||

817 | return "CircleConstraint"; |
||

818 | } |
||

819 | }; |
||

820 | |||

821 | NAMESPACE_END |
||

822 | |||

823 | |||

824 | `#endif` |