23 if (!line_valid)
return line_valid;
25 if (!plane_valid)
return plane_valid;
26 return context.consume_steps(6, operation);
36 std::isfinite(offset.
value().value);
40 const double safe_high = std::numeric_limits<double>::max() / 3.0;
41 const double safe_low = std::numeric_limits<double>::min();
42 return normal_scale > safe_high / direction_scale ||
43 normal_scale < safe_low / direction_scale;
51 std::numeric_limits<double>::max() / point_scale.
value() / 3.0;
57 return point_scale.
has_value() && numeric_plane_offset &&
58 point_scale.
value() > std::numeric_limits<double>::max() / 3.0;
62 const std::vector<double>& values,
double scale,
bool protect_point_dot,
63 std::vector<std::shared_ptr<SymbolicExpr>>& scaled
65 scaled.reserve(values.size());
66 for (
double component : values) {
67 double scaled_component = component / scale;
68 if (protect_point_dot) scaled_component /= 3.0;
69 scaled.push_back(SymbolicExpr::number(scaled_component));
74 const std::shared_ptr<SymbolicExpr>& offset,
75 double normal_scale,
bool protect_point_dot
77 auto scaled = SymbolicExpr::divide(
78 offset, SymbolicExpr::number(normal_scale));
79 if (protect_point_dot) {
80 scaled = SymbolicExpr::divide(scaled, SymbolicExpr::number(3.0));
86 return std::fma(
a[0],
b[0], std::fma(
a[1],
b[1],
a[2] *
b[2]));
90 const std::vector<double>& normal_values,
double normal_scale,
91 const std::vector<double>& direction_values,
double direction_scale,
92 const std::vector<double>& point_values,
double point_scale,
93 double plane_offset,
const std::string& operation
95 const double plane_location = plane_offset / normal_scale;
96 if (!std::isfinite(plane_location)) {
99 "line-plane intersection coordinate is outside the supported domain",
102 double spatial_scale = std::max(point_scale, std::abs(plane_location));
103 if (spatial_scale == 0.0) spatial_scale = 1.0;
105 double unit_normal[3];
106 double unit_direction[3];
107 double scaled_point[3];
108 for (
size_t i = 0; i < 3; ++i) {
109 unit_normal[i] = normal_values[i] / normal_scale;
110 unit_direction[i] = direction_values[i] / direction_scale;
111 scaled_point[i] = point_values[i] / spatial_scale;
117 "line is parallel to plane, so no unique intersection exists",
121 const double scaled_offset = plane_location / spatial_scale;
122 const double parameter = (scaled_offset - point_dot) /
denominator;
124 std::vector<std::shared_ptr<SymbolicExpr>> intersection;
125 intersection.reserve(3);
126 for (
size_t i = 0; i < 3; ++i) {
127 const double scaled_coordinate = std::fma(
128 parameter, unit_direction[i], scaled_point[i]);
129 const double coordinate = scaled_coordinate * spatial_scale;
130 if (!std::isfinite(coordinate)) {
133 "line-plane intersection coordinate is outside the supported domain",
136 intersection.push_back(SymbolicExpr::number(coordinate));
142 const std::vector<std::shared_ptr<SymbolicExpr>>& normal,
143 const std::vector<std::shared_ptr<SymbolicExpr>>&
direction,
144 const std::vector<std::shared_ptr<SymbolicExpr>>&
point,
145 const std::shared_ptr<SymbolicExpr>& offset,
149 (
context).limits().max_ast_nodes,
"transform");
157 "line is parallel to plane, so no unique intersection exists",
158 "line-plane denominator nonzero condition cannot be verified");
161 auto t = SymbolicExpr::divide(
164 SymbolicExpr::multiply(SymbolicExpr::number(-1), n_dot_a.value())),
166 std::vector<std::shared_ptr<SymbolicExpr>> intersection;
167 intersection.reserve(
point.size());
168 for (
size_t i = 0; i <
point.size(); ++i) {
169 auto coord = SymbolicExpr::add(
173 "line-plane intersection coordinate is outside the supported domain",
context);
177 intersection.push_back(std::move(simplified.value()));
182}
catch (
const std::bad_alloc&) {
184}
catch (
const std::length_error& error) {
186}
catch (
const std::exception& error) {
191 const std::vector<std::shared_ptr<SymbolicExpr>>&
point,
192 const std::vector<std::shared_ptr<SymbolicExpr>>& normal,
193 const std::shared_ptr<SymbolicExpr>& offset,
201 auto diff = SymbolicExpr::add(
203 SymbolicExpr::multiply(SymbolicExpr::number(-1), offset));
204 auto norm_n = SymbolicExpr::sqrt(norm_sq.value());
208 std::vector<std::shared_ptr<const SymbolicNode>>{
211 SymbolicExpr::divide(abs_diff, norm_n),
213 "point-plane distance is outside the supported domain",
context);
223 const std::string operation =
"line_plane_intersection";
225 auto valid = validate_intersection_inputs(line,
plane,
context, operation);
230 std::vector<double> normal_values;
231 std::vector<double> direction_values;
239 if (!direction_scale) {
242 std::vector<double> point_values;
245 if (!point_scale && interrupts_optional_numeric_evaluation(point_scale.error())) {
249 const bool numeric_plane_offset = finite_plane_offset(plane_offset);
250 if (!plane_offset && interrupts_optional_numeric_evaluation(plane_offset.error())) {
254 const bool scale_direction_products = direction_products_need_scaling(
255 normal_scale.value(), direction_scale.value());
256 const bool protect_point_dot =
257 point_dot_needs_protection(normal_scale.value(), point_scale);
258 const std::vector<std::shared_ptr<SymbolicExpr>>* effective_normal = &
plane.
normal;
259 const std::vector<std::shared_ptr<SymbolicExpr>>* effective_direction = &line.
direction;
260 std::vector<std::shared_ptr<SymbolicExpr>> scaled_normal;
261 std::vector<std::shared_ptr<SymbolicExpr>> scaled_direction;
262 std::shared_ptr<SymbolicExpr> effective_d =
plane.
d;
263 if (scale_direction_products || protect_point_dot) {
264 scale_symbolic_components(
265 normal_values, normal_scale.value(), protect_point_dot, scaled_normal);
266 effective_normal = &scaled_normal;
267 effective_d = scale_plane_offset(
plane.
d, normal_scale.value(), protect_point_dot);
269 if (scale_direction_products) {
270 scale_symbolic_components(
271 direction_values, direction_scale.value(),
false, scaled_direction);
272 effective_direction = &scaled_direction;
275 if (coordinate_update_needs_protection(point_scale, numeric_plane_offset)) {
276 return protected_coordinate_intersection(
277 normal_values, normal_scale.value(),
278 direction_values, direction_scale.value(),
279 point_values, point_scale.value(), plane_offset.value().value, operation);
281 return symbolic_line_plane_intersection(
282 *effective_normal, *effective_direction, line.
point, effective_d,
284 }
catch (
const std::bad_alloc&) {
286 "vector geometry allocation failed",
288 }
catch (
const std::exception&
e) {
290 e.what(), operation);
304 const std::vector<std::shared_ptr<SymbolicExpr>>&
point,
308 const std::string operation =
"point_plane_distance";
312 if (
point.size() != 3) {
315 "point-plane distance requires a 3-dimensional point",
320 auto step =
context.consume_steps(4, operation);
323 std::vector<double> normal_values;
331 if (!point_scale && interrupts_optional_numeric_evaluation(point_scale.error())) {
335 const double safe_low =
336 std::sqrt(std::numeric_limits<double>::min());
337 const double safe_high =
338 std::sqrt(std::numeric_limits<double>::max() / 3.0);
339 const bool protect_point_dot =
340 point_dot_needs_protection(normal_scale.value(), point_scale);
341 const std::vector<std::shared_ptr<SymbolicExpr>>* effective_normal =
343 std::vector<std::shared_ptr<SymbolicExpr>> scaled_normal;
344 std::shared_ptr<SymbolicExpr> effective_d =
plane.
d;
345 if (normal_scale.value() < safe_low ||
346 normal_scale.value() > safe_high ||
348 scale_symbolic_components(
349 normal_values, normal_scale.value(), protect_point_dot, scaled_normal);
350 effective_normal = &scaled_normal;
351 effective_d = scale_plane_offset(
plane.
d, normal_scale.value(), protect_point_dot);
354 return symbolic_point_plane_distance(
355 point, *effective_normal, effective_d,
context, operation);
356 }
catch (
const std::bad_alloc&) {
358 "vector geometry allocation failed",
360 }
catch (
const std::exception&
e) {
362 e.what(), operation);
367 const std::vector<std::shared_ptr<SymbolicExpr>>&
point,
bool has_value() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::vector< std::shared_ptr< SymbolicExpr > > value)
std::shared_ptr< SymbolicExpr > scale_plane_offset(const std::shared_ptr< SymbolicExpr > &offset, double normal_scale, bool protect_point_dot)
bool point_dot_needs_protection(double normal_scale, const Result< double > &point_scale)
bool interrupts_optional_numeric_evaluation(const CasError &error)
ExpressionResult symbolic_point_plane_distance(const std::vector< std::shared_ptr< SymbolicExpr > > &point, const std::vector< std::shared_ptr< SymbolicExpr > > &normal, const std::shared_ptr< SymbolicExpr > &offset, ComputationContext &context, const std::string &operation)
void scale_symbolic_components(const std::vector< double > &values, double scale, bool protect_point_dot, std::vector< std::shared_ptr< SymbolicExpr > > &scaled)
Result< void > validate_intersection_inputs(const LineSymbolic &line, const PlaneSymbolic &plane, ComputationContext &context, const std::string &operation)
VectorExprListResult protected_coordinate_intersection(const std::vector< double > &normal_values, double normal_scale, const std::vector< double > &direction_values, double direction_scale, const std::vector< double > &point_values, double point_scale, double plane_offset, const std::string &operation)
bool finite_plane_offset(const Result< ApproxReal > &offset)
double fused_dot_three(const double(&a)[3], const double(&b)[3])
VectorExprListResult symbolic_line_plane_intersection(const std::vector< std::shared_ptr< SymbolicExpr > > &normal, const std::vector< std::shared_ptr< SymbolicExpr > > &direction, const std::vector< std::shared_ptr< SymbolicExpr > > &point, const std::shared_ptr< SymbolicExpr > &offset, ComputationContext &context, const std::string &operation)
bool coordinate_update_needs_protection(const Result< double > &point_scale, bool numeric_plane_offset)
bool direction_products_need_scaling(double normal_scale, double direction_scale)
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)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
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 > validate_symbolic_vector(const std::vector< std::shared_ptr< SymbolicExpr > > &vector, const std::string &name, const std::string &operation)
Result< void > validate_line_checked(const LineSymbolic &line, ComputationContext &context, const std::string &operation)
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)
const std::string const LimitExprPtr & point
const PlaneSymbolic & plane
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const std::string const LimitExprPtr LimitDirection direction
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"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
VectorExprListResult line_plane_intersection_checked(const LineSymbolic &line, const PlaneSymbolic &plane, ComputationContext &context)
ExpressionResult point_plane_distance_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &point, const PlaneSymbolic &plane, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > normal
法向量。
Result< std::vector< std::shared_ptr< SymbolicExpr > > > VectorExprListResult
std::vector< std::shared_ptr< SymbolicExpr > > direction
方向向量。
const ExprPtr & denominator
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t
std::unordered_map< std::string, double > NumericBindings
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。