void QgsGrassEditDeleteVertex::mouseClick( QgsPoint & point, Qt::MouseButton button ) { double thresh = e->threshold(); switch ( button ) { case Qt::LeftButton: // Delete previously selected vertex if ( e->mSelectedLine > 0 ) { e->eraseDynamic(); e->eraseElement( e->mSelectedLine ); // Move vertex int type = e->mProvider->readLine( e->mPoints, e->mCats, e->mSelectedLine ); Vect_line_delete_point( e->mPoints, e->mSelectedPart ); if ( e->mPoints->n_points < 2 ) // delete line { e->mProvider->deleteLine( e->mSelectedLine ); // Check orphan records for ( int i = 0 ; i < e->mCats->n_cats; i++ ) { e->checkOrphan( e->mCats->field[i], e->mCats->cat[i] ); } } else { e->mProvider->rewriteLine( e->mSelectedLine, type, e->mPoints, e->mCats ); } e->updateSymb(); e->displayUpdated(); e->mSelectedLine = 0; Vect_reset_line( e->mEditPoints ); e->setCanvasPrompt( tr( "Select vertex" ), "", "" ); } else { // Select new/next line e->mSelectedLine = e->mProvider->findLine( point.x(), point.y(), GV_LINES, thresh ); if ( e->mSelectedLine ) // highlite { e->mProvider->readLine( e->mEditPoints, NULL, e->mSelectedLine ); e->displayElement( e->mSelectedLine, e->mSymb[QgsGrassEdit::SYMB_HIGHLIGHT], e->mSize ); double xl, yl; // nearest point on the line // Note first segment is 1! e->mSelectedPart = Vect_line_distance( e->mEditPoints, point.x(), point.y(), 0.0, 0, &xl, &yl, NULL, NULL, NULL, NULL ); double dist1 = Vect_points_distance( xl, yl, 0.0, e->mEditPoints->x[e->mSelectedPart-1], e->mEditPoints->y[e->mSelectedPart-1], 0.0, 0 ); double dist2 = Vect_points_distance( xl, yl, 0.0, e->mEditPoints->x[e->mSelectedPart], e->mEditPoints->y[e->mSelectedPart], 0.0, 0 ); if ( dist1 < dist2 ) e->mSelectedPart--; e->displayDynamic( e->mEditPoints->x[e->mSelectedPart], e->mEditPoints->y[e->mSelectedPart], QgsVertexMarker::ICON_BOX, e->mSize ); e->setCanvasPrompt( tr( "Delete vertex" ), "", tr( "Release vertex" ) ); } else { e->setCanvasPrompt( tr( "Select vertex" ), "", "" ); } } break; case Qt::RightButton: e->eraseDynamic(); e->displayElement( e->mSelectedLine, e->mSymb[e->mLineSymb[e->mSelectedLine]], e->mSize ); e->mSelectedLine = 0; Vect_reset_line( e->mEditPoints ); e->setCanvasPrompt( tr( "Select vertex" ), "", "" ); break; default: // ignore others break; } }
/* * This function generates parallel line (with loops, but not like the old ones). * It is not to be used directly for creating buffers. * + added elliptical buffers/par.lines support * * dalpha - direction of elliptical buffer major axis in degrees * da - distance along major axis * db: distance along minor (perp.) axis * side: side >= 0 - right side, side < 0 - left side * when (da == db) we have plain distances (old case) * round - 1 for round corners, 0 for sharp corners. (tol is used only if round == 1) */ static void parallel_line(struct line_pnts *Points, double da, double db, double dalpha, int side, int round, int caps, int looped, double tol, struct line_pnts *nPoints) { int i, j, res, np; double *x, *y; double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry; double vx1, vy1, wx1, wy1; double a0, b0, c0, a1, b1, c1; double phi1, phi2, delta_phi; double nsegments, angular_tol, angular_step; int inner_corner, turns360; G_debug(3, "parallel_line()"); if (looped && 0) { /* start point != end point */ return; } Vect_reset_line(nPoints); if (looped) { Vect_append_point(Points, Points->x[1], Points->y[1], Points->z[1]); } np = Points->n_points; x = Points->x; y = Points->y; if ((np == 0) || (np == 1)) return; if ((da == 0) || (db == 0)) { Vect_copy_xyz_to_pnts(nPoints, x, y, NULL, np); return; } side = (side >= 0) ? (1) : (-1); /* normalize variable */ dalpha *= PI / 180; /* convert dalpha from degrees to radians */ angular_tol = angular_tolerance(tol, da, db); for (i = 0; i < np - 1; i++) { /* save the old values */ a0 = a1; b0 = b1; c0 = c1; wx = vx; wy = vy; norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty); if ((tx == 0) && (ty == 0)) continue; elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy); nx = x[i] + vx; ny = y[i] + vy; mx = x[i + 1] + vx; my = y[i + 1] + vy; line_coefficients(nx, ny, mx, my, &a1, &b1, &c1); if (i == 0) { if (!looped) Vect_append_point(nPoints, nx, ny, 0); continue; } delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1], x[i] - x[i - 1]); if (delta_phi > PI) delta_phi -= 2 * PI; else if (delta_phi <= -PI) delta_phi += 2 * PI; /* now delta_phi is in [-pi;pi] */ turns360 = (fabs(fabs(delta_phi) - PI) < 1e-15); inner_corner = (side * delta_phi <= 0) && (!turns360); if ((turns360) && (!(caps && round))) { if (caps) { norm_vector(0, 0, vx, vy, &tx, &ty); elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty); } else { tx = 0; ty = 0; } Vect_append_point(nPoints, x[i] + wx + tx, y[i] + wy + ty, 0); Vect_append_point(nPoints, nx + tx, ny + ty, 0); /* nx == x[i] + vx, ny == y[i] + vy */ } else if ((!round) || inner_corner) { res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry); /* if (res == 0) { G_debug(4, "a0=%.18f, b0=%.18f, c0=%.18f, a1=%.18f, b1=%.18f, c1=%.18f", a0, b0, c0, a1, b1, c1); G_fatal_error("Two consequtive line segments are parallel, but not on one straight line! This should never happen."); return; } */ if (res == 1) { if (!round) Vect_append_point(nPoints, rx, ry, 0); else { /* d = dig_distance2_point_to_line(rx, ry, 0, x[i-1], y[i-1], 0, x[i], y[i], 0, 0, NULL, NULL, NULL, NULL, NULL); if ( */ Vect_append_point(nPoints, rx, ry, 0); } } } else { /* we should draw elliptical arc for outside corner */ /* inverse transforms */ elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1); elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1); phi1 = atan2(wy1, wx1); phi2 = atan2(vy1, vx1); delta_phi = side * (phi2 - phi1); /* make delta_phi in [0, 2pi] */ if (delta_phi < 0) delta_phi += 2 * PI; nsegments = (int)(delta_phi / angular_tol) + 1; angular_step = side * (delta_phi / nsegments); for (j = 0; j <= nsegments; j++) { elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx, &ty); Vect_append_point(nPoints, x[i] + tx, y[i] + ty, 0); phi1 += angular_step; } } if ((!looped) && (i == np - 2)) { Vect_append_point(nPoints, mx, my, 0); } } if (looped) { Vect_append_point(nPoints, nPoints->x[0], nPoints->y[0], nPoints->z[0]); } Vect_line_prune(nPoints); if (looped) { Vect_line_delete_point(Points, Points->n_points - 1); } }
/* Start from the first node on a polyline and walk to the other end, collecting the coordinates of each node en route. */ int walk_forward_and_pick_up_coords(struct Map_info *map, int start_line, int ltype, struct line_pnts *points, int *lines_visited, struct line_cats *Cats, int write_cats) { int cat_idx; int line, next_line, n1, n2; int type, node, next_node; struct line_pnts *pnts; struct line_cats *cats_tmp; G_debug(2, " walk_forward() start = %d", start_line); line = start_line; pnts = Vect_new_line_struct(); if (write_cats != NO_CATS) { cats_tmp = Vect_new_cats_struct(); } else { cats_tmp = NULL; } Vect_reset_line(points); /* Pick up first set of coordinates */ lines_visited[line] = 1; if (cats_tmp) type = Vect_read_line(map, pnts, Cats, line); else type = Vect_read_line(map, pnts, NULL, line); Vect_get_line_nodes(map, line, &n1, &n2); next_line = find_next_line(map, line, n1, ltype); if (next_line > 0) { /* continue at start node */ Vect_append_points(points, pnts, GV_BACKWARD); next_node = n1; } else { Vect_append_points(points, pnts, GV_FORWARD); next_line = find_next_line(map, line, n2, ltype); /* check end node */ if (next_line > 0) { next_node = n2; /* continue at end node */ } else { return 1; /* no other line */ } } /* While next line exist append coordinates */ line = next_line; node = next_node; while (line != 0 && line != start_line) { G_debug(2, " line = %d", line); type = Vect_read_line(map, pnts, cats_tmp, line); if (cats_tmp && write_cats == MULTI_CATS) { for (cat_idx = 0; cat_idx < cats_tmp->n_cats; cat_idx++) { Vect_cat_set(Cats, cats_tmp->field[cat_idx], cats_tmp->cat[cat_idx]); } } Vect_get_line_nodes(map, line, &n1, &n2); if (node == n1) { Vect_line_delete_point(pnts, 0); /* delete duplicate nodes */ Vect_append_points(points, pnts, GV_FORWARD); next_node = n2; } else { Vect_line_delete_point(pnts, pnts->n_points - 1); Vect_append_points(points, pnts, GV_BACKWARD); next_node = n1; } lines_visited[line] = 1; /* Find next one */ next_line = find_next_line(map, line, next_node, ltype); line = next_line; node = next_node; } if (cats_tmp) Vect_destroy_cats_struct(cats_tmp); return 1; }