1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "PresenterGeometryHelper.hxx"
21 
22 #include <math.h>
23 #include <algorithm>
24 #include <o3tl/safeint.hxx>
25 
26 
27 using namespace ::com::sun::star;
28 using namespace ::com::sun::star::uno;
29 
30 namespace {
31 
Right(const awt::Rectangle & rBox)32 sal_Int32 Right (const awt::Rectangle& rBox)
33 {
34     return rBox.X + rBox.Width - 1;
35 }
36 
Bottom(const awt::Rectangle & rBox)37 sal_Int32 Bottom (const awt::Rectangle& rBox)
38 {
39     return rBox.Y + rBox.Height - 1;
40 }
41 
Width(const sal_Int32 nLeft,const sal_Int32 nRight)42 sal_Int32 Width (const sal_Int32 nLeft, const sal_Int32 nRight)
43 {
44     return nRight - nLeft + 1;
45 }
46 
Height(const sal_Int32 nTop,const sal_Int32 nBottom)47 sal_Int32 Height (const sal_Int32 nTop, const sal_Int32 nBottom)
48 {
49     return nBottom - nTop + 1;
50 }
51 
52 } // end of anonymous namespace
53 
54 namespace sdext::presenter {
55 
Floor(const double nValue)56 sal_Int32 PresenterGeometryHelper::Floor (const double nValue)
57 {
58     return sal::static_int_cast<sal_Int32>(floor(nValue));
59 }
60 
Ceil(const double nValue)61 sal_Int32 PresenterGeometryHelper::Ceil (const double nValue)
62 {
63     return sal::static_int_cast<sal_Int32>(ceil(nValue));
64 }
65 
Round(const double nValue)66 sal_Int32 PresenterGeometryHelper::Round (const double nValue)
67 {
68     return sal::static_int_cast<sal_Int32>(floor(0.5 + nValue));
69 }
70 
ConvertRectangle(const geometry::RealRectangle2D & rBox)71 awt::Rectangle PresenterGeometryHelper::ConvertRectangle (
72     const geometry::RealRectangle2D& rBox)
73 {
74     const sal_Int32 nLeft (Floor(rBox.X1));
75     const sal_Int32 nTop (Floor(rBox.Y1));
76     const sal_Int32 nRight (Ceil(rBox.X2));
77     const sal_Int32 nBottom (Ceil(rBox.Y2));
78     return awt::Rectangle (nLeft,nTop,nRight-nLeft,nBottom-nTop);
79 }
80 
ConvertRectangleWithConstantSize(const geometry::RealRectangle2D & rBox)81 awt::Rectangle PresenterGeometryHelper::ConvertRectangleWithConstantSize (
82     const geometry::RealRectangle2D& rBox)
83 {
84     return awt::Rectangle (
85         Round(rBox.X1),
86         Round(rBox.Y1),
87         Round(rBox.X2 - rBox.X1),
88         Round(rBox.Y2 - rBox.Y1));
89 }
90 
ConvertRectangle(const css::awt::Rectangle & rBox)91 geometry::RealRectangle2D PresenterGeometryHelper::ConvertRectangle (
92     const css::awt::Rectangle& rBox)
93 {
94     return geometry::RealRectangle2D(
95         rBox.X,
96         rBox.Y,
97         rBox.X + rBox.Width,
98         rBox.Y + rBox.Height);
99 }
100 
TranslateRectangle(const css::awt::Rectangle & rBox,const sal_Int32 nXOffset,const sal_Int32 nYOffset)101 awt::Rectangle PresenterGeometryHelper::TranslateRectangle (
102     const css::awt::Rectangle& rBox,
103     const sal_Int32 nXOffset,
104     const sal_Int32 nYOffset)
105 {
106     return awt::Rectangle(rBox.X + nXOffset, rBox.Y + nYOffset, rBox.Width, rBox.Height);
107 }
108 
Intersection(const css::awt::Rectangle & rBox1,const css::awt::Rectangle & rBox2)109 awt::Rectangle PresenterGeometryHelper::Intersection (
110     const css::awt::Rectangle& rBox1,
111     const css::awt::Rectangle& rBox2)
112 {
113     const sal_Int32 nLeft (::std::max(rBox1.X, rBox2.X));
114     const sal_Int32 nTop (::std::max(rBox1.Y, rBox2.Y));
115     const sal_Int32 nRight (::std::min(Right(rBox1), Right(rBox2)));
116     const sal_Int32 nBottom (::std::min(Bottom(rBox1), Bottom(rBox2)));
117     if (nLeft >= nRight || nTop >= nBottom)
118         return awt::Rectangle();
119     else
120         return awt::Rectangle(nLeft,nTop, Width(nLeft,nRight), Height(nTop,nBottom));
121 }
122 
Intersection(const geometry::RealRectangle2D & rBox1,const geometry::RealRectangle2D & rBox2)123 geometry::RealRectangle2D PresenterGeometryHelper::Intersection (
124     const geometry::RealRectangle2D& rBox1,
125     const geometry::RealRectangle2D& rBox2)
126 {
127     const double nLeft (::std::max(rBox1.X1, rBox2.X1));
128     const double nTop (::std::max(rBox1.Y1, rBox2.Y1));
129     const double nRight (::std::min(rBox1.X2, rBox2.X2));
130     const double nBottom (::std::min(rBox1.Y2, rBox2.Y2));
131     if (nLeft >= nRight || nTop >= nBottom)
132         return geometry::RealRectangle2D(0,0,0,0);
133     else
134         return geometry::RealRectangle2D(nLeft,nTop, nRight, nBottom);
135 }
136 
IsInside(const css::geometry::RealRectangle2D & rBox,const css::geometry::RealPoint2D & rPoint)137 bool PresenterGeometryHelper::IsInside (
138     const css::geometry::RealRectangle2D& rBox,
139     const css::geometry::RealPoint2D& rPoint)
140 {
141     return rBox.X1 <= rPoint.X
142         && rBox.Y1 <= rPoint.Y
143         && rBox.X2 >= rPoint.X
144         && rBox.Y2 >= rPoint.Y;
145 }
146 
IsInside(const css::awt::Rectangle & rBox1,const css::awt::Rectangle & rBox2)147 bool PresenterGeometryHelper::IsInside (
148     const css::awt::Rectangle& rBox1,
149     const css::awt::Rectangle& rBox2)
150 {
151     return rBox1.X >= rBox2.X
152         && rBox1.Y >= rBox2.Y
153         && rBox1.X+rBox1.Width <= rBox2.X+rBox2.Width
154         && rBox1.Y+rBox1.Height <= rBox2.Y+rBox2.Height;
155 }
156 
Union(const geometry::RealRectangle2D & rBox1,const geometry::RealRectangle2D & rBox2)157 geometry::RealRectangle2D PresenterGeometryHelper::Union (
158     const geometry::RealRectangle2D& rBox1,
159     const geometry::RealRectangle2D& rBox2)
160 {
161     const double nLeft (::std::min(rBox1.X1, rBox2.X1));
162     const double nTop (::std::min(rBox1.Y1, rBox2.Y1));
163     const double nRight (::std::max(rBox1.X2, rBox2.X2));
164     const double nBottom (::std::max(rBox1.Y2, rBox2.Y2));
165     if (nLeft >= nRight || nTop >= nBottom)
166         return geometry::RealRectangle2D(0,0,0,0);
167     else
168         return geometry::RealRectangle2D(nLeft,nTop, nRight, nBottom);
169 }
170 
AreRectanglesDisjoint(const css::awt::Rectangle & rBox1,const css::awt::Rectangle & rBox2)171 bool PresenterGeometryHelper::AreRectanglesDisjoint (
172     const css::awt::Rectangle& rBox1,
173     const css::awt::Rectangle& rBox2)
174 {
175     return rBox1.X+rBox1.Width <= rBox2.X
176         || rBox1.Y+rBox1.Height <= rBox2.Y
177         || rBox1.X >= rBox2.X+rBox2.Width
178         || rBox1.Y >= rBox2.Y+rBox2.Height;
179 }
180 
CreatePolygon(const awt::Rectangle & rBox,const Reference<rendering::XGraphicDevice> & rxDevice)181 Reference<rendering::XPolyPolygon2D> PresenterGeometryHelper::CreatePolygon(
182     const awt::Rectangle& rBox,
183     const Reference<rendering::XGraphicDevice>& rxDevice)
184 {
185     if ( ! rxDevice.is())
186         return nullptr;
187 
188     Sequence<Sequence<geometry::RealPoint2D> > aPoints
189     {
190         {
191             { o3tl::narrowing<double>(rBox.X), o3tl::narrowing<double>(rBox.Y) },
192             { o3tl::narrowing<double>(rBox.X), o3tl::narrowing<double>(rBox.Y+rBox.Height) },
193             { o3tl::narrowing<double>(rBox.X+rBox.Width), o3tl::narrowing<double>(rBox.Y+rBox.Height) },
194             { o3tl::narrowing<double>(rBox.X+rBox.Width), o3tl::narrowing<double>(rBox.Y) }
195         }
196     };
197     Reference<rendering::XLinePolyPolygon2D> xPolygon (
198         rxDevice->createCompatibleLinePolyPolygon(aPoints));
199     if (xPolygon.is())
200         xPolygon->setClosed(0, true);
201 
202     return xPolygon;
203 }
204 
CreatePolygon(const geometry::RealRectangle2D & rBox,const Reference<rendering::XGraphicDevice> & rxDevice)205 Reference<rendering::XPolyPolygon2D> PresenterGeometryHelper::CreatePolygon(
206     const geometry::RealRectangle2D& rBox,
207     const Reference<rendering::XGraphicDevice>& rxDevice)
208 {
209     if ( ! rxDevice.is())
210         return nullptr;
211 
212     Sequence<Sequence<geometry::RealPoint2D> > aPoints
213     {
214         {
215             { rBox.X1, rBox.Y1 },
216             { rBox.X1, rBox.Y2 },
217             { rBox.X2, rBox.Y2 },
218             { rBox.X2, rBox.Y1 }
219         }
220     };
221     Reference<rendering::XLinePolyPolygon2D> xPolygon (
222         rxDevice->createCompatibleLinePolyPolygon(aPoints));
223     if (xPolygon.is())
224         xPolygon->setClosed(0, true);
225 
226     return xPolygon;
227 }
228 
CreatePolygon(const::std::vector<css::awt::Rectangle> & rBoxes,const Reference<rendering::XGraphicDevice> & rxDevice)229 Reference<rendering::XPolyPolygon2D> PresenterGeometryHelper::CreatePolygon(
230     const ::std::vector<css::awt::Rectangle>& rBoxes,
231     const Reference<rendering::XGraphicDevice>& rxDevice)
232 {
233     if ( ! rxDevice.is())
234         return nullptr;
235 
236     const sal_Int32 nCount (rBoxes.size());
237     Sequence<Sequence<geometry::RealPoint2D> > aPoints(nCount);
238     for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
239     {
240         const awt::Rectangle& rBox (rBoxes[nIndex]);
241         aPoints[nIndex] = Sequence<geometry::RealPoint2D>
242         {
243             { o3tl::narrowing<double>(rBox.X), o3tl::narrowing<double>(rBox.Y) },
244             { o3tl::narrowing<double>(rBox.X), o3tl::narrowing<double>(rBox.Y+rBox.Height) },
245             { o3tl::narrowing<double>(rBox.X+rBox.Width), o3tl::narrowing<double>(rBox.Y+rBox.Height) },
246             { o3tl::narrowing<double>(rBox.X+rBox.Width), o3tl::narrowing<double>(rBox.Y) }
247         };
248     }
249 
250     Reference<rendering::XLinePolyPolygon2D> xPolygon (
251         rxDevice->createCompatibleLinePolyPolygon(aPoints));
252     if (xPolygon.is())
253         for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
254             xPolygon->setClosed(nIndex, true);
255 
256     return xPolygon;
257 }
258 
259 }
260 
261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
262