void DrawPathTool::createPreviewCurve(MapCoord position, float direction) { if (!path_has_preview_point) { int last = preview_path->getCoordinateCount() - 1; (preview_path->getCoordinate(last)).setCurveStart(true); preview_path->addCoordinate(MapCoord(0, 0)); preview_path->addCoordinate(MapCoord(0, 0)); if (draw_dash_points) position.setDashPoint(true); position.setCurveStart(false); preview_path->addCoordinate(position); path_has_preview_point = true; } // Adjust the preview curve int last = preview_path->getCoordinateCount() - 1; MapCoord previous_point = preview_path->getCoordinate(last - 3); MapCoord last_point = preview_path->getCoordinate(last); double bezier_handle_distance = BEZIER_HANDLE_DISTANCE * previous_point.distanceTo(last_point); preview_path->setCoordinate(last - 2, MapCoord(previous_point.x() - bezier_handle_distance * sin(previous_point_direction), previous_point.y() - bezier_handle_distance * cos(previous_point_direction))); preview_path->setCoordinate(last - 1, MapCoord(last_point.x() + bezier_handle_distance * sin(direction), last_point.y() + bezier_handle_distance * cos(direction))); updatePreviewPath(); }
TestMap::TestMap() { MapCoord coord; map = new Map(); MapColor* black = new MapColor(); black->setCmyk(MapColorCmyk(0.0f, 0.0f, 0.0f, 1.0f)); black->setOpacity(1.0f); black->setName("black"); map->addColor(black, 0); line_symbol = new LineSymbol(); line_symbol->setLineWidth(1); line_symbol->setColor(black); map->addSymbol(line_symbol, 0); line_object = new PathObject(line_symbol); line_object->addCoordinate(MapCoord(10, 10)); coord = MapCoord(20, 10); coord.setCurveStart(true); line_object->addCoordinate(coord); line_object->addCoordinate(MapCoord(20, 20)); line_object->addCoordinate(MapCoord(30, 20)); line_object->addCoordinate(MapCoord(30, 10)); map->addObject(line_object); // TODO: fill map with more content as needed }
void TransformTest::testTransformTranslate() { MapCoord offset { 100.0, 100.0 }; QTransform qt; qt.translate(offset.x(), offset.y()); QVERIFY(qt.isTranslating()); QCOMPARE(int(qt.type()), int(QTransform::TxTranslate)); auto t = TemplateTransform::fromQTransform(qt); QCOMPARE(t.template_x, offset.nativeX()); QCOMPARE(t.template_y, offset.nativeY()); QCOMPARE(t.template_scale_x, 1.0); QCOMPARE(t.template_scale_y, 1.0); QCOMPARE(t.template_rotation, 0.0); }
void DrawPathTool::finishFollowing() { following = false; int last = preview_path->getCoordinateCount() - 1; if (last >= 3 && preview_path->getCoordinate(last - 3).isCurveStart()) { MapCoord first = preview_path->getCoordinate(last - 1); MapCoord second = preview_path->getCoordinate(last); previous_point_is_curve_point = true; previous_point_direction = -atan2(second.x() - first.x(), first.y() - second.y()); previous_pos_map = MapCoordF(second); previous_drag_map = MapCoordF(second.x() + (second.x() - first.x()) / 2, second.y() + (second.y() - first.y()) / 2); } else previous_point_is_curve_point = false; updateAngleHelper(); }
void DrawPathTool::closeDrawing() { Q_ASSERT(editingInProgress()); if (preview_path->getCoordinateCount() <= 1) return; if (previous_point_is_curve_point && preview_path->getCoordinate(0).isCurveStart()) { // Finish with a curve path_has_preview_point = false; if (dragging) previous_point_direction = -atan2(cur_pos_map.x() - click_pos_map.x(), click_pos_map.y() - cur_pos_map.y()); MapCoord first = preview_path->getCoordinate(0); MapCoord second = preview_path->getCoordinate(1); createPreviewCurve(first, -atan2(second.x() - first.x(), first.y() - second.y())); path_has_preview_point = false; } if (!preview_path->parts().empty()) preview_path->parts().front().setClosed(true, true); }
void EditPointTool::clickPress() { Q_ASSERT(!hover_state.testFlag(OverObjectNode) || !hover_state.testFlag(OverPathEdge) || hover_object); if (hover_state.testFlag(OverPathEdge) && active_modifiers & Qt::ControlModifier) { // Add new point to path PathObject* path = hover_object->asPath(); float distance_sq; PathCoord path_coord; path->calcClosestPointOnPath(cur_pos_map, distance_sq, path_coord); float click_tolerance_map_sq = cur_map_widget->getMapView()->pixelToLength(clickTolerance()); click_tolerance_map_sq = click_tolerance_map_sq * click_tolerance_map_sq; if (distance_sq <= click_tolerance_map_sq) { startEditing(); QScopedValueRollback<bool> no_effect_rollback(no_more_effect_on_click); no_more_effect_on_click = true; startDragging(); hover_state = OverObjectNode; hover_point = path->subdivide(path_coord); if (addDashPointDefault() ^ space_pressed) { MapCoord point = path->getCoordinate(hover_point); point.setDashPoint(true); path->setCoordinate(hover_point, point); map()->emitSelectionEdited(); } startEditingSetup(); updatePreviewObjects(); } } else if (hover_state.testFlag(OverObjectNode) && hover_object->getType() == Object::Path) { PathObject* hover_object = this->hover_object->asPath(); Q_ASSERT(hover_point < hover_object->getCoordinateCount()); if (space_pressed && !hover_object->isCurveHandle(hover_point)) { // Switch point between dash / normal point createReplaceUndoStep(hover_object); MapCoord& hover_coord = hover_object->getCoordinate(hover_point); hover_coord.setDashPoint(!hover_coord.isDashPoint()); hover_object->update(); updateDirtyRect(); no_more_effect_on_click = true; } else if (active_modifiers & Qt::ControlModifier) { auto hover_point_part_index = hover_object->findPartIndexForIndex(hover_point); PathPart& hover_point_part = hover_object->parts()[hover_point_part_index]; if (hover_object->isCurveHandle(hover_point)) { // Convert the curve into a straight line createReplaceUndoStep(hover_object); hover_object->deleteCoordinate(hover_point, false); hover_object->update(); map()->emitSelectionEdited(); updateHoverState(cur_pos_map); updateDirtyRect(); no_more_effect_on_click = true; } else { // Delete the point if (hover_point_part.countRegularNodes() <= 2 || ( !(hover_object->getSymbol()->getContainedTypes() & Symbol::Line) && hover_point_part.size() <= 3 ) ) { // Not enough remaining points -> delete the part and maybe object if (hover_object->parts().size() == 1) { map()->removeObjectFromSelection(hover_object, false); auto undo_step = new AddObjectsUndoStep(map()); auto part = map()->getCurrentPart(); int index = part->findObjectIndex(hover_object); Q_ASSERT(index >= 0); undo_step->addObject(index, hover_object); map()->deleteObject(hover_object, true); map()->push(undo_step); map()->setObjectsDirty(); map()->emitSelectionEdited(); updateHoverState(cur_pos_map); } else { createReplaceUndoStep(hover_object); hover_object->deletePart(hover_point_part_index); hover_object->update(); map()->emitSelectionEdited(); updateHoverState(cur_pos_map); updateDirtyRect(); } no_more_effect_on_click = true; } else { // Delete the point only createReplaceUndoStep(hover_object); int delete_bezier_spline_point_setting; if (active_modifiers & Qt::ShiftModifier) delete_bezier_spline_point_setting = Settings::EditTool_DeleteBezierPointActionAlternative; else delete_bezier_spline_point_setting = Settings::EditTool_DeleteBezierPointAction; hover_object->deleteCoordinate(hover_point, true, Settings::getInstance().getSettingCached((Settings::SettingsEnum)delete_bezier_spline_point_setting).toInt()); hover_object->update(); map()->emitSelectionEdited(); updateHoverState(cur_pos_map); updateDirtyRect(); no_more_effect_on_click = true; } } } } else if (hoveringOverSingleText()) { TextObject* hover_object = map()->getFirstSelectedObject()->asText(); startEditing(); // Don't show the original text while editing map()->removeRenderablesOfObject(hover_object, true); // Make sure that the TextObjectEditorHelper remembers the correct standard cursor cur_map_widget->setCursor(getCursor()); old_text = hover_object->getText(); old_horz_alignment = (int)hover_object->getHorizontalAlignment(); old_vert_alignment = (int)hover_object->getVerticalAlignment(); text_editor = new TextObjectEditorHelper(hover_object, editor); connect(text_editor, SIGNAL(selectionChanged(bool)), this, SLOT(textSelectionChanged(bool))); // Select clicked position int pos = hover_object->calcTextPositionAt(cur_pos_map, false); text_editor->setSelection(pos, pos); updatePreviewObjects(); } click_timer.restart(); }
void PointHandles::draw( QPainter* painter, const MapWidget* widget, const Object* object, MapCoordVector::size_type hover_point, bool draw_curve_handles, PointHandleState base_state ) const { if (object->getType() == Object::Point) { const PointObject* point = reinterpret_cast<const PointObject*>(object); draw(painter, widget->mapToViewport(point->getCoordF()), NormalHandle, (hover_point == 0) ? ActiveHandleState : base_state); } else if (object->getType() == Object::Text) { const TextObject* text = reinterpret_cast<const TextObject*>(object); std::vector<QPointF> text_handles(text->controlPoints()); for (std::size_t i = 0; i < text_handles.size(); ++i) draw(painter, widget->mapToViewport(text_handles[i]), NormalHandle, (hover_point == i) ? ActiveHandleState : base_state); } else if (object->getType() == Object::Path) { painter->setBrush(Qt::NoBrush); // for handle lines const PathObject* path = reinterpret_cast<const PathObject*>(object); for (const auto& part : path->parts()) { bool have_curve = part.isClosed() && part.size() > 3 && path->getCoordinate(part.last_index - 3).isCurveStart(); PointHandleType handle_type = NormalHandle; for (auto i = part.first_index; i <= part.last_index; ++i) { MapCoord coord = path->getCoordinate(i); if (coord.isClosePoint()) continue; QPointF point = widget->mapToViewport(coord); bool is_active = hover_point == i; if (i == part.first_index && !part.isClosed()) // || (i > part.start_index && path->getCoordinate(i-1).isHolePoint())) handle_type = StartHandle; else if (i == part.last_index && !part.isClosed()) // || coord.isHolePoint()) handle_type = EndHandle; else handle_type = coord.isDashPoint() ? DashHandle : NormalHandle; // Draw incoming curve handle QPointF curve_handle; if (draw_curve_handles && have_curve) { auto curve_index = (i == part.first_index) ? (part.last_index - 1) : (i - 1); curve_handle = widget->mapToViewport(path->getCoordinate(curve_index)); drawCurveHandleLine(painter, point, curve_handle, handle_type, is_active ? ActiveHandleState : base_state); draw(painter, curve_handle, CurveHandle, (is_active || hover_point == curve_index) ? ActiveHandleState : base_state); have_curve = false; } // Draw outgoing curve handle, first part if (draw_curve_handles && coord.isCurveStart()) { curve_handle = widget->mapToViewport(path->getCoordinate(i+1)); drawCurveHandleLine(painter, point, curve_handle,handle_type, is_active ? ActiveHandleState : base_state); } // Draw point draw(painter, point, handle_type, is_active ? ActiveHandleState : base_state); // Draw outgoing curve handle, second part if (coord.isCurveStart()) { if (draw_curve_handles) { draw(painter, curve_handle, CurveHandle, (is_active || hover_point == i + 1) ? ActiveHandleState : base_state); have_curve = true; } i += 2; } } } } else Q_ASSERT(false); }
bool DrawPathTool::mouseReleaseEvent(QMouseEvent* event, MapCoordF map_coord, MapWidget* widget) { if (!isDrawingButton(event->button())) return false; left_mouse_down = false; if (picking_angle) { picking_angle = false; picked_angle = pickAngle(map_coord, widget); return true; } else if (!editingInProgress()) { return false; } if (following) { finishFollowing(); if ((event->button() == Qt::RightButton) && drawOnRightClickEnabled()) finishDrawing(); return true; } if (!create_segment) return true; if (previous_point_is_curve_point && !dragging && !create_spline_corner) { // The new point has not been added yet MapCoord coord; if (shift_pressed) { coord = snap_helper->snapToObject(map_coord, widget); } else if (angle_helper->isActive()) { QPointF constrained_pos; angle_helper->getConstrainedCursorPositions(map_coord, constrained_pos_map, constrained_pos, widget); coord = MapCoord(constrained_pos_map); } else { coord = MapCoord(map_coord); } if (draw_dash_points) coord.setDashPoint(true); preview_path->addCoordinate(coord); updatePreviewPath(); updateDirtyRect(); } previous_point_is_curve_point = dragging; if (previous_point_is_curve_point) { QPointF constrained_pos; angle_helper->getConstrainedCursorPositions(map_coord, constrained_pos_map, constrained_pos, widget); previous_pos_map = click_pos_map; previous_drag_map = constrained_pos_map; previous_point_direction = calculateRotation(constrained_pos.toPoint(), constrained_pos_map); } updateAngleHelper(); create_spline_corner = false; path_has_preview_point = false; dragging = false; if ((event->button() == Qt::RightButton) && drawOnRightClickEnabled()) finishDrawing(); return true; }
/** * Removes flags from the coordinate to be able to use it in the reconstruction. */ static MapCoord resetCoordinate(MapCoord in) { in.setFlags(0); return in; }
/** * Compares a MapCoord and ClipperLib::IntPoint. */ bool operator==(const MapCoord& lhs, const ClipperLib::IntPoint& rhs) { return lhs.nativeX() == rhs.X && lhs.nativeY() == rhs.Y; }
bool DrawRectangleTool::mousePressEvent(QMouseEvent* event, MapCoordF map_coord, MapWidget* widget) { // Adjust flags to have possibly more recent state int modifiers = (event->modifiers() | (key_button_bar ? key_button_bar->activeModifiers() : 0)); ctrl_pressed = modifiers & Qt::ControlModifier; shift_pressed = modifiers & Qt::ShiftModifier; cur_map_widget = widget; if (isDrawingButton(event->button())) { dragging = false; click_pos = event->pos(); click_pos_map = map_coord; cur_pos = event->pos(); cur_pos_map = click_pos_map; if (shift_pressed) cur_pos_map = MapCoordF(snap_helper->snapToObject(cur_pos_map, widget)); constrained_pos_map = cur_pos_map; if (!editingInProgress()) { if (ctrl_pressed) { // Pick direction pickDirection(cur_pos_map, widget); } else { // Start drawing if (angle_helper->isActive()) angle_helper->setCenter(click_pos_map); startDrawing(); MapCoord coord = MapCoord(cur_pos_map); coord.setDashPoint(draw_dash_points); preview_path->addCoordinate(coord); preview_path->addCoordinate(coord); angles.push_back(0); updateStatusText(); } } else { if (angles.size() >= 2 && drawingParallelTo(angles[angles.size() - 2])) { // Drawing parallel to last section, just move the last point undoLastPoint(); } // Add new point int cur_point_index = angles.size(); if (!preview_path->getCoordinate(cur_point_index).isPositionEqualTo(preview_path->getCoordinate(cur_point_index - 1))) { MapCoord coord = MapCoord(cur_pos_map); coord.setDashPoint(draw_dash_points); preview_path->addCoordinate(coord); if (angles.size() == 1) { // Bring to correct number of points: line becomes a rectangle preview_path->addCoordinate(coord); } angles.push_back(0); angle_helper->setActive(true, MapCoordF(preview_path->getCoordinate(cur_point_index))); angle_helper->clearAngles(); angle_helper->addAngles(angles[0], M_PI/4); if (event->button() != Qt::RightButton || !drawOnRightClickEnabled()) { updateHover(false); updateHover(false); // Call it again, really. } } } } else if (event->button() == Qt::RightButton && editingInProgress()) { constrained_pos_map = MapCoordF(preview_path->getCoordinate(angles.size() - 1)); undoLastPoint(); if (editingInProgress()) // despite undoLastPoint() finishDrawing(); no_more_effect_on_click = true; } else { return false; } return true; }
void DrawRectangleTool::updateRectangle() { double angle = angle_helper->getConstrainedCursorPosMap(constrained_pos_map, constrained_pos_map); if (angles.size() == 1) { // Update vectors and angles forward_vector = constrained_pos_map - MapCoordF(preview_path->getCoordinate(0)); forward_vector.normalize(); angles.back() = -forward_vector.angle(); // Update rectangle MapCoord coord = MapCoord(constrained_pos_map); coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(1, coord); } else { // Update vectors and angles forward_vector = MapCoordF::fromPolar(1.0, -angle); angles.back() = angle; // Update rectangle auto cur_point_index = angles.size(); deleteClosePoint(); float forward_dist = MapCoordF::dotProduct(forward_vector, constrained_pos_map - MapCoordF(preview_path->getCoordinate(cur_point_index - 1))); MapCoord coord = preview_path->getCoordinate(cur_point_index - 1) + MapCoord(forward_dist * forward_vector); snapped_to_line = false; float best_snap_distance_sq = std::numeric_limits<float>::max(); if (ctrl_pressed && angles.size() > 2) { // Try to snap to existing lines MapCoord original_coord = coord; for (int i = 0; i < (int)angles.size() - 1; ++i) { MapCoordF direction(100, 0); direction.rotate(-angles[i]); int num_steps; double angle_step, angle_offset = 0; if (i == 0 || qAbs(qAbs(fmod_pos(angles[i], M_PI) - fmod_pos(angles[i-1], M_PI)) - (M_PI / 2)) < 0.1) { num_steps = 2; angle_step = M_PI/2; } else { num_steps = 4; angle_step = M_PI/4; } for (int k = 0; k < num_steps; ++k) { if (qAbs(fmod_pos(angle, M_PI) - fmod_pos(angles[i] - (angle_offset + k * angle_step), M_PI)) < 0.1) continue; MapCoordF rotated_direction = direction; rotated_direction.rotate(angle_offset + k * angle_step); QLineF a(QPointF(preview_path->getCoordinate(cur_point_index - 1)), MapCoordF(preview_path->getCoordinate(cur_point_index - 1)) + forward_vector); QLineF b(QPointF(preview_path->getCoordinate(i)), MapCoordF(preview_path->getCoordinate(i)) + rotated_direction); QPointF intersection_point; QLineF::IntersectType intersection_type = a.intersect(b, &intersection_point); if (intersection_type == QLineF::NoIntersection) continue; float snap_distance_sq = original_coord.distanceSquaredTo(MapCoord(intersection_point)); if (snap_distance_sq > best_snap_distance_sq) continue; best_snap_distance_sq = snap_distance_sq; coord = MapCoord(intersection_point); snapped_to_line_a = coord; snapped_to_line_b = coord + MapCoord(rotated_direction); snapped_to_line = true; } } } coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(cur_point_index, coord); auto close_vector = calculateClosingVector(); float close_dist = MapCoordF::dotProduct(close_vector, MapCoordF(preview_path->getCoordinate(0) - preview_path->getCoordinate(cur_point_index))); coord = preview_path->getCoordinate(cur_point_index) + MapCoord(close_dist * close_vector); coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(cur_point_index + 1, coord); preview_path->parts().front().setClosed(true, true); } updatePreviewPath(); updateDirtyRect(); }
void Template::setTemplatePosition(MapCoord coord) { transform.template_x = coord.nativeX(); transform.template_y = coord.nativeY(); updateTransformationMatrices(); }
#include <vector> #include "nuvieDefs.h" #include "DirFinder.h" #include "AStarPath.h" AStarPath::AStarPath() : final_node(0) {}void AStarPath::create_path() { astar_node *i = final_node; // iterator through steps, from back delete_path(); std::vector<astar_node *> reverse_list; while(i) { reverse_list.push_back(i); i = i->parent; } while(!reverse_list.empty()) { i = reverse_list.back(); add_step(i->loc); reverse_list.pop_back(); } set_path_size(step_count); }/* Get a new neighbor to nnode and score it, returning true if it's usable. */ bool AStarPath::score_to_neighbor(sint8 dir, astar_node *nnode, astar_node *neighbor, sint32 &nnode_to_neighbor) { sint8 sx = -1, sy = -1; DirFinder::get_adjacent_dir(sx, sy, dir); // sx,sy = neighbor -1,-1 + dir // get neighbor of nnode towards sx,sy, and cost to that neighbor neighbor->loc = nnode->loc.abs_coords(sx, sy); nnode_to_neighbor = step_cost(nnode->loc, neighbor->loc); if(nnode_to_neighbor == -1) { delete neighbor; // this neighbor is blocked return false; } return true; }/* Compare a node's score to the start node to already scored neighbors. */ bool AStarPath::compare_neighbors(astar_node *nnode, astar_node *neighbor, sint32 nnode_to_neighbor, astar_node *in_open, astar_node *in_closed) { neighbor->to_start = nnode->to_start + nnode_to_neighbor; // ignore this neighbor if already checked and closer to start if((in_open && in_open->to_start <= neighbor->to_start) || (in_closed && in_closed->to_start <= neighbor->to_start)) { delete neighbor; return false; } return true; }/* Check all neighbors of a node (location) and save them to the "seen" list. */ bool AStarPath::search_node_neighbors(astar_node *nnode, MapCoord &goal, const uint32 max_score) { for(uint32 dir = 1; dir < 8; dir += 2) { astar_node *neighbor = new astar_node; sint32 nnode_to_neighbor = -1; if(!score_to_neighbor(dir, nnode, neighbor, nnode_to_neighbor)) continue; // this neighbor is blocked astar_node *in_open = find_open_node(neighbor), *in_closed = find_closed_node(neighbor); if(!compare_neighbors(nnode, neighbor, nnode_to_neighbor, in_open, in_closed)) continue; neighbor->parent = nnode; neighbor->to_goal = path_cost_est(neighbor->loc, goal); neighbor->score = neighbor->to_start + neighbor->to_goal; neighbor->len = nnode->len + 1; if(neighbor->score > max_score) { delete neighbor; // too far away continue; } // take neighbor out of closed list and put into open list if(in_closed) remove_closed_node(in_closed); if(!in_open) push_open_node(neighbor); } return true; }/* Do A* search of tiles to create a path from `start' to `goal'. * Don't search past nodes with a score over the max. score. * Create a partial path to low-score nodes with a distance-to-start over the * max_steps count, defined here. Actor may perform another search when needed. * Returns true if a path is created */bool AStarPath::path_search(MapCoord &start, MapCoord &goal) {//DEBUG(0,LEVEL_DEBUGGING,"SEARCH: %d: %d,%d -> %d,%d\n",actor->get_actor_num(),start.x,start.y,goal.x,goal.y); astar_node *start_node = new astar_node; start_node->loc = start; start_node->to_start = 0; start_node->to_goal = path_cost_est(start, goal); start_node->score = start_node->to_start + start_node->to_goal; start_node->len = 0; push_open_node(start_node); const uint32 max_score = get_max_score(start_node->to_goal); const uint32 max_steps = 8*2*4; // walk up to four screen lengths before searching again while(!open_nodes.empty()) { astar_node *nnode = pop_open_node(); // next closest if(nnode->loc == goal || nnode->len >= max_steps) { if(nnode->loc != goal) DEBUG(0,LEVEL_DEBUGGING,"out of steps, making partial path (nnode->len=%d)\n",nnode->len); //DEBUG(0,LEVEL_DEBUGGING,"GOAL\n"); final_node = nnode; create_path(); delete_nodes(); return(true); // reached goal - success } // check cardinal neighbors (starting at top going clockwise) search_node_neighbors(nnode, goal, max_score); // node and neighbors checked, put into closed closed_nodes.push_back(nnode); } //DEBUG(0,LEVEL_DEBUGGING,"FAIL\n"); delete_nodes(); return(false); // out of open nodes - failure }/* Return the cost of moving one step from `c1' to `c2', which is always 1. This * isn't very helpful, so subclasses should provide their own function. * Returns -1 if c2 is blocked. */ sint32 AStarPath::step_cost(MapCoord &c1, MapCoord &c2) { if(!pf->check_loc(c2.x, c2.y, c2.z) || c2.distance(c1) > 1) return(-1); return(1); }/* Return an item in the list of closed nodes whose location matches `ncmp'.
QPointF MapView::mapToView(MapCoord coords) const { return QPointF(map_to_view.m11() * coords.x() + map_to_view.m12() * coords.y() + map_to_view.m13(), map_to_view.m21() * coords.x() + map_to_view.m22() * coords.y() + map_to_view.m23()); }