ilqgames
A new real-time solver for large-scale differential games.
polyline2_signed_distance_constraint.cpp
1 /*
2  * Copyright (c) 2020, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  */
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 //
39 // (Time-invariant) inequality constraint encoding
40 // g(x) = (+/-) (signed_distance(x, polyline) - d) <= 0
41 //
42 // NOTE: The `keep_left` argument specifies the sign of g (true corresponds to
43 // positive).
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 
47 #include <ilqgames/constraint/polyline2_signed_distance_constraint.h>
48 #include <ilqgames/geometry/line_segment2.h>
49 #include <ilqgames/geometry/polyline2.h>
50 #include <ilqgames/utils/types.h>
51 
52 #include <glog/logging.h>
53 #include <memory>
54 #include <string>
55 
56 namespace ilqgames {
57 
58 float Polyline2SignedDistanceConstraint::Evaluate(const VectorXf& input) const {
59  CHECK_LT(xidx_, input.size());
60  CHECK_LT(yidx_, input.size());
61 
62  // Compute signed squared distance by finding closest point.
63  float signed_distance_sq;
64  polyline_.ClosestPoint(Point2(input(xidx_), input(yidx_)), nullptr, nullptr,
65  &signed_distance_sq);
66 
67  const float value = signed_sqrt(signed_distance_sq) - threshold_;
68  return (keep_left_) ? value : -value;
69 }
70 
71 void Polyline2SignedDistanceConstraint::Quadraticize(Time t,
72  const VectorXf& input,
73  MatrixXf* hess,
74  VectorXf* grad) const {
75  CHECK_LT(xidx_, input.size());
76  CHECK_LT(yidx_, input.size());
77  CHECK_NOTNULL(grad);
78  CHECK_NOTNULL(hess);
79  CHECK_EQ(hess->rows(), input.size());
80  CHECK_EQ(hess->cols(), input.size());
81  CHECK_EQ(grad->size(), input.size());
82 
83  // Find closest point/segment and whether closest point is an interior point
84  // or a vertex.
85  bool is_vertex;
86  LineSegment2 closest_segment(Point2::Zero(), Point2::Ones());
87  float signed_distance_sq;
88  const Point2 closest_point =
89  polyline_.ClosestPoint(Point2(input(xidx_), input(yidx_)), &is_vertex,
90  &closest_segment, &signed_distance_sq);
91  const float s = sgn(signed_distance_sq);
92 
93  // Unpack geometry.
94  const float x = input(xidx_);
95  const float y = input(yidx_);
96  float px = closest_segment.FirstPoint().x();
97  float py = closest_segment.FirstPoint().y();
98  float rx = x - px;
99  float ry = y - py;
100  float d_sq = rx * rx + ry * ry;
101  float d = std::sqrt(d_sq);
102  const float ux = closest_segment.UnitDirection().x();
103  const float uy = closest_segment.UnitDirection().y();
104  const float sign = (keep_left_) ? 1.0 : -1.0;
105 
106  // Compute value of g.
107  const float g = (keep_left_) ? signed_sqrt(signed_distance_sq) - threshold_
108  : threshold_ - signed_sqrt(signed_distance_sq);
109 
110  // Compute derivatives of g using symbolic differentiation.
111  float dx = sign * uy;
112  float ddx = 0.0;
113  float dy = -sign * ux;
114  float ddy = 0.0;
115  float dxdy = 0.0;
116 
117  // Recompute if the nearest point is a vertex of the polyline.
118  if (is_vertex) {
119  px = closest_point.x();
120  py = closest_point.y();
121  rx = x - px;
122  ry = y - py;
123  d_sq = (rx * rx + ry * ry);
124  d = std::sqrt(d_sq);
125 
126  dx = sign * s * rx / d;
127  ddx = sign * s * (d_sq - px * px - x * x + 2 * px * x) / (d_sq * d);
128  dxdy = -sign * s * rx * ry / (d_sq * d);
129  dy = sign * s * ry / d;
130  ddy = sign * s * (d_sq - py * py - y * y + 2 * py * y) / (d_sq * d);
131  }
132 
133  // Modify derivatives according to augmented Lagrangian.
134  ModifyDerivatives(t, g, &dx, &ddx, &dy, &ddy, &dxdy);
135 
136  // Populate grad and hess.
137  (*grad)(xidx_) += dx;
138  (*grad)(yidx_) += dy;
139 
140  (*hess)(xidx_, xidx_) += ddx;
141  (*hess)(xidx_, yidx_) += dxdy;
142  (*hess)(yidx_, xidx_) += dxdy;
143  (*hess)(yidx_, yidx_) += ddy;
144 }
145 
146 } // namespace ilqgames