inline std::tuple < distance_from_start_to_point<typename arithmetic_type_of<Polyline>::type> , distance_from_point_to_end<typename arithmetic_type_of<Polyline>::type> , polyline_segment_index > point_on_polyline_length_characteristics(const Polyline& P, const Point& p, const NumberComparisonPolicy& cmp) { using access = point_sequence_traits<Polyline>; using length_t = typename arithmetic_type_of<Polyline>::type; length_t length = constants::zero<length_t>(), postLength = constants::zero<length_t>(); std::size_t size = access::size(P), index = (std::numeric_limits<std::size_t>::max)(); for (std::size_t i = 0, j = 1; j < size; ++i, ++j) { auto A = access::get_point(P, i); auto B = access::get_point(P, j); if (index == (std::numeric_limits<std::size_t>::max)()) { if (!is_between(A, B, p, true, cmp)) length += point_point_distance(A, B); else { index = i; length += point_point_distance(A, p); postLength += point_point_distance(p, B); } } else postLength += point_point_distance(A, B); } return std::make_tuple(distance_from_start_to_point<length_t>(length), distance_from_point_to_end<length_t>(postLength), polyline_segment_index(index)); }
inline oriented_bounding_box<Point, Vector> make_obb(const rectangle<Point>& r) { auto uWidth = point_point_distance(r[1], r[0]); Vector u = construct<Vector>((r[1] - r[0]) / uWidth); auto vWidth = point_point_distance(r[3], r[0]); Vector v = construct<Vector>((r[3] - r[0]) / vWidth); uWidth *= 0.5; vWidth *= 0.5; return oriented_bounding_box<Point, Vector>(r[0] + uWidth * u + vWidth * v, u, v, uWidth, vWidth); }
static double computeDistance(bool isLeaf, BOX * box, Point * point) { double result = 0.0; if (isLeaf) { /* simple point to point distance */ result = point_point_distance(point, &box->low); } else if (point->x <= box->high.x && point->x >= box->low.x && point->y <= box->high.y && point->y >= box->low.y) { /* point inside the box */ result = 0.0; } else if (point->x <= box->high.x && point->x >= box->low.x) { /* point is over or below box */ ASSERT(box->low.y <= box->high.y); if (point->y > box->high.y) result = point->y - box->high.y; else if (point->y < box->low.y) result = box->low.y - point->y; else elog(ERROR, "inconsistent point values"); } else if (point->y <= box->high.y && point->y >= box->low.y) { /* point is to left or right of box */ ASSERT(box->low.x <= box->high.x); if (point->x > box->high.x) result = point->x - box->high.x; else if (point->x < box->low.x) result = box->low.x - point->x; else elog(ERROR, "inconsistent point values"); } else { /* closest point will be a vertex */ Point p; double subresult; result = point_point_distance(point, &box->low); subresult = point_point_distance(point, &box->high); if (result > subresult) result = subresult; p.x = box->low.x; p.y = box->high.y; subresult = point_point_distance(point, &p); if (result > subresult) result = subresult; p.x = box->high.x; p.y = box->low.y; subresult = point_point_distance(point, &p); if (result > subresult) result = subresult; } return result; }
// TODO: why another version? // point_line_dist float point_line_dist(BPoint start, BPoint end, BPoint p, float radius) { BRect r(min_c(start.x, end.x), min_c(start.y, end.y), max_c(start.x, end.x), max_c(start.y, end.y)); r.InsetBy(-radius, -radius); if (r.Contains(p)) { return fabs(agg::calc_line_point_distance(start.x, start.y, end.x, end.y, p.x, p.y)); } return min_c(point_point_distance(start, p), point_point_distance(end, p)); }
// point_line_distance double point_line_distance(BPoint point, BPoint pa, BPoint pb) { // first figure out if point is between segment start and end points double a = point_point_distance(point, pb); double b = point_point_distance(point, pa); double c = point_point_distance(pa, pb); float currentDist = min_c(a, b); if (a > 0.0 && b > 0.0) { double alpha = acos((b*b + c*c - a*a) / (2*b*c)); double beta = acos((a*a + c*c - b*b) / (2*a*c)); if (alpha <= M_PI_2 && beta <= M_PI_2) { currentDist = fabs(point_line_distance(pa.x, pa.y, pb.x, pb.y, point.x, point.y)); } } return currentDist; }
inline typename geometric_traits<typename point_sequence_traits<Polygon>::point_type>::arithmetic_type polygon_length(const Polygon& poly) { typedef point_sequence_traits<Polygon> access; typedef typename point_sequence_traits<Polygon>::point_type point_type; typedef typename geometric_traits<point_type>::arithmetic_type length_t; length_t length = constants::zero<length_t>(); std::size_t size = access::size(poly); for (std::size_t i = 0, j = 1; i < size; ++i, j = (j+1)%size) { length += point_point_distance(access::get_point(poly, i), access::get_point(poly, j)); } return length; }
// calc_angle double calc_angle(BPoint origin, BPoint from, BPoint to, bool degree) { double angle = 0.0; double d = point_line_distance(from.x, from.y, origin.x, origin.y, to.x, to.y); if (d != 0.0) { double a = point_point_distance(from, to); double b = point_point_distance(from, origin); double c = point_point_distance(to, origin); if (a > 0.0 && b > 0.0 && c > 0.0) { angle = acos((b*b + c*c - a*a) / (2.0*b*c)); if (d < 0.0) angle = -angle; if (degree) angle = angle * 180.0 / M_PI; } } return angle; }
// _SetModeForMousePos void PathManipulator::_SetModeForMousePos(BPoint where) { uint32 mode = UNDEFINED; int32 index = -1; float zoomLevel = fCanvasView->ZoomLevel(); // see if we're close enough at a control point BPoint point; BPoint pointIn; BPoint pointOut; for (int32 i = 0; fPath->GetPointsAt(i, point, pointIn, pointOut) && mode == UNDEFINED; i++) { float distM = point_point_distance(point, where) * zoomLevel; float distIn = point_point_distance(pointIn, where) * zoomLevel; float distOut = point_point_distance(pointOut, where) * zoomLevel; if (distM < MOVE_THRESHOLD) { if (i == 0 && fClickToClose && !fPath->IsClosed() && fPath->CountPoints() > 1) { mode = fCommandDown ? TOGGLE_SHARP : (fOptionDown ? REMOVE_POINT : CLOSE_PATH); index = i; } else { mode = fCommandDown ? TOGGLE_SHARP : (fOptionDown ? REMOVE_POINT : MOVE_POINT); index = i; } } if (distM - distIn > 0.00001 && distIn < MOVE_THRESHOLD) { mode = fCommandDown ? TOGGLE_SHARP_IN : (fOptionDown ? REMOVE_POINT_IN : MOVE_POINT_IN); index = i; } if (distIn - distOut > 0.00001 && distOut < distM && distOut < MOVE_THRESHOLD) { mode = fCommandDown ? TOGGLE_SHARP_OUT : (fOptionDown ? REMOVE_POINT_OUT : MOVE_POINT_OUT); index = i; } } // selection mode overrides any other mode, // but we need to check for it after we know // the index of the point under the mouse (code above) int32 pointCount = fPath->CountPoints(); if (fShiftDown && pointCount > 0) { mode = SELECT_POINTS; } // see if user wants to start new sub path if (fAltDown) { mode = NEW_PATH; index = -1; } // see if we're close enough at a line if (mode == UNDEFINED) { float distance; if (fPath->GetDistance(where, &distance, &index)) { if (distance < (INSERT_DIST_THRESHOLD / zoomLevel)) { mode = INSERT_POINT; } } else { // restore index, since it was changed by call above index = fCurrentPathPoint; } } // nope, still undefined mode, last fall back if (mode == UNDEFINED) { if (fFallBackMode == SELECT_POINTS) { if (fPath->IsClosed() && pointCount > 0) { mode = SELECT_POINTS; index = -1; } else { mode = ADD_POINT; index = pointCount - 1; } } else { // user had clicked "New Path" icon mode = fFallBackMode; } } // switch mode if necessary if (mode != fMode || index != fCurrentPathPoint) { // invalidate path display (to highlight the respective point) _InvalidateHighlightPoints(index, mode); _SetMode(mode); fCurrentPathPoint = index; } }
// _DragStateFor //! where is expected in canvas view coordinates DragState* TransformBox::_DragStateFor(BPoint where, float canvasZoom) { DragState* state = NULL; // convert to canvas zoom level // // the conversion is necessary, because the "hot regions" // around a point should be the same size no matter what // zoom level the canvas is displayed at float inset = INSET / canvasZoom; // priorities: // transformation center point has highest priority ?!? if (point_point_distance(where, fPivot) < inset) state = fOffsetCenterState; if (!state) { // next, the inner area of the box // for the following calculations // we can apply the inverse transformation to all points // this way we have to consider BRects only, not transformed polygons BPoint lt = fLeftTop; BPoint rb = fRightBottom; BPoint w = where; InverseTransform(&w); InverseTransform(<); InverseTransform(&rb); // next priority has the inside of the box BRect iR(lt, rb); float hInset = min_c(inset, max_c(0, (iR.Width() - inset) / 2.0)); float vInset = min_c(inset, max_c(0, (iR.Height() - inset) / 2.0)); iR.InsetBy(hInset, vInset); if (iR.Contains(w)) state = fTranslateState; } if (!state) { // next priority have the corners float dLT = point_point_distance(fLeftTop, where); float dRT = point_point_distance(fRightTop, where); float dLB = point_point_distance(fLeftBottom, where); float dRB = point_point_distance(fRightBottom, where); float d = min4(dLT, dRT, dLB, dRB); if (d < inset) { if (d == dLT) state = fDragLTState; else if (d == dRT) state = fDragRTState; else if (d == dLB) state = fDragLBState; else if (d == dRB) state = fDragRBState; } } if (!state) { // next priority have the sides float dL = point_line_dist(fLeftTop, fLeftBottom, where, inset); float dR = point_line_dist(fRightTop, fRightBottom, where, inset); float dT = point_line_dist(fLeftTop, fRightTop, where, inset); float dB = point_line_dist(fLeftBottom, fRightBottom, where, inset); float d = min4(dL, dR, dT, dB); if (d < inset) { if (d == dL) state = fDragLState; else if (d == dR) state = fDragRState; else if (d == dT) state = fDragTState; else if (d == dB) state = fDragBState; } } if (!state) { BPoint lt = fLeftTop; BPoint rb = fRightBottom; BPoint w = where; InverseTransform(&w); InverseTransform(<); InverseTransform(&rb); // check inside of the box again BRect iR(lt, rb); if (iR.Contains(w)) { state = fTranslateState; } else { // last priority has the rotate state state = fRotateState; } } return state; }