File size: 3,418 Bytes
985c397
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: BSD-3-Clause

// Arc.cpp

// Copyright 2011, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.

#include "Arc.h"
#include "Curve.h"

void CArc::SetDirWithPoint(const Point& p)
{
    double angs = atan2(m_s.y - m_c.y, m_s.x - m_c.x);
    double ange = atan2(m_e.y - m_c.y, m_e.x - m_c.x);
    double angp = atan2(p.y - m_c.y, p.x - m_c.x);
    if (ange < angs) {
        ange += 6.2831853071795864;
    }
    if (angp < angs - 0.0000000000001) {
        angp += 6.2831853071795864;
    }
    if (angp > ange + 0.0000000000001) {
        m_dir = false;
    }
    else {
        m_dir = true;
    }
}

double CArc::IncludedAngle() const
{
    double angs = atan2(m_s.y - m_c.y, m_s.x - m_c.x);
    double ange = atan2(m_e.y - m_c.y, m_e.x - m_c.x);
    if (m_dir) {
        // make sure ange > angs
        if (ange < angs) {
            ange += 6.2831853071795864;
        }
    }
    else {
        // make sure angs > ange
        if (angs < ange) {
            angs += 6.2831853071795864;
        }
    }

    return fabs(ange - angs);
}

bool CArc::AlmostALine() const
{
    Point mid_point = MidParam(0.5);
    if (Line(m_s, m_e - m_s).Dist(mid_point) <= Point::tolerance) {
        return true;
    }

    const double max_arc_radius = 1.0 / Point::tolerance;
    double radius = m_c.dist(m_s);
    if (radius > max_arc_radius) {
        return true;  // We don't want to produce an arc whose radius is too large.
    }

    return false;
}

Point CArc::MidParam(double param) const
{
    /// returns a point which is 0-1 along arc
    if (fabs(param) < 0.00000000000001) {
        return m_s;
    }
    if (fabs(param - 1.0) < 0.00000000000001) {
        return m_e;
    }

    Point p;
    Point v = m_s - m_c;
    v.Rotate(param * IncludedAngle());
    p = v + m_c;

    return p;
}

// segments - number of segments per full revolution!
// d_angle - determines the direction and the amount of the arc to draw
void CArc::GetSegments(void (*callbackfunc)(const double* p), double pixels_per_mm) const
{
    if (m_s == m_e) {
        return;
    }

    Point Va = m_s - m_c;
    Point Vb = m_e - m_c;

    double start_angle = atan2(Va.y, Va.x);
    double end_angle = atan2(Vb.y, Vb.x);

    if (m_dir) {
        if (start_angle > end_angle) {
            end_angle += 6.28318530717958;
        }
    }
    else {
        if (start_angle < end_angle) {
            end_angle -= 6.28318530717958;
        }
    }

    double radius = m_c.dist(m_s);
    double d_angle = end_angle - start_angle;
    int segments = (int)(fabs(pixels_per_mm * radius * d_angle / 6.28318530717958 + 1));

    double theta = d_angle / (double)segments;
    while (theta > 1.0) {
        segments *= 2;
        theta = d_angle / (double)segments;
    }
    double tangential_factor = tan(theta);
    double radial_factor = 1 - cos(theta);

    double x = radius * cos(start_angle);
    double y = radius * sin(start_angle);

    double pp[3] = {0.0, 0.0, 0.0};

    for (int i = 0; i < segments + 1; i++) {
        Point p = m_c + Point(x, y);
        pp[0] = p.x;
        pp[1] = p.y;
        (*callbackfunc)(pp);

        double tx = -y;
        double ty = x;

        x += tx * tangential_factor;
        y += ty * tangential_factor;

        double rx = -x;
        double ry = -y;

        x += rx * radial_factor;
        y += ry * radial_factor;
    }
}