borderline: extended the expand logic
Extended and checked the expand logic for creating
the line extends. Now creating quite the right lines,
will need to check some speccial cases. Also some
cleanups.
Change-Id: I3a3bd4d23c7017ecd873147df2d93af61de39fa6
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index eba1f7f..6295d46 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -165,89 +165,6 @@ namespace drawinglayer
}
}
// static double fPatScFact(10.0); // 10.0 multiply, see old code
// const std::vector<double> aDashing(svtools::GetLineDashing(getStyle(), getPatternScale() * fPatScFact));
// const attribute::StrokeAttribute aStrokeAttribute(aDashing);
// if (3 == getBorderLines().size())
// {
// // double line with gap. Use mfSmallestAllowedDiscreteGapDistance (see get2DDecomposition) as distance.
// // That value is prepared to be at least one pixel (discrete unit) so that the
// // decomposition is view-dependent in this cases
// const BorderLine& rLeft(getBorderLines()[0]);
// const BorderLine& rGap(getBorderLines()[1]);
// const BorderLine& rRight(getBorderLines()[2]);
// const double fFullWidth(rLeft.getWidth() + mfSmallestAllowedDiscreteGapDistance + rRight.getWidth());
// {
// // inside line (left of vector). Create stroke primitive centered on left line width
// const double fDeltaY((rLeft.getWidth() - fFullWidth) * 0.5);
// const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
// const basegfx::B2DPoint aStart(getStart() - (aVector * rLeft.getBorderLineExtend().getStartAverage()) + aDeltaY);
// const basegfx::B2DPoint aEnd(getEnd() + (aVector * rLeft.getBorderLineExtend().getEndAverage()) + aDeltaY);
// const attribute::LineAttribute aLineAttribute(rLeft.getRGBColor(), rLeft.getWidth());
// addPolygonStrokePrimitive2D(
// rContainer,
// aStart,
// aEnd,
// aLineAttribute,
// aStrokeAttribute);
// }
// if (hasGapColor())
// {
// // gap (if visible, found practical usage in Writer MultiColorBorderLines).
// // Create stroke primitive on vector with given color centered on gap position
// const double fDeltaY(((fFullWidth - mfSmallestAllowedDiscreteGapDistance) * 0.5) - rRight.getWidth());
// const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
// const basegfx::B2DPoint aStart(getStart() - (aVector * rGap.getBorderLineExtend().getStartAverage()) + aDeltaY);
// const basegfx::B2DPoint aEnd(getEnd() + (aVector * rGap.getBorderLineExtend().getEndAverage()) + aDeltaY);
// const attribute::LineAttribute aLineAttribute(rGap.getRGBColor(), mfSmallestAllowedDiscreteGapDistance);
// addPolygonStrokePrimitive2D(
// rContainer,
// aStart,
// aEnd,
// aLineAttribute,
// aStrokeAttribute);
// }
// {
// // outside line (right of vector). Create stroke primitive centered on right line width
// const double fDeltaY((fFullWidth - rRight.getWidth()) * 0.5);
// const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
// const basegfx::B2DPoint aStart(getStart() - (aVector * rRight.getBorderLineExtend().getStartAverage()) + aDeltaY);
// const basegfx::B2DPoint aEnd(getEnd() + (aVector * rRight.getBorderLineExtend().getEndAverage()) + aDeltaY);
// const attribute::LineAttribute aLineAttribute(rRight.getRGBColor(), rRight.getWidth());
// addPolygonStrokePrimitive2D(
// rContainer,
// aStart,
// aEnd,
// aLineAttribute,
// aStrokeAttribute);
// }
// }
// else
// {
// // single line, only inside values used, no vertical offsets
// const BorderLine& rBorderLine(getBorderLines()[0]);
// const attribute::LineAttribute aLineAttribute(rBorderLine.getRGBColor(), rBorderLine.getWidth());
// addPolygonStrokePrimitive2D(
// rContainer,
// getStart() - (aVector * rBorderLine.getBorderLineExtend().getStartAverage()),
// getEnd() + (aVector * rBorderLine.getBorderLineExtend().getEndAverage()),
// aLineAttribute,
// aStrokeAttribute);
// }
// }
// }
bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const
{
if (!getStart().equal(getEnd()))
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index c7a6377..b755443 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -380,6 +380,7 @@ double getOffsetAndHalfWidthAndColorFromStyle(
Color aSecn(rStyle.GetColorSecn());
double fPrim(rStyle.Prim());
double fSecn(rStyle.Secn());
const bool bSecnUsed(0.0 != fSecn);
if(bMirrored)
{
@@ -389,8 +390,12 @@ double getOffsetAndHalfWidthAndColorFromStyle(
case RefMode::End: aRefMode = RefMode::Begin; break;
default: break;
}
std::swap(aPrim, aSecn);
std::swap(fPrim, fSecn);
if(bSecnUsed)
{
std::swap(aPrim, aSecn);
std::swap(fPrim, fSecn);
}
}
if (RefMode::Centered != aRefMode)
@@ -409,7 +414,7 @@ double getOffsetAndHalfWidthAndColorFromStyle(
}
}
if (rStyle.Dist() && fSecn)
if (bSecnUsed)
{
// both or all three lines used
const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency());
@@ -503,6 +508,103 @@ void getCutSet(
&rCutSet.mfORMR);
}
void getAllCutSets(
std::vector< CutSet >& rCutSets,
const basegfx::B2DPoint& rOrigin,
const basegfx::B2DPoint& rLeft,
const basegfx::B2DPoint& rRight,
const basegfx::B2DVector& rX,
const StyleVectorTable& rStyleVectorTable,
bool bUpper,
bool bLower)
{
for(const auto& rStyleVectorCombination : rStyleVectorTable)
{
if(bUpper || bLower)
{
// use only upper or lower vectors compared to rX
const double fCross(rX.cross(rStyleVectorCombination.getB2DVector()));
if(bUpper && fCross > 0.0)
{
// upper vectors wanted, but is lower
continue;
}
if(bLower && fCross < 0.0)
{
// lower vectors wanted, but is upper
continue;
}
}
std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
if(!otherOffsets.empty())
{
const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector()));
for(const auto& rOtherOffset : otherOffsets)
{
const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
CutSet aCutSet;
getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
rCutSets.push_back(aCutSet);
}
}
}
}
CutSet getMinMaxCutSet(
bool bMin,
const std::vector< CutSet >& rCutSets)
{
if(rCutSets.empty())
{
CutSet aRetval;
aRetval.mfOLML = aRetval.mfORML = aRetval.mfOLMR = aRetval.mfORMR = 0.0;
return aRetval;
}
const size_t aSize(rCutSets.size());
if(1 == aSize)
{
return rCutSets[0];
}
CutSet aRetval(rCutSets[0]);
double fRetval(aRetval.mfOLML + aRetval.mfORML + aRetval.mfOLMR + aRetval.mfORMR);
for(size_t a(1); a < aSize; a++)
{
const CutSet& rCandidate(rCutSets[a]);
const double fCandidate(rCandidate.mfOLML + rCandidate.mfORML + rCandidate.mfOLMR + rCandidate.mfORMR);
if(bMin)
{
if(fCandidate < fRetval)
{
fRetval = fCandidate;
aRetval = rCandidate;
}
}
else
{
if(fCandidate > fRetval)
{
fRetval = fCandidate;
aRetval = rCandidate;
}
}
}
return aRetval;
}
void getExtends(
std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill
const basegfx::B2DPoint& rOrigin, // own vector start
@@ -518,40 +620,98 @@ void getExtends(
for(size_t a(0); a < nOffsets; a++)
{
const OffsetAndHalfWidthAndColor& rOffset(rOffsets[a]);
ExtendSet& rExt(rExtendSet[a]);
bool bExtSet(false);
const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth)));
const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth)));
for(const auto& rStyleVectorCombination : rStyleVectorTable)
if(0xff != rOffset.maColor.GetTransparency())
{
std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth)));
const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth)));
std::vector< CutSet > aCutSets;
CutSet aResult;
bool bResultSet(false);
if(!otherOffsets.empty())
if(1 == nOffsets)
{
const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector()));
// single line:
// - get all CutSets
// - get minimum values as extension (biggest possible overlap)
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false);
for(const auto& rOtherOffset : otherOffsets)
if(!aCutSets.empty())
{
const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
CutSet aCutSet;
aResult = getMinMaxCutSet(true, aCutSets);
bResultSet = true;
}
}
else
{
// multiple lines
const bool bUpper(a < (nOffsets >> 1));
const bool bLower(a > (nOffsets >> 1));
getCutSet(aCutSet, aLeft, aRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
if(bUpper)
{
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false);
if(!bExtSet)
if(!aCutSets.empty())
{
rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML);
rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR);
bExtSet = true;
aResult = getMinMaxCutSet(false, aCutSets);
bResultSet = true;
}
else
{
rExt.mfExtLeft = std::min(rExt.mfExtLeft , std::min(aCutSet.mfOLML, aCutSet.mfORML));
rExt.mfExtRight = std::min(rExt.mfExtRight , std::min(aCutSet.mfOLMR, aCutSet.mfORMR));
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true);
if(!aCutSets.empty())
{
aResult = getMinMaxCutSet(true, aCutSets);
bResultSet = true;
}
}
}
else if(bLower)
{
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true);
if(!aCutSets.empty())
{
aResult = getMinMaxCutSet(false, aCutSets);
bResultSet = true;
}
else
{
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false);
if(!aCutSets.empty())
{
aResult = getMinMaxCutSet(true, aCutSets);
bResultSet = true;
}
}
}
else // middle line
{
getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false);
if(!aCutSets.empty())
{
const CutSet aResultMin(getMinMaxCutSet(true, aCutSets));
const CutSet aResultMax(getMinMaxCutSet(false, aCutSets));
aResult.mfOLML = (aResultMin.mfOLML + aResultMax.mfOLML) * 0.5;
aResult.mfORML = (aResultMin.mfORML + aResultMax.mfORML) * 0.5;
aResult.mfOLMR = (aResultMin.mfOLMR + aResultMax.mfOLMR) * 0.5;
aResult.mfORMR = (aResultMin.mfORMR + aResultMax.mfORMR) * 0.5;
bResultSet = true;
}
}
}
if(bResultSet)
{
ExtendSet& rExt(rExtendSet[a]);
rExt.mfExtLeft = std::min(aResult.mfOLML, aResult.mfORML);
rExt.mfExtRight = std::min(aResult.mfOLMR, aResult.mfORMR);
}
}
}
@@ -588,9 +748,22 @@ void CreateBorderPrimitives(
if(bHasEndStyles)
{
// create extends for line ends, use inverse point/vector and inverse offsets
std::reverse(myOffsets.begin(), myOffsets.end());
getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myOffsets, rEndStyleVectorTable);
// Create extends for line ends, use inverse point/vector and inverse offsets.
// Offsets need to be inverted for different width of lines. To invert, change
// order, but also sign of offset. Do this on a copy since myOffsets will be
// used below to create the primitives
std::vector< OffsetAndHalfWidthAndColor > myInverseOffsets(myOffsets);
std::reverse(myInverseOffsets.begin(), myInverseOffsets.end());
for(auto& offset : myInverseOffsets)
{
offset.mfOffset *= -1;
}
getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myInverseOffsets, rEndStyleVectorTable);
// also need to reverse the result to apply to the correct lines
std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end());
}
std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index db54294..5a52614 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -988,7 +988,7 @@ void HelperCreateVerticalEntry(
if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));
if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false));
if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true));
if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, -rY, true));
if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true));
if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true));
@@ -1002,9 +1002,9 @@ void HelperCreateVerticalEntry(
if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false));
if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false));
if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false));
if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true));
if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true));
if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, rY, false));
if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, -rX, true));
if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX - rY, true));
CreateBorderPrimitives(
rSequence,