[TD]handle odd projection cs in broken view

This commit is contained in:
wandererfan
2024-04-09 08:30:45 -04:00
committed by WandererFan
parent 5ef1b96a9d
commit 74556bced8
6 changed files with 307 additions and 129 deletions

View File

@@ -224,6 +224,10 @@ TopoDS_Shape DrawBrokenView::apply1Break(const App::DocumentObject& breakObj, co
builder.MakeCompound(result);
builder.Add(result, cut0);
builder.Add(result, cut1);
// BRepTools::Write(cut0, "DBVcut0.brep"); //debug
// BRepTools::Write(cut1, "DBVcut1.brep");
return result;
}
@@ -241,32 +245,27 @@ TopoDS_Shape DrawBrokenView::compressShape(const TopoDS_Shape& shapeToCompress)
//! move the broken pieces in the input shape "right" to close up the removed areas.
//! note: breaks and pieces should not intersect by this point
//! a break: BbbbbbbB
//! a piece: PpppP no need to move
//! a piece: PppppP move right by removed(B)
//! a piece: PpppP move right by removed(B)
//! a piece: PppppP no need to move
TopoDS_Shape DrawBrokenView::compressHorizontal(const TopoDS_Shape& shapeToCompress)const
{
// Base::Console().Message("DBV::compressHorizontal()\n");
auto pieces = getPieces(shapeToCompress);
auto breaksAll = Breaks.getValues();
// ?? not sure about using closestBasis here.
auto moveDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().XDirection()));
auto moveDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().XDirection()));
bool descend = false;
auto sortedBreaks = makeSortedBreakList(breaksAll, moveDirection, descend);
auto limits = getPieceUpperLimits(pieces, moveDirection);
auto limits = getPieceLimits(pieces, moveDirection);
// for each break, move all the pieces left of the break to the right by the removed amount
// for the break
for (auto& breakItem : sortedBreaks) {
// check each break against all the pieces
Base::Vector3d netBreakDisplace = moveDirection * (removedLengthFromObj(*breakItem.breakObj) - Gap.getValue());
Base::Vector3d netBreakDisplace =
moveDirection * (removedLengthFromObj(*breakItem.breakObj) - Gap.getValue());
size_t iPiece{0};
for (auto& pieceHighLimit : limits) {
for (auto& pieceLimit : limits) {
// check each piece against the current break
// We have a problem with low digits here. The cut operations and later
// bounding box creation may generate pieceHighLimits that are slightly
// off. We know that the pieces were cut by a break, so we use a fuzzy
// comparison.
if (pieceHighLimit < breakItem.lowLimit ||
DU::fpCompare(pieceHighLimit, breakItem.lowLimit, Precision::Confusion()) ) {
if (moveThisPiece(pieceLimit, breakItem, moveDirection)) {
// piece is to left of break, so needs to move right
TopoDS_Shape temp = ShapeUtils::moveShape(pieces.at(iPiece), netBreakDisplace);
pieces.at(iPiece) = temp;
@@ -293,20 +292,21 @@ TopoDS_Shape DrawBrokenView::compressVertical(const TopoDS_Shape& shapeToCompre
auto pieces = getPieces(shapeToCompress);
auto breaksAll = Breaks.getValues();
// not sure about using closestBasis here. may prevent oblique breaks later.
auto moveDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().YDirection()));
auto moveDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().YDirection()));
bool descend = false;
auto sortedBreaks = makeSortedBreakList(breaksAll, moveDirection, descend);
auto limits = getPieceUpperLimits(pieces, moveDirection);
// for each break, move all the pieces above the break down by the removed amount
auto limits = getPieceLimits(pieces, moveDirection);
// for each break, move all the pieces below the break up by the removed amount
// for the break
for (auto& breakItem : sortedBreaks) {
// check each break against all the pieces
Base::Vector3d netBreakDisplace = moveDirection * (removedLengthFromObj(*breakItem.breakObj) - Gap.getValue());
Base::Vector3d netBreakDisplace =
moveDirection * (removedLengthFromObj(*breakItem.breakObj) - Gap.getValue());
size_t iPiece{0};
for (auto& pieceHighLimit : limits) {
for (auto& pieceLimit : limits) {
// check each piece against the current break using a fuzzy equality
if (pieceHighLimit < breakItem.lowLimit ||
DU::fpCompare(pieceHighLimit, breakItem.lowLimit, Precision::Confusion()) ) {
if (moveThisPiece(pieceLimit, breakItem, moveDirection)) {
// piece is below the break, move it up
TopoDS_Shape temp = ShapeUtils::moveShape(pieces.at(iPiece), netBreakDisplace);
pieces.at(iPiece) = temp;
@@ -330,6 +330,10 @@ TopoDS_Shape DrawBrokenView::compressVertical(const TopoDS_Shape& shapeToCompre
//! plane normal) and a point inside the half space (pointInSpace).
TopoDS_Shape DrawBrokenView::makeHalfSpace(Base::Vector3d planePoint, Base::Vector3d planeNormal, Base::Vector3d pointInSpace) const
{
// Base::Console().Message("DBV::makeHalfSpace - planePoint: %s normal: %s pointInSpace: %s\n",
// DU::formatVector(planePoint).c_str(),
// DU::formatVector(planeNormal).c_str(),
// DU::formatVector(pointInSpace).c_str());
gp_Pnt origin = DU::togp_Pnt(planePoint);
gp_Dir axis = DU::togp_Dir(planeNormal);
gp_Pln plane(origin, axis);
@@ -361,13 +365,21 @@ std::pair<Base::Vector3d, Base::Vector3d> DrawBrokenView::breakPointsFromObj(con
//! perpendicular to the break lines.
Base::Vector3d DrawBrokenView::directionFromObj(const App::DocumentObject& breakObj) const
{
// Base::Console().Message("DBV::directionFromObj()\n");
std::pair<Base::Vector3d, Base::Vector3d> ends = breakPointsFromObj(breakObj);
Base::Vector3d direction = ends.second - ends.first;
direction.Normalize();
// does this need to be oriented?
return DU::closestBasis(direction);
}
//! extract the breakDirection from the break object in a form the gui will understand.
Base::Vector3d DrawBrokenView::guiDirectionFromObj(const App::DocumentObject& breakObj) const
{
return projectPoint(directionFromObj(breakObj));
}
//! calculate the length to be removed as specified by break object.
double DrawBrokenView::removedLengthFromObj(const App::DocumentObject& breakObj) const
{
@@ -445,12 +457,28 @@ std::pair<Base::Vector3d, Base::Vector3d> DrawBrokenView::breakPointsFromSketch(
TopoDS_Edge last = sketchEdges.back();
if ((isVertical(first) && isVertical(last)) ||
(isHorizontal(first) && isHorizontal(last))) {
// get points on each edge that are in line with the center of the sketch
// along the break direction
Bnd_Box edgeBox;
edgeBox.SetGap(0.0);
BRepBndLib::AddOptimal(first, edgeBox);
BRepBndLib::AddOptimal(last, edgeBox);
double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0;
edgeBox.Get(xMin, yMin, zMin, xMax, yMax, zMax);
Base::Vector3d center( (xMin + xMax) / 2.0,
(yMin + yMax) / 2.0,
(zMin + zMax) / 2.0 );
auto ends0 = SU::getEdgeEnds(first);
// trouble here if the break points are wildly out of line?
// std::pair makeCardinal(p0, p1) to force horiz or vert?
auto break0 = (ends0.first + ends0.second) / 2.0;
auto dir0 = ends0.second - ends0.first;
dir0.Normalize();
// get a point on edge first on a perpendicular line through center
auto break0 = center.Perpendicular(ends0.first, dir0);
auto ends1 = SU::getEdgeEnds(last);
auto break1 = (ends1.first + ends1.second) / 2.0;
auto dir1 = ends1.second - ends1.first;
dir1.Normalize();
auto break1 = center.Perpendicular(ends1.first, dir1);
return { break0, break1 };
}
@@ -496,31 +524,29 @@ std::pair<Base::Vector3d, Base::Vector3d> DrawBrokenView::breakBoundsFromObj(con
//! broken view. used in making break lines.
std::pair<Base::Vector3d, Base::Vector3d> DrawBrokenView::breakBoundsFromSketch(const App::DocumentObject& breakObj) const
{
// Base::Console().Message("DBV::breakBoundsFromSketch()\n");
//Base::Console().Message("DBV::breakBoundsFromSketch()\n");
std::pair<Base::Vector3d, Base::Vector3d> breakPoints = breakPointsFromObj(breakObj);
Base::Vector3d anchor = (breakPoints.first + breakPoints.second) / 2.0;
Base::Vector3d center = (breakPoints.first + breakPoints.second) / 2.0;
Base::Vector3d breakDir = directionFromObj(breakObj);
breakDir.Normalize();
Base::Vector3d lineDir = makePerpendicular(breakDir);
lineDir.Normalize();
// is this right? or do we need to project the points first? Should be alright
// if the break points are not skewed?
double removed = (breakPoints.first - breakPoints.second).Length();
Base::Vector3d perpDir = makePerpendicular(breakDir);
perpDir.Normalize();
// get the midpoint of the zigzags
Base::Vector3d ptOnLine0 = anchor + breakDir * removed / 2.0;
Base::Vector3d ptOnLine1 = anchor - breakDir * removed / 2.0;
Base::Vector3d ptOnLine0 = center + breakDir * removedLengthFromObj(breakObj) / 2.0;
Base::Vector3d ptOnLine1 = center - breakDir * removedLengthFromObj(breakObj) / 2.0;
double lineLength = breaklineLength(breakObj);
Base::Vector3d corner0 = ptOnLine0 - lineDir * lineLength / 2.0;
Base::Vector3d corner1 = ptOnLine1 + lineDir * lineLength / 2.0;
Base::Vector3d corner0 = ptOnLine0 - perpDir * lineLength / 2.0;
Base::Vector3d corner1 = ptOnLine1 + perpDir * lineLength / 2.0;
corner0 = mapPoint3dToView(corner0);
corner1 = mapPoint3dToView(corner1);
// these are unscaled, unrotated points
return{corner0, corner1};
}
//! extract the boundary of the break lines from an edge
std::pair<Base::Vector3d, Base::Vector3d> DrawBrokenView::breakBoundsFromEdge(const App::DocumentObject& breakObj) const
{
@@ -732,15 +758,15 @@ std::vector<TopoDS_Edge> DrawBrokenView::edgesFromCompound(TopoDS_Shape compound
}
//! find the upper limits of each piece's bounding box in direction (if we support oblique projection directions, then the
//! find the limits of each piece's bounding box in cardinal direction (if we support oblique projection directions, then the
//! piece will have to be transformed to align with OXYZ cardinal axes as in DrawViewPart::getSizeAlongVector)
std::vector<double> DrawBrokenView::getPieceUpperLimits(const std::vector<TopoDS_Shape>& pieces, Base::Vector3d direction)
PieceLimitList DrawBrokenView::getPieceLimits(const std::vector<TopoDS_Shape>& pieces, Base::Vector3d direction)
{
// Base::Console().Message("DBV::getPieceUpperLimits(%s)\n", DU::formatVector(direction).c_str());
Base::Vector3d stdX{1.0, 0.0, 0.0};
Base::Vector3d stdY{0.0, 1.0, 0.0};
Base::Vector3d stdZ{0.0, 0.0, 1.0};
std::vector<double> limits;
PieceLimitList limits;
limits.reserve(pieces.size());
for (auto& item : pieces) {
Bnd_Box pieceBox;
@@ -748,13 +774,21 @@ std::vector<double> DrawBrokenView::getPieceUpperLimits(const std::vector<TopoDS
BRepBndLib::AddOptimal(item, pieceBox);
double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0;
pieceBox.Get(xMin, yMin, zMin, xMax, yMax, zMax);
// this is a bit crude. will only work in well behaved cases
if (DU::fpCompare(std::fabs(direction.Dot(stdX)), 1.0, EWTOLERANCE)) {
limits.push_back(xMax);
PieceLimitEntry newEntry;
newEntry.highLimit = xMax;
newEntry.lowLimit = xMin;
limits.push_back(newEntry);
} else if (DU::fpCompare(std::fabs(direction.Dot(stdY)), 1.0, EWTOLERANCE)) {
limits.push_back(yMax);
PieceLimitEntry newEntry;
newEntry.highLimit = yMax;
newEntry.lowLimit = yMin;
limits.push_back(newEntry);
} else {
limits.push_back(zMax);
PieceLimitEntry newEntry;
newEntry.highLimit = zMax;
newEntry.lowLimit = zMin;
limits.push_back(newEntry);
}
}
@@ -779,6 +813,8 @@ std::vector<TopoDS_Shape> DrawBrokenView::getPieces(TopoDS_Shape brokenShape)
//! sort the breaks that match direction by their minimum limit
BreakList DrawBrokenView::makeSortedBreakList(const std::vector<App::DocumentObject*>& breaks, Base::Vector3d direction, bool descend) const
{
// Base::Console().Message("DBV::makeSortedBreakList(%d, %s)\n", breaks.size(),
// DU::formatVector(direction).c_str());
Base::Vector3d stdX{1.0, 0.0, 0.0};
Base::Vector3d stdY{0.0, 1.0, 0.0};
Base::Vector3d stdZ{0.0, 0.0, 1.0};
@@ -786,7 +822,7 @@ BreakList DrawBrokenView::makeSortedBreakList(const std::vector<App::DocumentObj
BreakList unsorted;
for (auto& breakObj : breaks) {
auto breakDirection = directionFromObj(*breakObj);
if (breakDirection.IsEqual(direction, EWTOLERANCE)) {
if (DU::fpCompare(std::fabs(direction.Dot(breakDirection)), 1.0, EWTOLERANCE)) {
// this break interests us
BreakListEntry newEntry;
newEntry.breakObj = breakObj;
@@ -856,41 +892,37 @@ BreakList DrawBrokenView::sortBreaks(BreakList& inList, bool descend)
return false;
}
//! transform a 3d point into its position within the broken view. used in creating
//! dimensions.
Base::Vector3d DrawBrokenView::mapPoint3dToView(Base::Vector3d point3d) const
{
// Base::Console().Message("DBV::mapPoint3dToView(%s)\n", DU::formatVector(point3d).c_str());
Base::Vector3d stdX(1.0, 0.0, 0.0);
Base::Vector3d stdY(0.0, 1.0, 0.0);
//Base::Console().Message("DBV::mapPoint3dToView(%s)\n", DU::formatVector(point3d).c_str());
Base::Vector3d result{point3d};
// if the input point has been projected, then we have to use stdX and stdY instead
// of XDirection and YDirection.
Base::Vector3d point2d = projectPoint(point3d, false); // don't invert
auto breaksAll = Breaks.getValues();
bool descend = false;
auto moveXDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().XDirection()));
auto moveXDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().XDirection()));
// get the breaks that move us in X
auto sortedXBreaks = makeSortedBreakList(breaksAll, moveXDirection, descend);
double xLimit = point2d.x;
double xShift = shiftAmountShrink(xLimit, sortedXBreaks);
Base::Vector3d xMove = stdX * xShift; // move to the right (+X)
double xLimit = DU::coordinateForDirection(point3d, moveXDirection);
auto moveYDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().YDirection()));
double xShift = shiftAmountShrink(xLimit, moveXDirection, sortedXBreaks);
Base::Vector3d xMove = moveXDirection * xShift; // move to the right (+X)
auto moveYDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().YDirection()));
descend = false;
// get the breaks that move us in Y
auto sortedYBreaks = makeSortedBreakList(breaksAll, moveYDirection, descend);
double yLimit = point2d.y;
double yShift = shiftAmountShrink(yLimit, sortedYBreaks);
Base::Vector3d yMove = stdY * yShift; // move up (+Y)
double yLimit = DU::coordinateForDirection(point3d, moveYDirection);
double yShift = shiftAmountShrink(yLimit, moveYDirection, sortedYBreaks);
Base::Vector3d yMove = moveYDirection * yShift; // move up (+Y)
point2d = point2d + xMove + yMove;
auto moved3d = point3d + xMove + yMove;
result = moved3d - getCompressedCentroid();
Base::Vector3d compressedCoM = projectPoint(getCompressedCentroid(), false);
result = point2d - compressedCoM;
result = projectPoint(result, false);
return result;
}
@@ -905,56 +937,105 @@ Base::Vector3d DrawBrokenView::mapPoint2dFromView(Base::Vector3d point2d) const
// convert point2d in view to pseudo-3d view coords
Base::Vector3d projectedCoM = projectPoint(getCompressedCentroid(), false);
Base::Vector3d result = projectedCoM + point2d;
// now shift down and left
auto breaksAll = Breaks.getValues();
Base::Vector3d pseudo3dx = point2d + projectedCoM;
double xReverser = -1.0;
auto moveXDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().XDirection()));
if (isDirectionReversed(moveXDirection)) {
pseudo3dx = point2d - projectedCoM;
xReverser = 1.0;
}
bool descend = false; // should be false so we move from lowest break to highest?
auto moveXDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().XDirection()));
// get the breaks that moved us in X
auto sortedXBreaks = makeSortedBreakListCompressed(breaksAll, moveXDirection, descend);
double xLimit = result.x;
double xShift = shiftAmountExpand(xLimit, sortedXBreaks);
Base::Vector3d xMove = stdX * xShift * -1.0; // move to the left (-X)
double xLimit = pseudo3dx.x;
double xShift = shiftAmountExpand(xLimit, moveXDirection, sortedXBreaks);
Base::Vector3d xMoved = pseudo3dx + stdX * xShift * xReverser; // move to the left (-X)
auto moveYDirection = DU::closestBasis(DU::toVector3d(getProjectionCS().YDirection()));
Base::Vector3d pseudo3dy = point2d + projectedCoM;
double yReverser = -1.0;
auto moveYDirection = DU::closestBasisOriented(DU::toVector3d(getProjectionCS().YDirection()));
if (isDirectionReversed(moveXDirection)) {
pseudo3dy = point2d - projectedCoM;
yReverser = 1.0;
}
descend = false;
// get the breaks that moved us in Y
auto sortedYBreaks = makeSortedBreakListCompressed(breaksAll, moveYDirection, descend);
double yLimit = result.y;
double yShift = shiftAmountExpand(yLimit, sortedYBreaks);
Base::Vector3d yMove = stdY * yShift * -1.0; // move down (-Y)
double yLimit = pseudo3dy.y;
double yShift = shiftAmountExpand(yLimit, moveYDirection, sortedYBreaks);
Base::Vector3d yMoved = pseudo3dy + stdY * yShift * yReverser; // move down (-Y)
result = result + xMove + yMove;
return result;
Base::Vector3d movedResult{xMoved.x, yMoved.y, 0.0};
return movedResult;
}
//! returns the amount a coordinate needs to move to reflect the effect of the breaks to the right/above
//! the input. used in mapping points to the broken view.
double DrawBrokenView::shiftAmountShrink(double pointCoord, const BreakList& sortedBreaks) const
double DrawBrokenView::shiftAmountShrink(double pointCoord, Base::Vector3d direction, const BreakList& sortedBreaks) const
{
// Base::Console().Message("DBV::shiftAmountShrink(%.3f, %d)\n", pointCoord, sortedBreaks.size());
// Base::Console().Message("DBV::shiftAmountShrink(%.3f, %s, %d)\n", pointCoord,
// DU::formatVector(direction).c_str(), sortedBreaks.size());
double shift{0};
for (auto& breakItem : sortedBreaks) {
if (pointCoord >= breakItem.highLimit) {
// leave alone, this break doesn't affect us
continue;
}
if (isDirectionReversed(direction)) {
if (pointCoord <= breakItem.lowLimit) {
// h--------l -ve
// p
// point is right/above break
// leave alone, this break doesn't affect us
continue;
}
if (pointCoord < breakItem.lowLimit ||
DU::fpCompare(pointCoord, breakItem.lowLimit, Precision::Confusion()) ) {
// move right/up by the removed area less the gap
shift += removedLengthFromObj(*breakItem.breakObj) - Gap.getValue();
continue;
}
if (pointCoord > breakItem.highLimit ||
DU::fpCompare(pointCoord, breakItem.highLimit, Precision::Confusion()) ) {
// h--------l -ve
// p
// point is left/below break, but we
shift += removedLengthFromObj(*breakItem.breakObj) - Gap.getValue();
continue;
}
// break.start < value < break.end - point is in the break area
// we move our point by a fraction of the Gap length
double penetration = pointCoord - breakItem.lowLimit;
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = 1 - (penetration / removed);
double netRemoved = breakItem.highLimit - factor * Gap.getValue();
shift += netRemoved - pointCoord;
// h--------l -ve
// p
// break.start < value < break.end - point is in the break area
// we move our point by a fraction of the Gap length
double penetration = fabs(pointCoord - breakItem.highLimit); // start(high) to point
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = 1 - (penetration / removed);
double netRemoved = breakItem.lowLimit - factor * Gap.getValue();
shift += fabs(netRemoved - pointCoord);
} else {
if (pointCoord >= breakItem.highLimit) {
// l--------h +ve
// p
// leave alone, this break doesn't affect us
continue;
}
if (pointCoord < breakItem.lowLimit ||
DU::fpCompare(pointCoord, breakItem.lowLimit, Precision::Confusion()) ) {
// l--------h +ve
// p
// move right/up by the removed area less the gap
shift += removedLengthFromObj(*breakItem.breakObj) - Gap.getValue();
continue;
}
// l--------h +ve
// p
// break.start < value < break.end - point is in the break area
// we move our point by a fraction of the Gap length
double penetration = fabs(pointCoord - breakItem.lowLimit);
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = 1 - (penetration / removed);
double netRemoved = breakItem.highLimit - factor * Gap.getValue();
shift += fabs(netRemoved - pointCoord);
}
}
return shift;
@@ -963,30 +1044,67 @@ double DrawBrokenView::shiftAmountShrink(double pointCoord, const BreakList& sor
//! returns the amount a compressed coordinate needs to be shifted to reverse the effect of breaking
//! the source shapes
double DrawBrokenView::shiftAmountExpand(double pointCoord, const BreakList& sortedBreaks) const
double DrawBrokenView::shiftAmountExpand(double pointCoord, Base::Vector3d direction, const BreakList& sortedBreaks) const
{
// Base::Console().Message("DBV::shiftAmountExpand(%.3f, %d)\n", pointCoord, sortedBreaks.size());
// Base::Console().Message("DBV::shiftAmountExpand(%.3f, %s, %d)\n", pointCoord,
// DU::formatVector(direction).c_str(), sortedBreaks.size());
double shift{0};
for (auto& breakItem : sortedBreaks) {
if (pointCoord >= breakItem.highLimit) {
// leave alone, this break doesn't affect us
continue;
}
if (isDirectionReversed(direction)) {
if (pointCoord <= breakItem.lowLimit) {
// h--------l -ve
// p
// leave alone, this break doesn't affect us
continue;
}
if (pointCoord < breakItem.lowLimit ||
DU::fpCompare(pointCoord, breakItem.lowLimit, Precision::Confusion()) ) {
// move by the whole removed area
shift += breakItem.netRemoved;
continue;
}
if (pointCoord > breakItem.highLimit ||
DU::fpCompare(pointCoord, breakItem.highLimit, Precision::Confusion()) ) {
// h--------l -ve
// p
// break.start < value < break.end - point is in the break area
// we move our point by the break's net removed * the penetration factor
double gapPenetration = pointCoord - breakItem.lowLimit;
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = 1 - gapPenetration / Gap.getValue();
double shiftAmount = factor * (removed - Gap.getValue());
shift += shiftAmount;
// move by the whole removed area
shift += breakItem.netRemoved;
continue;
}
// h--------l -ve
// p
// break.start < value < break.end - point is in the break area
// we move our point by the break's net removed * the penetration factor
double gapPenetration = fabs(pointCoord - breakItem.lowLimit);
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = gapPenetration / Gap.getValue();
double shiftAmount = factor * (removed - Gap.getValue());
shift += shiftAmount;
} else {
if (pointCoord >= breakItem.highLimit) {
// l--------h +ve
// p
// leave alone, this break doesn't affect us
continue;
}
if (pointCoord < breakItem.lowLimit ||
DU::fpCompare(pointCoord, breakItem.lowLimit, Precision::Confusion()) ) {
// l--------h +ve
// p
// move by the whole removed area
shift += breakItem.netRemoved;
continue;
}
// l--------h +ve
// p
// break.start < value < break.end - point is in the break area
// we move our point by the break's net removed * the penetration factor
double gapPenetration = pointCoord - breakItem.lowLimit;
double removed = removedLengthFromObj(*breakItem.breakObj);
double factor = 1 - gapPenetration / Gap.getValue();
double shiftAmount = factor * (removed - Gap.getValue());
shift += shiftAmount;
}
}
return shift;
@@ -1014,6 +1132,46 @@ Base::Vector3d DrawBrokenView::makePerpendicular(Base::Vector3d inDir) const
return DU::toVector3d(gRotated);
}
//! true if this piece should be moved
bool DrawBrokenView::moveThisPiece(PieceLimitEntry piece,
BreakListEntry breakItem,
Base::Vector3d moveDirection) const
{
if (isDirectionReversed(moveDirection)) {
// -ve direction
if (piece.lowLimit > breakItem.highLimit ||
DU::fpCompare(piece.lowLimit, breakItem.highLimit, Precision::Confusion()) ) {
return true;
}
} else {
// +ve direction
if (piece.highLimit < breakItem.lowLimit ||
DU::fpCompare(piece.highLimit, breakItem.lowLimit, Precision::Confusion()) ) {
return true;
}
}
return false;
}
//! true if direction is the reversed of a cardinal direction. (1.0, 0.0, 0.0)
//! returns false, (-1.0, 0.0, 0.0) returns true;
bool DrawBrokenView::isDirectionReversed(Base::Vector3d direction) const
{
Base::Vector3d stdX{1.0, 0.0, 0.0};
Base::Vector3d stdY{0.0, 1.0, 0.0};
Base::Vector3d stdZ{0.0, 0.0, 1.0};
if (DU::fpCompare(std::fabs(direction.Dot(stdX)), 1.0, EWTOLERANCE)) {
return DU::fpCompare(direction.Dot(stdX), -1.0, EWTOLERANCE);
}
if (DU::fpCompare(std::fabs(direction.Dot(stdY)), 1.0, EWTOLERANCE)) {
return DU::fpCompare(direction.Dot(stdY), -1.0, EWTOLERANCE);
}
if (DU::fpCompare(std::fabs(direction.Dot(stdZ)), 1.0, EWTOLERANCE)) {
return DU::fpCompare(direction.Dot(stdZ), -1.0, EWTOLERANCE);
}
return false;
}
void DrawBrokenView::printBreakList(const std::string& text, const BreakList& inBreaks) const
{
Base::Console().Message("DBV - %s\n", text.c_str());

View File

@@ -47,9 +47,14 @@ struct BreakListEntry {
// TODO: can the gap size change during the lifetime of BreakListEntry? if
// so, we need to save the gap size @ creation time?
};
using BreakList = std::vector<BreakListEntry>;
struct PieceLimitEntry {
double lowLimit;
double highLimit;
};
using PieceLimitList = std::vector<PieceLimitEntry>;
class TechDrawExport DrawBrokenView: public TechDraw::DrawViewPart
{
PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawBrokenView);
@@ -75,6 +80,7 @@ public:
std::pair<Base::Vector3d, Base::Vector3d>
breakBoundsFromObj(const App::DocumentObject& breakObj) const;
Base::Vector3d directionFromObj(const App::DocumentObject& breakObj) const;
Base::Vector3d guiDirectionFromObj(const App::DocumentObject& breakObj) const;
static bool isBreakObject(const App::DocumentObject& breakObj);
static bool isBreakObjectSketch(const App::DocumentObject& breakObj);
@@ -114,7 +120,7 @@ private:
TopoDS_Shape compressHorizontal(const TopoDS_Shape& inShape) const;
TopoDS_Shape compressVertical(const TopoDS_Shape& inShape) const;
static std::vector<double> getPieceUpperLimits(const std::vector<TopoDS_Shape>& pieces, Base::Vector3d direction);
static PieceLimitList getPieceLimits(const std::vector<TopoDS_Shape>& pieces, Base::Vector3d direction);
BreakList makeSortedBreakList(const std::vector<App::DocumentObject*>& breaks, Base::Vector3d direction, bool descend = false) const;
BreakList makeSortedBreakListCompressed(const std::vector<App::DocumentObject*>& breaks, Base::Vector3d moveDirection, bool descend = false) const;
@@ -123,8 +129,8 @@ private:
static bool breakLess(const BreakListEntry& entry0, const BreakListEntry& entry1);
// double pointToLimit(const Base::Vector3d& inPoint, const Base::Vector3d& direction) const;
double shiftAmountShrink(double pointCoord, const BreakList& sortedBreaks) const;
double shiftAmountExpand(double pointCoord, const BreakList& sortedBreaks) const;
double shiftAmountShrink(double pointCoord, Base::Vector3d direction, const BreakList& sortedBreaks) const;
double shiftAmountExpand(double pointCoord, Base::Vector3d direction, const BreakList& sortedBreaks) const;
void printBreakList(const std::string& text, const BreakList& inBreaks) const;
@@ -132,6 +138,9 @@ private:
scalePair(std::pair<Base::Vector3d, Base::Vector3d> inPair) const;
Base::Vector3d makePerpendicular(Base::Vector3d inDir) const;
bool moveThisPiece(PieceLimitEntry piece, BreakListEntry breakItem, Base::Vector3d moveDirection) const;
bool isDirectionReversed(Base::Vector3d direction) const;
Base::Vector3d m_unbrokenCenter;
TopoDS_Shape m_compressedShape;

View File

@@ -861,18 +861,15 @@ double DrawUtil::getWidthInDirection(gp_Dir direction, TopoDS_Shape& shape)
//! cardinal direction or the reverse of a cardinal direction.
gp_Vec DrawUtil::maskDirection(gp_Vec inVec, gp_Dir directionToMask)
{
if (directionToMask.XYZ().IsEqual(gp::OX().Direction().XYZ(), EWTOLERANCE) ||
directionToMask.XYZ().IsEqual(gp::OX().Direction().Reversed().XYZ(), EWTOLERANCE)) {
return {0.0, inVec.Y(), inVec.Z()};
if (fpCompare(std::fabs(directionToMask.Dot(gp::OX().Direction().XYZ())), 1.0, EWTOLERANCE)) {
return {0.0, inVec.Y(), inVec.Z()};
}
if (directionToMask.XYZ().IsEqual(gp::OY().Direction().XYZ(), EWTOLERANCE) ||
directionToMask.XYZ().IsEqual(gp::OY().Direction().Reversed().XYZ(), EWTOLERANCE)) {
if (fpCompare(std::fabs(directionToMask.Dot(gp::OY().Direction().XYZ())), 1.0, EWTOLERANCE)) {
return {inVec.X(), 0.0, inVec.Z()};
}
if (directionToMask.XYZ().IsEqual(gp::OZ().Direction().XYZ(), EWTOLERANCE) ||
directionToMask.XYZ().IsEqual(gp::OZ().Direction().Reversed().XYZ(), EWTOLERANCE)) {
if (fpCompare(std::fabs(directionToMask.Dot(gp::OZ().Direction().XYZ())), 1.0, EWTOLERANCE)) {
return {inVec.X(), inVec.Y(), 0.0};
}
@@ -880,6 +877,19 @@ gp_Vec DrawUtil::maskDirection(gp_Vec inVec, gp_Dir directionToMask)
return {};
}
Base::Vector3d DrawUtil::maskDirection(Base::Vector3d inVec, Base::Vector3d directionToMask)
{
return toVector3d(maskDirection(togp_Vec(inVec), togp_Vec(directionToMask)));
}
//! get the coordinate of inPoint for the cardinal unit direction.
double DrawUtil::coordinateForDirection(Base::Vector3d inPoint, Base::Vector3d cardinal)
{
auto masked = maskDirection(inPoint, cardinal);
auto stripped = inPoint - masked;
return stripped.x + stripped.y + stripped.z;
}
//based on Function provided by Joe Dowsett, 2014
double DrawUtil::sensibleScale(double working_scale)
{

View File

@@ -154,6 +154,8 @@ public:
static double getWidthInDirection(gp_Dir direction, TopoDS_Shape& shape);
static gp_Vec maskDirection(gp_Vec inVec, gp_Dir directionToMask);
static Base::Vector3d maskDirection(Base::Vector3d inVec, Base::Vector3d directionToMask);
static double coordinateForDirection(Base::Vector3d inPoint, Base::Vector3d cardinal);
static double getDefaultLineWeight(std::string s);
//! is pt between end1 and end2?

View File

@@ -75,7 +75,7 @@ void QGIBreakLine::draw()
Base::Vector3d horizontal{1.0, 0.0, 0.0};
prepareGeometryChange();
double offset = zigzagWidth / 2.0;
if (m_direction.IsEqual(horizontal, EWTOLERANCE)) {
if (DU::fpCompare(fabs(m_direction.Dot(horizontal)), 1.0, EWTOLERANCE)) {
// m_direction connects the two cut points. The zigzags have
// to be perpendicular to m_direction
// 2x vertical zigzag

View File

@@ -1056,13 +1056,12 @@ void QGIViewPart::drawBreakLines()
QGIBreakLine* breakLine = new QGIBreakLine();
addToGroup(breakLine);
Base::Vector3d direction = dbv->directionFromObj(*breakObj);
direction.Normalize();
Base::Vector3d direction = dbv->guiDirectionFromObj(*breakObj);
breakLine->setDirection(direction);
// the bounds describe two corners of the removed area
// the bounds describe two corners of the removed area in the view
std::pair<Base::Vector3d, Base::Vector3d> bounds = dbv->breakBoundsFromObj(*breakObj);
// the bounds are in 3d form, so we need to invert & rez them
Base::Vector3d topLeft = Rez::guiX(DU::invertY(bounds.first));
Base::Vector3d topLeft = Rez::guiX(DU::invertY(bounds.first));
Base::Vector3d bottomRight = Rez::guiX(DU::invertY(bounds.second));
breakLine->setBounds(topLeft, bottomRight);
breakLine->setPos(0.0, 0.0);