# Random Polygons, Surfaces, Segments for Automated Software Tests

Geometry programming: Degenerate cases, numeric issues and unexpected geometric settings make a developer’s life hard. Automated software stress tests with random data are essential to discover bugs early. But creating random polygons without self-intersections or even random surfaces is for example not trivial. For convenient debugging the module testDataGenerators provides repeatable

• Random surfaces
• Random polygons
• Random segments
• Random point clouds
• Random numbers
• Polylines from sine functions
• Circles

## Repeatability

What you likely want is repeatable randomness so that you can later regenerate the data that has crashed your software. For this reason all random object generators take a seed value to initialize the internal random number generator. A certain seed value leads always to the same sequence of objects. Only when the special seed value 0 is passed then random sequences of objects are created. Typically you will have a test loop like this:

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

## Random numbers

The code below creates two sequences of random numbers for seed=0, for seed=1 and seed=2. 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<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. Choose the number of segments, the min- and max-coordinates and you’re done:

```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.writeFile();
}
```

## Random segments

The code below creates random segments. Intersections are allowed.

```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.writeFile();
}
```

## 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.writeFile();
}

```

## Circles

The generateCircle(…) command creates points on a given circle. No randomness in this command. The code below creates two circles, one is scaled in x direction.

```void circles()
{
int numPoints(50);
double centerX(0.0);
double centerY(0.0);
vector<Point2> vCirclePoints0;
vector<Point2> vCirclePoints1;

Visualizer2 vis("circles.ps");
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.

```
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.writeFile();
}
```

## Random Surfaces

The source code /examples_2D/randomData.cpp uses Fade2D but works also with Fade2.5D. When Fade2.5D is used, random surfaces can be created additionally. Creation of random surfaces is shown in Cut-and-Fill. For completeness the used function is reviewed here:

```
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
);
dt.insert(vRndSurfacePoints);
dt.showGeomview("randomSurface.list");
}```

The function call above creates a 70×70 grid of points whose XY-range is (0,0)-(1000,1000). The elevations Z of these points are in the range (-100,+100). The numCenters parameter determines the waviness of the surface. The showGeomview command is convenient for Geomview users. But you can alternatively use writeObj() or writeWebScene() to visualize the result.

Random Surface Triangulation, 2.5D