src/layers/edittools.cpp

changeset 314
4642ba1218e8
parent 312
2637134bc37c
child 315
23b47902d857
equal deleted inserted replaced
313:c24d87f64bed 314:4642ba1218e8
82 } 82 }
83 83
84 void EditTools::mouseMoved(const QMouseEvent* event) 84 void EditTools::mouseMoved(const QMouseEvent* event)
85 { 85 {
86 this->worldPosition = this->renderer->screenToModelCoordinates(event->pos(), this->gridPlane); 86 this->worldPosition = this->renderer->screenToModelCoordinates(event->pos(), this->gridPlane);
87 this->localPosition = event->localPos();
87 if (this->worldPosition.has_value()) 88 if (this->worldPosition.has_value())
88 { 89 {
89 // Snap the position to grid. This procedure is basically the "change of basis" and almost follows the 90 // Snap the position to grid. This procedure is basically the "change of basis" and almost follows the
90 // A⁻¹ × M × A formula which is used to perform a transformation in some other coordinate system, except 91 // A⁻¹ × M × A formula which is used to perform a transformation in some other coordinate system, except
91 // we actually use the inverted matrix first and the regular one last to perform the transformation of 92 // we actually use the inverted matrix first and the regular one last to perform the transformation of
97 this->worldPosition = glm::round(*this->worldPosition); 98 this->worldPosition = glm::round(*this->worldPosition);
98 // And finally transform it back to grid coordinates by transforming it with the 99 // And finally transform it back to grid coordinates by transforming it with the
99 // grid matrix. 100 // grid matrix.
100 this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1}; 101 this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1};
101 this->polygon.back() = *this->worldPosition; 102 this->polygon.back() = *this->worldPosition;
102 } 103 this->numpoints = this->calcNumPoints();
103 this->numpoints = this->polygon.size();
104 if (this->isCloseToExistingPoints()) {
105 this->numpoints -= 1;
106 } 104 }
107 } 105 }
108 106
109 static QVector<QPointF> convertWorldPointsToScreenPoints( 107 static QVector<QPointF> convertWorldPointsToScreenPoints(
110 const std::vector<glm::vec3> &worldPoints, 108 const std::vector<glm::vec3> &worldPoints,
251 case CircleMode: 249 case CircleMode:
252 return circleModeActions(); 250 return circleModeActions();
253 } 251 }
254 } 252 }
255 253
254 constexpr QPointF vecToQPoint(const glm::vec2& a)
255 {
256 return {a.x, a.y};
257 }
258
256 void EditTools::renderPreview(QPainter* painter, const void* pensptr) 259 void EditTools::renderPreview(QPainter* painter, const void* pensptr)
257 { 260 {
258 const Pens& pens = *reinterpret_cast<const Pens*>(pensptr); 261 const Pens& pens = *reinterpret_cast<const Pens*>(pensptr);
259 painter->setPen(pens.polygonPen); 262 painter->setPen(pens.polygonPen);
260 for (const ModelAction& action : this->modelActions()) { 263 for (const ModelAction& action : this->modelActions()) {
276 painter->setBrush(pens.pointBrush); 279 painter->setBrush(pens.pointBrush);
277 painter->setPen(pens.pointPen); 280 painter->setPen(pens.pointPen);
278 for (const glm::vec3& point : this->polygon) { 281 for (const glm::vec3& point : this->polygon) {
279 drawWorldPoint(painter, point, this->renderer); 282 drawWorldPoint(painter, point, this->renderer);
280 } 283 }
284 if (this->mode == CircleMode and this->polygon.size() >= 2) {
285 const glm::vec3 circleOrigin = this->polygon[0];
286 const QPointF originScreen = this->renderer->modelToScreenCoordinates(circleOrigin);
287 const auto extremity = [this, &originScreen](const glm::vec3& p){
288 const QPointF s2 = this->renderer->modelToScreenCoordinates(p);
289 const auto intersection = rayRectangleIntersection(
290 rayFromPoints(toVec2(originScreen), toVec2(s2)),
291 this->renderer->rect());
292 if (intersection.has_value()) {
293 return intersection->position;
294 }
295 else {
296 return glm::vec2{s2.x(), s2.y()};
297 }
298 };
299 const glm::vec3 zvec = this->gridMatrix[2];
300 const glm::vec2 p1 = extremity(this->polygon[0] + zvec);
301 const glm::vec2 p2 = extremity(this->polygon[0] - zvec);
302 const glm::vec2 lateral = glm::normalize(glm::mat2{{0, 1}, {-1, 0}} * (p2 - p1));
303 painter->setPen(QPen{Qt::white, 3});
304 painter->drawLine(vecToQPoint(p1), vecToQPoint(p2));
305 constexpr float notchsize = 40.0f;
306 for (int a = -30; a <= 30; ++a) {
307 const glm::vec3 notch = this->polygon[0] + static_cast<float>(a) * zvec;
308 const QPointF s_notchcenter = this->renderer->modelToScreenCoordinates(notch);
309 const QPointF notch_s1 = s_notchcenter + notchsize * 0.5f * vecToQPoint(lateral);
310 const QPointF notch_s2 = s_notchcenter - notchsize * 0.5f * vecToQPoint(lateral);
311 painter->drawLine(notch_s1, notch_s2);
312 }
313 }
281 } 314 }
282 315
283 void EditTools::removeLastPoint() 316 void EditTools::removeLastPoint()
284 { 317 {
285 if (this->polygon.size() > 1) { 318 if (this->polygon.size() > 1) {
286 this->polygon.erase(this->polygon.end() - 2); 319 this->polygon.erase(this->polygon.end() - 2);
320 this->numpoints = this->calcNumPoints();
287 } 321 }
288 } 322 }
289 323
290 bool EditTools::isCloseToExistingPoints() const 324 bool EditTools::isCloseToExistingPoints() const
291 { 325 {
298 else { 332 else {
299 return false; 333 return false;
300 } 334 }
301 } 335 }
302 336
337 std::size_t EditTools::calcNumPoints() const
338 {
339 std::size_t result = this->polygon.size();
340 if (this->isCloseToExistingPoints()) {
341 result -= 1;
342 }
343 return result;
344 }
345
303 EditingMode EditTools::currentEditingMode() const 346 EditingMode EditTools::currentEditingMode() const
304 { 347 {
305 return this->mode; 348 return this->mode;
306 } 349 }
307 350
324 } 367 }
325 } 368 }
326 break; 369 break;
327 case CircleMode: 370 case CircleMode:
328 if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) { 371 if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) {
329 if (this->polygon.size() == 2) { 372 if (this->polygon.size() == 3) {
330 this->closeShape(); 373 this->closeShape();
331 } 374 }
332 else { 375 else {
333 this->polygon.push_back(*this->worldPosition); 376 this->polygon.push_back(*this->worldPosition);
334 } 377 }
404 447
405 448
406 const std::vector<ModelAction> EditTools::circleModeActions() const 449 const std::vector<ModelAction> EditTools::circleModeActions() const
407 { 450 {
408 std::vector<ModelAction> result; 451 std::vector<ModelAction> result;
409 if (this->numpoints == 2) { 452 if (this->numpoints == 3) {
410 const glm::vec3 x = polygon[1] - polygon[0]; 453 const glm::vec3 x = polygon[1] - polygon[0];
411 glm::mat4 transform{ 454 const opt<float> cyliheight = [&]() -> opt<float> {
412 glm::vec4{x, 0}, 455 const Plane plane{
413 this->gridMatrix[2], 456 .normal = glm::normalize(this->renderer->cameraVector(this->localPosition)),
414 glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0}, 457 .anchor = this->polygon[0],
415 glm::vec4{this->polygon[0], 1}, 458 };
416 }; 459 const opt<glm::vec3> p = this->renderer->screenToModelCoordinates(this->localPosition, plane);
417 Colored<CircularPrimitive> circ{ 460 if (p.has_value()) {
418 CircularPrimitive{ 461 const glm::vec3 heightvec = glm::normalize(glm::vec3{gridMatrix[2]});
419 .type = this->circleToolOptions.type, 462 return std::round(glm::dot(*p - polygon[0], heightvec));
420 .fraction = this->circleToolOptions.fraction, 463 }
421 .transformation = transform, 464 else {
422 }, 465 return {};
423 MAIN_COLOR 466 }
424 }; 467 }();
425 result.push_back(AppendToModel{.newElement = circ}); 468 if (cyliheight.has_value()) {
469 glm::mat4 transform{
470 glm::vec4{x, 0},
471 *cyliheight * this->gridMatrix[2],
472 glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0},
473 glm::vec4{this->polygon[0], 1},
474 };
475 Colored<CircularPrimitive> circ{
476 CircularPrimitive{
477 .type = this->circleToolOptions.type,
478 .fraction = this->circleToolOptions.fraction,
479 .transformation = transform,
480 },
481 MAIN_COLOR
482 };
483 result.push_back(AppendToModel{.newElement = circ});
484 }
426 } 485 }
427 return result; 486 return result;
428 } 487 }
429 488
430 const std::vector<ModelAction> EditTools::drawModeActions() const 489 const std::vector<ModelAction> EditTools::drawModeActions() const

mercurial