Permalink
Browse files

Implementation of ConvexHull

  • Loading branch information...
1 parent 555859b commit 5fe47535b1f34befa857d9fa99076ab20eeb42a4 @andrewfb andrewfb committed Apr 16, 2013
@@ -0,0 +1,39 @@
+/*
+ Copyright (c) 2013, The Cinder Project (http://libcinder.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/Cinder.h"
+#include "cinder/PolyLine.h"
+#include "cinder/Shape2d.h"
+
+#include <vector>
+
+namespace cinder {
+
+PolyLine2f calcConvexHull( const std::vector<Vec2f> &points );
+PolyLine2f calcConvexHull( const Vec2f *points, size_t numPoints );
+PolyLine2f calcConvexHull( const Shape2d &shape );
+PolyLine2f calcConvexHull( const Path2d &path );
+PolyLine2f calcConvexHull( const PolyLine2f &polyLine );
+
+} // namespace cinder
@@ -103,6 +103,11 @@ class Path2d {
//! Returns whether the point \a pt is contained within the boundaries of the path
bool contains( const Vec2f &pt ) const;
+ static int calcQuadraticBezierMonotoneRegions( const Vec2f p[3], float resultT[2] );
+ static Vec2f calcQuadraticBezierPos( const Vec2f p[3], float t );
+ static int calcCubicBezierMonotoneRegions( const Vec2f p[4], float resultT[4] );
+ static Vec2f calcCubicBezierPos( const Vec2f p[4], float t );
+
friend class Shape2d;
friend std::ostream& operator<<( std::ostream &out, const Path2d &p );
private:
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2013, The Cinder Project (http://libcinder.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "ConvexHull.h"
+
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/geometries/polygon.hpp>
+
+
+namespace cinder {
+
+typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;
+
+namespace {
+
+template<typename T>
+PolyLine<Vec2<T> > toPolyLine( const polygon &p )
+{
+ PolyLine<Vec2<T> > result;
+
+ for( auto pt = p.outer().begin(); pt != p.outer().end(); ++pt )
+ result.push_back( Vec2<T>( boost::geometry::get<0>(*pt), boost::geometry::get<1>(*pt) ) );
+
+
+ return result;
+}
+
+boost::geometry::model::d2::point_xy<double> makePoint( const Vec2f &p )
+{
+ return boost::geometry::make<boost::geometry::model::d2::point_xy<double> >( p.x, p.y );
+}
+
+void includePathExtremeties( const Path2d &p, polygon *output )
+{
+ size_t firstPoint = 0;
+ for( size_t s = 0; s < p.getSegments().size(); ++s ) {
+ switch( p.getSegments()[s] ) {
+ case Path2d::CUBICTO: {
+ float monotoneT[4];
+ int monotoneCnt = Path2d::calcCubicBezierMonotoneRegions( &(p.getPoints()[firstPoint]), monotoneT );
+ for( int monotoneIdx = 0; monotoneIdx < monotoneCnt; ++monotoneIdx )
+ output->outer().push_back( makePoint( Path2d::calcCubicBezierPos( &(p.getPoints()[firstPoint]), monotoneT[monotoneIdx] ) ) );
+
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+0] ) );
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+1] ) );
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+2] ) );
+ }
+ break;
+ case Path2d::QUADTO: {
+ float monotoneT[2];
+ int monotoneCnt = Path2d::calcCubicBezierMonotoneRegions( &(p.getPoints()[firstPoint]), monotoneT );
+ for( int monotoneIdx = 0; monotoneIdx < monotoneCnt; ++monotoneIdx )
+ output->outer().push_back( makePoint( Path2d::calcQuadraticBezierPos( &(p.getPoints()[firstPoint]), monotoneT[monotoneIdx] ) ) );
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+0] ) );
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+1] ) );
+ }
+ break;
+ case Path2d::LINETO:
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+0] ) );
+ break;
+ case Path2d::CLOSE:
+ output->outer().push_back( makePoint( p.getPoints()[firstPoint+0] ) );
+ break;
+ default:
+ throw Path2dExc();
+ }
+
+ firstPoint += Path2d::sSegmentTypePointCounts[p.getSegments()[s]];
+ }
+}
+
+} // anonymous namespace
+
+PolyLine2f calcConvexHull( const std::vector<Vec2f> &points )
+{
+ return calcConvexHull( &points[0], points.size() );
+}
+
+PolyLine2f calcConvexHull( const Vec2f *points, size_t numPoints )
+{
+ polygon poly;
+ for( size_t p = 0; p < numPoints; ++p )
+ poly.outer().push_back( boost::geometry::make<boost::geometry::model::d2::point_xy<double> >( points[p].x, points[p].y ) );
+
+ polygon result;
+ boost::geometry::convex_hull( poly, result );
+
+ return toPolyLine<float>( result );
+}
+
+PolyLine2f calcConvexHull( const Shape2d &shape )
+{
+ polygon poly;
+ for( auto contourIt = shape.getContours().begin(); contourIt != shape.getContours().end(); ++contourIt )
+ includePathExtremeties( *contourIt, &poly );
+
+ polygon result;
+ boost::geometry::convex_hull( poly, result );
+
+ return toPolyLine<float>( result );
+}
+
+PolyLine2f calcConvexHull( const Path2d &path )
+{
+ polygon poly;
+ includePathExtremeties( path, &poly );
+
+ polygon result;
+ boost::geometry::convex_hull( poly, result );
+
+ return toPolyLine<float>( result );
+}
+
+PolyLine2f calcConvexHull( const PolyLine2f &polyLine )
+{
+ polygon poly;
+ for( auto ptIt = polyLine.begin(); ptIt != polyLine.end(); ++ptIt )
+ poly.outer().push_back( boost::geometry::make<boost::geometry::model::d2::point_xy<double> >( ptIt->x, ptIt->y ) );
+
+ polygon result;
+ boost::geometry::convex_hull( poly, result );
+
+ return toPolyLine<float>( result );
+}
+
+} // namespace cinder
View
@@ -631,8 +631,7 @@ Rectf Path2d::calcBoundingBox() const
}
// calcPreciseBoundingBox helper routines
-namespace {
-int calcQuadraticBezierMonotoneRegions( const Vec2f p[3], float resultT[2] )
+int Path2d::calcQuadraticBezierMonotoneRegions( const Vec2f p[3], float resultT[2] )
{
int resultIdx = 0;
float dx = p[0].x - 2 * p[1].x + p[2].x;
@@ -651,13 +650,13 @@ int calcQuadraticBezierMonotoneRegions( const Vec2f p[3], float resultT[2] )
return resultIdx;
}
-Vec2f calcQuadraticBezierPos( const Vec2f p[3], float t )
+Vec2f Path2d::calcQuadraticBezierPos( const Vec2f p[3], float t )
{
float nt = 1 - t;
return Vec2f( nt * nt * p[0].x + 2 * nt * t * p[1].x + t * t * p[2].x, nt * nt * p[0].y + 2 * nt * t * p[1].y + t * t * p[2].y );
}
-int calcCubicBezierMonotoneRegions( const Vec2f p[4], float resultT[4] )
+int Path2d::calcCubicBezierMonotoneRegions( const Vec2f p[4], float resultT[4] )
{
float Ax = -p[0].x + 3 * p[1].x - 3 * p[2].x + p[3].x;
float Bx = 3 * p[0].x - 6 * p[1].x + 3 * p[2].x;
@@ -687,7 +686,7 @@ int calcCubicBezierMonotoneRegions( const Vec2f p[4], float resultT[4] )
return resultIdx;
}
-Vec2f calcCubicBezierPos( const Vec2f p[4], float t )
+Vec2f Path2d::calcCubicBezierPos( const Vec2f p[4], float t )
{
float nt = 1 - t;
float w0 = nt * nt * nt;
@@ -697,8 +696,6 @@ Vec2f calcCubicBezierPos( const Vec2f p[4], float t )
return Vec2f( w0 * p[0].x + w1 * p[1].x + w2 * p[2].x + w3 * p[3].x, w0 * p[0].y + w1 * p[1].y + w2 * p[2].y + w3 * p[3].y );
}
-} // anonymous namespace
-
Rectf Path2d::calcPreciseBoundingBox() const
{
if( mPoints.empty() )
View
@@ -114,6 +114,7 @@
<ClCompile Include="..\src\cinder\Channel.cpp" />
<ClCompile Include="..\src\cinder\Clipboard.cpp" />
<ClCompile Include="..\src\cinder\Color.cpp" />
+ <ClCompile Include="..\src\cinder\ConvexHull.cpp" />
<ClCompile Include="..\src\cinder\DataSource.cpp" />
<ClCompile Include="..\src\cinder\DataTarget.cpp" />
<ClCompile Include="..\src\cinder\Display.cpp" />
@@ -287,6 +288,7 @@
<ClInclude Include="..\include\cinder\Easing.h" />
<ClInclude Include="..\include\cinder\CinderResources.h" />
<ClInclude Include="..\include\cinder\Color.h" />
+ <ClInclude Include="..\include\cinder\ConvexHull.h" />
<ClInclude Include="..\include\cinder\DataSource.h" />
<ClInclude Include="..\include\cinder\DataTarget.h" />
<ClInclude Include="..\include\cinder\Display.h" />
@@ -120,6 +120,9 @@
<ClCompile Include="..\src\cinder\Color.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\cinder\ConvexHull.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\src\cinder\DataSource.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -527,6 +530,9 @@
<ClInclude Include="..\include\cinder\Color.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\include\cinder\ConvexHull.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\include\cinder\DataSource.h">
<Filter>Header Files</Filter>
</ClInclude>
View
@@ -114,6 +114,7 @@
<ClCompile Include="..\src\cinder\Channel.cpp" />
<ClCompile Include="..\src\cinder\Clipboard.cpp" />
<ClCompile Include="..\src\cinder\Color.cpp" />
+ <ClCompile Include="..\src\cinder\ConvexHull.cpp" />
<ClCompile Include="..\src\cinder\DataSource.cpp" />
<ClCompile Include="..\src\cinder\DataTarget.cpp" />
<ClCompile Include="..\src\cinder\Display.cpp" />
@@ -287,6 +288,7 @@
<ClInclude Include="..\include\cinder\Easing.h" />
<ClInclude Include="..\include\cinder\CinderResources.h" />
<ClInclude Include="..\include\cinder\Color.h" />
+ <ClInclude Include="..\include\cinder\ConvexHull.h" />
<ClInclude Include="..\include\cinder\DataSource.h" />
<ClInclude Include="..\include\cinder\DataTarget.h" />
<ClInclude Include="..\include\cinder\Display.h" />
@@ -120,6 +120,9 @@
<ClCompile Include="..\src\cinder\Color.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\cinder\ConvexHull.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\src\cinder\DataSource.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -527,6 +530,9 @@
<ClInclude Include="..\include\cinder\Color.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\include\cinder\ConvexHull.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\include\cinder\DataSource.h">
<Filter>Header Files</Filter>
</ClInclude>
Oops, something went wrong.

1 comment on commit 5fe4753

@meshula

Nice :) For 3d, maybe TriMesh could get StanHull and JulioHull from here! http://codesuppository.blogspot.com/2012/06/raycast-mesh-bug-fixes.html

Please sign in to comment.