Statistics
| Branch: | Revision:

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