public void PlaceGameObjects(GameObject container = null)
    {
        Debug.LogFormat("PlaceGameObjects - found {0} places", foundPlaces.Count);

        foreach (Place place in foundPlaces)
        {
            PlacementCriteria placmentCriteria = this.placmentCriteria.Where(pc => pc.tag.Equals(place.tag)).First();

            GameObject go = Instantiate(placmentCriteria.prefab);
            go.transform.position = place.position;
            //go.transform.up = place.normal;
            if (container != null)
            {
                go.transform.parent = container.transform;
            }
        }
    }
    void FindPlacesOnPlane(PlacementCriteria placementCriteria, GameObject plane, List <Place> places)
    {
        var boundingRadius = Mathf.Max(placementCriteria.Bounds.size.x, placementCriteria.Bounds.size.y, placementCriteria.Bounds.size.z) * 0.5f;

        var allPositions               = GetSurfacePositionsForPlane(plane, placementCriteria.Bounds, 1.5f);
        var filteredPositions          = FilterOutInvalidSurfacePositions(allPositions, -plane.transform.forward * boundingRadius, boundingRadius);
        var filteredAndSortedPositions = SortSurfacePosition(placementCriteria, filteredPositions);

        for (int i = 0; i < Mathf.Min(placementCriteria.count, filteredAndSortedPositions.Count); i++)
        {
            places.Add(new Place
            {
                tag      = placementCriteria.tag,
                position = filteredAndSortedPositions[i],
                normal   = -plane.transform.forward
            });
        }
    }
    List <Vector3> SortSurfacePosition(PlacementCriteria pc, List <Vector3> surfacePositions)
    {
        var costs = surfacePositions.Select((position, index) =>
        {
            Vector3 cameraPos = new Vector3(Camera.main.transform.position.x, 0, Camera.main.transform.position.z);
            Vector3 pos       = new Vector3(position.x, 0, position.z);

            Vector3 direction = (pos - cameraPos);
            float distance    = direction.magnitude;
            direction.Normalize();

            float dot     = Vector3.Dot(Camera.main.transform.forward, direction);
            float dotCost = Mathf.Pow(1f - dot, 2f);

            float minDistanceCost = 0;
            if (distance < pc.minDistance)
            {
                minDistanceCost = pc.minDistance / distance;
            }

            float maxDistanceCost = 0f;
            if (distance > pc.maxDistance)
            {
                maxDistanceCost = distance / pc.maxDistance;
            }

            float totalCost = dotCost + minDistanceCost + maxDistanceCost;

            return(new { index = index, cost = totalCost });
        }).ToList();

        costs.Sort((ca, cb) =>
        {
            return(ca.cost.CompareTo(cb.cost));
        });

        return(costs.Select(cost =>
        {
            return surfacePositions[cost.index];
        }).ToList());
    }