mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 06:58:56 +00:00
Fixes curve segment placement issues
This commit is contained in:
@@ -127,6 +127,7 @@ class segment_geometry_adjuster {
|
|||||||
// To determine the geometry adjustments the curve segment needs to be evaluated
|
// To determine the geometry adjustments the curve segment needs to be evaluated
|
||||||
// without adjustments. This function toggles the application of geometry adjustments
|
// without adjustments. This function toggles the application of geometry adjustments
|
||||||
void enable_adjustments(bool adjustments) { adjustments_ = adjustments; }
|
void enable_adjustments(bool adjustments) { adjustments_ = adjustments; }
|
||||||
|
bool enable_adjustments() const { return adjustments_; }
|
||||||
|
|
||||||
// This object doesn't have access to the eval_ property of the curve_segment_evaluator.
|
// This object doesn't have access to the eval_ property of the curve_segment_evaluator.
|
||||||
// The end point of the segment being adjusted, without adjustments, is computed externally
|
// The end point of the segment being adjusted, without adjustments, is computed externally
|
||||||
@@ -765,7 +766,7 @@ class curve_segment_evaluator {
|
|||||||
|
|
||||||
void operator()(const IfcSchema::IfcCircle* c)
|
void operator()(const IfcSchema::IfcCircle* c)
|
||||||
{
|
{
|
||||||
if (segment_type_ == ST_HORIZONTAL) {
|
if (segment_type_ == ST_HORIZONTAL || segment_type_ == ST_VERTICAL) {
|
||||||
auto R = c->Radius() * length_unit_;
|
auto R = c->Radius() * length_unit_;
|
||||||
auto position = c->Position()->as<IfcSchema::IfcAxis2Placement2D>();
|
auto position = c->Position()->as<IfcSchema::IfcAxis2Placement2D>();
|
||||||
auto location = position->Location()->as<IfcSchema::IfcCartesianPoint>();
|
auto location = position->Location()->as<IfcSchema::IfcCartesianPoint>();
|
||||||
@@ -787,8 +788,12 @@ class curve_segment_evaluator {
|
|||||||
pcDy = dr[1];
|
pcDy = dr[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// angle from X = 0 to the parent curve X-axis
|
||||||
|
auto pc_axis_angle = atan2(pcDy, pcDx);
|
||||||
|
// sweep angle from the parent curve X-axis to the first point on the trimmed curve
|
||||||
|
auto sweep_start_angle = start_ / R;
|
||||||
// angle from X = 0 to the first point on the trimmed curve
|
// angle from X = 0 to the first point on the trimmed curve
|
||||||
auto start_angle = atan2(pcDy, pcDx);
|
auto start_angle = pc_axis_angle + sweep_start_angle;
|
||||||
|
|
||||||
// first point on the trimmed curve
|
// first point on the trimmed curve
|
||||||
auto pcStartX = pcCenterX + R * cos(start_angle);
|
auto pcStartX = pcCenterX + R * cos(start_angle);
|
||||||
@@ -799,11 +804,30 @@ class curve_segment_evaluator {
|
|||||||
geometry_adjuster_ = std::make_shared<GEOMETRY_ADJUSTER>(mapping_, inst_, next_inst_);
|
geometry_adjuster_ = std::make_shared<GEOMETRY_ADJUSTER>(mapping_, inst_, next_inst_);
|
||||||
|
|
||||||
projected_length_ = length_;
|
projected_length_ = length_;
|
||||||
eval_ = [R, pcCenterX, pcCenterY, pcStartX, pcStartY, start_angle, sign_l, geometry_adjuster = geometry_adjuster_](double u)
|
eval_ = [R, pcCenterX, pcCenterY, pcStartX, pcStartY, pc_axis_angle, start_angle, sign_l, segment_type=segment_type_, geometry_adjuster = geometry_adjuster_](double u)
|
||||||
{
|
{
|
||||||
|
// If segment_type == ST_VERTICAL and adjustments are enabled the input u is measured along the horizontal.
|
||||||
|
// u needs to be the arc length along the circle. If adjustments are disabled u is one of the end points so its arc length
|
||||||
|
if (segment_type == ST_VERTICAL && geometry_adjuster->enable_adjustments()) {
|
||||||
|
// x and y are distance from center of circle as if circle was centered at (0,0)
|
||||||
|
auto x = pcStartX + u - pcCenterX;
|
||||||
|
auto y = -sign_l*sqrt(R * R - x * x);
|
||||||
|
// move x and y so they are relative to the center of the circle
|
||||||
|
x += pcCenterX;
|
||||||
|
y += pcCenterY;
|
||||||
|
// compute the distance between the start point and (x,y)
|
||||||
|
auto c = sqrt(pow(x - pcStartX,2.0) + pow(y - pcStartY,2.0));
|
||||||
|
// compute the subtended angle
|
||||||
|
// c = 2R*sin(delta/2)
|
||||||
|
auto delta = 2 * asin(c / (2 * R));
|
||||||
|
// compute the arc length (this will always be a positive value)
|
||||||
|
u = R * fabs(delta);
|
||||||
|
}
|
||||||
|
|
||||||
// u is measured along the circle
|
// u is measured along the circle
|
||||||
// angle from the parent curve X-axis to the current point
|
// angle from the X=0 axis to the current point
|
||||||
auto angle = start_angle + sign_l * u / R;
|
auto delta = sign_l * u / R;
|
||||||
|
auto angle = start_angle + delta;
|
||||||
|
|
||||||
// point on the parent curve
|
// point on the parent curve
|
||||||
auto pcX = R * cos(angle) + pcCenterX;
|
auto pcX = R * cos(angle) + pcCenterX;
|
||||||
@@ -819,9 +843,12 @@ class curve_segment_evaluator {
|
|||||||
auto csX = pcX * cos(rotate) - pcY * sin(rotate);
|
auto csX = pcX * cos(rotate) - pcY * sin(rotate);
|
||||||
auto csY = pcX * sin(rotate) + pcY * cos(rotate);
|
auto csY = pcX * sin(rotate) + pcY * cos(rotate);
|
||||||
|
|
||||||
// slope of the parent curve
|
// direction of vector tangent to the curve segment
|
||||||
auto dx = -sin(angle + rotate);
|
// at this point the curve has been rotated so the start is
|
||||||
auto dy = cos(angle + rotate);
|
// tangent to [1,0] so dx, dy in that coordinate system
|
||||||
|
// is dependent only on delta
|
||||||
|
auto dx = cos(delta);
|
||||||
|
auto dy = sin(delta);
|
||||||
|
|
||||||
// transform the point into the curve segment coordinate system
|
// transform the point into the curve segment coordinate system
|
||||||
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
|
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
|
||||||
@@ -831,35 +858,7 @@ class curve_segment_evaluator {
|
|||||||
return geometry_adjuster->transform_and_adjust(u, m);
|
return geometry_adjuster->transform_and_adjust(u, m);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (segment_type_ == ST_VERTICAL) {
|
else if (segment_type_ == ST_CANT) {
|
||||||
auto R = c->Radius() * length_unit_;
|
|
||||||
auto start_angle = start_/R;
|
|
||||||
auto end_angle = start_angle + length_ / R;
|
|
||||||
auto u_end = R * (cos(end_angle)-cos(start_angle));
|
|
||||||
auto sign_l = sign(length_);
|
|
||||||
|
|
||||||
const auto& p = taxonomy::cast<taxonomy::matrix4>(mapping_->map(inst_->Placement()))->ccomponents();
|
|
||||||
auto ys = p.col(3)(1) * length_unit_;
|
|
||||||
|
|
||||||
projected_length_ = u_end;
|
|
||||||
|
|
||||||
eval_ = [ys,R,u_end,start_angle,end_angle,sign_l](double u) -> Eigen::Matrix4d {
|
|
||||||
// u is measured along the x-axis, not along the circle
|
|
||||||
auto theta = start_angle + u * (end_angle - start_angle) / u_end;
|
|
||||||
//auto y = ys + R * (sin(theta) - sin(start_angle));
|
|
||||||
auto y = ys - sign_l*(sqrt(R * R - pow(R * cos(start_angle) + u, 2)) - sqrt(R * R - pow(R * cos(start_angle), 2)));
|
|
||||||
|
|
||||||
auto dx = -sin(theta);
|
|
||||||
auto dy = cos(theta);
|
|
||||||
|
|
||||||
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
|
|
||||||
m.col(0) = Eigen::Vector4d(dx, dy, 0, 0);
|
|
||||||
m.col(1) = Eigen::Vector4d(-dy, dx, 0, 0);
|
|
||||||
m.col(2) = Eigen::Vector4d(0, 0, 1, 0);
|
|
||||||
m.col(3) = Eigen::Vector4d(0.0/*u*/, y, 0.0, 1.0);
|
|
||||||
return m;
|
|
||||||
};
|
|
||||||
} else if (segment_type_ == ST_CANT) {
|
|
||||||
Logger::Warning(std::runtime_error("Use of IfcCircle for cant is not supported"));
|
Logger::Warning(std::runtime_error("Use of IfcCircle for cant is not supported"));
|
||||||
eval_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
|
eval_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user