1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_svx.hxx" 26 27 #include <basegfx/polygon/b2dpolygon.hxx> 28 #include <basegfx/polygon/b2dpolygontools.hxx> 29 30 #include "svx/polypolygoneditor.hxx" 31 32 namespace sdr { 33 34 PolyPolygonEditor::PolyPolygonEditor( const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed ) 35 : maPolyPolygon( rPolyPolygon ) 36 , mbIsClosed( bClosed ) 37 { 38 } 39 40 bool PolyPolygonEditor::DeletePoints( const std::set< sal_uInt16 >& rAbsPoints ) 41 { 42 bool bPolyPolyChanged = false; 43 44 std::set< sal_uInt16 >::const_reverse_iterator aIter;( rAbsPoints.rbegin() ); 45 for( aIter = rAbsPoints.rbegin(); aIter != rAbsPoints.rend(); aIter++ ) 46 { 47 sal_uInt32 nPoly, nPnt; 48 if( GetRelativePolyPoint(maPolyPolygon,(*aIter), nPoly, nPnt) ) 49 { 50 // remove point 51 basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPoly)); 52 53 aCandidate.remove(nPnt); 54 55 if( ( mbIsClosed && aCandidate.count() < 3L) || (aCandidate.count() < 2L) ) 56 { 57 maPolyPolygon.remove(nPoly); 58 } 59 else 60 { 61 maPolyPolygon.setB2DPolygon(nPoly, aCandidate); 62 } 63 64 bPolyPolyChanged = true; 65 } 66 } 67 68 return bPolyPolyChanged; 69 } 70 71 bool PolyPolygonEditor::SetSegmentsKind(SdrPathSegmentKind eKind, const std::set< sal_uInt16 >& rAbsPoints ) 72 { 73 bool bPolyPolyChanged = false; 74 75 std::set< sal_uInt16 >::const_reverse_iterator aIter;( rAbsPoints.rbegin() ); 76 for( aIter = rAbsPoints.rbegin(); aIter != rAbsPoints.rend(); aIter++ ) 77 { 78 sal_uInt32 nPolyNum, nPntNum; 79 80 if(PolyPolygonEditor::GetRelativePolyPoint(maPolyPolygon, (*aIter), nPolyNum, nPntNum)) 81 { 82 // do change at aNewPolyPolygon. Take a look at edge. 83 basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPolyNum)); 84 bool bCandidateChanged(false); 85 const sal_uInt32 nCount(aCandidate.count()); 86 87 if(nCount && (nPntNum + 1 < nCount || aCandidate.isClosed())) 88 { 89 // it's a valid edge, check control point usage 90 const sal_uInt32 nNextIndex((nPntNum + 1) % nCount); 91 const bool bContolUsed(aCandidate.areControlPointsUsed() 92 && (aCandidate.isNextControlPointUsed(nPntNum) || aCandidate.isPrevControlPointUsed(nNextIndex))); 93 94 if(bContolUsed) 95 { 96 if(SDRPATHSEGMENT_TOGGLE == eKind || SDRPATHSEGMENT_LINE == eKind) 97 { 98 // remove control 99 aCandidate.resetNextControlPoint(nPntNum); 100 aCandidate.resetPrevControlPoint(nNextIndex); 101 bCandidateChanged = true; 102 } 103 } 104 else 105 { 106 if(SDRPATHSEGMENT_TOGGLE == eKind || SDRPATHSEGMENT_CURVE == eKind) 107 { 108 // add control 109 const basegfx::B2DPoint aStart(aCandidate.getB2DPoint(nPntNum)); 110 const basegfx::B2DPoint aEnd(aCandidate.getB2DPoint(nNextIndex)); 111 112 aCandidate.setNextControlPoint(nPntNum, interpolate(aStart, aEnd, (1.0 / 3.0))); 113 aCandidate.setPrevControlPoint(nNextIndex, interpolate(aStart, aEnd, (2.0 / 3.0))); 114 bCandidateChanged = true; 115 } 116 } 117 118 if(bCandidateChanged) 119 { 120 maPolyPolygon.setB2DPolygon(nPolyNum, aCandidate); 121 bPolyPolyChanged = true; 122 } 123 } 124 } 125 } 126 127 return bPolyPolyChanged; 128 } 129 130 bool PolyPolygonEditor::SetPointsSmooth( basegfx::B2VectorContinuity eFlags, const std::set< sal_uInt16 >& rAbsPoints) 131 { 132 bool bPolyPolygonChanged(false); 133 134 std::set< sal_uInt16 >::const_reverse_iterator aIter;( rAbsPoints.rbegin() ); 135 for( aIter = rAbsPoints.rbegin(); aIter != rAbsPoints.rend(); aIter++ ) 136 { 137 sal_uInt32 nPolyNum, nPntNum; 138 139 if(PolyPolygonEditor::GetRelativePolyPoint(maPolyPolygon, (*aIter), nPolyNum, nPntNum)) 140 { 141 // do change at aNewPolyPolygon... 142 basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPolyNum)); 143 144 // set continuity in point, make sure there is a curve 145 bool bPolygonChanged(false); 146 bPolygonChanged = basegfx::tools::expandToCurveInPoint(aCandidate, nPntNum); 147 bPolygonChanged |= basegfx::tools::setContinuityInPoint(aCandidate, nPntNum, eFlags); 148 149 if(bPolygonChanged) 150 { 151 maPolyPolygon.setB2DPolygon(nPolyNum, aCandidate); 152 bPolyPolygonChanged = true; 153 } 154 } 155 } 156 157 return bPolyPolygonChanged; 158 } 159 160 bool PolyPolygonEditor::GetRelativePolyPoint( const basegfx::B2DPolyPolygon& rPoly, sal_uInt32 nAbsPnt, sal_uInt32& rPolyNum, sal_uInt32& rPointNum ) 161 { 162 const sal_uInt32 nPolyCount(rPoly.count()); 163 sal_uInt32 nPolyNum(0L); 164 165 while(nPolyNum < nPolyCount) 166 { 167 const sal_uInt32 nPointCount(rPoly.getB2DPolygon(nPolyNum).count()); 168 169 if(nAbsPnt < nPointCount) 170 { 171 rPolyNum = nPolyNum; 172 rPointNum = nAbsPnt; 173 174 return true; 175 } 176 else 177 { 178 nPolyNum++; 179 nAbsPnt -= nPointCount; 180 } 181 } 182 183 return false; 184 } 185 186 } // end of namespace sdr 187