private void CreateRandomPolygon(ref BottomPolygon[] poly)
    {
        BottomPolygon[] enlargedArray = new BottomPolygon[poly.Length + 1];
        //just a quick and dirty distorted circle... = simple polygon, convex or concave possible
        int            edgeCount = Random.Range(3, 20);
        float          radius    = Random.Range(10F, 30F);
        Vector3        pos       = new Vector3(Random.Range(-220F, 220F), 0F, Random.Range(-220F, 220F));
        List <Vector3> newPoly   = new List <Vector3>();

        //create some random angles
        List <float> angles = new List <float>();

        for (int i = 0; i < edgeCount; i++)
        {
            float angle = Random.Range(0F, 2F * Mathf.PI);
            angles.Add(angle);
        }

        //sort Array by either des or asc to test FixCCWOrder
        if (RandBool())
        {
            angles.Sort((p1, p2) => (p1.CompareTo(p2)));            //Debug.Log("normal order");
        }
        else
        {
            angles.Sort((p2, p1) => (p1.CompareTo(p2)));            //Debug.Log("reversed order");
        }

        for (int i = 0; i < edgeCount; i++)
        {
            float dis = Random.Range(0.2F, 1F) * radius;                //distance to center
            newPoly.Add(new Vector3(Mathf.Sin(angles[i]) * dis, 0F, Mathf.Cos(angles[i]) * dis) + pos);
        }

        //copy old Polys to Polygon Array
        for (int i = 0; i < enlargedArray.Length - 1; i++)
        {
            enlargedArray[i].vertices = poly[i].vertices;
        }

        //check Order
        if (checkCCW)
        {
            FixCCWOrder(ref newPoly);
        }

        //add new poly at last position
        enlargedArray[enlargedArray.Length - 1].vertices = newPoly.ToArray();

        //save new array
        poly = enlargedArray;
    }
    private void GeneratePolygonStructArr(ref BottomPolygon[] poly)
    {
        poly = new BottomPolygon[walls.Length];

        int iPoly = 0;	//polygon integrator
        foreach(GameObject wall in walls){

            //Save Transform reference
            poly[iPoly].transform = wall.transform;
            poly[iPoly].renderer = wall.GetComponent<Renderer>();

            Mesh mesh = wall.GetComponent<MeshFilter>().mesh;
            Vector3[] vertices = mesh.vertices;
            int[] triangles = mesh.triangles;

            Vector3[] normals = mesh.normals;

            if(worldNormals){
                for(int i = 0; i < vertices.Length; i++){
                    normals[i] = poly[iPoly].transform.TransformDirection(mesh.normals[i]);
                }
            }

        //SIZECHECK, list usage could get rid of this step
            //check how much valid vertex are present to assign array lengths in the next step
            int validVertices = 0;
            for(int i = 0; i < vertices.Length; i++){
                //BOTTOM, or which orthogonal direction you need... e.g. sidescroller: if mesh.normals.z-1
                if(normals[i].y == -1){	//if the normal of this vertice is pointing down
                    validVertices++;
                }
            }

        //BOTTOM-VERTICES of the walls bottom-plane
            poly[iPoly].vertices = new Vector3[validVertices];	//init new Vector3 array of the struct with the needed length
            int[] validIndices = new int[validVertices];					//the original indices of the valid vertices, used to find the right triangles
            Vector3[] bottomVertices = new Vector3[validVertices];
            //int[] newIndices = new int[validVertices];						//new indices of the vertices, used to map newTriangles

            //save the valid vertices and triangles of the current wall
            int iv = 0;	//array integrator
            for(int i = 0; i < vertices.Length; i++){	//for ALL vertices of the wall mesh
                if(normals[i].y == -1){	//if the normal of this vertice is pointing down, e.g. should be only 4 vertices per cube
                    //actual saving of the vertex in WORLD COORDINATES
                    bottomVertices[iv] = wall.transform.TransformPoint(vertices[i]);
                    validIndices[iv] = i;
                    //newIndices[iv] = iv;
                    iv++;
                }
            }

            if(validIndices.Length == 0){break;}//early out

        //BOTTOM-TRIANGLES of one poly, maybe we dont need them directly later, but here they are needed to delete inner vertices (e.g. center of cylinder vertex)
            List<int> bottomTrianglesList = new List<int>();	//using the OLD indices
            int iAs = 0; //iterator for assigned triangles
            for(int it = 0; it < triangles.Length;){// iterator triangles
                //check if the next 3 indices of triangles match
                int match = 0;//check the next 3 indices of this triangles
                for(int imatch = 0; imatch<3; imatch++){
                    for(int ivv = 0; ivv < validIndices.Length; ivv++){//check with all vertices
                        if(validIndices[ivv]==triangles[it+imatch]){
                            match++;
                        }
                    }
                }
                //if all 3 indices of a triangle match with the validIndices, it is a bottom triangle
                if(match == 3){ //create new triangle in list
                    bottomTrianglesList.Add(triangles[it+0]);
                    bottomTrianglesList.Add(triangles[it+1]);
                    bottomTrianglesList.Add(triangles[it+2]);
                    iAs += 3; //assign iterator rdy for next triangle
                }
                it+=3;//next triangle
            }
            //now we have all triangles that are contained in the bottom plane, but with the original indices

            int[] bottomTrianglesArr = bottomTrianglesList.ToArray();
            int[] bottomTriangles = new int[bottomTrianglesArr.Length];	//using the OLD indices
            //Update indices to refer to bottomVertices:
            for(int ib = 0; ib < bottomTrianglesArr.Length; ib++){
                for(int ivi = 0; ivi < validIndices.Length; ivi++){	//check for original index, assign corresponding new index, must hit once per loop!
                    if(bottomTrianglesArr[ib] == validIndices[ivi]){
                        bottomTriangles[ib] = ivi;//currently the same as newTriangles[ib] = newIndices[ivi];, we dont need newIndices[]
                    }
                }
            }

        //AT THIS POINT we have the bottom vertices and triangles of the bottomPlane rdy for any use
        //			bottomVertices & bottomTriangles

            //Now we have to find the outlining polygon:
            ExtractPolygon(bottomVertices, bottomTriangles, ref poly[iPoly]);	//extracts polygon and saves it directly in passed poly struct

        //OTHER assignments for future purpose
            //add and save visibilityFader Reference and set Blackness of the Fader
            if(!wall.GetComponent<VisibilityFader>()){
                poly[iPoly].fader = wall.AddComponent<VisibilityFader>();
                poly[iPoly].fader.ManualInit();
            }else{
                poly[iPoly].fader = wall.GetComponent<VisibilityFader>();
            }

            poly[iPoly].fader.SetBlackness(0.0F);			//set lower fadeout boundary
            poly[iPoly].fader.EnableTransparentFade(true);	//transparent or black obstacles on fadeout

            poly[iPoly].include = true;

            CalculateCenterAndRadius(ref poly[iPoly]);
        //OTHER END

            iPoly++;
        }
    }
 private void FaderTest(ref BottomPolygon[] poly)
 {
     for(int ip = 0; ip < poly.Length; ip++){	//polygon
         if(poly[ip].fader){
             poly[ip].fader.Fade(fadeTest);
         }
     }
 }
    private void ExtractPolygon(Vector3[] vertices, int[] triangles, ref BottomPolygon poly)
    {
        //definitions used (see http://www.geosensor.net/papers/duckham08.PR.pdf)
        //→A triangulation ∆ is a combinatorial map which has the property that every edge in a set of edges belongs to either one or two triangle s
        //→Aboundary edge of ∆ is an edge that belongs to exactly one triangle in ∆.

        //for simple polygons(edges do not cross themselfes) which we are dealing with,
        //the outline polygon consists out of the edges that appear only in one triangle:

        //earlyOutTest
        //poly.vertices	= vertices;	return;

        List<int[]> allEdges = new List<int[]>();					//list of 2 integers each representing the index of a vertex
        List<int[]> unsortedBE = new List<int[]>();					//unsortedBoundaryEdges
        List<int[]> boundaryEdges = new List<int[]>();				//sorted outer edges

        List<Vector3> boundaryVertices = new List<Vector3>();	//the vertices of the polygon in ccw order, this is what we need!

        //get all edges
        for(int it = 0; it<triangles.Length;){//for all triangles, add their adges to the list
            allEdges.Add(new int[2]{triangles[it+0],triangles[it+1]});	//edge1
            allEdges.Add(new int[2]{triangles[it+1],triangles[it+2]});	//edge2
            allEdges.Add(new int[2]{triangles[it+2],triangles[it+0]});	//edge3
            it+=3;
        }//Debug.Log("Edges:"+allEdges.Count);

        //DROP all edges that appear in more than one triangle
        for( int iT = 0; iT < allEdges.Count; iT++){	//for each edge
            int o = iT%3;	//offset to find the edges that belong to the same triangle
            bool addEdge = true;
            for(int iC = 0; iC < allEdges.Count; iC++){	//compare loop, check all other edges
                if(	!((iT+0-o) == iC	||	(iT+1-o) == iC	||	(iT+2-o) == iC)	){	//except edges of current triangle from check
                    if(		(allEdges[iT][0] == allEdges[iC][0] && allEdges[iT][1] == allEdges[iC][1]) ||
                            (allEdges[iT][0] == allEdges[iC][1] && allEdges[iT][1] == allEdges[iC][0]) ){
                        addEdge = false;
                        break;
                    }
                }
            }
            //if this edge has not appeared twice we can add it to our boundary edge List
            if(addEdge){	unsortedBE.Add(allEdges[iT]);	}
        }//Debug.Log("Edges:"+unsortedBE.Count);

        //SORT unsortedBE, no edge will be dropped now, indices of each edge may be swapped
        //→	unsorted List:
        //	edge1		edge2		edge3		edge4
        //	[4][2]		[0][1]		[1][4]		[0][2]

        //→	sorted List:
        //	edge1		edge2(4)	edge3(2)	edge4(3)
        //	[4][2]		[2][0]		[0][1]		[1][4]

        //add first edge to start:
        boundaryEdges.Add(unsortedBE[0]);
        int failsave = 100;	//if bottomplane is faulty we cannot create a closed loop
        for(int iList = 1; iList < unsortedBE.Count;){	//compare loop, one edge has to match each run (closed edge loop)
            for(int iC = 1; iC < unsortedBE.Count; iC++){	//check all edges but the first (already added)
                //check if last index matches with another index, then add it to the sorted list
                //Debug.Log(boundaryEdges[iList-1][1] +"|"+ unsortedBE[iC][0]);
                if( boundaryEdges[iList-1][1] == unsortedBE[iC][0] ){	//common vertex on compare-edge[0], add!
                    boundaryEdges.Add(new int[2]{unsortedBE[iC][0],unsortedBE[iC][1]});
                    iList++;
                }else if( boundaryEdges[iList-1][1] == unsortedBE[iC][1] ){	//common vertex on compare-edge[1], add swapped!
                    boundaryEdges.Add(new int[2]{unsortedBE[iC][1],unsortedBE[iC][0]});
                    iList++;
                }
            }

            if(failsave<1){
                Debug.Log("Aborted Loop, bottomplane of ["+poly.transform.name+"] has gap or is faulty!");
                break;
            }
            failsave--;
        }

        //Finally! generate the vertices of the polygon out of the sorted list
        foreach(int[] intArr in boundaryEdges){
            //just add one side([0] or [1]) of each element in the sorted List and we have the vertices in right order
            boundaryVertices.Add(vertices[intArr[0]]);
        }

        if(checkCCW){
            FixCCWOrder(ref boundaryVertices);
        }

        //put this in boundaryVertices assignment if always needed
        if(clampY){
            for(int iV = 0; iV<boundaryVertices.Count; iV++){
                boundaryVertices[iV] = new Vector3(boundaryVertices[iV].x,0F,boundaryVertices[iV].z);
            }
        }

        poly.vertices = boundaryVertices.ToArray();
    }
    //RANDOM POLY
    private void CreateRandomPolygon(ref BottomPolygon[] poly)
    {
        BottomPolygon[] enlargedArray = new BottomPolygon[poly.Length+1];
        //just a quick and dirty distorted circle... = simple polygon, convex or concave possible
        int edgeCount = Random.Range(3,20);
        float radius  = Random.Range(10F,30F);
        Vector3 pos = new Vector3(Random.Range(-220F,220F),0F,Random.Range(-220F,220F));
        List<Vector3> newPoly = new List<Vector3>();

        //create some random angles
        List<float> angles = new List<float>();
        for(int i = 0; i < edgeCount; i++){
            float angle = Random.Range(0F,pi2);
            angles.Add(angle);
        }

        //sort Array by either des or asc to test FixCCWOrder
        if(RandBool()){
            angles.Sort((p1, p2) => (p1.CompareTo(p2)));//Debug.Log("normal order");
        }else{
            angles.Sort((p2, p1) => (p1.CompareTo(p2)));//Debug.Log("reversed order");
        }

        for(int i = 0; i < edgeCount; i++){
            float dis = Random.Range(0.2F,1F)*radius;	//distance to center
            newPoly.Add(new Vector3(Mathf.Sin(angles[i])*dis,0F,Mathf.Cos(angles[i])*dis) +pos);
        }

        //copy old Polys to Polygon Array
        for(int i = 0; i< enlargedArray.Length-1; i++){
            enlargedArray[i].vertices = poly[i].vertices;
        }

        //check Order
        if(checkCCW){
            FixCCWOrder(ref newPoly);
        }

        //add new poly at last position
        enlargedArray[enlargedArray.Length-1].vertices = newPoly.ToArray();

        //save new array
        poly = enlargedArray;
        //CreateBottomPlane(false);

        RefreshRandPolygons(ref randomPolys);
    }
 //draw the polygon CYAN
 private void DrawPolygons(ref BottomPolygon[] poly)
 {
     for(int ip = 0; ip < poly.Length; ip++){	//polygon
         for(int iv = 0; iv < poly[ip].vertices.Length; iv++){	//vertices of the polygon
             int nv = (iv+1)%poly[ip].vertices.Length; //next vertex
             Debug.DrawLine(poly[ip].vertices[iv], poly[ip].vertices[nv], new Color(0F,1F,1F,0.4F), 0F, false);
         }
     }
 }
    private void GeneratePolygonStructArr(ref BottomPolygon[] poly)
    {
        //Table of polygones
        poly = new BottomPolygon[walls.Length];
        int iPoly = 0;          //polygon integrator
        int cpt   = 0;

        foreach (GameObject wall in walls)
        {
            cpt++;
            //Save Transform reference
            poly[iPoly].transform = wall.transform;

            Mesh mesh = wall.GetComponent <MeshFilter>().mesh;

            //Get vertices, triangles & normals
            Vector3[] vertices  = mesh.vertices;
            int[]     triangles = mesh.triangles;
            Vector3[] normals   = mesh.normals;


/*
 *                      if(worldNormals)
 *                      {
 *                              for(int i = 0; i < vertices.Length; i++)
 *                              {
 *                                      normals[i] = poly[iPoly].transform.TransformDirection(mesh.normals[i]);
 *                              }
 *                      }
 */

            //SIZECHECK, list usage could get rid of this step
            //check how much valid vertex are present to assign array lengths in the next step



            //C'est utile ??????
            int validVertices = 0;
            for (int i = 0; i < vertices.Length; i++)
            {
                //BOTTOM, or which orthogonal direction you need... e.g. sidescroller: if mesh.normals.z-1
                if (normals[i].y == -1)
                {                       //if the normal of this vertice is pointing down, should be only 4 vertices per rectangle
                    validVertices++;
                }
            }

            //BOTTOM-VERTICES of the walls bottom-plane
            poly[iPoly].vertices = new Vector3[validVertices];                                                  //init new Vector3 array of the struct with the needed length
            int[]     validIndices   = new int[validVertices];                                                  //the original indices of the valid vertices, used to find the right triangles
            Vector3[] bottomVertices = new Vector3[validVertices];
            //int[] newIndices = new int[validVertices];						//new indices of the vertices, used to map newTriangles


            //save the valid vertices and triangles of the current wall
            int iv = 0;                 //array integrator
            for (int i = 0; i < vertices.Length; i++)
            {
                //for ALL vertices of the wall mesh
                if (normals[i].y == -1)
                {
                    //if the normal of this vertice is pointing down, e.g. should be only 4 vertices per rectangle
                    //actual saving of the vertex in WORLD COORDINATES
                    bottomVertices[iv] = wall.transform.TransformPoint(vertices[i]);
                    validIndices[iv]   = i;
                    //newIndices[iv] = iv;
                    iv++;
                }
            }

            if (validIndices.Length == 0)
            {
                break;
            }                                               //early out

            //BOTTOM-TRIANGLES of one poly, maybe we dont need them directly later, but here they are needed to delete inner vertices (e.g. center of cylinder vertex)
            List <int> bottomTrianglesList = new List <int>(); //using the OLD indices
            int        iAs = 0;                                //iterator for assigned triangles
            for (int it = 0; it < triangles.Length;)
            {                                                  // iterator triangles
                                                               //check if the next 3 indices of triangles match
                int match = 0;                                 //check the next 3 indices of this triangles
                for (int imatch = 0; imatch < 3; imatch++)
                {
                    for (int ivv = 0; ivv < validIndices.Length; ivv++)
                    {                    //check with all vertices
                        if (validIndices[ivv] == triangles[it + imatch])
                        {
                            match++;
                        }
                    }
                }
                //if all 3 indices of a triangle match with the validIndices, it is a bottom triangle
                if (match == 3)
                {                 //create new triangle in list
                    bottomTrianglesList.Add(triangles[it + 0]);
                    bottomTrianglesList.Add(triangles[it + 1]);
                    bottomTrianglesList.Add(triangles[it + 2]);
                    iAs += 3;         //assign iterator rdy for next triangle
                }
                it += 3;              //next triangle
            }
            //now we have all triangles that are contained in the bottom plane, but with the original indices

            int[] bottomTrianglesArr = bottomTrianglesList.ToArray();
            int[] bottomTriangles    = new int[bottomTrianglesArr.Length];              //using the OLD indices
            //Update indices to refer to bottomVertices:
            for (int ib = 0; ib < bottomTrianglesArr.Length; ib++)
            {
                for (int ivi = 0; ivi < validIndices.Length; ivi++)
                {                       //check for original index, assign corresponding new index, must hit once per loop!
                    if (bottomTrianglesArr[ib] == validIndices[ivi])
                    {
                        bottomTriangles[ib] = ivi;                        //currently the same as newTriangles[ib] = newIndices[ivi];, we dont need newIndices[]
                    }
                }
            }

//AT THIS POINT we have the bottom vertices and triangles of the bottomPlane rdy for any use
//			bottomVertices & bottomTriangles

            //Now we have to find the outlining polygon:
            ExtractPolygon(bottomVertices, bottomTriangles, ref poly[iPoly]);                   //extracts polygon and saves it directly in passed poly struct


            //OTHER assignments for future purpose
            //add and save visibilityFader Reference and set Blackness of the Fader
            if (!wall.GetComponent <VisibilityFader>())
            {
                poly[iPoly].fader = wall.AddComponent <VisibilityFader>();
                poly[iPoly].fader.ManualInit();
            }
            else
            {
                poly[iPoly].fader = wall.GetComponent <VisibilityFader>();
            }
            poly[iPoly].fader.SetBlackness(0.5F);

            //Not implemented yet
            //poly[iPoly].position = CalculateCenter(poly[iPoly].vertices);
            //poly[iPoly].relevantRadius = CalculateRadius(poly[iPoly].vertices);
            //OTHER END

            iPoly++;
        }
    }
    private void CheapGather(ref BottomPolygon[] poly)
    {
        Vector3 off = source.position;
        for(int ip = 0; ip < poly.Length; ip++){	//polygon

            if(!poly[ip].include){continue;}

            //writing values into list "segmentLines"

            int length = poly[ip].vertices.Length;
            if(!invisibleFaces){
                for(int iv = 0; iv < length; iv++){	//vertices of the polygon
                    //int nv = (iv<length-1)? iv+1 : 0; //next vertex
                    int nv = (iv+1)%length;
                    Vector3 vertexDirection = poly[ip].vertices[iv]-poly[ip].vertices[nv];
                    Vector3 sourceDirection = source.position-poly[ip].vertices[iv];

                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)<0F ){
                        segmentLines.Add(poly[ip].vertices[iv]-off);
                        segmentLines.Add(poly[ip].vertices[nv]-off);
                    }
                }
            }else{
                for(int iv = 0; iv < length; iv++){	//vertices of the polygon
                    int nv = (iv+1)%length;
                    Vector3 vertexDirection = poly[ip].vertices[iv]-poly[ip].vertices[nv];
                    Vector3 sourceDirection = source.position-poly[ip].vertices[iv];

                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)>0F ){
                        segmentLines.Add(poly[ip].vertices[iv]-off);
                        segmentLines.Add(poly[ip].vertices[nv]-off);
                    }
                }
            }
        }
    }
 //cheaper 360° Gather for 2nd approach, without the top/bottom distinction and cut
 //gather relevant Polygons, check the polygon position increased by its radius if it is near our relevant radius
 //    ↘viewport may be rotateable, for convenience we check if in radius not if within a maybe rotated rectangular area
 private void CheckInclusion(ref BottomPolygon[] polys, Vector3 lightPosition, float radius)
 {
     for(int iP =0; iP<polys.Length;iP++){
         //Vector3.magnitude or Distance is slower than sqrMag
         if( ((polys[iP].position-lightPosition).sqrMagnitude - polys[iP].relevantRadius*polys[iP].relevantRadius) < radius*radius){//faster than distance
         //if( Vector3.Distance(polys[iP].position, lightPosition) < radius){
             polys[iP].include = true;
         }else{
             polys[iP].include = false;
         }
     }
 }
 private void RefreshRandPolygons(ref BottomPolygon[] polyArr)
 {
     //check Order
     if(checkCCW){
         for(int i = 0; i < polyArr.Length; i++){
             polyArr[i].vertices = FixCCWOrder(polyArr[i].vertices);
         }
     }
 }
    //cheaper 360° Gather for 2nd approach, without the top/bottom distinction and cut
    private void CheapGather(ref BottomPolygon[] poly)
    {
        Vector3 off = source.position;
        for(int ip = 0; ip < poly.Length; ip++){	//polygon

            Segment newSeg = new Segment();
            newSeg.vert = new List<Vector3>();

            int length = poly[ip].vertices.Length;
            if(!invisibleFaces){
                for(int iv = 0; iv < length; iv++){	//vertices of the polygon
                    //int nv = (iv<length-1)? iv+1 : 0; //next vertex
                    int nv = (iv+1)%length;
                    Vector3 vertexDirection = poly[ip].vertices[iv]-poly[ip].vertices[nv];
                    Vector3 sourceDirection = source.position-poly[ip].vertices[iv];

                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)<0F ){
                        newSeg.vert.Add(poly[ip].vertices[iv]-off);
                        newSeg.vert.Add(poly[ip].vertices[nv]-off);
                    }
                }
            }else{
                for(int iv = 0; iv < length; iv++){	//vertices of the polygon
                    int nv = (iv+1)%length;
                    Vector3 vertexDirection = poly[ip].vertices[iv]-poly[ip].vertices[nv];
                    Vector3 sourceDirection = source.position-poly[ip].vertices[iv];

                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)>0F ){
                        newSeg.vert.Add(poly[ip].vertices[iv]-off);
                        newSeg.vert.Add(poly[ip].vertices[nv]-off);
                    }
                }
            }
            segments.Add(newSeg);
        }
    }
    private void GatherSegments(ref BottomPolygon[] poly, bool top)
    {
        //top or bottom half of poly

        Vector3 s = source.position;
        //Vector3 s = Vector3.zero;

        Segment newSeg = new Segment();
        newSeg.vert = new List<Vector3>();
        newSeg.segmin = 6500F;
        newSeg.segmax = 0F;

        for(int ip = 0; ip < poly.Length; ip++){	//polygon

            //future: check if this poly can be dropped immidiately
            //if( Vector3.Distance(polys[i].position, source.position) < radius + polys[i].relevantRadius){
            //if( ((polys[iP].position-position).sqrMagnitude - polys[iP].relevantRadius*polys[iP].relevantRadius) < radius*radius){
            //	continue;	//next poly
            //}

            bool lastVisible = false;	//if last checked face was visible
            int vertexCount = 0;

            int length = poly[ip].vertices.Length;
            bool[] visFaces = new bool[length];
            //check visible faces
            for(int iv = 0; iv < length; iv++){
                int nv = (iv+1)%length;
                Vector3 curV = poly[ip].vertices[iv];
                Vector3 nexV = poly[ip].vertices[nv];

                //visFaces[iv] = (curV.z*nexV.x-curV.x*nexV.z) < 0F;
                Vector3 vertexDirection = curV-nexV;
                Vector3 sourceDirection = s-curV;

                visFaces[iv] = false;
                //is the face on the right half and between this and next vertex visible?
                if(top){
                    if(curV.z-s.z>0F || nexV.z-s.z>0F){//if at least one vertix of the line is in the right half
                        visFaces[iv] = TestFaceVisibility(ref vertexDirection, ref sourceDirection);
                    }
                }else{
                    if(curV.z-s.z<0F || nexV.z-s.z<0F){
                        visFaces[iv] = TestFaceVisibility(ref vertexDirection, ref sourceDirection);
                    }
                }
            }

            //find any invisible vertex to start from, because segments overlapping first vertex would create 2 seperate segments
            int offset = 0;
            for(int iv = 0; iv < length; iv++){
                    if(!visFaces[iv]){offset = iv+1; break;};
            }

            //for testing visFaces...
            //Debug.DrawLine(poly[ip].vertices[offset], source.position, Color.cyan,0F,false);
            //for(int iv = offset; iv < (length+offset); iv++){
            //	if(visFaces[iv%length])
            //	Debug.DrawLine(poly[ip].vertices[iv%length], poly[ip].vertices[(iv+1)%length], Color.green,0F,false);
            //}

            //needed fpr pseudoangles inaccuracys on Cutlines that are all very close
            //otherwise the drop rate of segments on horizonatal lines would suffer

            //Intersection with the X-Axis?
            bool axisInterFromBelow = false;
            bool axisInterFromAbove = false;

            for(int iv = offset; iv < (length+offset); iv++){
                //from now on we save vector points with the light source as origin
                Vector3 curV = poly[ip].vertices[ iv	%length]-s;
                Vector3 nexV = poly[ip].vertices[(iv+1)	%length]-s;
                if(visFaces[iv%length]){	//this step adds one line segment and one vertex (or two vertices if its the first)
                    //Cut line with horizon
                    if(curV.z>0.0f != nexV.z>0.0f){ //horizon is cut if the signs of the 2 vectice's z values don't match
                        float	h1	= -curV.z;
                        Vector3	hv	= nexV-curV;
                        if(top && hv.z<0.0f || !top && hv.z>0.0f){
                            nexV.x -= hv.x * (hv.z-h1)/hv.z;	//x-axis intersection x
                            nexV.z	= 0.0f;						//x-axis intersection y (zero of course)
                            axisInterFromAbove = true;			//line has intersected X-axis from ABOVE the axis
                            //Debug.DrawLine(drawOrigin, nexV+drawOrigin,Color.blue,0F,false);
                        }else{
                            curV.x += hv.x * h1/hv.z;			//x-axis intersection x
                            curV.z	= 0.0f;						//x-axis intersection y (zero of course)
                            axisInterFromBelow = true;			//line has intersected X-axis from BELOW the axis
                            //Debug.DrawLine(drawOrigin, curV+drawOrigin,Color.red,0F,false);
                        }
                    }else{
                        axisInterFromBelow = false;
                        axisInterFromAbove = false;
                    }
                    float distance = curV.magnitude;
                    //first vertex
                    if(vertexCount == 0){
                        newSeg.vert.Add(curV);	//add first vertex
                        vertexCount++;
                            //angle(radian) to first point
                            //newSeg.start = Mathf.Atan2(curV.z,curV.x);// * Mathf.Rad2Deg;
                            //if(newSeg.start<0){newSeg.start += pi2;}	//fix to positive 0-360° representation
                            //newSeg.start = pi2-newSeg.start;//invert angle count direction
                        if(axisInterFromBelow){
                            newSeg.start = -1.0f;
                        }else{
                            newSeg.start = newSeg.startnew = PseudoAngle(curV,Lenght(curV));
                            newSeg.startd = distance;
                        }
                    }

                    newSeg.vert.Add(nexV);		//add next vertex
                    vertexCount++;

                    //Vector3 proj = Vector3.Project(-curV, curV-nexV)+curV;
                    //newSeg.segmin = Min(newSeg.segmin, proj.magnitude);//substitute for LineMinDistance
                        //if(ip == 0 && vertexCount == 2){//test MinDistance substitute
                        //	Debug.DrawLine(curV+drawOrigin, nexV+drawOrigin,Color.blue,0F,false);
                        //	Debug.DrawRay(drawOrigin,proj,Color.white,0F,false);
                        //}//doesnt work, we would have to add a check if the projection hits the line

                    //CheckXAxisIntersection(ref curV, ref nexV, ref newSeg.right);

                    newSeg.segmin = Min(newSeg.segmin, LineMinDistance(curV,nexV,Vector3.zero));
                    newSeg.segmin = Min(newSeg.segmin, distance);//it cannot happen that distance issmaller than lineMinDistance
                    newSeg.segmax = Max(newSeg.segmax, distance);
                    lastVisible = true;	//remember that last face was visible
                }else{	//this step ends the Segment
                    if((vertexCount > 0) && lastVisible){	//if this is the first vertex after a segment
                        float distance = curV.magnitude;
                            //angle(radian) to last point
                            //newSeg.end = Mathf.Atan2(curV.z,curV.x);// * Mathf.Rad2Deg;
                            //if(newSeg.end<0){newSeg.end += pi2;}
                            //newSeg.end = pi2-newSeg.end;//invert angle count direction

                        if(axisInterFromAbove){
                            newSeg.end = 1.0f;
                        }else{
                            newSeg.end = PseudoAngle(curV,Lenght(curV));
                            newSeg.endd = distance;
                        }
                        newSeg.segmin = Min(newSeg.segmin, distance);
                        newSeg.segmax = Max(newSeg.segmax, distance);

                        newSeg.vertCnt = vertexCount;

                        //there may be multiple seperated segments on a poly, reset vertCnt for possible second segment on this poly
                        vertexCount = 0;

                        //angleFlip

                        //pseudo angles
                        //if(newSeg.start>newSeg.end){newSeg.end = 1.0f;}
                        /*if(newSeg.start>newSeg.end){
                            float end = newSeg.end;
                            newSeg.end = newSeg.start;
                            newSeg.start = end;
                        }*/

                        //normal angles

                        //angle offset:
                        //if(newSeg.right){newSeg.end += pi2;}// newSeg.start = pi2-newSeg.start;}
                        //if(newSeg.right && newSeg.end<180F){newSeg.end += pi2;}//works only if segment is above
                        //if(newSeg.right && newSeg.end>180F){newSeg.end -= pi2/2;}//

                        //angleFlip
                        /*if(newSeg.start>newSeg.end){
                            float end = newSeg.end;
                            newSeg.end = newSeg.start;
                            newSeg.start = end;
                        }*/

                        newSeg.startnew = newSeg.start;
                        newSeg.endnew = newSeg.end;

                        newSeg.radLenght = newSeg.end-newSeg.start; //used to make the check independent from the angle jump (0to360°)

                        //SAVE SEGMENT
                        segments.Add(newSeg);
                        segmentCount++;

                        //debug
                        if(showSegStats){
                            int sv = 0;//which index of segmentValues
                            if(segmentCount==2){sv = 1;}
                            segmentValues[sv] = "Segment owner: random poly";
                            if(poly[ip].transform){
                                newSeg.transform = poly[ip].transform;
                                segmentValues[sv] = "Segment"+sv+" owner: "+poly[ip].transform.name;
                                if(poly[ip].fader){newSeg.fader = poly[ip].fader;}
                            }

                            segmentValues[sv] +=
                                "\noffset\t\t"	+offset+
                                "\nsegmin\t\t"	+newSeg.segmin+
                                "\nsegmax\t\t"	+newSeg.segmax+
                                "\nstart\t\t\t"	+newSeg.start		+//* Mathf.Rad2Deg+"(blue)"+
                                "\nend\t\t\t"	+newSeg.end			+//* Mathf.Rad2Deg+"(yellow)"+
                                //"\nstartnew\t\t"+newSeg.startnew	+//* Mathf.Rad2Deg+
                                //"\nendnew\t\t"	+newSeg.endnew		+//* Mathf.Rad2Deg+
                                "\nstartd\t\t\t"+newSeg.startd+
                                "\nendd\t\t\t"	+newSeg.endd+
                                "\nactive\t\t"	+newSeg.active+
                                "\n\nlightpos\t"+s+
                                "\nvertices:"+
                                "\nvertCnt\t\t"	+newSeg.vertCnt +
                                "\nvertices\t"+newSeg.vert[0];

                            for(int i = 1; i<newSeg.vertCnt; i++){
                                segmentValues[sv] += ("\n\t\t\t"	+newSeg.vert[i]);
                            }
                            //if(sv==0){
                            //	Vector3 startDirection = Quaternion.Euler(new Vector3(0F, newSeg.start*Mathf.Rad2Deg, 0F)) * Vector3.right;
                            //	Vector3 endDirection = Quaternion.Euler(new Vector3(0F, newSeg.end*Mathf.Rad2Deg, 0F)) * Vector3.right;
                            //	Debug.DrawRay(drawOrigin,startDirection*3F,Color.blue,0F,false);
                            //	Debug.DrawRay(drawOrigin,endDirection*3F,Color.yellow,0F,false);
                                    //Debug.DrawRay(drawOrigin,startDirection*newSeg.segmin,Color.blue,0F,false);
                                    //Debug.DrawRay(drawOrigin,endDirection*newSeg.segmax,Color.yellow,0F,false);
                            //}
                        }

                        //create new Segment
                        newSeg = new Segment();
                        newSeg.vert = new List<Vector3>();
                        newSeg.segmin = 6500F;
                        newSeg.segmax = 0F;
                    }
                    lastVisible = false;
                }
            }
        }
        segments.Sort((segment2, segment1) => (segment1.start.CompareTo(segment2.start)));//sort segments by the angle of the start vertex

        //string segmentList = "";
        //for(int i=0; i < segments.Count; i++){
        //	segmentList += "start\t"+segments[i].start+"\n";
        //}
        //Debug.Log(segmentList);

        /*if(showSegStats){
            segmentCount = segments.Count;
        }*/
    }
 //NOT NEEDED YET, CONSIDER REMOVAL: JUST USE: Renderer.isVisible maybe
 //↘EDIT: no if 2 Cameras! we need to have area since objects between 2 cameras could get ignored
 //gather relevant Polygons, check the polygon position increased by its radius if it is near our relevant radius
 //    ↘viewport may be rotateable, for convenience we check if in radius not if within a maybe rotated rectangular area
 private void GatherPolygons(ref BottomPolygon[] polys, Vector3 position, float radius)
 {
     List<BottomPolygon> relevantPolygons = new List<BottomPolygon>();
     for(int iP =0; iP<polys.Length;iP++){
         //Vector3.magnitude or Distance is slower than sqrMag
         if( ((polys[iP].position-position).sqrMagnitude - polys[iP].relevantRadius*polys[iP].relevantRadius) < radius*radius){
         //if( Vector3.Distance(polys[i].position, position) < radius){
             //relevantPolygons.Add(ref polys[iP]);
             relevantPolygons.Add(polys[iP]);
         }
     }
 }
    private void DrawVisibleFaces(ref BottomPolygon[] poly)
    {
        for(int ip = 0; ip < poly.Length; ip++){	//polygon
            for(int iv = 0; iv < poly[ip].vertices.Length; iv++){	//vertices of the polygon
                int nv = (iv+1)%poly[ip].vertices.Length; //next vertex

                Vector3 vertexDirection = poly[ip].vertices[iv]-poly[ip].vertices[nv];
                Vector3 sourceDirection = source.position-poly[ip].vertices[iv];
                if(!invisibleFaces){
                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)<0F ){
                        Debug.DrawLine(poly[ip].vertices[iv], poly[ip].vertices[nv], Color.white,0F,false);
                    }
                }else{
                    if( AngleDir(vertexDirection,sourceDirection,Vector3.up)>0F ){
                        Debug.DrawLine(poly[ip].vertices[iv], poly[ip].vertices[nv], Color.white,0F,false);
                    }
                }
            }
        }
    }
 private void RefreshRandPolygons(ref BottomPolygon[] polyArr)
 {
     //check Order
     if(checkCCW){
         for(int i = 0; i < polyArr.Length; i++){
             polyArr[i].vertices = FixCCWOrder(polyArr[i].vertices);
             polyArr[i].include = true;
             CalculateCenterAndRadius(ref polyArr[i]);
         }
     }
 }
 //costum inclusion check for a game that uses splitscreen cameras
 //if the 2 cameras would be far apart the objects in between the 2 viewport rectangles would not be into the calculation (renderer.isVisible would be false)
 //so i include only those objects which extents lie inside the rectangle strip between the 2 viewports
 private void CheckInclusionPerRectangle(ref BottomPolygon[] polys)
 {
     //future
 }
    //average of all vertices does not need to be accurate, only not to small
    private void CalculateCenterAndRadius(ref BottomPolygon polygon)
    {
        float minX =  9000F;
        float maxX = -9000F;
        float minY =  9000F;
        float maxY = -9000F;
        for(int i=0; i< polygon.vertices.Length; i++){
            if(polygon.vertices[i].x<minX)	{ minX = polygon.vertices[i].x;	}
            if(polygon.vertices[i].x>maxX)	{ maxX = polygon.vertices[i].x;	}
            if(polygon.vertices[i].z<minY)	{ minY = polygon.vertices[i].z;	}
            if(polygon.vertices[i].z>maxY)	{ maxY = polygon.vertices[i].z;	}
        }

        polygon.position		= new Vector3((minX+maxX)*0.5F,0F,(minY+maxY)*0.5F);			// center of max values
        polygon.relevantRadius	= (Mathf.Sqrt( (maxX-minX)*(maxX-minX)+(maxY-minY)*(maxY-minY) ))/2F;// perimeter

        Debug.DrawLine(new Vector3(minX,0F,minY), new Vector3(minX,0F,maxY), Color.blue, 1.5F, false);
        Debug.DrawLine(new Vector3(minX,0F,maxY), new Vector3(maxX,0F,maxY), Color.blue, 1.5F, false);
        Debug.DrawLine(new Vector3(maxX,0F,maxY), new Vector3(maxX,0F,minY), Color.blue, 1.5F, false);
        Debug.DrawLine(new Vector3(maxX,0F,minY), new Vector3(minX,0F,minY), Color.blue, 1.5F, false);

        Debug.DrawLine(	new Vector3(polygon.position.x-polygon.relevantRadius, 0F, polygon.position.z),
                        new Vector3(polygon.position.x+polygon.relevantRadius, 0F, polygon.position.z), Color.cyan, 1.5F, false);
        Debug.DrawLine(	new Vector3(polygon.position.x, 0F, polygon.position.z-polygon.relevantRadius),
                        new Vector3(polygon.position.x, 0F, polygon.position.z+polygon.relevantRadius), Color.cyan, 1.5F, false);
    }
 private void CheckInclusionPerRenderer(ref BottomPolygon[] polys)
 {
     for(int iP =0; iP<polys.Length;iP++){
         if( polys[iP].renderer.isVisible){
             polys[iP].include = true;
         }else{
             polys[iP].include = false;
         }
     }
 }
    private void ExtractPolygon(Vector3[] vertices, int[] triangles, ref BottomPolygon poly)
    {
        //definitions used (see http://www.geosensor.net/papers/duckham08.PR.pdf)
        //→A triangulation ∆ is a combinatorial map which has the property that every edge in a set of edges belongs to either one or two triangle s
        //→Aboundary edge of ∆ is an edge that belongs to exactly one triangle in ∆.

        //for simple polygons(edges do not cross themselfes) which we are dealing with,
        //the outline polygon consists out of the edges that appear only in one triangle:

        //earlyOutTest
        //poly.vertices	= vertices;	return;

        List <int[]> allEdges      = new List <int[]>();                //list of 2 integers each representing the index of a vertex
        List <int[]> unsortedBE    = new List <int[]>();                //unsortedBoundaryEdges
        List <int[]> boundaryEdges = new List <int[]>();                //sorted outer edges

        List <Vector3> boundaryVertices = new List <Vector3>();         //the vertices of the polygon in ccw order, this is what we need!

        //get all edges
        for (int it = 0; it < triangles.Length;)      //for all triangles, add their adges to the list
        {
            allEdges.Add(new int[2] {
                triangles[it + 0], triangles[it + 1]
            });                                                                         //edge1
            allEdges.Add(new int[2] {
                triangles[it + 1], triangles[it + 2]
            });                                                                         //edge2
            allEdges.Add(new int[2] {
                triangles[it + 2], triangles[it + 0]
            });  //edge3
            it += 3;
        }        //Debug.Log("Edges:"+allEdges.Count);

        //DROP all edges that appear in more than one triangle
        for (int iT = 0; iT < allEdges.Count; iT++)                                    //for each edge
        {
            int  o       = iT % 3;                                                     //offset to find the edges that belong to the same triangle
            bool addEdge = true;
            for (int iC = 0; iC < allEdges.Count; iC++)                                //compare loop, check all other edges
            {
                if (!((iT + 0 - o) == iC || (iT + 1 - o) == iC || (iT + 2 - o) == iC)) //except edges of current triangle from check
                {
                    if ((allEdges[iT][0] == allEdges[iC][0] && allEdges[iT][1] == allEdges[iC][1]) ||
                        (allEdges[iT][0] == allEdges[iC][1] && allEdges[iT][1] == allEdges[iC][0]))
                    {
                        addEdge = false;
                        break;
                    }
                }
            }
            //if this edge has not appeared twice we can add it to our boundary edge List
            if (addEdge)
            {
                unsortedBE.Add(allEdges[iT]);
            }
        }        //Debug.Log("Edges:"+unsortedBE.Count);

        //SORT unsortedBE, no edge will be dropped now, indices of each edge may be swapped
        //→	unsorted List:
        //	edge1		edge2		edge3		edge4
        //	[4][2]		[0][1]		[1][4]		[0][2]

        //→	sorted List:
        //	edge1		edge2(4)	edge3(2)	edge4(3)
        //	[4][2]		[2][0]		[0][1]		[1][4]

        //add first edge to start:
        boundaryEdges.Add(unsortedBE[0]);
        int failsave = 100;                               //if bottomplane is faulty

        for (int iList = 1; iList < unsortedBE.Count;)    //compare loop, one edge has to match each run (closed edge loop)
        {
            for (int iC = 1; iC < unsortedBE.Count; iC++) //check all edges but the first (already added)
            //check if last index matches with another index, then add it to the sorted list
            //Debug.Log(boundaryEdges[iList-1][1] +"|"+ unsortedBE[iC][0]);
            {
                if (boundaryEdges[iList - 1][1] == unsortedBE[iC][0])                   //common vertex on compare-edge[0], add!
                {
                    boundaryEdges.Add(new int[2] {
                        unsortedBE[iC][0], unsortedBE[iC][1]
                    });
                    iList++;
                }
                else if (boundaryEdges[iList - 1][1] == unsortedBE[iC][1])                      //common vertex on compare-edge[1], add swapped!
                {
                    boundaryEdges.Add(new int[2] {
                        unsortedBE[iC][1], unsortedBE[iC][0]
                    });
                    iList++;
                }
            }

            if (failsave < 1)
            {
                Debug.Log("Aborted Loop, bottomplane faulty!");
                break;
            }
            failsave--;
        }

        //Finally! generate the vertices of the polygon out of the sorted list
        foreach (int[] intArr in boundaryEdges)
        {
            //just add one side([0] or [1]) of each element in the sorted List and we have the vertices in right order
            boundaryVertices.Add(vertices[intArr[0]]);
        }

        if (checkCCW)
        {
            FixCCWOrder(ref boundaryVertices);
        }

        //put this in boundaryVertices assignment if always needed
        if (clampY)
        {
            for (int iV = 0; iV < boundaryVertices.Count; iV++)
            {
                boundaryVertices[iV] = new Vector3(boundaryVertices[iV].x, 0F, boundaryVertices[iV].z);
            }
        }

        poly.vertices = boundaryVertices.ToArray();
    }
 private void ClearRandomPolygons(ref BottomPolygon[] polyArr)
 {
     polyArr = new BottomPolygon[0];
 }
 private void ClearRandomPolygons(ref BottomPolygon[] polyArr)
 {
     polyArr = new BottomPolygon[0];
 }
 //just to see the order of the vertices, different colors to see order
 private void DrawLineToVertices(ref BottomPolygon[] poly)
 {
     for(int ip = 0; ip < poly.Length; ip++){	//polygon
         for(int iv = 0; iv < poly[ip].vertices.Length; iv++){	//vertices of the polygon
             Color color = new Color(0F,0F,1F,0.2F);
             if(iv == 0){color = new Color(0F,0.5F,1F,1F);}
             if(iv == 1){color = new Color(0F,0.5F,1F,0.5F);}
             Debug.DrawLine(drawOrigin, poly[ip].vertices[iv], color, 0F, false);
         }
     }
 }