package d2isometricimg

import 

// Move a caster only along the viewing ray. Its screen location is unchanged,
// but its shadow on the common receiver now has exactly the projection of its
// shadow on the root's local receiver. One ground atlas can cover every root;
// physical surface shadows continue to use the original unmodified geometry.
func rasterGroundTriangles( []Triangle,  float64,  Vec) []Triangle {
	 := false
	for ,  := range  {
		if .ShadowGround != nil && *.ShadowGround !=  {
			 = true
			break
		}
	}
	if ! {
		return 
	}
	 := append([]Triangle(nil), ...)
	for  := range  {
		 := &[]
		if .ShadowGround == nil || *.ShadowGround ==  {
			continue
		}
		 := nmul(, (-*.ShadowGround)/.Y)
		for  := range .V {
			.V[].Position = nadd(.V[].Position, )
		}
	}
	return 
}

type hierarchyShadowSpan struct {
	first, last int
	board       string
}

// Domain identity follows visible root containment, including layout-only
// wrappers. It is independent of any unrelated root's depth or shape count.
func hierarchyShadowDomains( []d2isometric.Board) map[string]string {
	 := make(map[string]int, len())
	for ,  := range  {
		[.ID] = 
	}
	 := make(map[string]string, len())
	 := make([]uint8, len())
	var  func(int) string
	 = func( int) string {
		 := []
		if [] != 0 {
			if  := [.ID];  != "" {
				return 
			}
			return .ID
		}
		[] = 1
		 := .ID
		if ,  := [.ParentID];  && .Kind != "platform" {
			 = ()
		}
		[.ID], [] = , 2
		return 
	}
	for  := range  {
		()
	}
	return 
}

func hierarchyShadowReceivers( []Triangle,  []d2isometric.Board,  []hierarchyShadowSpan) {
	 := hierarchyShadowDomains()
	 := make(map[string]*float64)
	for ,  := range  {
		,  := [.board]
		if ! {
			continue
		}
		 := []
		if  == nil {
			 = new(float64)
			[] = 
		}
		for ,  := range [.first:.last] {
			for ,  := range .V {
				* = min(*, .Position.Y)
			}
		}
	}
	for ,  := range  {
		* += .08
	}
	for ,  := range  {
		 := [[.board]]
		if  == nil {
			continue
		}
		for  := .first;  < .last; ++ {
			[].ShadowGround = 
		}
	}
}