Spinning Topp Logo BlackTopp Studios
inc
multishape.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 /*
41  -----------------------------------------------------------------------------
42  This source file is part of ogre-procedural
43 
44  For the latest info, see http://code.google.com/p/ogre-procedural/
45 
46  Copyright (c) 2010-2013 Michael Broutin
47 
48  Permission is hereby granted, free of charge, to any person obtaining a copy
49  of this software and associated documentation files (the "Software"), to deal
50  in the Software without restriction, including without limitation the rights
51  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52  copies of the Software, and to permit persons to whom the Software is
53  furnished to do so, subject to the following conditions:
54 
55  The above copyright notice and this permission notice shall be included in
56  all copies or substantial portions of the Software.
57 
58  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64  THE SOFTWARE.
65  -----------------------------------------------------------------------------
66  */
67 #ifndef _graphicsproceduralmultishape_cpp
68 #define _graphicsproceduralmultishape_cpp
69 
70 #include "Graphics/Procedural/multishape.h"
71 #include "Graphics/Procedural/shape.h"
72 
73 #include "Graphics/meshmanager.h"
74 
75 #include "MathTools/mathtools.h"
76 
77 #include "Ogre.h"
78 
79 namespace Mezzanine
80 {
81  namespace Graphics
82  {
83  namespace Procedural
84  {
86  { }
87 
89  { this->Shapes.push_back(ToAdd); }
90 
92  { this->Shapes.insert(this->Shapes.end(),ToAdd.begin(),ToAdd.end()); }
93 
95  { }
96 
97  ///////////////////////////////////////////////////////////////////////////////
98  // Utility
99 
100  Mesh* MultiShape::GenerateMesh(const String& Name, const String& Group)
101  {
102  Ogre::ManualObject* TempMan = new Ogre::ManualObject("TempMan");
103 
104  for( ShapeIterator It = this->Shapes.begin() ; It != this->Shapes.end() ; ++It )
105  {
106  TempMan->begin("BaseWhiteNoLighting",Ogre::RenderOperation::OT_LINE_STRIP);
107  (*It)._AppendToManualObject(TempMan);
108  TempMan->end();
109  }
110 
111  Mesh* NewMesh = MeshManager::GetSingletonPtr()->_WrapInternalMesh( TempMan->convertToMesh(Name,Group) );
112  delete TempMan;
113  return NewMesh;
114  }
115 
117  {
118  typedef std::multimap<Vector2,Vector2,Vector2LengthCompare> Vec2MultiMap;
119  typedef std::pair<Vector2,Vector2> Vec2Pair;
120 
121  Vec2MultiMap SegMap;
122  for( ConstLineSegmentIterator SegIt = Segments.begin() ; SegIt != Segments.end() ; ++SegIt )
123  {
124  SegMap.insert( Vec2Pair(SegIt->PointA,SegIt->PointB) );
125  SegMap.insert( Vec2Pair(SegIt->PointB,SegIt->PointA) );
126  }
127  while( !SegMap.empty() )
128  {
129  Vector2 headFirst = SegMap.begin()->first;
130  Vector2 headSecond = SegMap.begin()->second;
131 
132  Shape s;
133  s.AddPoint(headFirst).AddPoint(headSecond);
134 
135  Vec2MultiMap::iterator firstSeg = SegMap.begin();
136  std::pair<Vec2MultiMap::iterator,Vec2MultiMap::iterator> correspondants2 = SegMap.equal_range(headSecond);
137 
138  for( Vec2MultiMap::iterator Vec2It = correspondants2.first ; Vec2It != correspondants2.second ; )
139  {
140  Vec2MultiMap::iterator RemoveIt = ++Vec2It;
141  if( ( RemoveIt->second - firstSeg->first ).SquaredLength() < 1e-8 )
142  SegMap.erase(RemoveIt);
143  }
144 
145  SegMap.erase(firstSeg);
146  Boole FoundSomething = true;
147  while( !SegMap.empty() && FoundSomething )
148  {
149  FoundSomething = false;
150  Vec2MultiMap::iterator next = SegMap.find(headSecond);
151  if( next != SegMap.end() ) {
152  FoundSomething = true;
153  headSecond = next->second;
154  s.AddPoint(headSecond);
155  std::pair<Vec2MultiMap::iterator, Vec2MultiMap::iterator> correspondants = SegMap.equal_range(headSecond);
156  for( Vec2MultiMap::iterator it = correspondants.first ; it != correspondants.second ; )
157  {
158  Vec2MultiMap::iterator RemoveIt = ++it;
159  if( ( RemoveIt->second - next->first ).SquaredLength() < 1e-8)
160  SegMap.erase(RemoveIt);
161  }
162  SegMap.erase(next);
163  }
164  Vec2MultiMap::iterator previous = SegMap.find(headFirst);
165  if( previous != SegMap.end() ) {
166  FoundSomething = true;
167  s.InsertPoint(0, previous->second);
168  headFirst = previous->second;
169  std::pair<Vec2MultiMap::iterator,Vec2MultiMap::iterator> correspondants = SegMap.equal_range(headFirst);
170  for( Vec2MultiMap::iterator it = correspondants.first ; it != correspondants.second ; )
171  {
172  Vec2MultiMap::iterator RemoveIt = ++it;
173  if( ( RemoveIt->second - previous->first ).SquaredLength() < 1e-8 )
174  SegMap.erase(RemoveIt);
175  }
176  SegMap.erase(previous);
177  }
178  }
179  if( s.GetPoint(0).SquaredDistance( s.GetPoint( s.GetSegCount() + 1 ) ) < 1e-6 ) {
180  s.GetPointsReference().pop_back();
181  s.Close();
182  }
183  this->AddShape(s);
184  }
185  }
186 
188  {
189  Point2DContainer Ret;
190  for( Whole Index = 0 ; Index < this->Shapes.size() ; Index++ )
191  {
192  Point2DContainer Points = this->Shapes[Index].GetPoints();
193  Ret.insert( Ret.end(), Points.begin(), Points.end() );
194  }
195  return Ret;
196  }
197 
199  {
200  // Draw a horizontal lines that goes through "point"
201  // Using the closest intersection, find whether the point is actually inside
202  Integer ClosestSegmentIndex = -1;
203  Real ClosestSegmentDistance = std::numeric_limits<Real>::max();
204  Vector2 ClosestSegmentIntersection;
205  const Shape* ClosestSegmentShape = 0;
206 
207  for( Whole ShapeIndex = 0 ; ShapeIndex < this->Shapes.size() ; ShapeIndex++ )
208  {
209  const Shape& CurrShape = this->Shapes[ShapeIndex];
210  for( Whole SegmentIndex = 0 ; SegmentIndex < CurrShape.GetSegCount() ; SegmentIndex++ )
211  {
212  Vector2 A = CurrShape.GetPoint(SegmentIndex);
213  Vector2 B = CurrShape.GetPoint(SegmentIndex + 1);
214  if( A.Y != B.Y && ( A.Y - Point.Y ) * ( B.Y - Point.Y ) <= 0.0 ) {
215  Vector2 Intersect( A.X + ( Point.Y - A.Y ) * ( B.X - A.X ) / ( B.Y - A.Y ), Point.Y );
216  Real Dist = MathTools::Abs( Point.X - Intersect.X );
217  if( Dist < ClosestSegmentDistance ) {
218  ClosestSegmentIndex = SegmentIndex;
219  ClosestSegmentDistance = Dist;
220  ClosestSegmentIntersection = Intersect;
221  ClosestSegmentShape = &CurrShape;
222  }
223  }
224  }
225  }
226  if( ClosestSegmentIndex != -1 ) {
227  Integer EdgePoint = -1;
228  if( ClosestSegmentIntersection.SquaredDistance( ClosestSegmentShape->GetPoint(ClosestSegmentIndex) ) < 1e-8 ) {
229  EdgePoint = ClosestSegmentIndex;
230  }else if( ClosestSegmentIntersection.SquaredDistance( ClosestSegmentShape->GetPoint(ClosestSegmentIndex + 1) ) < 1e-8) {
231  EdgePoint = ClosestSegmentIndex + 1;
232  }
233  if( EdgePoint > -1 ) {
234  Real Alpha1 = ( Point - ClosestSegmentShape->GetPoint(EdgePoint) ).AngleBetween( ClosestSegmentShape->GetDirectionAfter(EdgePoint) );
235  Real Alpha2 = ( Point - ClosestSegmentShape->GetPoint(EdgePoint) ).AngleBetween( -ClosestSegmentShape->GetDirectionBefore(EdgePoint) );
236  if( Alpha1 < Alpha2 ) {
237  ClosestSegmentIndex = EdgePoint;
238  }else{
239  ClosestSegmentIndex = EdgePoint - 1;
240  }
241  }
242  return ( ClosestSegmentShape->GetNormalAfter(ClosestSegmentIndex).X * ( Point.X - ClosestSegmentIntersection.X ) < 0 );
243  }
244  // We're in the case where the point is on the "real outside" of the multishape
245  // So, if the real outside == user defined outside, then the point is "user-defined outside"
246  return !this->IsOutsideRealOutside();
247  }
248 
250  {
251  Real X = std::numeric_limits<Real>::min();
252  Integer PointIndex = 0;
253  Integer ShapeIndex = 0;
254  for( Whole SIndex = 0 ; SIndex < this->Shapes.size() ; SIndex++ )
255  {
256  const Shape& CurrShape = this->Shapes[SIndex];
257  const std::vector<Vector2>& Points = CurrShape.GetPointsReference();
258  for( Whole PIndex = 0 ; PIndex < Points.size() ; PIndex++ )
259  {
260  if( X < Points[PIndex].X ) {
261  X = Points[PIndex].X;
262  PointIndex = PIndex;
263  ShapeIndex = SIndex;
264  }
265  }
266  }
267  Real Alpha1 = Vector2::Unit_Y().AngleTo( this->Shapes[ShapeIndex].GetDirectionAfter(PointIndex) );
268  Real Alpha2 = Vector2::Unit_Y().AngleTo( -this->Shapes[ShapeIndex].GetDirectionBefore(PointIndex) );
270  if( Alpha1 < Alpha2 ) {
271  Side = Procedural::SS_Right;
272  }else{
273  Side = Procedural::SS_Left;
274  }
275  return ( Side == this->Shapes[ShapeIndex].GetOutSide() );
276  }
277 
279  {
280  for( ShapeIterator It = this->Shapes.begin() ; It != this->Shapes.end(); ++It )
281  { It->Close(); }
282  return *this;
283  }
284 
286  {
287  for( ConstShapeIterator It = this->Shapes.begin() ; It != this->Shapes.end() ; ++It )
288  {
289  if( !It->IsClosed() )
290  return false;
291  }
292  return true;
293  }
294 
295  ///////////////////////////////////////////////////////////////////////////////
296  // Shape Management
297 
299  {
300  this->Shapes.push_back(ToAdd);
301  return *this;
302  }
303 
305  {
306  for( ConstShapeIterator it = Other.Shapes.begin() ; it != Other.Shapes.end() ; ++it )
307  { this->Shapes.push_back(*it); }
308  return *this;
309  }
310 
312  { return this->Shapes[Index]; }
313 
314  const Shape& MultiShape::GetShape(const Whole Index) const
315  { return this->Shapes[Index]; }
316 
318  { return this->Shapes.size(); }
319 
321  { this->Shapes.clear(); }
322  }//Procedural
323  }//Graphics
324 }//Mezzanine
325 
326 #endif
Boole IsOutsideRealOutside() const
Gets whether the currently set OutSide is the real Outside.
Definition: multishape.cpp:249
static Vector2 Unit_Y()
Gets a vector representing the Y unit of a Vector2.
Definition: vector2.cpp:87
ShapeContainer::iterator ShapeIterator
Iterator type for Shape instances being stored in this class.
Definition: multishape.h:93
Vector2 GetDirectionBefore(const Whole Index) const
Gets the direction from a point to the previous point in the sequence.
Definition: shape.cpp:784
Shape & AddPoint(const Vector2 &Point)
Adds a point to the shape.
Definition: shape.cpp:650
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
const Vector2 & GetPoint(const Integer Index) const
Gets a point by index which can be out of bounds and will wrap.
Definition: shape.cpp:694
Vector2 GetDirectionAfter(const Whole Index) const
Gets the direction of a point to the next point in the sequence.
Definition: shape.cpp:773
ShapeContainer Shapes
Container storing all of the Shapes that form this MultiShape.
Definition: multishape.h:105
Point2DContainer & GetPointsReference()
Gets raw vector data of this shape as a non-const reference.
Definition: shape.cpp:715
LineSegmentContainer::const_iterator ConstLineSegmentIterator
Const Iterator type for LineSegment2D instances being stored in this class.
Definition: multishape.h:101
MultiShape & AddShape(const Shape &ToAdd)
Adds a shape to this MultiShape.
Definition: multishape.cpp:298
This class is used to check and modify the properties of a graphics mesh.
Definition: mesh.h:63
int Integer
A datatype used to represent any integer close to.
Definition: datatypes.h:154
MultiShape & Close()
Closes each shape in this MultiShape.
Definition: multishape.cpp:278
Real AngleTo(const Vector2 &Other) const
Gets an oriented angle between this Vector2 and another Vector2.
Definition: vector2.cpp:288
Boole IsClosed() const
Gets whether or not every Shape in this MultiShape is closed.
Definition: multishape.cpp:285
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
Boole IsPointInside(const Vector2 &Point) const
Gets whether or not a point is inside this MultiShape.
Definition: multishape.cpp:198
ShapeSide
An enum used to express which side to work with in Shape operations.
std::vector< Vector2 > Point2DContainer
Basic container type for the storage of 2D points.
static MeshManager * GetSingletonPtr()
Fetches a pointer to the singleton.
Definition: singleton.h:97
Real Y
Coordinate on the Y vector.
Definition: vector2.h:69
Shape & Close()
Makes this a closed shape, connecting the last point to the first point.
Definition: shape.cpp:623
Real X
Coordinate on the X vector.
Definition: vector2.h:67
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
Whole GetSegCount() const
Gets the number of segments in this shape.
Definition: shape.cpp:472
Point2DContainer GetPoints() const
Gets a container of all the points in this MultiShape.
Definition: multishape.cpp:187
void BuildFromSegmentSoup(const LineSegmentContainer &Segments)
Creates this MultiShape from a listing of segments.
Definition: multishape.cpp:116
Real SquaredDistance(const Vector2 &Other) const
Gets the squared distance between this and another vector.
Definition: vector2.cpp:254
Mesh * GenerateMesh(const String &Name, const String &Group)
Outputs a mesh representing this MultiShape.
Definition: multishape.cpp:100
void RemoveAllShapes()
Removes all shapes from this MultiShape.
Definition: multishape.cpp:320
Whole GetNumShapes() const
Gets the number of shapes in this MultiShape.
Definition: multishape.cpp:317
std::vector< Shape > ShapeContainer
Basic container type for Shape storage in this class.
Definition: multishape.h:91
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
ShapeContainer::const_iterator ConstShapeIterator
Const Iterator type for Shape instances being stored in this class.
Definition: multishape.h:95
std::vector< LineSegment2D > LineSegmentContainer
Basic container type for LineSegment2D storage in this class.
Definition: multishape.h:97
MultiShape & AddMultiShape(const MultiShape &Other)
Append every shape of another MultiShape to this MultiShape.
Definition: multishape.cpp:304
A collection of interconnected 2D points used to express an arbitrary 2D shape.
Definition: shape.h:95
Vector2 GetNormalAfter(const Whole Index) const
Gets the normal of the segment after the specified point.
Definition: shape.cpp:800
Shape & GetShape(const Whole Index)
Gets a shape by index.
Definition: multishape.cpp:311
A grouping of individual 2D shapes used to express more elaborate shapes.
Definition: multishape.h:87
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
Shape & InsertPoint(const Whole Index, const Real X, const Real Y)
Inserts a point to the shape.
Definition: shape.cpp:682