72 arrowType = EricArrowType.NORMAL |
82 arrowType = EricArrowType.NORMAL |
73 arrowFilled = True |
83 arrowFilled = True |
74 elif assocType == AssociationType.GENERALISATION: |
84 elif assocType == AssociationType.GENERALISATION: |
75 arrowType = EricArrowType.WIDE |
85 arrowType = EricArrowType.WIDE |
76 arrowFilled = False |
86 arrowFilled = False |
77 |
87 |
78 EricArrowItem.__init__(self, QPointF(0, 0), QPointF(100, 100), |
88 EricArrowItem.__init__( |
79 arrowFilled, arrowType, colors, parent) |
89 self, |
80 |
90 QPointF(0, 0), |
|
91 QPointF(100, 100), |
|
92 arrowFilled, |
|
93 arrowType, |
|
94 colors, |
|
95 parent, |
|
96 ) |
|
97 |
81 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, False) |
98 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, False) |
82 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, False) |
99 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, False) |
83 |
100 |
84 if topToBottom: |
101 if topToBottom: |
85 self.calculateEndingPoints = ( |
102 self.calculateEndingPoints = self.__calculateEndingPoints_topToBottom |
86 self.__calculateEndingPoints_topToBottom |
|
87 ) |
|
88 else: |
103 else: |
89 #- self.calculateEndingPoints = self.__calculateEndingPoints_center |
104 # - self.calculateEndingPoints = self.__calculateEndingPoints_center |
90 self.calculateEndingPoints = self.__calculateEndingPoints_rectangle |
105 self.calculateEndingPoints = self.__calculateEndingPoints_rectangle |
91 |
106 |
92 self.itemA = itemA |
107 self.itemA = itemA |
93 self.itemB = itemB |
108 self.itemB = itemB |
94 self.assocType = assocType |
109 self.assocType = assocType |
95 self.topToBottom = topToBottom |
110 self.topToBottom = topToBottom |
96 |
111 |
97 self.regionA = AssociationPointRegion.NO_REGION |
112 self.regionA = AssociationPointRegion.NO_REGION |
98 self.regionB = AssociationPointRegion.NO_REGION |
113 self.regionB = AssociationPointRegion.NO_REGION |
99 |
114 |
100 self.calculateEndingPoints() |
115 self.calculateEndingPoints() |
101 |
116 |
102 self.itemA.addAssociation(self) |
117 self.itemA.addAssociation(self) |
103 self.itemB.addAssociation(self) |
118 self.itemB.addAssociation(self) |
104 |
119 |
105 def __mapRectFromItem(self, item): |
120 def __mapRectFromItem(self, item): |
106 """ |
121 """ |
107 Private method to map item's rectangle to this item's coordinate |
122 Private method to map item's rectangle to this item's coordinate |
108 system. |
123 system. |
109 |
124 |
110 @param item reference to the item to be mapped |
125 @param item reference to the item to be mapped |
111 @type QGraphicsRectItem |
126 @type QGraphicsRectItem |
112 @return item's rectangle in local coordinates |
127 @return item's rectangle in local coordinates |
113 @rtype QRectF |
128 @rtype QRectF |
114 """ |
129 """ |
115 rect = item.rect() |
130 rect = item.rect() |
116 tl = self.mapFromItem(item, rect.topLeft()) |
131 tl = self.mapFromItem(item, rect.topLeft()) |
117 return QRectF(tl.x(), tl.y(), rect.width(), rect.height()) |
132 return QRectF(tl.x(), tl.y(), rect.width(), rect.height()) |
118 |
133 |
119 def __calculateEndingPoints_topToBottom(self): |
134 def __calculateEndingPoints_topToBottom(self): |
120 """ |
135 """ |
121 Private method to calculate the ending points of the association item. |
136 Private method to calculate the ending points of the association item. |
122 |
137 |
123 The ending points are calculated from the top center of the lower item |
138 The ending points are calculated from the top center of the lower item |
124 to the bottom center of the upper item. |
139 to the bottom center of the upper item. |
125 """ |
140 """ |
126 if self.itemA is None or self.itemB is None: |
141 if self.itemA is None or self.itemB is None: |
127 return |
142 return |
128 |
143 |
129 self.prepareGeometryChange() |
144 self.prepareGeometryChange() |
130 |
145 |
131 rectA = self.__mapRectFromItem(self.itemA) |
146 rectA = self.__mapRectFromItem(self.itemA) |
132 rectB = self.__mapRectFromItem(self.itemB) |
147 rectB = self.__mapRectFromItem(self.itemB) |
133 midA = QPointF(rectA.x() + rectA.width() / 2.0, |
148 midA = QPointF( |
134 rectA.y() + rectA.height() / 2.0) |
149 rectA.x() + rectA.width() / 2.0, rectA.y() + rectA.height() / 2.0 |
135 midB = QPointF(rectB.x() + rectB.width() / 2.0, |
150 ) |
136 rectB.y() + rectB.height() / 2.0) |
151 midB = QPointF( |
|
152 rectB.x() + rectB.width() / 2.0, rectB.y() + rectB.height() / 2.0 |
|
153 ) |
137 if midA.y() > midB.y(): |
154 if midA.y() > midB.y(): |
138 startP = QPointF(rectA.x() + rectA.width() / 2.0, rectA.y()) |
155 startP = QPointF(rectA.x() + rectA.width() / 2.0, rectA.y()) |
139 endP = QPointF(rectB.x() + rectB.width() / 2.0, |
156 endP = QPointF(rectB.x() + rectB.width() / 2.0, rectB.y() + rectB.height()) |
140 rectB.y() + rectB.height()) |
|
141 else: |
157 else: |
142 startP = QPointF(rectA.x() + rectA.width() / 2.0, |
158 startP = QPointF( |
143 rectA.y() + rectA.height()) |
159 rectA.x() + rectA.width() / 2.0, rectA.y() + rectA.height() |
|
160 ) |
144 endP = QPointF(rectB.x() + rectB.width() / 2.0, rectB.y()) |
161 endP = QPointF(rectB.x() + rectB.width() / 2.0, rectB.y()) |
145 self.setPoints(startP.x(), startP.y(), endP.x(), endP.y()) |
162 self.setPoints(startP.x(), startP.y(), endP.x(), endP.y()) |
146 |
163 |
147 def __calculateEndingPoints_center(self): |
164 def __calculateEndingPoints_center(self): |
148 """ |
165 """ |
149 Private method to calculate the ending points of the association item. |
166 Private method to calculate the ending points of the association item. |
150 |
167 |
151 The ending points are calculated from the centers of the |
168 The ending points are calculated from the centers of the |
152 two associated items. |
169 two associated items. |
153 """ |
170 """ |
154 if self.itemA is None or self.itemB is None: |
171 if self.itemA is None or self.itemB is None: |
155 return |
172 return |
156 |
173 |
157 self.prepareGeometryChange() |
174 self.prepareGeometryChange() |
158 |
175 |
159 rectA = self.__mapRectFromItem(self.itemA) |
176 rectA = self.__mapRectFromItem(self.itemA) |
160 rectB = self.__mapRectFromItem(self.itemB) |
177 rectB = self.__mapRectFromItem(self.itemB) |
161 midA = QPointF(rectA.x() + rectA.width() / 2.0, |
178 midA = QPointF( |
162 rectA.y() + rectA.height() / 2.0) |
179 rectA.x() + rectA.width() / 2.0, rectA.y() + rectA.height() / 2.0 |
163 midB = QPointF(rectB.x() + rectB.width() / 2.0, |
180 ) |
164 rectB.y() + rectB.height() / 2.0) |
181 midB = QPointF( |
|
182 rectB.x() + rectB.width() / 2.0, rectB.y() + rectB.height() / 2.0 |
|
183 ) |
165 startP = self.__findRectIntersectionPoint(self.itemA, midA, midB) |
184 startP = self.__findRectIntersectionPoint(self.itemA, midA, midB) |
166 endP = self.__findRectIntersectionPoint(self.itemB, midB, midA) |
185 endP = self.__findRectIntersectionPoint(self.itemB, midB, midA) |
167 |
186 |
168 if ( |
187 if startP.x() != -1 and startP.y() != -1 and endP.x() != -1 and endP.y() != -1: |
169 startP.x() != -1 and |
188 # __IGNORE_WARNING_C111__ |
170 startP.y() != -1 and |
|
171 endP.x() != -1 and |
|
172 endP.y() != -1 |
|
173 ): |
|
174 self.setPoints(startP.x(), startP.y(), endP.x(), endP.y()) |
189 self.setPoints(startP.x(), startP.y(), endP.x(), endP.y()) |
175 |
190 |
176 def __calculateEndingPoints_rectangle(self): |
191 def __calculateEndingPoints_rectangle(self): |
177 r""" |
192 r""" |
178 Private method to calculate the ending points of the association item. |
193 Private method to calculate the ending points of the association item. |
179 |
194 |
180 The ending points are calculated by the following method. |
195 The ending points are calculated by the following method. |
181 |
196 |
182 For each item the diagram is divided in four Regions by its diagonals |
197 For each item the diagram is divided in four Regions by its diagonals |
183 as indicated below |
198 as indicated below |
184 <pre> |
199 <pre> |
185 +------------------------------+ |
200 +------------------------------+ |
186 | \ Region 2 / | |
201 | \ Region 2 / | |
195 | |--------| | |
210 | |--------| | |
196 | / \ | |
211 | / \ | |
197 | / Region 4 \ | |
212 | / Region 4 \ | |
198 +------------------------------+ |
213 +------------------------------+ |
199 </pre> |
214 </pre> |
200 |
215 |
201 Each diagonal is defined by two corners of the bounding rectangle. |
216 Each diagonal is defined by two corners of the bounding rectangle. |
202 |
217 |
203 To calculate the start point we have to find out in which |
218 To calculate the start point we have to find out in which |
204 region (defined by itemA's diagonals) is itemB's TopLeft corner |
219 region (defined by itemA's diagonals) is itemB's TopLeft corner |
205 (lets call it region M). After that the start point will be |
220 (lets call it region M). After that the start point will be |
206 the middle point of rectangle's side contained in region M. |
221 the middle point of rectangle's side contained in region M. |
207 |
222 |
208 To calculate the end point we repeat the above but in the opposite |
223 To calculate the end point we repeat the above but in the opposite |
209 direction (from itemB to itemA) |
224 direction (from itemB to itemA) |
210 """ |
225 """ |
211 if self.itemA is None or self.itemB is None: |
226 if self.itemA is None or self.itemB is None: |
212 return |
227 return |
213 |
228 |
214 self.prepareGeometryChange() |
229 self.prepareGeometryChange() |
215 |
230 |
216 rectA = self.__mapRectFromItem(self.itemA) |
231 rectA = self.__mapRectFromItem(self.itemA) |
217 rectB = self.__mapRectFromItem(self.itemB) |
232 rectB = self.__mapRectFromItem(self.itemB) |
218 |
233 |
219 xA = rectA.x() + rectA.width() / 2.0 |
234 xA = rectA.x() + rectA.width() / 2.0 |
220 yA = rectA.y() + rectA.height() / 2.0 |
235 yA = rectA.y() + rectA.height() / 2.0 |
221 xB = rectB.x() + rectB.width() / 2.0 |
236 xB = rectB.x() + rectB.width() / 2.0 |
222 yB = rectB.y() + rectB.height() / 2.0 |
237 yB = rectB.y() + rectB.height() / 2.0 |
223 |
238 |
224 # find itemA region |
239 # find itemA region |
225 rc = QRectF(xA, yA, rectA.width(), rectA.height()) |
240 rc = QRectF(xA, yA, rectA.width(), rectA.height()) |
226 self.regionA = self.__findPointRegion(rc, xB, yB) |
241 self.regionA = self.__findPointRegion(rc, xB, yB) |
227 # move some regions to the standard ones |
242 # move some regions to the standard ones |
228 if self.regionA == AssociationPointRegion.NORTH_WEST: |
243 if self.regionA == AssociationPointRegion.NORTH_WEST: |
231 self.regionA = AssociationPointRegion.EAST |
246 self.regionA = AssociationPointRegion.EAST |
232 elif self.regionA == AssociationPointRegion.SOUTH_EAST: |
247 elif self.regionA == AssociationPointRegion.SOUTH_EAST: |
233 self.regionA = AssociationPointRegion.SOUTH |
248 self.regionA = AssociationPointRegion.SOUTH |
234 elif self.regionA in ( |
249 elif self.regionA in ( |
235 AssociationPointRegion.SOUTH_WEST, |
250 AssociationPointRegion.SOUTH_WEST, |
236 AssociationPointRegion.CENTER |
251 AssociationPointRegion.CENTER, |
237 ): |
252 ): |
238 self.regionA = AssociationPointRegion.WEST |
253 self.regionA = AssociationPointRegion.WEST |
239 |
254 |
240 self.__updateEndPoint(self.regionA, True) |
255 self.__updateEndPoint(self.regionA, True) |
241 |
256 |
242 # now do the same for itemB |
257 # now do the same for itemB |
243 rc = QRectF(xB, yB, rectB.width(), rectB.height()) |
258 rc = QRectF(xB, yB, rectB.width(), rectB.height()) |
244 self.regionB = self.__findPointRegion(rc, xA, yA) |
259 self.regionB = self.__findPointRegion(rc, xA, yA) |
245 # move some regions to the standard ones |
260 # move some regions to the standard ones |
246 if self.regionB == AssociationPointRegion.NORTH_WEST: |
261 if self.regionB == AssociationPointRegion.NORTH_WEST: |
249 self.regionB = AssociationPointRegion.EAST |
264 self.regionB = AssociationPointRegion.EAST |
250 elif self.regionB == AssociationPointRegion.SOUTH_EAST: |
265 elif self.regionB == AssociationPointRegion.SOUTH_EAST: |
251 self.regionB = AssociationPointRegion.SOUTH |
266 self.regionB = AssociationPointRegion.SOUTH |
252 elif self.regionB in ( |
267 elif self.regionB in ( |
253 AssociationPointRegion.SOUTH_WEST, |
268 AssociationPointRegion.SOUTH_WEST, |
254 AssociationPointRegion.CENTER |
269 AssociationPointRegion.CENTER, |
255 ): |
270 ): |
256 self.regionB = AssociationPointRegion.WEST |
271 self.regionB = AssociationPointRegion.WEST |
257 |
272 |
258 self.__updateEndPoint(self.regionB, False) |
273 self.__updateEndPoint(self.regionB, False) |
259 |
274 |
260 def __findPointRegion(self, rect, posX, posY): |
275 def __findPointRegion(self, rect, posX, posY): |
261 """ |
276 """ |
262 Private method to find out, which region of rectangle rect contains |
277 Private method to find out, which region of rectangle rect contains |
263 the point (PosX, PosY) and returns the region number. |
278 the point (PosX, PosY) and returns the region number. |
264 |
279 |
265 @param rect rectangle to calculate the region for |
280 @param rect rectangle to calculate the region for |
266 @type QRectF |
281 @type QRectF |
267 @param posX x position of point |
282 @param posX x position of point |
268 @type float |
283 @type float |
269 @param posY y position of point |
284 @param posY y position of point |
286 y = rect.y() |
301 y = rect.y() |
287 slope2 = w / h |
302 slope2 = w / h |
288 slope1 = -slope2 |
303 slope1 = -slope2 |
289 b1 = x + w / 2.0 - y * slope1 |
304 b1 = x + w / 2.0 - y * slope1 |
290 b2 = x + w / 2.0 - y * slope2 |
305 b2 = x + w / 2.0 - y * slope2 |
291 |
306 |
292 eval1 = slope1 * posY + b1 |
307 eval1 = slope1 * posY + b1 |
293 eval2 = slope2 * posY + b2 |
308 eval2 = slope2 * posY + b2 |
294 |
309 |
295 result = AssociationPointRegion.NO_REGION |
310 result = AssociationPointRegion.NO_REGION |
296 |
311 |
297 # inside region 1 |
312 # inside region 1 |
298 if eval1 > posX and eval2 > posX: |
313 if eval1 > posX and eval2 > posX: |
299 result = AssociationPointRegion.WEST |
314 result = AssociationPointRegion.WEST |
300 |
315 |
301 #inside region 2 |
316 # inside region 2 |
302 elif eval1 > posX and eval2 < posX: |
317 elif eval1 > posX and eval2 < posX: |
303 result = AssociationPointRegion.NORTH |
318 result = AssociationPointRegion.NORTH |
304 |
319 |
305 # inside region 3 |
320 # inside region 3 |
306 elif eval1 < posX and eval2 < posX: |
321 elif eval1 < posX and eval2 < posX: |
307 result = AssociationPointRegion.EAST |
322 result = AssociationPointRegion.EAST |
308 |
323 |
309 # inside region 4 |
324 # inside region 4 |
310 elif eval1 < posX and eval2 > posX: |
325 elif eval1 < posX and eval2 > posX: |
311 result = AssociationPointRegion.SOUTH |
326 result = AssociationPointRegion.SOUTH |
312 |
327 |
313 # inside region 5 |
328 # inside region 5 |
314 elif eval1 == posX and eval2 < posX: |
329 elif eval1 == posX and eval2 < posX: |
315 result = AssociationPointRegion.NORTH_WEST |
330 result = AssociationPointRegion.NORTH_WEST |
316 |
331 |
317 # inside region 6 |
332 # inside region 6 |
318 elif eval1 < posX and eval2 == posX: |
333 elif eval1 < posX and eval2 == posX: |
319 result = AssociationPointRegion.NORTH_EAST |
334 result = AssociationPointRegion.NORTH_EAST |
320 |
335 |
321 # inside region 7 |
336 # inside region 7 |
322 elif eval1 == posX and eval2 > posX: |
337 elif eval1 == posX and eval2 > posX: |
323 result = AssociationPointRegion.SOUTH_EAST |
338 result = AssociationPointRegion.SOUTH_EAST |
324 |
339 |
325 # inside region 8 |
340 # inside region 8 |
326 elif eval1 > posX and eval2 == posX: |
341 elif eval1 > posX and eval2 == posX: |
327 result = AssociationPointRegion.SOUTH_WEST |
342 result = AssociationPointRegion.SOUTH_WEST |
328 |
343 |
329 # inside region 9 |
344 # inside region 9 |
330 elif eval1 == posX and eval2 == posX: |
345 elif eval1 == posX and eval2 == posX: |
331 result = AssociationPointRegion.CENTER |
346 result = AssociationPointRegion.CENTER |
332 |
347 |
333 return result |
348 return result |
334 |
349 |
335 def __updateEndPoint(self, region, isWidgetA): |
350 def __updateEndPoint(self, region, isWidgetA): |
336 """ |
351 """ |
337 Private method to update an endpoint. |
352 Private method to update an endpoint. |
338 |
353 |
339 @param region the region for the endpoint |
354 @param region the region for the endpoint |
340 @type AssociationPointRegion |
355 @type AssociationPointRegion |
341 @param isWidgetA flag indicating update for itemA is done |
356 @param isWidgetA flag indicating update for itemA is done |
342 @type bool |
357 @type bool |
343 """ |
358 """ |
344 if region == AssociationPointRegion.NO_REGION: |
359 if region == AssociationPointRegion.NO_REGION: |
345 return |
360 return |
346 |
361 |
347 rect = ( |
362 rect = ( |
348 self.__mapRectFromItem(self.itemA) |
363 self.__mapRectFromItem(self.itemA) |
349 if isWidgetA else |
364 if isWidgetA |
350 self.__mapRectFromItem(self.itemB) |
365 else self.__mapRectFromItem(self.itemB) |
351 ) |
366 ) |
352 x = rect.x() |
367 x = rect.x() |
353 y = rect.y() |
368 y = rect.y() |
354 ww = rect.width() |
369 ww = rect.width() |
355 wh = rect.height() |
370 wh = rect.height() |
356 ch = wh / 2.0 |
371 ch = wh / 2.0 |
357 cw = ww / 2.0 |
372 cw = ww / 2.0 |
358 |
373 |
359 if region == AssociationPointRegion.WEST: |
374 if region == AssociationPointRegion.WEST: |
360 px = x |
375 px = x |
361 py = y + ch |
376 py = y + ch |
362 elif region == AssociationPointRegion.NORTH: |
377 elif region == AssociationPointRegion.NORTH: |
363 px = x + cw |
378 px = x + cw |
364 py = y |
379 py = y |
365 elif region == AssociationPointRegion.EAST: |
380 elif region == AssociationPointRegion.EAST: |
366 px = x + ww |
381 px = x + ww |
367 py = y + ch |
382 py = y + ch |
368 elif region in ( |
383 elif region in (AssociationPointRegion.SOUTH, AssociationPointRegion.CENTER): |
369 AssociationPointRegion.SOUTH, |
|
370 AssociationPointRegion.CENTER |
|
371 ): |
|
372 px = x + cw |
384 px = x + cw |
373 py = y + wh |
385 py = y + wh |
374 |
386 |
375 if isWidgetA: |
387 if isWidgetA: |
376 self.setStartPoint(px, py) |
388 self.setStartPoint(px, py) |
377 else: |
389 else: |
378 self.setEndPoint(px, py) |
390 self.setEndPoint(px, py) |
379 |
391 |
380 def __findRectIntersectionPoint(self, item, p1, p2): |
392 def __findRectIntersectionPoint(self, item, p1, p2): |
381 """ |
393 """ |
382 Private method to find the intersection point of a line with a |
394 Private method to find the intersection point of a line with a |
383 rectangle. |
395 rectangle. |
384 |
396 |
385 @param item item to check against |
397 @param item item to check against |
386 @type UMLItem |
398 @type UMLItem |
387 @param p1 first point of the line |
399 @param p1 first point of the line |
388 @type QPointF |
400 @type QPointF |
389 @param p2 second point of the line |
401 @param p2 second point of the line |
394 rect = self.__mapRectFromItem(item) |
406 rect = self.__mapRectFromItem(item) |
395 lines = [ |
407 lines = [ |
396 QLineF(rect.topLeft(), rect.topRight()), |
408 QLineF(rect.topLeft(), rect.topRight()), |
397 QLineF(rect.topLeft(), rect.bottomLeft()), |
409 QLineF(rect.topLeft(), rect.bottomLeft()), |
398 QLineF(rect.bottomRight(), rect.bottomLeft()), |
410 QLineF(rect.bottomRight(), rect.bottomLeft()), |
399 QLineF(rect.bottomRight(), rect.topRight()) |
411 QLineF(rect.bottomRight(), rect.topRight()), |
400 ] |
412 ] |
401 intersectLine = QLineF(p1, p2) |
413 intersectLine = QLineF(p1, p2) |
402 intersectPoint = QPointF(0, 0) |
414 intersectPoint = QPointF(0, 0) |
403 for line in lines: |
415 for line in lines: |
404 if ( |
416 if ( |
405 intersectLine.intersect(line, intersectPoint) == |
417 intersectLine.intersect(line, intersectPoint) |
406 QLineF.IntersectType.BoundedIntersection |
418 == QLineF.IntersectType.BoundedIntersection |
407 ): |
419 ): |
408 return intersectPoint |
420 return intersectPoint |
409 return QPointF(-1.0, -1.0) |
421 return QPointF(-1.0, -1.0) |
410 |
422 |
411 def __findIntersection(self, p1, p2, p3, p4): |
423 def __findIntersection(self, p1, p2, p3, p4): |
412 """ |
424 """ |
413 Private method to calculate the intersection point of two lines. |
425 Private method to calculate the intersection point of two lines. |
414 |
426 |
415 The first line is determined by the points p1 and p2, the second |
427 The first line is determined by the points p1 and p2, the second |
416 line by p3 and p4. If the intersection point is not contained in |
428 line by p3 and p4. If the intersection point is not contained in |
417 the segment p1p2, then it returns (-1.0, -1.0). |
429 the segment p1p2, then it returns (-1.0, -1.0). |
418 |
430 |
419 For the function's internal calculations remember:<br /> |
431 For the function's internal calculations remember:<br /> |
420 QT coordinates start with the point (0,0) as the topleft corner |
432 QT coordinates start with the point (0,0) as the topleft corner |
421 and x-values increase from left to right and y-values increase |
433 and x-values increase from left to right and y-values increase |
422 from top to bottom; it means the visible area is quadrant I in |
434 from top to bottom; it means the visible area is quadrant I in |
423 the regular XY coordinate system |
435 the regular XY coordinate system |
424 |
436 |
425 <pre> |
437 <pre> |
426 Quadrant II | Quadrant I |
438 Quadrant II | Quadrant I |
427 -----------------|----------------- |
439 -----------------|----------------- |
428 Quadrant III | Quadrant IV |
440 Quadrant III | Quadrant IV |
429 </pre> |
441 </pre> |
430 |
442 |
431 In order for the linear function calculations to work in this method |
443 In order for the linear function calculations to work in this method |
432 we must switch x and y values (x values become y values and viceversa) |
444 we must switch x and y values (x values become y values and viceversa) |
433 |
445 |
434 @param p1 first point of first line |
446 @param p1 first point of first line |
435 @type QPointF |
447 @type QPointF |
436 @param p2 second point of first line |
448 @param p2 second point of first line |
437 @type QPointF |
449 @type QPointF |
438 @param p3 first point of second line |
450 @param p3 first point of second line |
508 else: |
520 else: |
509 if not (y3 <= pt.x() and pt.x() <= y4): |
521 if not (y3 <= pt.x() and pt.x() <= y4): |
510 pt.setX(-1.0) |
522 pt.setX(-1.0) |
511 pt.setY(-1.0) |
523 pt.setY(-1.0) |
512 return pt |
524 return pt |
513 |
525 |
514 if slope1 == slope2: |
526 if slope1 == slope2: |
515 pt.setX(-1.0) |
527 pt.setX(-1.0) |
516 pt.setY(-1.0) |
528 pt.setY(-1.0) |
517 return pt |
529 return pt |
518 |
530 |
519 pt.setY((b2 - b1) / (slope1 - slope2)) |
531 pt.setY((b2 - b1) / (slope1 - slope2)) |
520 pt.setX(slope1 * pt.y() + b1) |
532 pt.setX(slope1 * pt.y() + b1) |
521 # the intersection point must be inside the segment (x1, y1) (x2, y2) |
533 # the intersection point must be inside the segment (x1, y1) (x2, y2) |
522 if x2 >= x1 and y2 >= y1: |
534 if x2 >= x1 and y2 >= y1: |
523 if not ((x1 <= pt.y() and pt.y() <= x2) and |
535 if not ( |
524 (y1 <= pt.x() and pt.x() <= y2)): |
536 (x1 <= pt.y() and pt.y() <= x2) and (y1 <= pt.x() and pt.x() <= y2) |
|
537 ): |
525 pt.setX(-1.0) |
538 pt.setX(-1.0) |
526 pt.setY(-1.0) |
539 pt.setY(-1.0) |
527 elif x2 < x1 and y2 >= y1: |
540 elif x2 < x1 and y2 >= y1: |
528 if not ((x2 <= pt.y() and pt.y() <= x1) and |
541 if not ( |
529 (y1 <= pt.x() and pt.x() <= y2)): |
542 (x2 <= pt.y() and pt.y() <= x1) and (y1 <= pt.x() and pt.x() <= y2) |
|
543 ): |
530 pt.setX(-1.0) |
544 pt.setX(-1.0) |
531 pt.setY(-1.0) |
545 pt.setY(-1.0) |
532 elif x2 >= x1 and y2 < y1: |
546 elif x2 >= x1 and y2 < y1: |
533 if not ((x1 <= pt.y() and pt.y() <= x2) and |
547 if not ( |
534 (y2 <= pt.x() and pt.x() <= y1)): |
548 (x1 <= pt.y() and pt.y() <= x2) and (y2 <= pt.x() and pt.x() <= y1) |
|
549 ): |
535 pt.setX(-1.0) |
550 pt.setX(-1.0) |
536 pt.setY(-1.0) |
551 pt.setY(-1.0) |
537 else: |
552 else: |
538 if not ((x2 <= pt.y() and pt.y() <= x1) and |
553 if not ( |
539 (y2 <= pt.x() and pt.x() <= y1)): |
554 (x2 <= pt.y() and pt.y() <= x1) and (y2 <= pt.x() and pt.x() <= y1) |
|
555 ): |
540 pt.setX(-1.0) |
556 pt.setX(-1.0) |
541 pt.setY(-1.0) |
557 pt.setY(-1.0) |
542 |
558 |
543 return pt |
559 return pt |
544 |
560 |
545 def widgetMoved(self): |
561 def widgetMoved(self): |
546 """ |
562 """ |
547 Public method to recalculate the association after a widget was moved. |
563 Public method to recalculate the association after a widget was moved. |
548 """ |
564 """ |
549 self.calculateEndingPoints() |
565 self.calculateEndingPoints() |
550 |
566 |
551 def unassociate(self): |
567 def unassociate(self): |
552 """ |
568 """ |
553 Public method to unassociate from the widgets. |
569 Public method to unassociate from the widgets. |
554 """ |
570 """ |
555 self.itemA.removeAssociation(self) |
571 self.itemA.removeAssociation(self) |
556 self.itemB.removeAssociation(self) |
572 self.itemB.removeAssociation(self) |
557 |
573 |
558 @classmethod |
574 @classmethod |
559 def parseAssociationItemDataString(cls, data): |
575 def parseAssociationItemDataString(cls, data): |
560 """ |
576 """ |
561 Class method to parse the given persistence data. |
577 Class method to parse the given persistence data. |
562 |
578 |
563 @param data persisted data to be parsed |
579 @param data persisted data to be parsed |
564 @type str |
580 @type str |
565 @return tuple with the IDs of the source and destination items, |
581 @return tuple with the IDs of the source and destination items, |
566 the association type and a flag indicating to associate from top |
582 the association type and a flag indicating to associate from top |
567 to bottom |
583 to bottom |
580 dst = int(value) |
596 dst = int(value) |
581 elif key == "type": |
597 elif key == "type": |
582 assocType = AssociationType(int(value)) |
598 assocType = AssociationType(int(value)) |
583 elif key == "topToBottom": |
599 elif key == "topToBottom": |
584 topToBottom = Utilities.toBool(value) |
600 topToBottom = Utilities.toBool(value) |
585 |
601 |
586 return src, dst, assocType, topToBottom |
602 return src, dst, assocType, topToBottom |
587 |
603 |
588 def toDict(self): |
604 def toDict(self): |
589 """ |
605 """ |
590 Public method to collect data to be persisted. |
606 Public method to collect data to be persisted. |
591 |
607 |
592 @return dictionary containing data to be persisted |
608 @return dictionary containing data to be persisted |
593 @rtype dict |
609 @rtype dict |
594 """ |
610 """ |
595 return { |
611 return { |
596 "src": self.itemA.getId(), |
612 "src": self.itemA.getId(), |
597 "dst": self.itemB.getId(), |
613 "dst": self.itemB.getId(), |
598 "type": self.assocType.value, |
614 "type": self.assocType.value, |
599 "topToBottom": self.topToBottom, |
615 "topToBottom": self.topToBottom, |
600 } |
616 } |
601 |
617 |
602 @classmethod |
618 @classmethod |
603 def fromDict(cls, data, umlItems, colors=None): |
619 def fromDict(cls, data, umlItems, colors=None): |
604 """ |
620 """ |
605 Class method to create an association item from persisted data. |
621 Class method to create an association item from persisted data. |
606 |
622 |
607 @param data dictionary containing the persisted data as generated |
623 @param data dictionary containing the persisted data as generated |
608 by toDict() |
624 by toDict() |
609 @type dict |
625 @type dict |
610 @param umlItems list of UML items |
626 @param umlItems list of UML items |
611 @type list of UMLItem |
627 @type list of UMLItem |