LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_geometry_plane.cpp
浏览该文件的文档.
5
6#include <algorithm>
7#include <cmath>
8#include <limits>
9#include <stdexcept>
10#include <utility>
11
12namespace LMCAS {
13using namespace geometry_detail;
14
15namespace {
16
18 return !result &&
19 (result.error().code == CasErrc::Cancelled ||
21}
22
24 const std::vector<double>& p1,
25 const std::vector<double>& p2,
26 const std::vector<double>& p3) {
27 for (size_t i = 0; i < 3; ++i) {
28 if (!std::isfinite(p2[i] - p1[i]) ||
29 !std::isfinite(p3[i] - p1[i])) {
30 return true;
31 }
32 }
33 return false;
34}
35
37 const std::vector<double>& p1,
38 const std::vector<double>& p2,
39 const std::vector<double>& p3,
40 double point_scale,
41 std::vector<std::shared_ptr<SymbolicExpr>>& v1,
42 std::vector<std::shared_ptr<SymbolicExpr>>& v2) {
43 for (size_t i = 0; i < 3; ++i) {
44 v1.push_back(SymbolicExpr::number(
45 p2[i] / point_scale - p1[i] / point_scale));
46 v2.push_back(SymbolicExpr::number(
47 p3[i] / point_scale - p1[i] / point_scale));
48 }
49}
50
52 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
53 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
54 const std::vector<std::shared_ptr<SymbolicExpr>>& p3,
55 std::vector<std::shared_ptr<SymbolicExpr>>& v1,
56 std::vector<std::shared_ptr<SymbolicExpr>>& v2,
57 const std::string& operation, ComputationContext& context) {
58 for (size_t i = 0; i < 3; ++i) {
59 auto left = simplify_checked(
60 SymbolicExpr::add(
61 p2[i],
62 SymbolicExpr::multiply(SymbolicExpr::number(-1), p1[i])),
63 operation,
64 "plane edge vector is outside the supported domain", context);
65 if (!left) return Result<void>::failure(left.error());
67 SymbolicExpr::add(
68 p3[i],
69 SymbolicExpr::multiply(SymbolicExpr::number(-1), p1[i])),
70 operation,
71 "plane edge vector is outside the supported domain", context);
72 if (!right) return Result<void>::failure(right.error());
73 v1.push_back(std::move(left.value()));
74 v2.push_back(std::move(right.value()));
75 }
76 return Result<void>::success();
77}
78
80 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
81 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
82 const std::vector<std::shared_ptr<SymbolicExpr>>& p3,
83 std::vector<std::shared_ptr<SymbolicExpr>>& v1,
84 std::vector<std::shared_ptr<SymbolicExpr>>& v2,
86 const std::string& operation) {
87 std::vector<double> p1_values;
88 std::vector<double> p2_values;
89 std::vector<double> p3_values;
90 auto p1_scale = numeric_vector_scale_checked(
91 p1, context, operation, &p1_values);
92 auto p2_scale = numeric_vector_scale_checked(
93 p2, context, operation, &p2_values);
94 auto p3_scale = numeric_vector_scale_checked(
95 p3, context, operation, &p3_values);
96 if (is_plane_budget_error(p1_scale)) {
97 return Result<void>::failure(p1_scale.error());
98 }
99 if (is_plane_budget_error(p2_scale)) {
100 return Result<void>::failure(p2_scale.error());
101 }
102 if (is_plane_budget_error(p3_scale)) {
103 return Result<void>::failure(p3_scale.error());
104 }
105
106 const bool numeric_points =
107 p1_scale.has_value() && p2_scale.has_value() && p3_scale.has_value();
108 bool scale_differences = false;
109 double point_scale = 0.0;
110 if (numeric_points) {
111 point_scale = std::max(
112 p1_scale.value(), std::max(p2_scale.value(), p3_scale.value()));
113 scale_differences = plane_point_differences_overflow(
114 p1_values, p2_values, p3_values);
115 }
116 v1.reserve(3);
117 v2.reserve(3);
118 if (scale_differences) {
120 p1_values, p2_values, p3_values, point_scale, v1, v2);
121 return Result<void>::success();
122 }
123 return append_symbolic_plane_edges(p1, p2, p3, v1, v2, operation, context);
124}
125
127 std::vector<std::shared_ptr<SymbolicExpr>>& v1,
128 std::vector<std::shared_ptr<SymbolicExpr>>& v2,
130 const std::string& operation) {
131 std::vector<double> v1_values;
132 std::vector<double> v2_values;
133 auto v1_scale = numeric_vector_scale_checked(
134 v1, context, operation, &v1_values);
135 auto v2_scale = numeric_vector_scale_checked(
136 v2, context, operation, &v2_values);
137 const bool numeric_edges = v1_scale.has_value() && v2_scale.has_value();
138 if (!numeric_edges) {
139 if (is_plane_budget_error(v1_scale) || is_plane_budget_error(v2_scale)) {
141 !v1_scale ? v1_scale.error() : v2_scale.error());
142 }
143 } else if (v1_scale.value() != 0.0 && v2_scale.value() != 0.0) {
144 const double safe_high =
145 std::sqrt(std::numeric_limits<double>::max() / 12.0);
146 const double safe_low =
147 std::sqrt(std::numeric_limits<double>::min());
148 const bool scale_cross =
149 v1_scale.value() > safe_high / v2_scale.value() ||
150 v1_scale.value() < safe_low / v2_scale.value();
151 if (scale_cross) {
152 for (size_t i = 0; i < 3; ++i) {
153 v1[i] = SymbolicExpr::number(
154 v1_values[i] / v1_scale.value());
155 v2[i] = SymbolicExpr::number(
156 v2_values[i] / v2_scale.value());
157 }
158 }
159 }
160 return Result<bool>::success(numeric_edges);
161}
162
164 const std::vector<std::shared_ptr<SymbolicExpr>>& normal,
165 bool numeric_edges,
167 const std::string& operation) {
168 Result<void> nonzero = numeric_edges
170 normal, context, operation,
171 "three points are collinear, so no unique plane exists",
172 "plane normal nonzero condition cannot be verified")
175 "plane normal nonzero condition cannot be verified",
176 operation);
177 if (!numeric_edges) {
178 auto norm_sq = vector_dot_checked(normal, normal, context);
179 if (!norm_sq) return Result<void>::failure(norm_sq.error());
181 norm_sq.value(), context, operation,
182 "three points are collinear, so no unique plane exists",
183 "plane normal nonzero condition cannot be verified");
184 }
185 return nonzero;
186}
187
189 std::vector<std::shared_ptr<SymbolicExpr>>&& normal,
190 const std::vector<std::shared_ptr<SymbolicExpr>>& point,
192 const std::string& operation) {
193 auto d = vector_dot_checked(normal, point, context);
194 if (!d) return PlaneSymbolicResult::failure(d.error());
195 auto d_simplified = simplify_checked(
196 d.value(), operation,
197 "plane constant is outside the supported domain", context);
198 if (!d_simplified) return PlaneSymbolicResult::failure(d_simplified.error());
199
201 plane.normal = std::move(normal);
202 for (auto& component : plane.normal) {
203 auto simplified = simplify_checked(
204 component, operation,
205 "plane normal component is outside the supported domain", context);
206 if (!simplified) return PlaneSymbolicResult::failure(simplified.error());
207 component = std::move(simplified.value());
208 }
209 plane.d = std::move(d_simplified.value());
210 return PlaneSymbolicResult::success(std::move(plane));
211}
212
213}
214
216 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
217 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
218 const std::vector<std::shared_ptr<SymbolicExpr>>& p3,
220 const std::string operation = "plane_from_three_points";
221 try {
222 auto v12 = validate_same_dimension_vectors(p1, p2, context, operation);
223 if (!v12) {
224 return PlaneSymbolicResult::failure(v12.error());
225 }
226 auto v13 = validate_same_dimension_vectors(p1, p3, context, operation);
227 if (!v13) {
228 return PlaneSymbolicResult::failure(v13.error());
229 }
230 if (p1.size() != 3) {
233 "plane construction requires 3-dimensional points",
234 operation);
235 }
236 auto step = context.consume_steps(8, operation);
237 if (!step) {
238 return PlaneSymbolicResult::failure(step.error());
239 }
240
241 std::vector<std::shared_ptr<SymbolicExpr>> v1, v2;
242 auto edges = build_plane_edges(p1, p2, p3, v1, v2, context, operation);
243 if (!edges) {
244 return PlaneSymbolicResult::failure(edges.error());
245 }
246 auto numeric_edges = scale_plane_edges_for_cross(v1, v2, context, operation);
247 if (!numeric_edges) {
248 return PlaneSymbolicResult::failure(numeric_edges.error());
249 }
250
251 auto normal = vector_cross_checked(v1, v2, context);
252 if (!normal) {
253 return PlaneSymbolicResult::failure(normal.error());
254 }
255 auto nonzero = check_plane_normal_nonzero(
256 normal.value(), numeric_edges.value(), context, operation);
257 if (!nonzero) {
258 return PlaneSymbolicResult::failure(nonzero.error());
259 }
260 return assemble_plane(std::move(normal.value()), p1, context, operation);
261 } catch (const std::bad_alloc&) {
263 "vector geometry allocation failed",
264 operation);
265 } catch (const std::exception& e) {
267 e.what(), operation);
268 }
269}
270
272 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
273 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
274 const std::vector<std::shared_ptr<SymbolicExpr>>& p3) {
277}
278
279
281 const PlaneSymbolic& p1,
282 const PlaneSymbolic& p2,
284 const std::string operation = "dihedral_angle";
285 try {
286 auto p1_valid = validate_plane_checked(p1, context, operation);
287 if (!p1_valid) return ExpressionResult::failure(p1_valid.error());
288 auto p2_valid = validate_plane_checked(p2, context, operation);
289 if (!p2_valid) return ExpressionResult::failure(p2_valid.error());
290
291 auto angle = vector_angle_checked(p1.normal, p2.normal, context);
292 if (!angle) return ExpressionResult::failure(angle.error());
293 const double pi = std::acos(-1.0);
294 const double acute_angle =
295 std::min(angle.value(), pi - angle.value());
297 SymbolicExpr::number(acute_angle));
298 } catch (const std::bad_alloc&) {
300 "vector geometry allocation failed",
301 operation);
302 } catch (const std::exception& e) {
304 e.what(), operation);
305 }
306}
307
314
315}
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< void > build_plane_edges(const std::vector< std::shared_ptr< SymbolicExpr > > &p1, const std::vector< std::shared_ptr< SymbolicExpr > > &p2, const std::vector< std::shared_ptr< SymbolicExpr > > &p3, std::vector< std::shared_ptr< SymbolicExpr > > &v1, std::vector< std::shared_ptr< SymbolicExpr > > &v2, ComputationContext &context, const std::string &operation)
Result< bool > scale_plane_edges_for_cross(std::vector< std::shared_ptr< SymbolicExpr > > &v1, std::vector< std::shared_ptr< SymbolicExpr > > &v2, ComputationContext &context, const std::string &operation)
PlaneSymbolicResult assemble_plane(std::vector< std::shared_ptr< SymbolicExpr > > &&normal, const std::vector< std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context, const std::string &operation)
Result< void > check_plane_normal_nonzero(const std::vector< std::shared_ptr< SymbolicExpr > > &normal, bool numeric_edges, ComputationContext &context, const std::string &operation)
Result< void > append_symbolic_plane_edges(const std::vector< std::shared_ptr< SymbolicExpr > > &p1, const std::vector< std::shared_ptr< SymbolicExpr > > &p2, const std::vector< std::shared_ptr< SymbolicExpr > > &p3, std::vector< std::shared_ptr< SymbolicExpr > > &v1, std::vector< std::shared_ptr< SymbolicExpr > > &v2, const std::string &operation, ComputationContext &context)
void append_scaled_plane_edges(const std::vector< double > &p1, const std::vector< double > &p2, const std::vector< double > &p3, double point_scale, std::vector< std::shared_ptr< SymbolicExpr > > &v1, std::vector< std::shared_ptr< SymbolicExpr > > &v2)
bool plane_point_differences_overflow(const std::vector< double > &p1, const std::vector< double > &p2, const std::vector< double > &p3)
Result< double > numeric_vector_scale_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &expressions, ComputationContext &context, const std::string &operation, std::vector< double > *values=nullptr)
Result< void > validate_plane_checked(const PlaneSymbolic &plane, ComputationContext &context, const std::string &operation)
ExpressionResult simplify_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &operation, const std::string &message, ComputationContext &context)
Result< void > checked_nonzero_numeric_or_exact(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context, const std::string &operation, const std::string &domain_message, const std::string &inconclusive_message)
Result< void > validate_same_dimension_vectors(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context, const std::string &operation)
Result< void > checked_nonzero_numeric_vector(const std::vector< std::shared_ptr< SymbolicExpr > > &expressions, ComputationContext &context, const std::string &operation, const std::string &domain_message, const std::string &inconclusive_message)
const std::string const LimitExprPtr & point
VectorExprListResult vector_cross_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
const PlaneSymbolic & plane
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
Result< PlaneSymbolic > PlaneSymbolicResult
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
PlaneSymbolicResult plane_from_three_points_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &p1, const std::vector< std::shared_ptr< SymbolicExpr > > &p2, const std::vector< std::shared_ptr< SymbolicExpr > > &p3, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > normal
法向量。
const ExprPtr & right
ExprResult pi()
ExpressionResult dihedral_angle_checked(const PlaneSymbolic &p1, const PlaneSymbolic &p2, ComputationContext &context)
__attribute__((visibility("default"))) LineSymbolicResult line_from_two_points_checked(const std __attribute__((visibility("default"))) LineSymbolicResult line_from_two_points_checked(const std __attribute__((visibility("default"))) PlaneSymbolicResult plane_from_three_points_checked(const std __attribute__((visibility("default"))) PlaneSymbolicResult plane_from_three_points_checked(const std const PlaneSymbolic & p2
VectorAngleResult vector_angle_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
ExpressionResult vector_dot_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
std::shared_ptr< SymbolicExpr > d
常数项。
由法向量和常数 d 定义的符号平面 ax + by + cz = d。
内部 AST 定义。