1 /* 2 * Copyright 2001-2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers, mflerackers@androme.be 7 * Marcus Overhagen 8 */ 9 10 11 #include <AffineTransform.h> 12 #include <Polygon.h> 13 14 #include <stdlib.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 19 // Limit to avoid integer overflow when calculating the size to allocate 20 #define MAX_POINT_COUNT 10000000 21 22 23 BPolygon::BPolygon(const BPoint *ptArray, int32 numPoints) 24 : 25 fBounds(0.0, 0.0, 0.0, 0.0), 26 fCount(numPoints), 27 fPoints(NULL) 28 { 29 if (fCount) { 30 if (fCount > MAX_POINT_COUNT) 31 debugger("BPolygon::BPolygon too many points"); 32 33 // Note the use of memcpy here. The assumption is that an array of BPoints can 34 // be copied bit by bit and not use a copy constructor or an assignment 35 // operator. This breaks the containment of BPoint but will result in better 36 // performance. An example where the memcpy will fail would be if BPoint begins 37 // to do lazy copying through reference counting. By copying the bits, we will 38 // copy reference counting state which will not be relevant at the destination. 39 // Luckily, BPoint is a very simple class which isn't likely to change much. 40 // 41 // Similar use of memcpy appears later in this implementation also. 42 size_t size = fCount * sizeof(BPoint); 43 fPoints = (BPoint *)malloc(size); 44 if (!fPoints) { 45 fprintf(stderr, "BPolygon::BPolygon out of memory\n"); 46 fCount = 0; 47 return; 48 } 49 memcpy(fPoints, ptArray, size); 50 _ComputeBounds(); 51 } 52 } 53 54 55 BPolygon::BPolygon(const BPolygon *poly) 56 : 57 fBounds(0.0, 0.0, 0.0, 0.0), 58 fCount(0), 59 fPoints(NULL) 60 { 61 *this = *poly; 62 } 63 64 65 BPolygon::BPolygon() 66 : 67 fBounds(0.0, 0.0, 0.0, 0.0), 68 fCount(0), 69 fPoints(NULL) 70 { 71 } 72 73 74 BPolygon::~BPolygon() 75 { 76 free(fPoints); 77 } 78 79 80 BPolygon & 81 BPolygon::operator=(const BPolygon &from) 82 { 83 // Make sure we aren't trying to perform a "self assignment". 84 if (this != &from) { 85 free(fPoints); 86 fBounds = from.fBounds; 87 fCount = from.fCount; 88 if (fCount) { 89 if (fCount > MAX_POINT_COUNT) 90 debugger("BPolygon::operator= too many points"); 91 fPoints = (BPoint *)malloc(fCount * sizeof(BPoint)); 92 if (!fPoints) { 93 fprintf(stderr, "BPolygon::operator= out of memory\n"); 94 fCount = 0; 95 } else { 96 memcpy(fPoints, from.fPoints, fCount * sizeof(BPoint)); 97 } 98 } else { 99 fPoints = NULL; 100 } 101 } 102 return *this; 103 } 104 105 106 BRect 107 BPolygon::Frame() const 108 { 109 return fBounds; 110 } 111 112 113 void 114 BPolygon::AddPoints(const BPoint *ptArray, int32 numPoints) 115 { 116 if (numPoints < 0) 117 debugger("BPolygon::AddPoints negative points"); 118 if (numPoints > MAX_POINT_COUNT || (fCount + numPoints) > MAX_POINT_COUNT) 119 debugger("BPolygon::AddPoints too many points"); 120 121 if (numPoints > 0) { 122 BPoint *points = (BPoint *)realloc(fPoints, (fCount + numPoints) * sizeof(BPoint)); 123 if (!points) { 124 fprintf(stderr, "BPolygon::AddPoints out of memory\n"); 125 } else { 126 fPoints = points; 127 memcpy(fPoints + fCount, ptArray, numPoints * sizeof(BPoint)); 128 fCount += numPoints; 129 _ComputeBounds(); 130 } 131 } 132 } 133 134 135 int32 136 BPolygon::CountPoints() const 137 { 138 return fCount; 139 } 140 141 142 void 143 BPolygon::MapTo(BRect srcRect, BRect dstRect) 144 { 145 for (uint32 i = 0; i < fCount; i++) 146 _MapPoint(fPoints + i, srcRect, dstRect); 147 _MapRectangle(&fBounds, srcRect, dstRect); 148 } 149 150 151 void 152 BPolygon::PrintToStream () const 153 { 154 for (uint32 i = 0; i < fCount; i++) 155 fPoints[i].PrintToStream(); 156 } 157 158 159 void 160 BPolygon::Transform(const BAffineTransform& transform) 161 { 162 transform.Apply(fPoints, (int32)fCount); 163 _ComputeBounds(); 164 } 165 166 167 BPolygon& 168 BPolygon::TransformBySelf(const BAffineTransform& transform) 169 { 170 Transform(transform); 171 return *this; 172 } 173 174 175 BPolygon* 176 BPolygon::TransformByCopy(const BAffineTransform& transform) const 177 { 178 BPolygon* copy = new BPolygon(this); 179 copy->Transform(transform); 180 return copy; 181 } 182 183 184 void 185 BPolygon::_ComputeBounds() 186 { 187 if (fCount == 0) { 188 fBounds = BRect(0.0, 0.0, 0.0, 0.0); 189 return; 190 } 191 192 fBounds = BRect(fPoints[0], fPoints[0]); 193 194 for (uint32 i = 1; i < fCount; i++) { 195 if (fPoints[i].x < fBounds.left) 196 fBounds.left = fPoints[i].x; 197 if (fPoints[i].y < fBounds.top) 198 fBounds.top = fPoints[i].y; 199 if (fPoints[i].x > fBounds.right) 200 fBounds.right = fPoints[i].x; 201 if (fPoints[i].y > fBounds.bottom) 202 fBounds.bottom = fPoints[i].y; 203 } 204 } 205 206 207 void 208 BPolygon::_MapPoint(BPoint *point, BRect srcRect, BRect dstRect) 209 { 210 point->x = (point->x - srcRect.left) * dstRect.Width() / srcRect.Width() 211 + dstRect.left; 212 point->y = (point->y - srcRect.top) * dstRect.Height() / srcRect.Height() 213 + dstRect.top; 214 } 215 216 217 void 218 BPolygon::_MapRectangle(BRect *rect, BRect srcRect, BRect dstRect) 219 { 220 BPoint leftTop = rect->LeftTop(); 221 BPoint bottomRight = rect->RightBottom(); 222 223 _MapPoint(&leftTop, srcRect, dstRect); 224 _MapPoint(&bottomRight, srcRect, dstRect); 225 226 *rect = BRect(leftTop, bottomRight); 227 } 228