Skip to content

Commit 551bd40

Browse files
author
mhugent
committed
added a method for vertex moving which also works for muliring polygons. Add/delete vertex will follow soon (as well as similar methods for multiline and multipolygon)
git-svn-id: http://svn.osgeo.org/qgis/trunk@5245 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent a776fa5 commit 551bd40

File tree

2 files changed

+174
-183
lines changed

2 files changed

+174
-183
lines changed

src/core/qgsgeometry.cpp

Lines changed: 162 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -507,188 +507,43 @@ bool QgsGeometry::insertVertexBefore(double x, double y,
507507

508508
}
509509

510-
511-
bool QgsGeometry::moveVertexAt(double x, double y,
512-
int atVertex,
513-
const geos::CoordinateSequence* old_sequence,
514-
geos::CoordinateSequence** new_sequence)
515-
{
516-
int numPoints = old_sequence->getSize();
517-
518-
// Bounds checking
519-
if (
520-
(atVertex < 0) ||
521-
(atVertex >= numPoints)
522-
)
523-
{
524-
(*new_sequence) = 0;
525-
return FALSE;
526-
}
527-
528-
// Copy to the new sequence, including the moved vertex
529-
(*new_sequence) = new geos::DefaultCoordinateSequence();
530-
531-
for (int i = 0; i < numPoints; i++)
532-
{
533-
// Do we move the vertex here?
534-
if (atVertex == i)
535-
{
536-
(*new_sequence)->add( geos::Coordinate(x, y) );
537-
}
538-
else
539-
{
540-
(*new_sequence)->add( old_sequence->getAt(i) );
541-
}
542-
}
543-
// TODO: Check that the sequence is still simple, e.g. with geos::Geometry->isSimple()
544-
return true;
545-
}
546-
547-
548510
bool QgsGeometry::moveVertexAt(double x, double y,
549511
QgsGeometryVertexIndex atVertex)
550512
{
551-
552-
#ifdef QGISDEBUG
553-
std::cout << "QgsGeometry::moveVertexAt: Entered with "
554-
<< "x " << x << ", y " << y
555-
// << "beforeVertex " << beforeVertex << ", atRing " << atRing << ", atItem"
556-
// << " " << atItem
557-
<< "." << std::endl;
558-
#endif
559-
560513
exportWkbToGeos();
561-
562514
if (mGeos)
563515
{
564-
geos::CoordinateSequence* old_sequence = mGeos->getCoordinates();
565-
geos::CoordinateSequence* new_sequence;
566-
if(moveVertexAt(x, y, atVertex.back(), old_sequence, &new_sequence))
567-
{
568-
switch (mGeos->getGeometryTypeId())
569-
{
570-
case geos::GEOS_POINT:
571-
{
572-
delete new_sequence;
573-
return false;
574-
}
575-
case geos::GEOS_LINESTRING:
576-
{
577-
setGeos( static_cast<geos::Geometry*>( geosGeometryFactory->createLineString(new_sequence) ) );
578-
break;
579-
}
580-
case geos::GEOS_POLYGON:
581-
{
582-
//make sure the ring is closed if the first/last point is moved
583-
if(atVertex.back() == 0)
584-
{
585-
new_sequence->setAt(geos::Coordinate(x, y), new_sequence->getSize()-1);
586-
}
587-
else if(atVertex.back() == new_sequence->getSize()-1)
588-
{
589-
new_sequence->setAt(geos::Coordinate(x, y), 0);
590-
}
591-
#ifdef QGISDEBUG
592-
for(int i = 0; i < new_sequence->getSize(); ++i)
593-
{
594-
qWarning(QString::number(new_sequence->getAt(i).x)+"//"+QString::number(new_sequence->getAt(i).y));
595-
}
596-
#endif
597-
geos::LinearRing* theRing;
598-
try
599-
{
600-
theRing = geosGeometryFactory->createLinearRing(new_sequence);
601-
}
602-
catch(geos::IllegalArgumentException* e)
603-
{
604-
return false;
605-
}
606-
std::vector<geos::Geometry*>* holes = new std::vector<geos::Geometry*>(); //no holes
607-
setGeos(static_cast<geos::Geometry*>(geosGeometryFactory->createPolygon(theRing, holes)));
608-
break;
609-
}
610-
}
611-
delete old_sequence;
612-
mDirtyWkb = true;
613-
return true;
614-
}
615-
else
616-
{
617-
return false;
618-
}
619-
#if 0
620516
switch (mGeos->getGeometryTypeId())
621517
{
622-
case geos::GEOS_POINT: // a point
623-
{
624-
// Cannot move an arbitrary vertex to a point!
625-
return FALSE;
626-
627-
} // case geos::GEOS_POINT
628-
629-
case geos::GEOS_LINESTRING: // a linestring
630-
{
631-
// Get the embedded GEOS Coordinate Sequence
632-
geos::LineString* geosls = static_cast<geos::LineString*>(mGeos);
633-
const geos::CoordinateSequence* old_sequence = geosls->getCoordinatesRO();
634-
geos::CoordinateSequence* new_sequence;
635-
636-
if ( moveVertexAt(x, y, atVertex.back(), old_sequence, (&new_sequence) ) )
637-
{
638-
// Put in the new GEOS geometry
639-
setGeos( static_cast<geos::Geometry*>( geosGeometryFactory->createLineString(new_sequence) ) );
640-
mDirtyWkb = true;
641-
return TRUE;
642-
}
643-
else
644-
{
645-
return FALSE;
646-
}
647-
648-
} // case geos::GEOS_LINESTRING
649-
650-
case geos::GEOS_LINEARRING: // a linear ring (linestring with 1st point == last point)
651-
{
652-
// TODO
653-
break;
654-
} // case geos::GEOS_LINEARRING
655-
656-
case geos::GEOS_POLYGON: // a polygon
657-
{
658-
// TODO
659-
break;
660-
} // case geos::GEOS_POLYGON
661-
662-
case geos::GEOS_MULTIPOINT: // a collection of points
518+
case geos::GEOS_POINT:
663519
{
664-
// TODO
665-
break;
666-
} // case geos::GEOS_MULTIPOINT
667-
668-
case geos::GEOS_MULTILINESTRING: // a collection of linestrings
669-
{
670-
// TODO
671-
break;
672-
} // case geos::GEOS_MULTILINESTRING
673-
674-
case geos::GEOS_MULTIPOLYGON: // a collection of polygons
520+
return false;
521+
}
522+
case geos::GEOS_LINESTRING:
675523
{
676-
// TODO
677-
break;
678-
} // case geos::GEOS_MULTIPOLYGON
679-
680-
case geos::GEOS_GEOMETRYCOLLECTION: // a collection of heterogeneus geometries
524+
geos::CoordinateSequence* sequence = mGeos->getCoordinates();
525+
sequence->setAt(geos::Coordinate(x, y), atVertex.back());
526+
setGeos( static_cast<geos::Geometry*>( geosGeometryFactory->createLineString(sequence) ) );
527+
break;
528+
}
529+
case geos::GEOS_POLYGON:
681530
{
682-
// TODO
683-
break;
684-
} // case geos::GEOS_GEOMETRYCOLLECTION
685-
686-
} // switch (mGeos->getGeometryTypeId())
687-
#endif //0
688-
} // if (mGeos)
689-
690-
return FALSE;
691-
531+
if(moveVertexFromPolygon(atVertex.back(), x, y))
532+
{
533+
mDirtyWkb = true;
534+
return true;
535+
}
536+
else
537+
{
538+
return false;
539+
}
540+
}
541+
mDirtyWkb = true;
542+
return true;
543+
}
544+
}
545+
546+
return false;
692547
}
693548

694549

@@ -2225,4 +2080,140 @@ double QgsGeometry::distanceSquaredPointToSegment(QgsPoint& point,
22252080

22262081
}
22272082

2083+
bool QgsGeometry::moveVertexFromPolygon(int atVertex, double x, double y)
2084+
{
2085+
if(!mGeos)
2086+
{
2087+
return false;
2088+
}
22282089

2090+
geos::Polygon* originalpoly = dynamic_cast<geos::Polygon*>(mGeos);
2091+
if(!originalpoly)
2092+
{
2093+
return false;
2094+
}
2095+
2096+
geos::CoordinateSequence* coordinates = originalpoly->getCoordinates();
2097+
std::vector<int> rings(originalpoly->getNumInteriorRing() + 1); //a vector storing the number of points in each ring
2098+
//todo: consider that the point to be moved could be the starting point/ end point of a ring
2099+
const geos::LineString* outerRing = originalpoly->getExteriorRing();
2100+
int pointcounter = 0;
2101+
2102+
if(atVertex == 0 || atVertex == outerRing->getNumPoints()-1)
2103+
{
2104+
coordinates->setAt(geos::Coordinate(x, y), 0);
2105+
coordinates->setAt(geos::Coordinate(x, y), outerRing->getNumPoints()-1);
2106+
}
2107+
else if(atVertex < outerRing->getNumPoints())
2108+
{
2109+
coordinates->setAt(geos::Coordinate(x, y), atVertex);
2110+
}
2111+
rings[0] = outerRing->getNumPoints();
2112+
pointcounter += outerRing->getNumPoints();
2113+
2114+
for(int i = 0; i < originalpoly->getNumInteriorRing(); ++i)
2115+
{
2116+
const geos::LineString* innerRing = originalpoly->getInteriorRingN(i);
2117+
if(atVertex == pointcounter || atVertex== pointcounter + innerRing->getNumPoints()-1)
2118+
{
2119+
coordinates->setAt(geos::Coordinate(x, y), pointcounter);
2120+
coordinates->setAt(geos::Coordinate(x, y), pointcounter + innerRing->getNumPoints()-1);
2121+
}
2122+
else if(atVertex > pointcounter && atVertex < pointcounter + innerRing->getNumPoints()-1)
2123+
{
2124+
coordinates->setAt(geos::Coordinate(x, y), atVertex);
2125+
}
2126+
rings[i+1] = innerRing->getNumPoints();
2127+
pointcounter += innerRing->getNumPoints();
2128+
}
2129+
2130+
geos::Polygon* newPolygon = createPolygonFromCoordSequence(coordinates, rings);
2131+
delete coordinates;
2132+
if(newPolygon)
2133+
{
2134+
delete mGeos;
2135+
mGeos = newPolygon;
2136+
return true;
2137+
}
2138+
else
2139+
{
2140+
return false;
2141+
}
2142+
}
2143+
2144+
bool QgsGeometry::deleteVertexFromPolygon(int atVertex)
2145+
{
2146+
return false; //soon
2147+
}
2148+
2149+
bool QgsGeometry::insertVertexToPolygon(int beforeVertex, double x, double y)
2150+
{
2151+
return false; //soon
2152+
}
2153+
2154+
geos::Polygon* QgsGeometry::createPolygonFromCoordSequence(const geos::CoordinateSequence* coords, const std::vector<int>& pointsInRings) const
2155+
{
2156+
2157+
geos::CoordinateSequence* outerRingSequence = new geos::DefaultCoordinateSequence();
2158+
int pointcounter = 0;
2159+
for(int i = 0; i < pointsInRings[0]; ++i)
2160+
{
2161+
outerRingSequence->add(geos::Coordinate(coords->getAt(pointcounter)));
2162+
++pointcounter;
2163+
}
2164+
geos::LinearRing* newOuterRing = 0;
2165+
try
2166+
{
2167+
newOuterRing = geosGeometryFactory->createLinearRing(outerRingSequence);
2168+
}
2169+
catch(geos::IllegalArgumentException* e)
2170+
{
2171+
delete outerRingSequence;
2172+
return 0;
2173+
}
2174+
2175+
std::vector<geos::Geometry*>* newInnerRings = new std::vector<geos::Geometry*>(pointsInRings.size()-1);
2176+
2177+
for(int i = 0; i < pointsInRings.size()-1; ++i)
2178+
{
2179+
geos::CoordinateSequence* innerRingSequence = new geos::DefaultCoordinateSequence();
2180+
for(int j = 0; j < pointsInRings[i+1]; ++j)
2181+
{
2182+
innerRingSequence->add(geos::Coordinate(coords->getAt(pointcounter)));
2183+
++pointcounter;
2184+
}
2185+
geos::LinearRing* newInnerRing = 0;
2186+
try
2187+
{
2188+
newInnerRing = geosGeometryFactory->createLinearRing(innerRingSequence);
2189+
}
2190+
catch(geos::IllegalArgumentException* e)
2191+
{
2192+
delete outerRingSequence;
2193+
//also delete the already created rings
2194+
for(int j = 0; j < i; ++j)
2195+
{
2196+
delete (*newInnerRings)[i];
2197+
}
2198+
return 0;
2199+
}
2200+
(*newInnerRings)[i] = newInnerRing;
2201+
}
2202+
2203+
geos::Polygon* newPolygon = 0;
2204+
try
2205+
{
2206+
newPolygon = geosGeometryFactory->createPolygon(newOuterRing, newInnerRings);
2207+
}
2208+
catch(geos::IllegalArgumentException* e)
2209+
{
2210+
delete newOuterRing;
2211+
for(int i = 0; i < newInnerRings->size(); ++i)
2212+
{
2213+
delete (*newInnerRings)[i];
2214+
}
2215+
return 0;
2216+
}
2217+
2218+
return newPolygon;
2219+
}

src/core/qgsgeometry.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,6 @@ class QgsGeometry {
243243
const geos::CoordinateSequence* old_sequence,
244244
geos::CoordinateSequence** new_sequence);
245245

246-
/** Moves the vertex at the given vertex index (first number is index 0)
247-
* in the given GEOS Coordinate Sequence.
248-
* @param old_sequence The sequence to update (The caller remains the owner).
249-
* @param new_sequence The updated sequence (The caller becomes the owner if the function returns TRUE).
250-
* Returns FALSE if atVertex does not correspond to a valid vertex number
251-
* on the Coordinate Sequence.
252-
*/
253-
bool moveVertexAt(double x, double y,
254-
int atVertex,
255-
const geos::CoordinateSequence* old_sequence,
256-
geos::CoordinateSequence** new_sequence);
257-
258246
/** Removes the vertex at the given vertex index (first number is index 0)
259247
* in the given GEOS Coordinate Sequence.
260248
* @param old_sequence The sequence to update (The caller remains the owner).
@@ -270,6 +258,18 @@ class QgsGeometry {
270258
const geos::CoordinateSequence* old_sequence,
271259
geos::CoordinateSequence** new_sequence);
272260

261+
/**Moves a vertex of mGeos to a new position. Internally, a new polygon is created instead of mGeos.
262+
Returns true in case of success*/
263+
bool moveVertexFromPolygon(int atVertex, double x, double y);
264+
265+
bool deleteVertexFromPolygon(int atVertex);
266+
267+
bool insertVertexToPolygon(int beforeVertex, double x, double y);
268+
269+
/**Creates a new polygon from a coordinate sequence
270+
@param coords The coordinate array for the new polygon (the new polygon does not take ownership of the sequence
271+
@param pointsInRings A vector containing the number of points going into each ring*/
272+
geos::Polygon* createPolygonFromCoordSequence(const geos::CoordinateSequence* coords, const std::vector<int>& pointsInRings) const;
273273

274274
}; // class QgsGeometry
275275

0 commit comments

Comments
 (0)