Ok.
I start witha a vector in a default direction (RND/0), being a vector of random length, pointimg “to the right”.
Then I rotate this vector (or the onit vector counterpart of it) by a random degree angle. After the rotation, I scale the vector to a new arbitrary length.
You just keep adding the rotation angles up until you accumulate 360 deg (or 2pi rad):
EDIT: Just saw that I forgot to include the brown line in my masterpiece… But I guess you get what I mean…
When you connect the points to a polygon, say clockwise, the next vertex is guaranteed to be “left” of the current one. So folding over is impossible, no matter what the random values are.
Just avoid the zero vector, so set reasonable ranges for rhe randoms in length and angle.
The functions are quite simple. Here is the code.
(Sorry, no C++, Im a Delphi coder).
Please note that in Delphi a function does not return result assignments immediately to the caller. Only if the function body is left, the result is returned, making the result effectively a local variable.)
type
TVector = record
X : extended; // X component
Y : extended; // Y component
end;
const
SafeZero = 0.000000000000001; // A "zero" that you can safely divide by
VZero : TVector = (X:0;Y:0);
VBaseX : TVector = (X:1;Y:0); // Vector space base vector, X-axis
VBaseY : TVector = (X:0;Y:1); // Vector space base vector, Y-axis
function VRotate(V:TVector;A:TScalar):TVector;
begin
Result.X := (V.X*cos(DegToRad(A))) - (V.Y*sin(DegToRad(A)));
Result.Y := (V.X*sin(DegToRad(A))) + (V.Y*cos(DegToRad(A)));
end;
function VScale(V: TVector; S: TScalar): TVector;
begin
Result.X := V.X * S;
Result.Y := V.Y * S;
end;
As you can see, the rotation is a simple implementation of the rotation matrix : https://en.wikipedia.org/wiki/Rotation_matrix
If you have the above setup, you can then place some of those polygons randomly near/over each other, so that they overlap in an interesting way.
Then you check all polygon edges for collisions.
My collision test looks like this:
type
TCollisionResult = record
C : boolean; // Collision result
P : TPoint; // Collision coordinates
end;
type
TLine = record
A : TVector; // Line start
B : TVector; // Line end
end;
Function VCollision(P,Q:TLine):TCollisionResult;
Var
T,S,N:Extended;
Begin
Result.C := false;
N:= P.A.X*Q.B.Y + Q.B.X*P.B.Y + P.B.X*Q.A.Y + Q.A.X*P.A.Y -
Q.B.X*P.A.Y - P.A.X*Q.A.Y - Q.A.X*P.B.Y - P.B.X*Q.B.Y;
If N=0 then Exit;
T:=(P.A.X*P.B.Y + P.B.X*Q.A.Y + Q.A.X*P.A.Y -
P.B.X*P.A.Y - Q.A.X*P.B.Y - P.A.X*Q.A.Y) / N;
If (T<0) or (T>1) then Exit;
S:=(P.A.X*Q.B.Y + Q.B.X*Q.A.Y + Q.A.X*P.A.Y -
Q.B.X*P.A.Y - Q.A.X*Q.B.Y - P.A.X*Q.A.Y) / N;
If (S<0) or (S>1) then Exit;
Result.P := point(Round(Q.A.X+T*(Q.B.X-Q.A.X)),Round(Q.A.Y+T*(Q.B.Y-Q.A.Y)));
Result.C := true;
End;
When you then subdivide the polygons at the intersections you get a nice network of random roads that dont look too fabricated…