Categories
Fade2D Examples

Random Polygons, Surfaces and more – Example 9

When coding geometry, numerical errors and unexpected geometric settings occur frequently. Thus automated software testing with random geometric data is essential. But for example creating random polygons without self-intersection is not trivial at all. Therefore the module testDataGenerators is provided to create repeatable sequences of random geometric objects for software testing and debugging. These are for instance random surfaces, random polygons or random segments. Moreover deterministic generators for circles and polylines from sine functions exist.

Repeatability

What you most likely want is repeatable randomness so that you can later re-generate the data that crashed your software. For this reason, all random object generators take a seed value to statically initialize the internal random number generator. That means a specific seed value always results in the same sequence of objects. However, if the special seed value 0 is passed, the generated sequence will be different from call to call. Typically you will use a test loop like this:

for(int seed=1;seed<1000000;++seed)
{
	vector<...> vRandomObjects;
	generateRandom...(..,..,..,vRandomObjects,seed);
	bool bOK=mySoftware(vRandomObjects);
	if(!bOK)
	{
		cout<<"Error, seed="<<seed<<endl;
		exit(1);
	}
}

Random numbers

The code below creates two sequences of random numbers for seed=0, 1 and 2. As a result the sequences for seed=0 differ while the ones for non-zero seeds are reproducable.

size_t num(5);
double min(-100.0);
double max(100.0);

for(int seed=0;seed&lt;3;++seed)
{
	cout<<"seed "<<seed<<": "<<endl;
	vector<double> vRandomNumbers0;
	vector<double> vRandomNumbers1;
	generateRandomNumbers(num,min,max,vRandomNumbers0,seed);
	generateRandomNumbers(num,min,max,vRandomNumbers1,seed);

	for(size_t i=0;i<vRandomNumbers0.size();++i)
	{
		cout<<vRandomNumbers0[i]<<" ";
	}
	for(size_t i=0;i<vRandomNumbers1.size();++i)
	{
		cout<<vRandomNumbers1[i]<<" ";
	}
}

seed 0:
67.6368 -81.1831 24.9494 -74.8083 34.5807
67.9391 37.8979 74.0638 89.8681 -35.0061

seed 1:
68.0375 -21.1234 56.6198 59.688 82.3295
68.0375 -21.1234 56.6198 59.688 82.3295

seed 2:
40.1953 61.9353 -82.2409 -75.7042 -30.3386
40.1953 61.9353 -82.2409 -75.7042 -30.3386

Random polygons

Creating and visualizing a random simple polygon works similarly i.e., choose the number of segments, the min- and max-coordinates and you’re done:

Random Polygon
void randomPolygon()
{
	size_t num(50);
	double min(-100.0);
	double max(100.0);
	int seed(0); // seed=0 for real randomness

	vector<Segment2> vRandomPolygon;
	generateRandomPolygon(num,min,max,vRandomPolygon,seed);
	Visualizer2 vis("rndPolygon.ps");
	vis.addObject(vRandomPolygon,Color(CBLACK));
	vis.writeFile();
}

Random segments

The code below uses creates random segments.

Random Segments created by the test data generator
Random Segments
void randomSegments()
{
  size_t num(50);
  double min(-100.0);
  double max(100.0);
  double maxLen(50);
  int seed(0);// seed=0 for real randomness
 
  vector<Segment2> vRandomSegments;
  generateRandomSegments(num,min,max,maxLen,vRandomSegments,seed);
  Visualizer2 vis("rndSegments.ps");
  vis.addObject(vRandomSegments,Color(CBLACK));
  vis.writeFile();
}

Random points

Random points in a certain bounding box are created by the code below.

Radom Points created by the test data generator
Random Points
void randomPoints()
{
  size_t num(1000);
  double min(-100.0);
  double max(100.0);
  int seed(0); // seed=0 for real randomness
 
  vector<Point2> vRandomPoints;
  generateRandomPoints(num,min,max,vRandomPoints,seed);
  Visualizer2 vis("rndPoints.ps");
  vis.addObject(vRandomPoints,Color(CBLACK));
  vis.writeFile();
}

Circles

The generateCircle(…) command creates points on a given circle. In contrast to the above commands there is no randomness in this case. The code below creates two circles, one is scaled in x direction.

Circles
void circles()
{
  int numPoints(50);
  double centerX(0.0);
  double centerY(0.0);
  double radiusX(1.0);
  double radiusY(1.0);
  vector<Point2> vCirclePoints0;
  vector<Point2> vCirclePoints1;
  generateCircle(numPoints,centerX,centerY,radiusX,radiusY,vCirclePoints0);
  generateCircle(2*numPoints,centerX,centerY,2*radiusX,radiusY,vCirclePoints1);
 
  Visualizer2 vis("circles.ps");
  vis.addObject(vCirclePoints0,Color(CBLUE));
  vis.addObject(vCirclePoints1,Color(CGREEN));
  vis.writeFile();
}

Sine functions

The example below generates four curves. The base function is sin(x), but x and y can be swapped and independent offsets and scale factors can be applied for x- and y-direction.

Polylines from sine functions, test data generator
Polylines
void sineFunctions()
{
  int numSegments(50);
  int numPeriods(1);
  double xOffset(0);
  double yOffset(0);
  double xFactor(1.0);
  double yFactor(1.0);
  bool bSwapXY(false);
 
  vector<Segment2> vSineSegments0;
  vector<Segment2> vSineSegments1;
  vector<Segment2> vSineSegments2;
  vector<Segment2> vSineSegments3;
  generateSineSegments(numSegments,numPeriods,xOffset,yOffset,xFactor,yFactor,bSwapXY,vSineSegments0);
  generateSineSegments(numSegments,numPeriods,3.14159/2.0,yOffset,xFactor,yFactor,bSwapXY,vSineSegments1);
  generateSineSegments(numSegments,3,xOffset,yOffset,.33,yFactor,true,vSineSegments2);
  generateSineSegments(numSegments,3,xOffset,yOffset,.33,-yFactor,true,vSineSegments3);
 
  Visualizer2 vis("sine.ps");
  vis.addObject(vSineSegments0,Color(CBLUE));
  vis.addObject(vSineSegments1,Color(CGREEN));
  vis.addObject(vSineSegments2,Color(CRED));
  vis.addObject(vSineSegments3,Color(CBLACK));
  vis.writeFile();
}

Random Surfaces

The test data generators work also with Fade2.5D where there is the additional possibility to generate random surfaces. This functionality is for instance used in the Example Cut-and-Fill and or completeness this is reviewed here:

Random Surface Triangulation, 2.5D
void randomSurface()
{
    vector<Point2> vRndSurfacePoints;
    generateRandomSurfacePoints(
        70, // numPointsX
        70, // numPointsY
        15, // numCenters
        0,0,-100,1000,1000,100, // Bounds xmin,ymin,zmin,xmax,ymax,zmax
        vRndSurfacePoints,// Output vector
        1// Seed
    );
    Fade_2D dt;
    dt.insert(vRndSurfacePoints);
    dt.showGeomview("randomSurface.list");
}

The function call above creates a 70×70 grid of points whose x,y-range is (0,0)-(1000,1000). These points have elevations z in the range (-100,+100). The numCenters parameter determines the waviness of the surface. Use showGeomview(), writeObj() or writeWebScene() to visualize the result.

Leave a Reply

Your email address will not be published. Required fields are marked *