Kaydet (Commit) 53599a9a authored tarafından Armin Le Grand's avatar Armin Le Grand

borderline: merge redefined, mirrored Styles

Redefined merge of BorderlinePrimitives, removed old Writer
stuff for it. Also added support for handling Styles mirrored
for extension calculations.
üst 98ceb50c
......@@ -144,7 +144,7 @@ namespace drawinglayer
for(const auto& candidate : maBorderLines)
{
const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance) * 0.5);
const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance));
if(!candidate.isGap())
{
......@@ -369,6 +369,116 @@ namespace drawinglayer
// provide unique ID
ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
Primitive2DReference tryMergeBorderLinePrimitive2D(
const Primitive2DReference& rCandidateA,
const Primitive2DReference& rCandidateB)
{
// try to cast to BorderLinePrimitive2D
const primitive2d::BorderLinePrimitive2D* pCandidateA = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateA.get());
const primitive2d::BorderLinePrimitive2D* pCandidateB = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateB.get());
// we need a comparable BorderLinePrimitive2D
if(nullptr == pCandidateA || nullptr == pCandidateB)
{
return Primitive2DReference();
}
// start of candidate has to match end of this
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
{
return Primitive2DReference();
}
// candidate A needs a length
if(pCandidateA->getStart().equal(pCandidateA->getEnd()))
{
return Primitive2DReference();
}
// candidate B needs a length
if(pCandidateB->getStart().equal(pCandidateB->getEnd()))
{
return Primitive2DReference();
}
// StrokeAttribute has to be equal
if(!(pCandidateA->getStrokeAttribute() == pCandidateB->getStrokeAttribute()))
{
return Primitive2DReference();
}
// direction has to be equal -> cross product == 0.0
const basegfx::B2DVector aVT(pCandidateA->getEnd() - pCandidateA->getStart());
const basegfx::B2DVector aVC(pCandidateB->getEnd() - pCandidateB->getStart());
if(!rtl::math::approxEqual(0.0, aVC.cross(aVT)))
{
return Primitive2DReference();
}
// number BorderLines has to be equal
const size_t count(pCandidateA->getBorderLines().size());
if(count != pCandidateB->getBorderLines().size())
{
return Primitive2DReference();
}
for(size_t a(0); a < count; a++)
{
const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
const BorderLine& rBC(pCandidateB->getBorderLines()[a]);
// LineAttribute has to be the same
if(!(rBC.getLineAttribute() == rBT.getLineAttribute()))
{
return Primitive2DReference();
}
// isGap has to be the same
if(rBC.isGap() != rBT.isGap())
{
return Primitive2DReference();
}
if(!rBT.isGap())
{
// when not gap, the line extends have at least reach to the center ( > 0.0),
// else there is a extend usage. When > 0.0 they just overlap, no problem
if(rBT.getEndLeft() >= 0.0
&& rBT.getEndRight() >= 0.0
&& rBC.getStartLeft() >= 0.0
&& rBC.getStartRight() >= 0.0)
{
// okay
}
else
{
return Primitive2DReference();
}
}
}
// all conditions met, create merged primitive
std::vector< BorderLine > aMergedBorderLines;
for(size_t a(0); a < count; a++)
{
const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
const BorderLine& rBC(pCandidateB->getBorderLines()[a]);
aMergedBorderLines.push_back(
BorderLine(
rBT.getLineAttribute(),
rBT.getStartLeft(), rBT.getStartRight(),
rBC.getEndLeft(), rBC.getEndRight()));
}
return Primitive2DReference(
new BorderLinePrimitive2D(
pCandidateA->getStart(),
pCandidateB->getEnd(),
aMergedBorderLines,
pCandidateA->getStrokeAttribute()));
}
} // end of namespace primitive2d
} // end of namespace drawinglayer
......
......@@ -87,6 +87,13 @@ namespace drawinglayer
bool operator==(const BorderLine& rBorderLine) const;
};
/// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible,
/// a merged version is in the returned Primitive2DReference. Lots of preconditions
/// have to be met to allow that, see implementation (and maybe even expand)
Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D(
const Primitive2DReference& rCandidateA,
const Primitive2DReference& rCandidateB);
/** BorderLinePrimitive2D class
This is the basic primitive to build frames around objects, e.g. tables.
......
......@@ -213,66 +213,27 @@ public:
inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); }
// Various helper functions
/** Checks whether two horizontal frame borders are "connectable".
Two borders are "connectable" in terms of this function, if both can be
drawn with only one call of a border drawing function. This means, the two
frame borders must have equal style and color, and none of the other
vertical and diagonal frame borders break the lines of the two borders in
any way (i.e. two vertical double frame borders would break the horizonal
frame borders). Of course this function can be used for vertical frame
borders as well.
The following picture shows the meaning of all passed parameters:
\ rTFromT /
\ | /
rTFromTL | rTFromTR
\ | /
\ | /
======== rLBorder ========= ========== rRBorder =======
/ | \
/ | \
rBFromBL | rBFromBR
/ | \
/ rBFromB \
@return
True, if rLBorder and rRBorder can be drawn in one step without
interruption at their connection point.
*/
SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
const Style& rLBorder, /// Style of the left frame border to connect.
const Style& rRBorder, /// Style of the right frame border to connect.
const Style& rTFromTL, /// Diagonal frame border from top-left to connection point.
const Style& rTFromT, /// Vertical frame border from top to connection point.
const Style& rTFromTR, /// Horizontal frame border from top-right to connection point.
const Style& rBFromBL, /// Diagonal frame border from bottom-left to connection point.
const Style& rBFromB, /// Vertical frame border from bottom to connection point.
const Style& rBFromBR /// Horizontal frame border from bottom-right to connection point.
);
// Drawing functions
class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorCombination
{
private:
const Style& mrStyle;
const basegfx::B2DVector& mrB2DVector;
const basegfx::B2DVector maB2DVector;
const bool mbMirrored;
public:
StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector) :
StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector, bool bMirrored) :
mrStyle(rStyle),
mrB2DVector(rB2DVector)
{}
maB2DVector(rB2DVector),
mbMirrored(bMirrored)
{
}
const Style& getStyle() const { return mrStyle; }
const basegfx::B2DVector& getB2DVector() const { return mrB2DVector; }
const basegfx::B2DVector& getB2DVector() const { return maB2DVector; }
bool isMirrored() const { return mbMirrored; }
};
typedef std::vector< StyleVectorCombination > StyleVectorTable;
......
......@@ -88,7 +88,7 @@ void Style::SetPatternScale( double fScale )
{
if(!maImplStyle)
{
if(1.0 == fScale)
if(rtl::math::approxEqual(1.0, fScale))
{
return;
}
......@@ -334,29 +334,6 @@ bool Style::operator<( const Style& rOther) const
return false;
}
bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
{
return // returns 1 AND (2a OR 2b)
// 1) only, if both frame borders are equal
(rLBorder == rRBorder)
&&
(
(
// 2a) if the borders are not double, at least one of the vertical must not be double
!rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
)
||
(
// 2b) if the borders are double, all other borders must not be double
rLBorder.Secn() &&
!rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
!rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
)
);
}
// Drawing functions
struct OffsetAndHalfWidthAndColor
{
......@@ -387,48 +364,70 @@ struct ExtendSet
ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {}
};
void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pForceColor, std::vector< OffsetAndHalfWidthAndColor >& offsets)
double getOffsetAndHalfWidthAndColorFromStyle(
const Style& rStyle,
const Color* pForceColor,
bool bMirrored,
std::vector< OffsetAndHalfWidthAndColor >& offsets)
{
// do not forget RefMode offset, primitive is free of it
double fRefModeOffset(0.0);
if (rStyle.IsUsed())
{
// do not forget RefMode offset, primitive is free of it
double fRefModeOffset(0.0);
RefMode aRefMode(rStyle.GetRefMode());
Color aPrim(rStyle.GetColorPrim());
Color aSecn(rStyle.GetColorSecn());
double fPrim(rStyle.Prim());
double fSecn(rStyle.Secn());
if(bMirrored)
{
switch(aRefMode)
{
case RefMode::Begin: aRefMode = RefMode::End; break;
case RefMode::End: aRefMode = RefMode::Begin; break;
default: break;
}
std::swap(aPrim, aSecn);
std::swap(fPrim, fSecn);
}
if (RefMode::Centered != rStyle.GetRefMode())
if (RefMode::Centered != aRefMode)
{
const double fHalfWidth(rStyle.GetWidth() * 0.5);
if (RefMode::Begin == rStyle.GetRefMode())
if (RefMode::Begin == aRefMode)
{
// move aligned below vector
fRefModeOffset = fHalfWidth;
}
else if (RefMode::End == rStyle.GetRefMode())
else if (RefMode::End == aRefMode)
{
// move aligned above vector
fRefModeOffset = -fHalfWidth;
}
}
if (rStyle.Dist() && rStyle.Secn())
if (rStyle.Dist() && fSecn)
{
// both or all three lines used
const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency());
const bool bDistTransparent(!rStyle.UseGapColor() || 0xff == rStyle.GetColorGap().GetTransparency());
const bool bSecnTransparent(0xff == rStyle.GetColorSecn().GetTransparency());
const bool bSecnTransparent(0xff == aSecn.GetTransparency());
if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
{
const double a(fRefModeOffset - (rStyle.GetWidth() * 0.5));
const double b(a + rStyle.Prim());
const double b(a + fPrim);
const double c(b + rStyle.Dist());
const double d(c + rStyle.Secn());
const double d(c + fSecn);
offsets.push_back(
OffsetAndHalfWidthAndColor(
(a + b) * 0.5,
rStyle.Prim() * 0.5,
nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
fPrim * 0.5,
nullptr != pForceColor ? *pForceColor : aPrim));
offsets.push_back(
OffsetAndHalfWidthAndColor(
......@@ -441,8 +440,8 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
offsets.push_back(
OffsetAndHalfWidthAndColor(
(c + d) * 0.5,
rStyle.Secn() * 0.5,
nullptr != pForceColor ? *pForceColor : rStyle.GetColorSecn()));
fSecn * 0.5,
nullptr != pForceColor ? *pForceColor : aSecn));
}
}
else
......@@ -453,11 +452,13 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
offsets.push_back(
OffsetAndHalfWidthAndColor(
fRefModeOffset,
rStyle.Prim() * 0.5,
nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
fPrim * 0.5,
nullptr != pForceColor ? *pForceColor : aPrim));
}
}
}
return fRefModeOffset;
}
void getCutSet(
......@@ -525,7 +526,7 @@ void getExtends(
for(const auto& rStyleVectorCombination : rStyleVectorTable)
{
std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, otherOffsets);
getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
if(!otherOffsets.empty())
{
......@@ -568,7 +569,7 @@ void CreateBorderPrimitives(
{
// get offset color pairs for style, one per visible line
std::vector< OffsetAndHalfWidthAndColor > myOffsets;
getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, myOffsets);
const double fRefModeOffset(getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, false, myOffsets));
const size_t nOffsets(myOffsets.size());
if(nOffsets)
......@@ -624,12 +625,13 @@ void CreateBorderPrimitives(
static double fPatScFact(10.0); // 10.0 multiply, see old code
const std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact));
const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing);
const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * fRefModeOffset));
rTarget.append(
drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::BorderLinePrimitive2D(
rOrigin,
rOrigin + rX,
aStart,
aStart + rX,
aBorderlines,
aStrokeAttribute)));
}
......
......@@ -197,7 +197,7 @@ namespace sdr
return svx::frame::Style();
}
void createForVector(drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
const svx::frame::Style& rLine,
const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC,
const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC)
......@@ -206,17 +206,16 @@ namespace sdr
svx::frame::StyleVectorTable aStart;
svx::frame::StyleVectorTable aEnd;
const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX));
const double fTwipsToMM(127.0 / 72.0);
/// Fill top-left Style Table
if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY));
if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX));
if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY));
if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false));
if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true));
if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true));
/// Fill bottom-right Style Table
if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY));
if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX));
if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY));
if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false));
if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false));
if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true));
CreateBorderPrimitives(
rContainer,
......@@ -350,32 +349,31 @@ namespace sdr
const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0));
const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0));
const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0));
const double fTwipsToMM(127.0 / 72.0);
if(aLeftLine.IsUsed())
{
createForVector(aBorderSequence, aOrigin, aY, aLeftLine,
createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine,
aTopLine, aLeftFromTLine, aTopFromLLine,
aBottomLine, aLeftFromBLine, aBottomFromLLine);
}
if(aBottomLine.IsUsed())
{
createForVector(aBorderSequence, aOrigin + aY, aX, aBottomLine,
createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine,
aLeftLine, aBottomFromLLine, aLeftFromBLine,
aRightLine, aBottomFromRLine, aRightFromBLine);
}
if(aRightLine.IsUsed())
{
createForVector(aBorderSequence, aOrigin + aX, aY, aRightLine,
createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine,
aTopFromRLine, aRightFromTLine, aTopLine,
aBottomFromRLine, aRightFromBLine, aBottomLine);
}
if(aTopLine.IsUsed())
{
createForVector(aBorderSequence, aOrigin, aX, aTopLine,
createForVector(true, aBorderSequence, aOrigin, aX, aTopLine,
aLeftFromTLine, aTopFromLLine, aLeftLine,
aRightFromTLine, aTopFromRLine, aRightLine);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment