LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_geometry_line.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 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
19 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
21 const std::string& operation,
22 std::vector<double>& p1_values,
23 std::vector<double>& p2_values)
24{
25 auto p1_scale = numeric_vector_scale_checked(
26 p1, context, operation, &p1_values);
27 auto p2_scale = numeric_vector_scale_checked(
28 p2, context, operation, &p2_values);
29 if (!p1_scale &&
30 (p1_scale.error().code == CasErrc::Cancelled ||
31 p1_scale.error().code == CasErrc::ResourceLimit)) {
32 return Result<double>::failure(p1_scale.error());
33 }
34 if (!p2_scale &&
35 (p2_scale.error().code == CasErrc::Cancelled ||
36 p2_scale.error().code == CasErrc::ResourceLimit)) {
37 return Result<double>::failure(p2_scale.error());
38 }
39 if (!p1_scale || !p2_scale) {
40 return Result<double>::success(0.0);
41 }
42 const double scale = std::max(p1_scale.value(), p2_scale.value());
43 for (size_t i = 0; i < 3; ++i) {
44 if (!std::isfinite(p2_values[i] - p1_values[i])) {
45 return Result<double>::success(scale);
46 }
47 }
48 return Result<double>::success(0.0);
49}
50
52 const std::vector<std::shared_ptr<SymbolicExpr>>& direction1,
53 const std::vector<std::shared_ptr<SymbolicExpr>>& direction2,
54 const std::vector<std::shared_ptr<SymbolicExpr>>& difference,
55 double point_scale,
57 const std::string& operation)
58{
59 auto cross = vector_cross_checked(direction1, direction2, context);
60 if (!cross) return ExpressionResult::failure(cross.error());
61 auto cross_nonzero = checked_nonzero_numeric_vector(
62 cross.value(), context, operation,
63 "skew line distance requires non-parallel directions",
64 "cross-product nonzero condition cannot be verified");
65 if (!cross_nonzero) {
66 return ExpressionResult::failure(cross_nonzero.error());
67 }
68 auto cross_norm_sq = vector_dot_checked(
69 cross.value(), cross.value(), context);
70 if (!cross_norm_sq) {
71 return ExpressionResult::failure(cross_norm_sq.error());
72 }
73 auto cross_norm = SymbolicExpr::sqrt(cross_norm_sq.value());
74 auto numerator = vector_dot_checked(difference, cross.value(), context);
75 if (!numerator) return ExpressionResult::failure(numerator.error());
79 std::vector<std::shared_ptr<const SymbolicNode>>{
80 LMCAS::detail::node(numerator.value())}));
81 auto distance = SymbolicExpr::divide(abs_num, cross_norm);
82 if (point_scale != 0.0) {
83 distance = SymbolicExpr::multiply(
84 distance, SymbolicExpr::number(point_scale));
85 }
86 return simplify_checked(
87 distance, operation,
88 "skew line distance is outside the supported domain", context);
89}
90
91}
92
94 const LineSymbolic& l1,
95 const LineSymbolic& l2,
97) {
98 const std::string operation = "skew_lines_distance";
99 try {
100 auto l1_valid = validate_line_checked(l1, context, operation);
101 if (!l1_valid) {
102 return ExpressionResult::failure(l1_valid.error());
103 }
104 auto l2_valid = validate_line_checked(l2, context, operation);
105 if (!l2_valid) {
106 return ExpressionResult::failure(l2_valid.error());
107 }
108 auto step = context.consume_steps(8, operation);
109 if (!step) {
110 return ExpressionResult::failure(step.error());
111 }
112
113 std::vector<double> direction1_values;
114 std::vector<double> direction2_values;
115 auto scale1 = numeric_vector_scale_checked(
116 l1.direction, context, operation, &direction1_values);
117 if (!scale1) {
118 return ExpressionResult::failure(scale1.error());
119 }
120 auto scale2 = numeric_vector_scale_checked(
121 l2.direction, context, operation, &direction2_values);
122 if (!scale2) {
123 return ExpressionResult::failure(scale2.error());
124 }
125
126 std::vector<std::shared_ptr<SymbolicExpr>> direction1;
127 std::vector<std::shared_ptr<SymbolicExpr>> direction2;
128 direction1.reserve(3);
129 direction2.reserve(3);
130 for (size_t i = 0; i < 3; ++i) {
131 direction1.push_back(SymbolicExpr::number(
132 direction1_values[i] / scale1.value()));
133 direction2.push_back(SymbolicExpr::number(
134 direction2_values[i] / scale2.value()));
135 }
136
137 std::vector<double> point1_values;
138 std::vector<double> point2_values;
139 auto difference_scale = point_difference_scale_checked(
140 l1.point, l2.point, context, operation, point1_values, point2_values);
141 if (!difference_scale) {
142 return ExpressionResult::failure(difference_scale.error());
143 }
144 const double point_scale = difference_scale.value();
145
146 std::vector<std::shared_ptr<SymbolicExpr>> a2_minus_a1;
147 a2_minus_a1.reserve(3);
148 for (size_t i = 0; i < l1.point.size(); ++i) {
149 if (point_scale != 0.0) {
150 a2_minus_a1.push_back(SymbolicExpr::number(
151 point2_values[i] / point_scale -
152 point1_values[i] / point_scale));
153 continue;
154 }
155 a2_minus_a1.push_back(SymbolicExpr::add(
156 l2.point[i],
157 SymbolicExpr::multiply(
158 SymbolicExpr::number(-1), l1.point[i])));
159 }
160 return skew_distance_from_directions(
161 direction1, direction2, a2_minus_a1, point_scale, context, operation);
162 } catch (const std::bad_alloc&) {
164 "vector geometry allocation failed",
165 operation);
166 } catch (const std::exception& e) {
168 e.what(), operation);
169 }
170}
171
179
180
182 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
183 const std::vector<std::shared_ptr<SymbolicExpr>>& p2,
185 const std::string operation = "line_from_two_points";
186 try {
187 auto valid = validate_same_dimension_vectors(p1, p2, context, operation);
188 if (!valid) return LineSymbolicResult::failure(valid.error());
189 if (p1.size() != 3) {
192 "line construction requires 3-dimensional points",
193 operation);
194 }
195 auto step = context.consume_steps(4, operation);
196 if (!step) return LineSymbolicResult::failure(step.error());
197
198 std::vector<double> p1_values;
199 std::vector<double> p2_values;
200 auto difference_scale = point_difference_scale_checked(
201 p1, p2, context, operation, p1_values, p2_values);
202 if (!difference_scale) {
203 return LineSymbolicResult::failure(difference_scale.error());
204 }
205 const double point_scale = difference_scale.value();
206
207 LineSymbolic line;
208 line.point = p1;
209 line.direction.reserve(3);
210 for (size_t i = 0; i < p1.size(); ++i) {
211 if (point_scale != 0.0) {
212 line.direction.push_back(SymbolicExpr::number(
213 p2_values[i] / point_scale -
214 p1_values[i] / point_scale));
215 continue;
216 }
217 auto component = SymbolicExpr::add(
218 p2[i],
219 SymbolicExpr::multiply(SymbolicExpr::number(-1), p1[i]));
220 auto simplified = simplify_checked(
221 component, operation,
222 "line direction component is outside the supported domain", context);
223 if (!simplified) return LineSymbolicResult::failure(simplified.error());
224 line.direction.push_back(std::move(simplified.value()));
225 }
226 auto line_valid = validate_line_checked(line, context, operation);
227 if (!line_valid) return LineSymbolicResult::failure(line_valid.error());
228 return LineSymbolicResult::success(std::move(line));
229 } catch (const std::bad_alloc&) {
231 "vector geometry allocation failed",
232 operation);
233 } catch (const std::exception& e) {
235 e.what(), operation);
236 }
237}
238
240 const std::vector<std::shared_ptr<SymbolicExpr>>& p1,
241 const std::vector<std::shared_ptr<SymbolicExpr>>& p2) {
244}
245
246}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ExpressionResult skew_distance_from_directions(const std::vector< std::shared_ptr< SymbolicExpr > > &direction1, const std::vector< std::shared_ptr< SymbolicExpr > > &direction2, const std::vector< std::shared_ptr< SymbolicExpr > > &difference, double point_scale, ComputationContext &context, const std::string &operation)
Result< double > point_difference_scale_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &p1, const std::vector< std::shared_ptr< SymbolicExpr > > &p2, ComputationContext &context, const std::string &operation, std::vector< double > &p1_values, std::vector< double > &p2_values)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
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)
ExpressionResult simplify_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &operation, const std::string &message, ComputationContext &context)
Result< void > validate_line_checked(const LineSymbolic &line, ComputationContext &context, const std::string &operation)
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)
VectorExprListResult vector_cross_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
LineSymbolicResult line_from_two_points_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &p1, const std::vector< std::shared_ptr< SymbolicExpr > > &p2, ComputationContext &context)
__attribute__((visibility("default"))) ExpressionResult point_plane_distance_checked(const std __attribute__((visibility("default"))) ExpressionResult point_plane_distance_checked(const std const LineSymbolic & l2
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::vector< std::shared_ptr< SymbolicExpr > > point
直线上一点。
__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
Result< LineSymbolic > LineSymbolicResult
std::vector< std::shared_ptr< SymbolicExpr > > direction
方向向量。
ExpressionResult skew_lines_distance_checked(const LineSymbolic &l1, const LineSymbolic &l2, ComputationContext &context)
ExpressionResult vector_dot_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &a, const std::vector< std::shared_ptr< SymbolicExpr > > &b, ComputationContext &context)
由一点和方向向量定义的符号直线。
内部 AST 定义。