| 125 | |
| 126 | |
| 127 | void EditTool::setupAngleHelperFromEditedObjects() |
| 128 | { |
| 129 | constexpr auto max_num_primary_directions = std::size_t(5); |
| 130 | constexpr auto angle_window = (2 * M_PI) * 2 / 360.0; |
| 131 | // Amount of all path length which has to be covered by an angle |
| 132 | // to be classified as "primary angle" |
| 133 | constexpr auto path_angle_threshold = qreal(1 / 5.0); |
| 134 | |
| 135 | angle_helper->clearAngles(); |
| 136 | |
| 137 | std::unordered_set<qreal> primary_directions; |
| 138 | for (const Object* object : editedObjects()) |
| 139 | { |
| 140 | if (object->getType() == Object::Point) |
| 141 | { |
| 142 | primary_directions.insert(fmod_pos(object->asPoint()->getRotation(), M_PI / 2)); |
| 143 | } |
| 144 | else if (object->getType() == Object::Text) |
| 145 | { |
| 146 | primary_directions.insert(fmod_pos(object->asText()->getRotation(), M_PI / 2)); |
| 147 | } |
| 148 | else if (object->getType() == Object::Path) |
| 149 | { |
| 150 | const auto* path = object->asPath(); |
| 151 | // Maps angles to the path distance covered by them |
| 152 | std::map<qreal, qreal> path_directions; |
| 153 | |
| 154 | // Collect segment directions, only looking at the first part |
| 155 | auto& part = path->parts().front(); |
| 156 | auto path_length = part.path_coords.back().clen; |
| 157 | for (auto c = part.first_index; c < part.last_index; c = part.nextCoordIndex(c)) |
| 158 | { |
| 159 | if (!path->getCoordinate(c).isCurveStart()) |
| 160 | { |
| 161 | auto segment = MapCoordF(path->getCoordinate(c + 1) - path->getCoordinate(c)); |
| 162 | auto angle = fmod_pos(-segment.angle(), M_PI / 2); |
| 163 | auto length = segment.length(); |
| 164 | |
| 165 | auto angle_it = path_directions.find(angle); |
| 166 | if (angle_it != path_directions.end()) |
| 167 | angle_it->second += length; |
| 168 | else |
| 169 | path_directions.insert({angle, length}); |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | // Determine primary directions by moving a window over the collected angles |
| 174 | // and determining maxima. |
| 175 | // The iterators are the next angle which crosses the respective window border. |
| 176 | auto angle_start = -angle_window; |
| 177 | auto start_it = path_directions.begin(); |
| 178 | auto angle_end = qreal(0.0); |
| 179 | auto end_it = path_directions.begin(); |
| 180 | |
| 181 | auto length_increasing = true; |
| 182 | auto cur_length = qreal(0.0); |
| 183 | while (start_it != path_directions.end()) |
| 184 | { |
nothing calls this directly
no test coverage detected