basegfx: generalize B2DRange and B2IRange with Range2D template

Also add and/or re-arrange B2DRange and B2IRange tests

Change-Id: I0f582b30c92776ffbab8b69810ec855da0931714
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134111
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
Tomaž Vajngerl
2022-05-10 21:06:22 +09:00
committed by Tomaž Vajngerl
parent 24417d8c3c
commit 04669a3a46
8 changed files with 301 additions and 353 deletions

View File

@@ -23,6 +23,7 @@ $(eval $(call gb_CppunitTest_use_libraries,basegfx,\
$(eval $(call gb_CppunitTest_add_exception_objects,basegfx,\
basegfx/test/B2DRangeTest \
basegfx/test/B2IRangeTest \
basegfx/test/B2DPolyRangeTest \
basegfx/test/B2DHomMatrixTest \
basegfx/test/B2DPointTest \

View File

@@ -23,12 +23,12 @@
namespace basegfx
{
B2DRange::B2DRange( const B2IRange& rRange )
B2DRange::B2DRange(const B2IRange& rRange)
{
if( !rRange.isEmpty() )
if (!rRange.isEmpty())
{
maRangeX = MyBasicRange(rRange.getMinX());
maRangeY = MyBasicRange(rRange.getMinY());
maRangeX = basegfx::BasicRange<ValueType, TraitsType>(rRange.getMinX());
maRangeY = basegfx::BasicRange<ValueType, TraitsType>(rRange.getMinY());
maRangeX.expand(rRange.getMaxX());
maRangeY.expand(rRange.getMaxY());
@@ -48,9 +48,9 @@ namespace basegfx
}
}
B2DRange& B2DRange::operator*=( const ::basegfx::B2DHomMatrix& rMat )
B2DRange& B2DRange::operator*=(const basegfx::B2DHomMatrix& rMatrix)
{
transform(rMat);
transform(rMatrix);
return *this;
}

View File

@@ -27,7 +27,7 @@
class B2DRangeTest : public CppUnit::TestFixture
{
void testRange()
void testCreation()
{
basegfx::B2DRange aRange(1.2, 2.3, 3.5, 4.8);
CPPUNIT_ASSERT_EQUAL(1.2, aRange.getMinX());
@@ -37,17 +37,30 @@ class B2DRangeTest : public CppUnit::TestFixture
CPPUNIT_ASSERT_EQUAL(2.3, aRange.getWidth());
CPPUNIT_ASSERT_EQUAL(2.5, aRange.getHeight());
}
void testRound()
{
basegfx::B2DRange aRange(1.2, 2.3, 3.5, 4.8);
CPPUNIT_ASSERT_EQUAL_MESSAGE("simple range rounding from double to integer",
basegfx::B2IRange(1, 2, 4, 5), fround(aRange));
}
void testCenter()
{
basegfx::B2DRange aRange(1.0, 2.0, 2.0, 3.0);
CPPUNIT_ASSERT_EQUAL(1.5, aRange.getCenterX());
CPPUNIT_ASSERT_EQUAL(2.5, aRange.getCenterY());
}
// Change the following lines only, if you add, remove or rename
// member functions of the current class,
// because these macros are need by auto register mechanism.
CPPUNIT_TEST_SUITE(B2DRangeTest);
CPPUNIT_TEST(testRange);
CPPUNIT_TEST(testCreation);
CPPUNIT_TEST(testRound);
CPPUNIT_TEST(testCenter);
CPPUNIT_TEST_SUITE_END();
};

View File

@@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <basegfx/range/b2irange.hxx>
class B2IRangeTest : public CppUnit::TestFixture
{
void testCreation()
{
basegfx::B2IRange aRange(1, 2, 3, 4);
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRange.getMinX());
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aRange.getMaxX());
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aRange.getMinY());
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aRange.getMaxY());
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aRange.getWidth());
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aRange.getHeight());
}
void testCenter()
{
basegfx::B2IRange aRange(1, 2, 2, 3);
CPPUNIT_ASSERT_EQUAL(1.5, aRange.getCenterX());
CPPUNIT_ASSERT_EQUAL(2.5, aRange.getCenterY());
}
CPPUNIT_TEST_SUITE(B2IRangeTest);
CPPUNIT_TEST(testCreation);
CPPUNIT_TEST(testCenter);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(B2IRangeTest);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#pragma once
#include <basegfx/basegfxdllapi.h>
#include <basegfx/range/basicrange.hxx>
#include <basegfx/tuple/Tuple2D.hxx>
namespace basegfx
{
template <typename TYPE, typename TRAITS> class Range2D
{
protected:
basegfx::BasicRange<TYPE, TRAITS> maRangeX;
basegfx::BasicRange<TYPE, TRAITS> maRangeY;
public:
typedef TYPE ValueType;
typedef TRAITS TraitsType;
Range2D() = default;
/// Create degenerate interval consisting of a single point
explicit Range2D(const Tuple2D<TYPE>& rTuple)
: maRangeX(rTuple.getX())
, maRangeY(rTuple.getY())
{
}
/// Create proper interval between the two given points
Range2D(const Tuple2D<TYPE>& rTuple1, const Tuple2D<TYPE>& rTuple2)
: maRangeX(rTuple1.getX())
, maRangeY(rTuple1.getY())
{
expand(rTuple2);
}
/// Create proper interval between the two given pairs
Range2D(TYPE x1, TYPE y1, TYPE x2, TYPE y2)
: maRangeX(x1)
, maRangeY(y1)
{
maRangeX.expand(x2);
maRangeY.expand(y2);
}
/** Check if the interval set is empty
@return false, if no value is in this set - having a
single point included will already return true.
*/
bool isEmpty() const { return maRangeX.isEmpty() || maRangeY.isEmpty(); }
/// reset the object to empty state again, clearing all values
void reset()
{
maRangeX.reset();
maRangeY.reset();
}
bool operator==(const Range2D& rRange) const
{
return maRangeX == rRange.maRangeX && maRangeY == rRange.maRangeY;
}
bool operator!=(const Range2D& rRange) const
{
return maRangeX != rRange.maRangeX || maRangeY != rRange.maRangeY;
}
bool equal(const Range2D& rRange) const
{
return maRangeX.equal(rRange.maRangeX) && maRangeY.equal(rRange.maRangeY);
}
/// get lower bound of the set. returns arbitrary values for empty sets.
TYPE getMinX() const { return maRangeX.getMinimum(); }
/// get lower bound of the set. returns arbitrary values for empty sets.
TYPE getMinY() const { return maRangeY.getMinimum(); }
/// get upper bound of the set. returns arbitrary values for empty sets.
TYPE getMaxX() const { return maRangeX.getMaximum(); }
/// get upper bound of the set. returns arbitrary values for empty sets.
TYPE getMaxY() const { return maRangeY.getMaximum(); }
/// return difference between upper and lower X value. returns 0 for empty sets.
TYPE getWidth() const { return maRangeX.getRange(); }
/// return difference between upper and lower Y value. returns 0 for empty sets.
TYPE getHeight() const { return maRangeY.getRange(); }
/// return center X value of set. returns 0 for empty sets.
double getCenterX() const { return maRangeX.getCenter(); }
/// return center Y value of set. returns 0 for empty sets.
double getCenterY() const { return maRangeY.getCenter(); }
/// yields true if given point is contained in set
bool isInside(const Tuple2D<TYPE>& rTuple) const
{
return maRangeX.isInside(rTuple.getX()) && maRangeY.isInside(rTuple.getY());
}
/// yields true if rRange is inside, or equal to set
bool isInside(const Range2D& rRange) const
{
return maRangeX.isInside(rRange.maRangeX) && maRangeY.isInside(rRange.maRangeY);
}
/// yields true if rRange at least partly inside set
bool overlaps(const Range2D& rRange) const
{
return maRangeX.overlaps(rRange.maRangeX) && maRangeY.overlaps(rRange.maRangeY);
}
/// yields true if overlaps(rRange) does, and the overlap is larger than infinitesimal
bool overlapsMore(const Range2D& rRange) const
{
return maRangeX.overlapsMore(rRange.maRangeX) && maRangeY.overlapsMore(rRange.maRangeY);
}
/// add point to the set, expanding as necessary
void expand(const Tuple2D<TYPE>& rTuple)
{
maRangeX.expand(rTuple.getX());
maRangeY.expand(rTuple.getY());
}
/// add rRange to the set, expanding as necessary
void expand(const Range2D& rRange)
{
maRangeX.expand(rRange.maRangeX);
maRangeY.expand(rRange.maRangeY);
}
/// calc set intersection
void intersect(const Range2D& rRange)
{
maRangeX.intersect(rRange.maRangeX);
maRangeY.intersect(rRange.maRangeY);
}
/// grow set by fValue on all sides
void grow(TYPE fValue)
{
maRangeX.grow(fValue);
maRangeY.grow(fValue);
}
/// clamp value on range
Tuple2D<TYPE> clamp(const Tuple2D<TYPE>& rTuple) const
{
return Tuple2D<TYPE>(maRangeX.clamp(rTuple.getX()), maRangeY.clamp(rTuple.getY()));
}
};
} // end of namespace basegfx
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -22,11 +22,12 @@
#include <ostream>
#include <vector>
#include <basegfx/basegfxdllapi.h>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tuple/b2dtuple.hxx>
#include <basegfx/range/basicrange.hxx>
#include <basegfx/basegfxdllapi.h>
#include <basegfx/range/Range2D.hxx>
namespace basegfx
{
@@ -49,118 +50,32 @@ namespace basegfx
@see B1DRange
*/
class SAL_WARN_UNUSED B2DRange
class SAL_WARN_UNUSED B2DRange : public Range2D<double, DoubleTraits>
{
public:
typedef double ValueType;
typedef DoubleTraits TraitsType;
B2DRange() {}
B2DRange()
: Range2D()
{}
/// Create degenerate interval consisting of a single point
explicit B2DRange(const B2DTuple& rTuple)
: maRangeX(rTuple.getX()),
maRangeY(rTuple.getY())
explicit B2DRange(const Tuple2D<ValueType>& rTuple)
: Range2D(rTuple)
{
}
/// Create proper interval between the two given double pairs
B2DRange(double x1,
double y1,
double x2,
double y2)
: maRangeX(x1),
maRangeY(y1)
{
maRangeX.expand(x2);
maRangeY.expand(y2);
}
/// Create proper interval between the two given points
B2DRange(const B2DTuple& rTuple1,
const B2DTuple& rTuple2)
: maRangeX(rTuple1.getX()),
maRangeY(rTuple1.getY())
B2DRange(const Tuple2D<ValueType>& rTuple1,
const Tuple2D<ValueType>& rTuple2)
: Range2D(rTuple1, rTuple2)
{
expand( rTuple2 );
}
B2DRange(ValueType x1, ValueType y1, ValueType x2, ValueType y2)
: Range2D(x1, y1, x2, y2)
{}
BASEGFX_DLLPUBLIC explicit B2DRange(const B2IRange& rRange);
/** Check if the interval set is empty
@return false, if no value is in this set - having a
single point included will already return true.
*/
bool isEmpty() const
{
return (
maRangeX.isEmpty()
|| maRangeY.isEmpty()
);
}
/// reset the object to empty state again, clearing all values
void reset()
{
maRangeX.reset();
maRangeY.reset();
}
bool operator==( const B2DRange& rRange ) const
{
return (maRangeX == rRange.maRangeX
&& maRangeY == rRange.maRangeY);
}
bool operator!=( const B2DRange& rRange ) const
{
return (maRangeX != rRange.maRangeX
|| maRangeY != rRange.maRangeY);
}
bool equal(const B2DRange& rRange) const
{
return (maRangeX.equal(rRange.maRangeX)
&& maRangeY.equal(rRange.maRangeY));
}
/// get lower bound of the set. returns arbitrary values for empty sets.
double getMinX() const
{
return maRangeX.getMinimum();
}
/// get lower bound of the set. returns arbitrary values for empty sets.
double getMinY() const
{
return maRangeY.getMinimum();
}
/// get upper bound of the set. returns arbitrary values for empty sets.
double getMaxX() const
{
return maRangeX.getMaximum();
}
/// get upper bound of the set. returns arbitrary values for empty sets.
double getMaxY() const
{
return maRangeY.getMaximum();
}
/// return difference between upper and lower X value. returns 0 for empty sets.
double getWidth() const
{
return maRangeX.getRange();
}
/// return difference between upper and lower Y value. returns 0 for empty sets.
double getHeight() const
{
return maRangeY.getRange();
}
/// get lower bound of the set. returns arbitrary values for empty sets.
B2DPoint getMinimum() const
{
@@ -197,90 +112,6 @@ namespace basegfx
);
}
/// return center X value of set. returns 0 for empty sets.
double getCenterX() const
{
return maRangeX.getCenter();
}
/// return center Y value of set. returns 0 for empty sets.
double getCenterY() const
{
return maRangeY.getCenter();
}
/// yields true if given point is contained in set
bool isInside(const B2DTuple& rTuple) const
{
return (
maRangeX.isInside(rTuple.getX())
&& maRangeY.isInside(rTuple.getY())
);
}
/// yields true if rRange is inside, or equal to set
bool isInside(const B2DRange& rRange) const
{
return (
maRangeX.isInside(rRange.maRangeX)
&& maRangeY.isInside(rRange.maRangeY)
);
}
/// yields true if rRange at least partly inside set
bool overlaps(const B2DRange& rRange) const
{
return (
maRangeX.overlaps(rRange.maRangeX)
&& maRangeY.overlaps(rRange.maRangeY)
);
}
/// yields true if overlaps(rRange) does, and the overlap is larger than infinitesimal
bool overlapsMore(const B2DRange& rRange) const
{
return (
maRangeX.overlapsMore(rRange.maRangeX)
&& maRangeY.overlapsMore(rRange.maRangeY)
);
}
/// add point to the set, expanding as necessary
void expand(const B2DTuple& rTuple)
{
maRangeX.expand(rTuple.getX());
maRangeY.expand(rTuple.getY());
}
/// add rRange to the set, expanding as necessary
void expand(const B2DRange& rRange)
{
maRangeX.expand(rRange.maRangeX);
maRangeY.expand(rRange.maRangeY);
}
/// calc set intersection
void intersect(const B2DRange& rRange)
{
maRangeX.intersect(rRange.maRangeX);
maRangeY.intersect(rRange.maRangeY);
}
/// grow set by fValue on all sides
void grow(double fValue)
{
maRangeX.grow(fValue);
maRangeY.grow(fValue);
}
/// clamp value on range
B2DTuple clamp(const B2DTuple& rTuple) const
{
return B2DTuple(
maRangeX.clamp(rTuple.getX()),
maRangeY.clamp(rTuple.getY()));
}
/** Transform Range by given transformation matrix. */
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix& rMatrix);
@@ -295,12 +126,6 @@ namespace basegfx
/** Get a range filled with (0.0, 0.0, 1.0, 1.0) */
static const B2DRange& getUnitB2DRange();
private:
typedef ::basegfx::BasicRange< ValueType, TraitsType > MyBasicRange;
MyBasicRange maRangeX;
MyBasicRange maRangeY;
};
/** Transform B2DRange by given transformation matrix (see operator*=())
@@ -332,13 +157,15 @@ namespace basegfx
@return the input vector
*/
BASEGFX_DLLPUBLIC ::std::vector< B2DRange >& computeSetDifference( ::std::vector< B2DRange >& o_rResult,
const B2DRange& rFirst,
const B2DRange& rSecond );
BASEGFX_DLLPUBLIC std::vector<B2DRange>& computeSetDifference(
std::vector<B2DRange>& o_rResult,
const B2DRange& rFirst,
const B2DRange& rSecond);
template< typename charT, typename traits >
inline std::basic_ostream<charT, traits> & operator <<(
std::basic_ostream<charT, traits> & stream, const B2DRange& range )
/** Write to char stream */
template<typename charT, typename traits>
inline std::basic_ostream<charT, traits>& operator<<(
std::basic_ostream<charT, traits>& stream, const B2DRange& range)
{
return stream << range.getWidth() << "x" << range.getHeight() << "@" << range.getMinimum();
}

View File

@@ -22,11 +22,12 @@
#include <ostream>
#include <vector>
#include <basegfx/basegfxdllapi.h>
#include <basegfx/point/b2ipoint.hxx>
#include <basegfx/tuple/b2ituple.hxx>
#include <basegfx/tuple/b2i64tuple.hxx>
#include <basegfx/range/basicrange.hxx>
#include <basegfx/basegfxdllapi.h>
#include <basegfx/range/Range2D.hxx>
namespace basegfx
{
@@ -48,106 +49,29 @@ namespace basegfx
@see B2IBox
*/
class B2IRange
class B2IRange : public Range2D<sal_Int32, Int32Traits>
{
public:
typedef sal_Int32 ValueType;
typedef Int32Traits TraitsType;
B2IRange() {}
B2IRange()
: Range2D()
{}
/// Create degenerate interval consisting of a single point
explicit B2IRange(const B2ITuple& rTuple)
: maRangeX(rTuple.getX()),
maRangeY(rTuple.getY())
explicit B2IRange(const Tuple2D<ValueType>& rTuple)
: Range2D(rTuple)
{
}
/// Create proper interval between the two given integer pairs
B2IRange(sal_Int32 x1,
sal_Int32 y1,
sal_Int32 x2,
sal_Int32 y2)
: maRangeX(x1),
maRangeY(y1)
{
maRangeX.expand(x2);
maRangeY.expand(y2);
}
/// Create proper interval between the two given points
B2IRange(const B2ITuple& rTuple1,
const B2ITuple& rTuple2)
: maRangeX(rTuple1.getX()),
maRangeY(rTuple1.getY())
B2IRange(const Tuple2D<ValueType>& rTuple1,
const Tuple2D<ValueType>& rTuple2)
: Range2D(rTuple1, rTuple2)
{
expand( rTuple2 );
}
/** Check if the interval set is empty
@return false, if no value is in this set - having a
single point included will already return true.
*/
bool isEmpty() const
{
return maRangeX.isEmpty() || maRangeY.isEmpty();
}
/// reset the object to empty state again, clearing all values
void reset()
{
maRangeX.reset();
maRangeY.reset();
}
bool operator==( const B2IRange& rRange ) const
{
return (maRangeX == rRange.maRangeX
&& maRangeY == rRange.maRangeY);
}
bool operator!=( const B2IRange& rRange ) const
{
return (maRangeX != rRange.maRangeX
|| maRangeY != rRange.maRangeY);
}
/// get lower bound of the set. returns arbitrary values for empty sets.
sal_Int32 getMinX() const
{
return maRangeX.getMinimum();
}
/// get lower bound of the set. returns arbitrary values for empty sets.
sal_Int32 getMinY() const
{
return maRangeY.getMinimum();
}
/// get upper bound of the set. returns arbitrary values for empty sets.
sal_Int32 getMaxX() const
{
return maRangeX.getMaximum();
}
/// get upper bound of the set. returns arbitrary values for empty sets.
sal_Int32 getMaxY() const
{
return maRangeY.getMaximum();
}
/// return difference between upper and lower X value. returns 0 for empty sets.
sal_Int64 getWidth() const
{
return maRangeX.getRange();
}
/// return difference between upper and lower Y value. returns 0 for empty sets.
sal_Int64 getHeight() const
{
return maRangeY.getRange();
}
B2IRange(ValueType x1, ValueType y1, ValueType x2, ValueType y2)
: Range2D(x1, y1, x2, y2)
{}
/// get lower bound of the set. returns arbitrary values for empty sets.
B2IPoint getMinimum() const
@@ -175,49 +99,6 @@ namespace basegfx
maRangeY.getRange()
);
}
/// yields true if given point is contained in set
bool isInside(const B2ITuple& rTuple) const
{
return (
maRangeX.isInside(rTuple.getX())
&& maRangeY.isInside(rTuple.getY())
);
}
/// add point to the set, expanding as necessary
void expand(const B2ITuple& rTuple)
{
maRangeX.expand(rTuple.getX());
maRangeY.expand(rTuple.getY());
}
/// add rRange to the set, expanding as necessary
void expand(const B2IRange& rRange)
{
maRangeX.expand(rRange.maRangeX);
maRangeY.expand(rRange.maRangeY);
}
/// calc set intersection
void intersect(const B2IRange& rRange)
{
maRangeX.intersect(rRange.maRangeX);
maRangeY.intersect(rRange.maRangeY);
}
B2ITuple clamp(const B2ITuple& rTuple) const
{
return B2ITuple(
maRangeX.clamp(rTuple.getX()),
maRangeY.clamp(rTuple.getY()));
}
private:
typedef ::basegfx::BasicRange< ValueType, TraitsType > MyBasicRange;
MyBasicRange maRangeX;
MyBasicRange maRangeY;
};
/** Compute the set difference of the two given ranges
@@ -239,19 +120,20 @@ namespace basegfx
@return the input vector
*/
BASEGFX_DLLPUBLIC ::std::vector< B2IRange >& computeSetDifference( ::std::vector< B2IRange >& o_rResult,
const B2IRange& rFirst,
const B2IRange& rSecond );
BASEGFX_DLLPUBLIC std::vector<B2IRange>& computeSetDifference(
std::vector<B2IRange>& o_rResult,
const B2IRange& rFirst,
const B2IRange& rSecond);
template< typename charT, typename traits >
inline std::basic_ostream<charT, traits> & operator <<(
std::basic_ostream<charT, traits> & stream, const B2IRange& range )
/** Write to char stream */
template<typename charT, typename traits>
inline std::basic_ostream<charT, traits>& operator<<(
std::basic_ostream<charT, traits>& stream, const B2IRange& range)
{
if (range.isEmpty())
return stream << "EMPTY";
else
return stream << range.getWidth() << 'x' << range.getHeight()
<< "@(" << range.getMinX() << "," << range.getMinY() << ")";
return stream << range.getWidth() << 'x' << range.getHeight() << "@" << range.getMinimum();
}
} // end of namespace basegfx

View File

@@ -29,8 +29,8 @@ namespace basegfx
template< typename T, typename Traits > class BasicRange
{
protected:
T mnMinimum;
T mnMaximum;
T mnMinimum;
T mnMaximum;
public:
typedef T ValueType;
@@ -285,18 +285,18 @@ namespace basegfx
// some pre-fabricated traits
struct DoubleTraits
{
static double minVal() { return DBL_MIN; };
static double maxVal() { return DBL_MAX; };
static double neutral() { return 0.0; };
static constexpr double minVal() { return DBL_MIN; };
static constexpr double maxVal() { return DBL_MAX; };
static constexpr double neutral() { return 0.0; };
typedef double DifferenceType;
};
struct Int32Traits
{
static sal_Int32 minVal() { return SAL_MIN_INT32; };
static sal_Int32 maxVal() { return SAL_MAX_INT32; };
static sal_Int32 neutral() { return 0; };
static constexpr sal_Int32 minVal() { return SAL_MIN_INT32; };
static constexpr sal_Int32 maxVal() { return SAL_MAX_INT32; };
static constexpr sal_Int32 neutral() { return 0; };
typedef sal_Int64 DifferenceType;
};