X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fspring.cc;h=60bc0aec77ca736084ed1afd18430b6a4bc0d9ea;hb=e3a15ec3c1951dd16f6ee71fbd79870d9e2fb3a0;hp=679ccfa29db3f00d2f792785a950e40be85f0b6a;hpb=b80683cc94b0c22bbe3fccb94a9b2e23787fd10b;p=lilypond.git diff --git a/lily/spring.cc b/lily/spring.cc index 679ccfa29d..60bc0aec77 100644 --- a/lily/spring.cc +++ b/lily/spring.cc @@ -1,9 +1,20 @@ /* - spring.cc -- declare Spring + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 2007--2011 Joe Neeman - (c) 2007 Joe Neeman + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ #include "spring.hh" @@ -22,6 +33,8 @@ Spring::Spring (Real dist, Real min_dist) { distance_ = 1.0; min_distance_ = 1.0; + inverse_stretch_strength_ = 1.0; + inverse_compress_strength_ = 1.0; set_distance (dist); set_min_distance (min_dist); @@ -32,10 +45,20 @@ Spring::Spring (Real dist, Real min_dist) void Spring::update_blocking_force () { - if (distance_ == min_distance_) - blocking_force_ = 0.0; + if (min_distance_ > distance_) + blocking_force_ = (min_distance_ - distance_) / inverse_stretch_strength_; else blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_; + + // If the spring is fixed, it's not clear what the natural value + // of blocking_force_ would be (because it always blocks). + // -infinity_f works fine for now. + // If inverse_stretch_strength > 0, the spring is not fixed (because it can stretch). + if (isnan (blocking_force_) || blocking_force_ == infinity_f) + blocking_force_ = (inverse_stretch_strength_ > 0) ? 0.0 : -infinity_f; + + if (blocking_force_ >= 0) + inverse_compress_strength_ = 0; } /* scale a spring, but in a way that doesn't violate min_distance */ @@ -43,8 +66,9 @@ void Spring::operator*= (Real r) { distance_ = max (min_distance_, distance_ * r); - inverse_compress_strength_ = distance_ - min_distance_; + inverse_compress_strength_ = max (0.0, distance_ - min_distance_); inverse_stretch_strength_ *= 0.8; + update_blocking_force (); } bool @@ -61,20 +85,24 @@ merge_springs (vector const &springs) Real avg_distance = 0; Real min_distance = 0; Real avg_stretch = 0; + Real avg_compress = 0; for (vsize i = 0; i < springs.size (); i++) { avg_distance += springs[i].distance (); avg_stretch += springs[i].inverse_stretch_strength (); + avg_compress += 1 / springs[i].inverse_compress_strength (); min_distance = max (springs[i].min_distance (), min_distance); } avg_stretch /= springs.size (); + avg_compress /= springs.size (); avg_distance /= springs.size (); avg_distance = max (min_distance + 0.3, avg_distance); Spring ret = Spring (avg_distance, min_distance); ret.set_inverse_stretch_strength (avg_stretch); + ret.set_inverse_compress_strength (1 / avg_compress); return ret; } @@ -86,7 +114,6 @@ Spring::set_distance (Real d) programming_error ("insane spring distance requested, ignoring it"); else { - min_distance_ = min (min_distance_, d); distance_ = d; update_blocking_force (); } @@ -100,11 +127,16 @@ Spring::set_min_distance (Real d) else { min_distance_ = d; - distance_ = max (distance_, min_distance_); update_blocking_force (); } } +void +Spring::ensure_min_distance (Real d) +{ + set_min_distance (max (d, min_distance_)); +} + void Spring::set_inverse_stretch_strength (Real f) { @@ -112,6 +144,8 @@ Spring::set_inverse_stretch_strength (Real f) programming_error ("insane spring constant"); else inverse_stretch_strength_ = f; + + update_blocking_force (); } void @@ -143,8 +177,21 @@ Spring::set_blocking_force (Real f) void Spring::set_default_strength () { - inverse_compress_strength_ = distance_ - min_distance_; - inverse_stretch_strength_ = distance_ - min_distance_; + set_default_stretch_strength (); + set_default_compress_strength (); +} + +void +Spring::set_default_compress_strength () +{ + inverse_compress_strength_ = (distance_ >= min_distance_) ? distance_ - min_distance_ : 0; + update_blocking_force (); +} + +void +Spring::set_default_stretch_strength () +{ + inverse_stretch_strength_ = distance_; } Real @@ -152,5 +199,16 @@ Spring::length (Real f) const { Real force = max (f, blocking_force_); Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_; - return distance_ + force * inv_k; + + if (force == infinity_f) + { + programming_error ("cruelty to springs"); + force = 0.0; + } + + // There is a corner case here: if min_distance_ is larger than + // distance_ but the spring is fixed, then inv_k will be zero + // and we need to make sure that we return min_distance_. + return max (min_distance_, distance_ + force * inv_k); } +