# 15.1.151. tablet_qt/graphics/geometry.cpp¶

```/*
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

This file is part of CamCOPS.

CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#include "geometry.h"
#include <QtMath>
#include "maths/mathfunc.h"
using mathfunc::mod;

namespace geometry
{

const qreal DEG_0 = 0.0;
const qreal DEG_90 = 90.0;
const qreal DEG_270 = 270.0;
const qreal DEG_180 = 180.0;
const qreal DEG_360 = 360.0;

int sixteenthsOfADegree(const qreal degrees)
{
// http://doc.qt.io/qt-5/qpainter.html#drawPie
return qRound(degrees * 16.0);
}

{
}

bool headingNearlyEq(const qreal heading_deg, const qreal value_deg)
{
}

qreal second_bound_deg,
const bool inclusive)
{
// The values in degrees are taken as a COMPASS HEADING, i.e. increasing
// is clockwise. The valid sector is defined CLOCKWISE from the first bound
// to the second.
// First, we deal with "on the boundary" conditions:
if (heading_deg == first_bound_deg || heading_deg == second_bound_deg) {
return inclusive;
}
const bool range_increases = first_bound_deg < second_bound_deg;
qreal lower_bound;
qreal upper_bound;
if (range_increases) {
lower_bound = first_bound_deg;
upper_bound = second_bound_deg;
} else {
lower_bound = second_bound_deg;
upper_bound = first_bound_deg;
}
const bool within = lower_bound < heading_deg && heading_deg < upper_bound;
// Second bound is clockwise ("right") from first.
// If the second bound is numerically greater than the first, then
// we have a simple range that doesn't cross "North" (0 = 360),
// and the heading is in range if it's within the two. For example,
// if the range is (50, 70), then the heading is in range if
// 50 < x < 70. However, if the range decreases, we're crossing North,
// e.g. (350, 10); in that case, the heading is in range if and only if
// it is NOT true that 10 < x < 350.
return within == range_increases;
}

const qreal pseudo_north_deg,
const bool normalize)
{
// Example: pseudo_north_deg is 30;
// then 0 in true North is -30 in pseudo-North.
const qreal h = true_north_heading_deg - pseudo_north_deg;
return normalize ? normalizeHeading(h) : h;
}

const qreal pseudo_north_deg,
const bool normalize)
{
const qreal h = pseudo_north_heading_deg + pseudo_north_deg;
return normalize ? normalizeHeading(h) : h;
}

QPointF polarToCartesian(const qreal r, const qreal theta_deg)
{
// theta == 0 implies along the x axis in a positive direction (right).
return QPointF(r * qCos(theta_rad), r * qSin(theta_rad));
}

qreal distanceBetween(const QPointF& from, const QPointF& to)
{
const qreal dx = to.x() - from.x();
const qreal dy = to.y() - from.y();
// Pythagoras:
return qSqrt(qPow(dx, 2) + qPow(dy, 2));
}

qreal polarThetaToHeading(const qreal theta_deg, const qreal north_deg)
{
// Polar coordinates have theta 0 == East, and theta positive is
// clockwise (in Qt coordinates with y down).
// Compass headings have 0 == North, unless adjusted by
// north_deg (e.g. specifying north_deg = 90 makes the heading 0 when
// actually East), and positive clockwise.
// - The first step converts to "clockwise, up is 0":
const qreal true_north_heading = theta_deg + DEG_90;
}

const qreal north_deg,
const bool normalize)
{
// Polar coordinates have theta 0 == East, and theta positive is
// anticlockwise. Compass headings have 0 == North, unless adjusted by
// north_deg (e.g. specifying north_deg = 90 makes the heading 0 when
// actually East), and positive clockwise.
const qreal theta = true_north_heading - DEG_90;
return normalize ? normalizeHeading(theta) : theta;
}

qreal polarThetaDeg(const QPointF& from, const QPointF& to)
{
const qreal dx = to.x() - from.x();
const qreal dy = to.y() - from.y();
if (qFuzzyIsNull(dx) && qFuzzyIsNull(dy)) {
// Nonsensical; no movement.
return 0.0;
}
// The arctan function will give us 0 = East, the geometric form.
}

qreal polarThetaDeg(const QPointF& to)
{
return polarThetaDeg(QPointF(0, 0), to);
}

qreal headingDegrees(const QPointF& from, const QPointF& to, qreal north_deg)
{
// Returns a COMPASS HEADING (0 is North = up).
}

bool lineSegmentsIntersect(const QPointF& first_from, const QPointF& first_to,
const QPointF& second_from, const QPointF& second_to)
{
const LineSegment s1(first_from, first_to);
const LineSegment s2(second_from, second_to);
return s1.intersects(s2);
}

bool pointOnLineSegment(const QPointF& point,
const QPointF& line_start, const QPointF& line_end)
{
const LineSegment ls(line_start, line_end);
return ls.pointOn(point);
}

const qreal north_deg,
{
const QPointF distant_point = point + polarToCartesian(radius, theta);
return LineSegment(point, distant_point);
}

const QPointF& from, const QPointF& to,
const QPointF& point, const qreal heading_deg,
const qreal north_deg, const qreal radius)
{
if (from == to) {
return false;
}
const LineSegment from_to = LineSegment(from, to);
return from_to.intersects(ls_trajectory);
}

bool linePassesBelowPoint(const QPointF& from, const QPointF& to,
const QPointF& point)
{