package layoutgraph

import (
	
	
	
	
	
	

	
	
	

	
	
	
)

const (
	defaultIconSize = 32.0
	threeDOffset    = 15.0
	multipleOffset  = 10.0
)

// HasLeakyEdge checks if
// 1. node is a container
// 2. a descendant has an edge going outside the container
func ( *Node) () bool {
	if !.isContainer {
		return false
	}

	 := false
	.dfsWalk(func( *Node) ( bool) {
		if  ==  {
			return false
		}
		for ,  := range .Edges {
			 := .adjacent()
			if !.isDescendantOf() {
				 = true
				return true
			}
		}
		return false
	})
	return 
}

func ( *Node) ( *Graph,  Spacing) {
	,  := Nodes(.Nodes).fixedBounds()
	.expandForLabels(, )
	.fitToBoundingBox(, , )
}

func ( *Node) (,  *geo.Point,  Spacing) {
	 := .X - .X
	 := .Y - .Y
	if .Label != nil && !.Label.Position.IsOutside() {
		 := .Label.Width - .left - .right + label.PADDING*4
		 := .Label.Height - .top - .bottom + label.PADDING*4
		if .DesiredWidth == nil {
			 = math.Max(, )
		}
		if .DesiredHeight == nil {
			 = math.Max(, )
		}
	}
	// TODO move type Spacing to d2 and update GetDimensionsToFit for all shapes
	,  := .GetDimensionsToFit(, , .left+.right, .top+.bottom)
	if .DesiredWidth != nil {
		.Width = math.Max(, *.DesiredWidth)
	} else {
		.Width = 
	}
	if .DesiredHeight != nil {
		.Height = math.Max(, *.DesiredHeight)
	} else {
		.Height = 
	}
}

func ( *Node) ( Nodes) (*geo.Point, *geo.Point) {
	return .boundsWithRounding(, true)
}

func ( *Node) ( Nodes,  bool) (*geo.Point, *geo.Point) {
	,  := .boundingBoxValues(, )
	return &, &
}

func ( *Node) ( Nodes,  bool) (geo.Point, geo.Point) {
	 := *.TopLeft
	 := geo.Point{X: .X + .Width, Y: .Y + .Height}
	if  {
		.X = math.Round(.X)
		.Y = math.Round(.Y)
	}
	if ,  := .modifierElementAdjustments();  != 0 ||  != 0 {
		.Y -= 
		.X += 
	}
	.X -= .LoopOffsets[geo.Left]
	.Y -= .LoopOffsets[geo.Top]
	.X += .LoopOffsets[geo.Right]
	.Y += .LoopOffsets[geo.Bottom]

	if .Label != nil && .Label.Position.IsOutside() &&  != nil {
		 := .LabelTopLeft(.Label.Position, .Label.Width, .Label.Height)

		// include 2x padding so that outside labels will always be closest to their own node
		// . ┌─────┐                ┌─────┐
		// . │     │ ┌───────────┐  │     │
		// . │  A  │ │ A's label │  │  B  │
		// . │     │ └───────────┘  │     │
		// . └─────┘                └─────┘
		// .       ├─┤           ├──┤
		// .    label.PADDING   2xlabel.PADDING
		 := float64(label.PADDING)
		// If the node is at the boundary, there won't be ambiguity
		 := 2. * label.PADDING

		if .X < .X {
			if .Leftmost() {
				.X = math.Floor(.X - )
			} else {
				.X = math.Floor(.X - )
			}
		}
		if .Y < .Y {
			if .Topmost() {
				.Y = math.Floor(.Y - )
			} else {
				.Y = math.Floor(.Y - )
			}
		}
		if .X > .X {
			if .Rightmost() {
				.X = math.Ceil(.X + .Label.Width + )
			} else {
				.X = math.Ceil(.X + .Label.Width + )
			}
		}

		if .Y > .Y {
			if .Bottommost() {
				.Y = math.Ceil(.Y + .Label.Height + )
			} else {
				.Y = math.Ceil(.Y + .Label.Height + )
			}
		}
	}
	if .Icon != nil && .shapeType != imageType && .Icon.Position.IsOutside() &&  != nil {
		 := float64(MaxIconSize)
		 := .LabelTopLeft(.Icon.Position, , )

		 := 2. * label.PADDING

		 := math.Floor(.X - )
		if  < .X {
			.X = 
		}
		 := math.Floor(.Y - )
		if  < .Y {
			.Y = 
		}
		 := math.Ceil(.X +  + )
		if  > .X {
			.X = 
		}
		 := math.Ceil(.Y +  + )
		if  > .Y {
			.Y = 
		}
	}
	return , 
}

// TODO: verify whether this correctly finds all overlapping ports.
func ( *Node) ( *Node) map[geo.Point]bool {
	 := make(map[geo.Point]bool)

	// Don't count container overlaps
	if .isDescendantOf() || .isDescendantOf() {
		return 
	}

	 := .ports()
	 := .ports()
	for ,  := range  {
		 := slices.Contains(, )
		if  {
			[] = true
		}
	}

	return 
}

type Nodes []*Node

func ( Nodes) ( *Node) bool {
	for ,  := range  {
		if  ==  {
			continue
		}
		if .TopLeft == nil {
			continue
		}
		if .TopLeft.X < .TopLeft.X {
			return false
		}
	}
	return true
}

func ( Nodes) ( *Node) bool {
	for ,  := range  {
		if  ==  {
			continue
		}
		if .TopLeft == nil {
			continue
		}
		if .TopLeft.Y < .TopLeft.Y {
			return false
		}
	}
	return true
}

func ( Nodes) ( *Node) bool {
	for ,  := range  {
		if  ==  {
			continue
		}
		if .TopLeft == nil {
			continue
		}
		if .TopLeft.X+.Width > .TopLeft.X+.Width {
			return false
		}
	}
	return true
}

func ( Nodes) ( *Node) bool {
	for ,  := range  {
		if  ==  {
			continue
		}
		if .TopLeft == nil {
			continue
		}
		if .TopLeft.Y+.Height > .TopLeft.Y+.Height {
			return false
		}
	}
	return true
}

func ( Nodes) () string {
	 := []string{}
	for ,  := range  {
		 = append(, .DebugID())
	}
	return "[" + strings.Join(, ", ") + "]"
}

func ( Nodes) ( *Graph) {
	for ,  := range  {
		.Graph = 
		for ,  := range .allDescendantNodes(, true) {
			.Graph = 
		}
	}
}

func ( Nodes) () int {
	 := 0
	for ,  := range  {
		 += len(.Edges)
	}
	return 
}

// 1. Algorithm is to seed clusters with nodes which connected/near and further than a threshold distance
// 2. Do recursive scans in the threshold distance perimeter
// ---- if the scan finds a node which is not part of a cluster, it becomes part of the scanning node's cluster
// ---- if the scan finds a node which is part of a cluster, that cluster is merged into the scanning node's cluster
func ( Nodes) ( float64) [][]*Node {
	,  := .clustersWithWorkGuard(, nil)
	if  != nil {
		panic()
	}
	return 
}

func ( Nodes) ( float64,  *limits.WorkGuard) ([][]*Node, error) {
	 := func( int64) error {
		if  == nil {
			return nil
		}
		return .Add()
	}
	 := func() error {
		if  == nil {
			return nil
		}
		return .Finish()
	}
	 := func( int) error {
		for  := 1;  < ;  *= 2 {
			if  := (int64());  != nil {
				return 
			}
			if  > /2 {
				break
			}
		}
		return nil
	}

	 := make(map[*Node]int)

	 := 0
	 := func( *Node) {
		if ,  := []; ! {
			 := 
			++
			[] = 
		}
	}

	 := make([]*Node, 0)
	 := func(,  *Node) {
		 := .distance(, true)
		if geo.PrecisionCompare(, , geo.PRECISION) > 0 {
			 = append(, , )
		}
	}
	// Step 1
	for ,  := range  {
		if  := (1 + int64(len(.Edges)) + int64(len(.Nears)));  != nil {
			return nil, 
		}
		for ,  := range .Edges {
			 := .adjacent()
			(, )
		}
		if  := (len(.Nears));  != nil {
			return nil, 
		}
		for ,  := range .orderedNears() {
			if .Cluster != nil {
				 = .Cluster.Vessel
			} else if .Sequence != nil {
				 = .Sequence.Vessel
			} else if ,  := .Graph.NodeToTree[];  {
				if  == nil {
					 = .root().sentinelNode()
				} else {
					for .Parent != nil {
						if  := .Step();  != nil {
							return nil, 
						}
						 = .Parent
					}
					 = .sentinelNode()
				}
			}
			if .Container != .Container {
				continue
			}
			(, )
		}
	}

	if len() < 2 {
		return nil, ()
	}

	// Step 2
	var  func( *Node) error
	 = func( *Node) error {
		if  := (int64(len()));  != nil {
			return 
		}
		 := []
		for ,  := range  {
			if  ==  {
				continue
			}
			if .FixedTopLeft != nil {
				continue
			}
			// TODO: consider caching this distance & comparison as it's the same computed a few lines above
			 := .distance(, true)
			if geo.PrecisionCompare(, , geo.PRECISION) > 0 {
				continue
			}
			,  := []
			if  &&  ==  {
				continue
			}

			[] = []
			if ! {
				if  := ();  != nil {
					return 
				}
			}
		}
		return nil
	}

	if  := (int64(len()));  != nil {
		return nil, 
	}
	for ,  := range  {
		if .FixedTopLeft != nil {
			continue
		}
		()
		if  := ();  != nil {
			return nil, 
		}
	}

	if  := (int64(len()));  != nil {
		return nil, 
	}
	if !.hasFixedNode() {
		if len() != len() {
			panic(fmt.Sprintf("Clustered nodes: %v. Total: %v", len(), len()))
		}
	}

	 := make(map[int][]*Node)
	if  := (int64(len()));  != nil {
		return nil, 
	}
	for ,  := range  {
		,  := []
		if ! {
			[] = make([]*Node, 0)
		}
		[] = append([], )
	}

	for ,  := range  {
		if  := (len());  != nil {
			return nil, 
		}
		sortNodesByID()
	}

	 := make([]int, 0, len())
	if  := (int64(len()));  != nil {
		return nil, 
	}
	for  := range  {
		 = append(, )
	}
	if  := (len());  != nil {
		return nil, 
	}
	sort.Ints()

	 := make([][]*Node, 0)
	if  := (int64(len()));  != nil {
		return nil, 
	}
	for ,  := range  {
		 = append(, [])
	}

	if  := ();  != nil {
		return nil, 
	}
	return , nil
}

func ( Nodes) () *geo.Point {
	,  := .bounds()
	return geo.NewPoint(.X+(.X-.X)/2, .Y+(.Y-.Y)/2)
}

func ( Nodes) ( *limits.WorkGuard) (*geo.Point, error) {
	, ,  := .boundsWithWorkGuard()
	if  != nil {
		return nil, 
	}
	return geo.NewPoint(.X+(.X-.X)/2, .Y+(.Y-.Y)/2), nil
}

func ( Nodes) () (*geo.Point, *geo.Point) {
	return .boundingBox(true)
}

func ( Nodes) ( *limits.WorkGuard) (*geo.Point, *geo.Point, error) {
	if len() == 0 {
		if  := .Finish();  != nil {
			return nil, nil, 
		}
		return geo.NewPoint(math.Inf(-1), math.Inf(-1)), geo.NewPoint(math.Inf(1), math.Inf(1)), nil
	}
	 := math.Inf(1)
	 := math.Inf(1)
	 := math.Inf(-1)
	 := math.Inf(-1)

	for ,  := range  {
		if  := .Step();  != nil {
			return nil, nil, 
		}
		if .TopLeft == nil {
			return nil, nil, nil
		}
		if .Label != nil && .Label.Position.IsOutside() {
			// An outside label can scan the complete peer set along each axis.
			if  := .Add(2 * int64(len()));  != nil {
				return nil, nil, 
			}
		}
		,  := .boundingBoxValues(, true)
		 = math.Min(, .X)
		 = math.Min(, .Y)
		 = math.Max(, .X)
		 = math.Max(, .Y)
	}

	if  := .Finish();  != nil {
		return nil, nil, 
	}
	return geo.NewPoint(, ), geo.NewPoint(, ), nil
}

func ( Nodes) () (*geo.Point, *geo.Point) {
	return .boundingBox(false)
}

func ( Nodes) ( bool) (*geo.Point, *geo.Point) {
	if len() == 0 {
		return geo.NewPoint(math.Inf(-1), math.Inf(-1)), geo.NewPoint(math.Inf(1), math.Inf(1))
	}
	 := math.Inf(1)
	 := math.Inf(1)
	 := math.Inf(-1)
	 := math.Inf(-1)

	for ,  := range  {
		if .TopLeft == nil {
			return nil, nil
		}
		,  := .boundingBoxValues(, )
		 = math.Min(, .X)
		 = math.Min(, .Y)
		 = math.Max(, .X)
		 = math.Max(, .Y)
	}

	return geo.NewPoint(, ), geo.NewPoint(, )
}

// for nodes in the same container, return the bounding box accounting for any fixed node offset
func ( Nodes) () (*geo.Point, *geo.Point) {
	,  := .bounds()
	if  := .fixedOrigin();  != nil {
		 = 
	}
	return , 
}

func ( Nodes) () (*geo.Point, *geo.Point) {
	,  := .unroundedBounds()
	if  := .fixedOrigin();  != nil {
		 = 
	}
	return , 
}

func ( Nodes) ( *Edge) bool {
	// Check for intersections on other nodes
	for ,  := range  {
		// Can intersect with a container if one endpoint is inside it
		if .From.isDescendantOf() {
			continue
		}
		if .To.isDescendantOf() {
			continue
		}

		for  := 0;  < len(.Points)-1; ++ {
			if .passesThrough(.Points[], .Points[+1]) {
				return true
			}
		}
	}
	return false
}

type Spacing struct {
	top, bottom, left, right float64
}

// Node positions and dimensions for shapes should always be whole numbers
// When used in OVGs for edge routing, they can take decimal values
type Node struct {
	D2ID *string
	ID   EntityID
	geo.Box
	Edges []*Edge
	// Nears is a list of nodes which this node wants to position itself close to one of
	// They're different from edges that have additional heuristics like alignment, symmetry, tree/cluster-formation, etc
	// And we don't reward being closer to all of them
	Nears    map[*Node]struct{}
	Graph    *Graph
	FontSize *int

	// This defines the snap points
	nodeshape.Shape
	shapeType nodeshape.Kind

	ForceHierarchy bool

	Container      *Node
	Cluster        *Cluster
	Sequence       *Sequence
	HerdAssignment *HerdAssignment
	Hierarchy      *Hierarchy

	Label *Label
	Icon  *Icon

	FixedTopLeft *geo.Point

	// The node should be be these dimensions, but containers can still grow to fit their children
	DesiredWidth  *float64
	DesiredHeight *float64

	// LoopOffsets contains the distance (offset) from the node bounding box
	// to loop borders as shown in the example below.
	// For diagonals, take the max of the coordinates: TopLeft=max(Top, Left)
	//         left
	//        |----|                right
	//      ┬ ┌─────────┐        |--------|
	//  top | │ ┌───────┤     ┌────┐
	//      ┴ │ │  ┌────▼─────┴──┐ a label
	//        │ │  │             ◄─┘
	//        └─┴──┤     node    │
	//             │             │
	//          ┌──►             │
	//          │  │             │
	// bottom ┬ │  └──┬──────────┘
	//        ┴ └─────┘
	LoopOffsets map[geo.Orientation]float64

	margin  Spacing
	padding Spacing

	isClusterVessel bool
	isContainer     bool

	// to adjust where connections are for 3d/multiple styles
	Is3D       bool
	IsMultiple bool

	// Connections can go through invisible nodes.
	// For example, opacity 0 grid cells used for spacing
	IsInvisible bool

	// LongDistanceNeighborRequirements records optimizer-derived parallel-edge
	// spacing by adjacent node.
	LongDistanceNeighborRequirements map[*Node]LongDistanceNeighborRequirements
}

func ( *Node) () string {
	if  == nil {
		return "nil"
	}
	if .D2ID != nil {
		return *.D2ID
	}
	if .isClusterVessel {
		return "Cluster vessel of: " + .Graph.Clusters[].DebugID()
	}
	if .Graph != nil && len(.Graph.Sequences) > 0 {
		if ,  := .Graph.Sequences[];  {
			return "Sequence vessel of: " + .DebugID()
		}
	}
	return strconv.FormatInt(.ID, 10)
}

func ( *Node) () int {
	if  == nil {
		return 0
	}
	if .Cluster.isActive() {
		return .Cluster.Vessel.()
	}
	if .Sequence.isActive() {
		return .Sequence.Vessel.()
	}
	return 1 + .Container.()
}

func ( *Node) ( *Edge) *Node {
	if  == .From {
		return .To
	}
	return .From
}

func ( EntityID, ,  float64) *Node {
	 := &Node{
		ID: ,
		Box: geo.Box{
			Width:  ,
			Height: ,
		},
	}
	.Edges = make([]*Edge, 0)
	.Nears = make(map[*Node]struct{})
	.SetShape("")
	return 
}

func ( *Node) () {
	.Icon = &Icon{}
}

func ( *Node) ( string) {
	// The shape retains this exact box pointer so its geometry follows node
	// moves and resizes.
	, ,  := nodeshape.New(, &.Box)
	if  {
		.Shape = 
		.shapeType = 
	}
}

// ShapeType reports the node's canonical shape type.
func ( *Node) () string {
	return .Shape.GetType()
}

// NumColumns reports the number of columns in a table-shaped node.
func ( *Node) () int {
	return nodeshape.NumColumns(.Shape)
}

func ( *Node) ( int) {
	nodeshape.SetNumColumns(.Shape, )
}

func ( *Node) ( *Node) {
	if  == nil ||  == nil ||  ==  {
		return
	}
	if .Nears == nil {
		.Nears = make(map[*Node]struct{})
	}
	if .Nears == nil {
		.Nears = make(map[*Node]struct{})
	}
	.Nears[] = struct{}{}
	.Nears[] = struct{}{}
}

func ( *Node) () EntityID {
	if  == nil {
		return 0
	}
	return .ID
}

func ( *Node) ( *Node,  *geo.Point) int {
	,  := .deltaToGuarded(, , nil)
	if  != nil {
		panic()
	}
	return 
}

func ( *Node) ( *Node,  *geo.Point,  workStepper) (int, error) {
	if  == nil ||  == nil ||  == nil {
		return 0, invariant.New("spacing check received incomplete nodes")
	}
	// n1 may have multiple edges to n2. We want to get the largest distance that we need to maintain
	 := math.MinInt
	 := math.MinInt
	 := false
	for ,  := range .Edges {
		if  != nil {
			if  := .Step();  != nil {
				return 0, 
			}
		}
		if  == nil || .From == nil || .To == nil {
			return 0, invariant.New("spacing check encountered an incomplete edge")
		}
		// TODO (Sun Apr 10 16:07:25 2022) this doesn't take edge abductions into consideration, so it may not find a minWidth to a child
		if .adjacent() ==  {
			 = true
			if .MinWidth >  {
				 = .MinWidth
			}
			if .MinHeight >  {
				 = .MinHeight
			}
		}
	}

	var ,  int
	if  {
		 = ConnectedNodeGap
		 = ConnectedNodeGap
	} else {
		 = NodeGap
		 = NodeGap
	}

	if .shapeType == tableType || .shapeType == tableType {
		 = TableNodeGap
	}

	if  >  {
		 = 
	}
	if  >  {
		 = 
	}

	// Ordinary unlabeled boxes often require the same gap in every direction.
	// In that case the orientation and directional-margin switches cannot
	// affect the result; retain the edge scan above for its validation and work.
	if  ==  && len(.LoopOffsets) == 0 && len(.LoopOffsets) == 0 &&
		.margin == (Spacing{}) && .margin == (Spacing{}) {
		return , nil
	}
	 := .orientationAtPoint(, )

	if len(.LoopOffsets) > 0 || len(.LoopOffsets) > 0 {
		 := NodeGap
		if len(.LoopOffsets) > 0 {
			 += int(.LoopOffsets[.GetOpposite()])
		}
		if len(.LoopOffsets) > 0 {
			 += int(.LoopOffsets[])
		}
		if  >  {
			 = 
		}
		if  >  {
			 = 
		}
	}

	var , , ,  int
	switch .GetOpposite() {
	case geo.Bottom:
		 = int(.margin.bottom)
	case geo.Top:
		 = int(.margin.top)
	case geo.Right:
		 = int(.margin.right)
	case geo.Left:
		 = int(.margin.left)
	case geo.BottomLeft:
		 = int(.margin.left)
		 = int(.margin.bottom)
	case geo.BottomRight:
		 = int(.margin.right)
		 = int(.margin.bottom)
	case geo.TopLeft:
		 = int(.margin.left)
		 = int(.margin.top)
	case geo.TopRight:
		 = int(.margin.right)
		 = int(.margin.top)
	}
	switch  {
	case geo.Bottom:
		 = int(.margin.bottom)
	case geo.Top:
		 = int(.margin.top)
	case geo.Right:
		 = int(.margin.right)
	case geo.Left:
		 = int(.margin.left)
	case geo.BottomLeft:
		 = int(.margin.left)
		 = int(.margin.bottom)
	case geo.BottomRight:
		 = int(.margin.right)
		 = int(.margin.bottom)
	case geo.TopLeft:
		 = int(.margin.left)
		 = int(.margin.top)
	case geo.TopRight:
		 = int(.margin.right)
		 = int(.margin.top)
	}
	if  < + {
		 =  + 
	}
	if  < + {
		 =  + 
	}

	switch  {
	case geo.Top, geo.Bottom:
		return , nil
	case geo.Left, geo.Right:
		return , nil
	default:
		if  <  {
			return , nil
		}
		return , nil
	}
}

func ( *Node) () {
	if .Label != nil && .Label.PositionFixed() {
		 := .Label.Width + 2*label.PADDING
		 := .Label.Height + 2*label.PADDING
		switch .Label.Position {
		case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
			.margin.top = 
		case label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight:
			.margin.bottom = 
		case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom:
			.margin.left = 
		case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
			.margin.right = 
		case label.InsideTopLeft, label.InsideTopCenter, label.InsideTopRight:
			.padding.top = 
		case label.InsideBottomLeft, label.InsideBottomCenter, label.InsideBottomRight:
			.padding.bottom = 
		case label.InsideMiddleLeft:
			.padding.left = 
		case label.InsideMiddleRight:
			.padding.right = 
		}
	}

	if .Icon != nil && .Icon.PositionFixed() {
		 := float64(MaxIconSize + 2*label.PADDING)
		switch .Icon.Position {
		case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
			.margin.top = math.Max(.margin.top, )
		case label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight:
			.margin.bottom = math.Max(.margin.bottom, )
		case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom:
			.margin.left = math.Max(.margin.left, )
		case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
			.margin.right = math.Max(.margin.right, )
		case label.InsideTopLeft, label.InsideTopCenter, label.InsideTopRight:
			.padding.top = math.Max(.padding.top, )
		case label.InsideBottomLeft, label.InsideBottomCenter, label.InsideBottomRight:
			.padding.bottom = math.Max(.padding.bottom, )
		case label.InsideMiddleLeft:
			.padding.left = math.Max(.padding.left, )
		case label.InsideMiddleRight:
			.padding.right = math.Max(.padding.right, )
		}
	}

	if ,  := .modifierElementAdjustments();  != 0 ||  != 0 {
		.margin.top += 
		.margin.right += 
	}
}

// . ┌────────────────┐
// . │        ┌───┐   │
// . │      A │ B │   │
// . │        └───┘   │
// . │  ┌─────────────┼──┐
// . └──┼───────C─────┘  │
// .    └────────────────┘
// A covers B but not C, B does not cover A
func ( *Node) ( *Node) bool {
	return covers(&.Box, &.Box)
}

// TODO move to d2 geo.Box
func covers(,  *geo.Box) bool {
	return (.TopLeft.X >= .TopLeft.X) &&
		(.TopLeft.Y >= .TopLeft.Y) &&
		(.TopLeft.X+.Width <= .TopLeft.X+.Width) &&
		(.TopLeft.Y+.Height <= .TopLeft.Y+.Height)
}

func ( *Node) ( *Node,  float64) bool {
	return boxesOverlapWithPadding(.Box, .Box, )
}

// boxesOverlapWithPadding reports whether the interiors of two axis-aligned
// boxes overlap, treating a gap smaller than padding as overlap. Boundary
// contact, including a gap exactly equal to padding, is not an overlap.
func boxesOverlapWithPadding(,  geo.Box,  float64) bool {
	 := .TopLeft.X + .Width
	 := .TopLeft.X + .Width
	if .TopLeft.X >= + || .TopLeft.X >= + {
		return false
	}

	 := .TopLeft.Y + .Height
	 := .TopLeft.Y + .Height
	return .TopLeft.Y < + && .TopLeft.Y < +
}

// DoesOverlapExact reports whether node boxes overlap without clearance padding.
func ( *Node) ( *Node) bool {
	return .doesOverlapCalc(, 0)
}

// doesOverlapAt returns whether placing n1 at p overlaps with n2
func ( *Node) ( *Node,  *geo.Point) bool {
	 := float64(.deltaTo(, ))
	 := geo.Box{TopLeft: , Width: .Width, Height: .Height}
	return boxesOverlapWithPadding(, .Box, )
}

func ( *Node) ( *Node) bool {
	 := float64(.deltaTo(, .TopLeft))
	return .doesOverlapCalc(, )
}

// for 2 overlapping nodes, return the area of the overlap
func ( *Node) ( *Node) float64 {
	// area of overlap is area of rect from middle 2 xs and middle 2 ys
	var ,  []float64

	 = append(, .TopLeft.X)
	 = append(, .TopLeft.X+.Width)
	 = append(, .TopLeft.Y)
	 = append(, .TopLeft.Y+.Height)

	 = append(, .TopLeft.X)
	 = append(, .TopLeft.X+.Width)
	 = append(, .TopLeft.Y)
	 = append(, .TopLeft.Y+.Height)

	slices.Sort()
	slices.Sort()

	 := [2] - [1]
	 := [2] - [1]

	return  * 
}

func sortNodesByID( []*Node) {
	if len() < 2 {
		return
	}
	sort.Slice(, func(,  int) bool {
		return [].entityID() < [].entityID()
	})
}

func ( *Node) ( *Edge) {
	.Edges = append(.Edges, )
}

func ( *Node) ( *Edge) {
	for ,  := range .Edges {
		if  ==  {
			.Edges = append(.Edges[:], .Edges[+1:]...)
			break
		}
	}
}

func ( *Node) ( *geo.Point) bool {
	return (((.TopLeft.X - MinRouteNodeClearance) <= .X) && ((.TopLeft.X + .Width + MinRouteNodeClearance) >= .X)) &&
		(((.TopLeft.Y - MinRouteNodeClearance) <= .Y) && ((.TopLeft.Y + .Height + MinRouteNodeClearance) >= .Y))
}

func ( *Node) ( *geo.Point) bool {
	return ((.TopLeft.X <= .X) && ((.TopLeft.X + .Width) >= .X)) &&
		((.TopLeft.Y <= .Y) && ((.TopLeft.Y + .Height) >= .Y))
}

func ( *Node) ( *Node,  bool) float64 {
	return distanceBetweenBoxes(nodeDistanceBox(, ), nodeDistanceBox(, ))
}

func nodeDistanceBox( *Node,  bool) geo.Box {
	 := geo.Box{TopLeft: .TopLeft}
	if  {
		.Width = .Width
		.Height = .Height
	}
	return 
}

// distanceBetweenBoxes returns the shortest Euclidean distance between two
// closed, axis-aligned boxes. Overlapping and touching boxes have distance 0.
func distanceBetweenBoxes(,  geo.Box) float64 {
	 := intervalGap(.TopLeft.X, .TopLeft.X+.Width, .TopLeft.X, .TopLeft.X+.Width)
	 := intervalGap(.TopLeft.Y, .TopLeft.Y+.Height, .TopLeft.Y, .TopLeft.Y+.Height)
	return geo.EuclideanDistance(0, 0, , )
}

func intervalGap(, , ,  float64) float64 {
	if  <  {
		return  - 
	}
	if  <  {
		return  - 
	}
	return 0
}

func ( *Node) ( *Node,  bool) bool {
	 := .distanceTo(, )
	if  {
		if  <= .Graph.CellSize {
			return true
		}
	} else {
		if  <= 1.0 {
			return true
		}
	}
	return false
}

func ( *Node) (,  *geo.Point) bool {
	if .TopLeft.X > .X {
		return false
	}
	if .TopLeft.Y > .Y {
		return false
	}
	if .TopLeft.X+.Width < .X {
		return false
	}
	if .TopLeft.Y+.Height < .Y {
		return false
	}

	return true
}

func ( *Node) ( *Node,  bool) float64 {
	 := 1.0 / 20.0

	 := math.Abs(.TopLeft.X - .TopLeft.X)
	 := math.Abs(.TopLeft.Y - .TopLeft.Y)

	if  {
		 := .Width
		 := .Height
		 := .Width
		 := .Height

		 = math.Abs((.TopLeft.X+/2)-(.TopLeft.X+/2)) / ( + )
		 = math.Abs((.TopLeft.Y+/2)-(.TopLeft.Y+/2)) / ( + )
	}

	return  * math.Min(, )
}

func ( *Node) (,  *Node, ,  bool) bool {
	// Check that node is in front of nodeA and behind nodeB (in between)
	// ----------
	if  {
		if  {
			if !((.TopLeft.X >= (.TopLeft.X + .Width)) && ((.TopLeft.X + .Width) <= .TopLeft.X)) {
				return false
			}
		} else {
			if !((.TopLeft.X >= .TopLeft.X) && (.TopLeft.X <= .TopLeft.X)) {
				return false
			}
		}
	} else {
		if  {
			if !((.TopLeft.Y >= (.TopLeft.Y + .Height)) && ((.TopLeft.Y + .Height) <= .TopLeft.Y)) {
				return false
			}
		} else {
			if !((.TopLeft.Y >= .TopLeft.Y) && (.TopLeft.Y <= .TopLeft.Y)) {
				return false
			}
		}
	}

	// Check that node blocks nodeA from nodeB
	// ----------
	if  {
		/**
		                   +----+
		           +       |    |
		+----+     |       |    |
		|    |     |       |    |
		|    |     |       |    |
		|    |     |       |    |
		|    |     |       +----+
		|    |     +
		+----+

		+----+
		|    |    +
		|    |    |
		|    |    |   +----+
		|    |    |   |    |
		|    |    |   |    |
		+----+    |   |    |
		          |   |    |
		          +   |    |
		              +----+
		*/

		if  {
			if (.TopLeft.Y <= math.Max(.TopLeft.Y, .TopLeft.Y)) &&
				((.TopLeft.Y + .Height) >= math.Min(.TopLeft.Y+.Height, .TopLeft.Y+.Height)) {
				return true
			}
		} else {
			if (.TopLeft.Y <= math.Max(.TopLeft.Y, .TopLeft.Y)) &&
				(.TopLeft.Y >= math.Min(.TopLeft.Y, .TopLeft.Y)) {
				return true
			}
		}
	} else {
		// Same as horizontal, just axis flipped
		if  {
			if (.TopLeft.X <= math.Max(.TopLeft.X, .TopLeft.X)) &&
				((.TopLeft.X + .Width) >= math.Min(.TopLeft.X+.Width, .TopLeft.X+.Width)) {
				return true
			}
		} else {
			if (.TopLeft.X <= math.Max(.TopLeft.X, .TopLeft.X)) &&
				(.TopLeft.X >= math.Min(.TopLeft.X, .TopLeft.X)) {
				return true
			}
		}
	}

	return false
}

func ( *Node) ( *Node,  bool) float64 {
	return .distanceTo(, ) + .distanceBetweenCenters(, )
}

// HAS TO BE DIAGONAL FROM EACH OTHER
func ( *Node) ( *Node) ( float64,  float64) {
	 := .TopLeft.X + .Width
	 := .TopLeft.Y + .Height
	 := .TopLeft.X + .Width
	 := .TopLeft.Y + .Height

	if .TopLeft.X < .TopLeft.X {
		 = math.Max(0, .TopLeft.X-)
	} else {
		 = math.Max(0, .TopLeft.X-)
	}

	if .TopLeft.Y < .TopLeft.Y {
		 = math.Max(0, .TopLeft.Y-)
	} else {
		 = math.Max(0, .TopLeft.Y-)
	}

	return , 
}

// 0 for not aligned at all
// 1 for fully aligned
// As a measure of alignment, 3 arrows are extended from the widest/tallest node
// Each hit is 0.33, scaled by size of node
// In this example,
// - the top node is widest
// - the middle node can only hit 1, so is 0.33*3 = 1
// - the bottom node can hit 2, so is 0.33*2 = 0.66
// - Total: 1.66/2 = 0.83
/*
//
//       ┌────────────────────────────┐
//       │                            │
//       │                            │
//       │     │         │        │   │
//       │     │         │        │   │
//       │     │         │        │   │
//       └─────┼─────────┼────────┼───┘
//             │         │        │
//             │      ┌──┼───┐    │
//             │      │  │   │    │
//             │      └──┼───┘    │
//             │         │        │
// ┌───────────┴──────┐  │        │
// │           ▼      │  ▼        ▼
// └──────────────────┘
*/
func ( *Node) () *geo.Point {
	return geo.NewPoint(.TopLeft.X+.Width/2, .TopLeft.Y+.Height/2)
}

func ( *Node) ( *Node, ,  bool) bool {
	if  {
		if  {
			if .TopLeft.Y > (.TopLeft.Y + .Height) {
				return false
			}
			if (.TopLeft.Y + .Height) < .TopLeft.Y {
				return false
			}
		} else {
			if .TopLeft.Y > .TopLeft.Y {
				return false
			}
			if .TopLeft.Y < .TopLeft.Y {
				return false
			}
		}
	} else {
		if  {
			if .TopLeft.X > (.TopLeft.X + .Width) {
				return false
			}
			if (.TopLeft.X + .Width) < .TopLeft.X {
				return false
			}
		} else {
			if .TopLeft.X > .TopLeft.X {
				return false
			}
			if .TopLeft.X < .TopLeft.X {
				return false
			}
		}
	}
	return true
}

// isVisibilityGraphCandidate checks for nodes which are in between given parameters node and otherNode
// a = node
// c = otherNode
// b = visible candidate given the padding
// .          ┌─────┐
// .          │  b  │
// .          └─────┘  ──┬─
// .                     │
// .                     │ padding
// . ┌─────┐           ──┴─ ┌────┐
// . │     │                │    │
// . │  a  │                │ c  │
// . └─────┘                └────┘
func ( *Node) (, ,  bool,  *Node,  float64) bool {
	if  {
		if  && (.TopLeft.X >= .TopLeft.X) {
			return false
		}
		if  {
			if .TopLeft.Y > (.TopLeft.Y + .Height + ) {
				return false
			}
			if (.TopLeft.Y + .Height + ) < .TopLeft.Y {
				return false
			}
		} else {
			if .TopLeft.Y > .TopLeft.Y {
				return false
			}
			if .TopLeft.Y < .TopLeft.Y {
				return false
			}
		}
	} else {
		if  && (.TopLeft.Y >= .TopLeft.Y) {
			return false
		}
		if  {
			if .TopLeft.X > (.TopLeft.X + .Width + ) {
				return false
			}
			if (.TopLeft.X + .Width + ) < .TopLeft.X {
				return false
			}
		} else {
			if .TopLeft.X > .TopLeft.X {
				return false
			}
			if .TopLeft.X < .TopLeft.X {
				return false
			}
		}
	}

	return true
}

func ( *Node) (,  *geo.Point) bool {
	return segmentIntersectsBox(, , &.Box)
}

// TODO: extract to `geo` package
func segmentIntersectsBox(,  *geo.Point,  *geo.Box) bool {
	if  == nil ||  == nil ||  == nil || .TopLeft == nil {
		return false
	}

	,  := .TopLeft.X, .TopLeft.X+.Width
	if  >  {
		,  = , 
	}
	,  := .TopLeft.Y, .TopLeft.Y+.Height
	if  >  {
		,  = , 
	}
	// A NaN box boundary cannot contain a point or survive the clipping below.
	// Handle it explicitly so ordered comparisons can replace math.Min/Max in
	// the broad phase without changing their special-value behavior.
	if  !=  ||  !=  ||  !=  ||  !=  {
		return false
	}

	// Reject a segment only when both endpoints lie outside the same box side.
	// This is the same bounding-box test without sorting the segment endpoints
	// or calling the general-purpose NaN-aware math.Min/Max helpers per blocker.
	if (.X <  && .X < ) || (.X >  && .X > ) ||
		(.Y <  && .Y < ) || (.Y >  && .Y > ) {
		return false
	}

	 := func( *geo.Point) bool {
		return  <= .X && .X <=  &&  <= .Y && .Y <= 
	}
	if () || () {
		return true
	}

	// Clip the segment against the closed box. Both endpoints are outside here,
	// so a zero-length clipped interval is a single-point tangency rather than a
	// crossover. We allow that case, while a positive-length interval means the
	// segment crosses the box or overlaps one of its boundaries.
	,  := 0.0, 1.0
	 := func(, , ,  float64) bool {
		if  == 0 {
			return  <=  &&  <= 
		}
		 := ( - ) / 
		 := ( - ) / 
		if  >  {
			,  = , 
		}
		 = math.Max(, )
		 = math.Min(, )
		return  <= 
	}

	if !(.X, .X-.X, , ) ||
		!(.Y, .Y-.Y, , ) {
		return false
	}
	return  < 
}

// orientation returns a positive value for a clockwise turn, a negative value
// for a counter-clockwise turn, and zero for collinear points.
func orientation(, ,  *geo.Point) float64 {
	 := .X - .X
	 := .Y - .Y
	 := .X - .X
	 := .Y - .Y
	return * - *
}

func intersects(, , ,  *geo.Point) bool {
	 := orientation(, , )
	 := orientation(, , )
	 := orientation(, , )
	 := orientation(, , )

	if  == 0 &&  == 0 &&  == 0 &&  == 0 {
		return closedIntervalsOverlap(.X, .X, .X, .X) &&
			closedIntervalsOverlap(.Y, .Y, .Y, .Y)
	}

	return straddlesLine(, ) && straddlesLine(, )
}

func straddlesLine(,  float64) bool {
	return  == 0 ||  == 0 || ( < 0) != ( < 0)
}

func closedIntervalsOverlap(, , ,  float64) bool {
	,  := math.Min(, ), math.Max(, )
	,  := math.Min(, ), math.Max(, )
	return  <=  &&  <= 
}

// return true if the point is within the node's bounding box with delta padding
// Example: A: false; B: true; C: true; D: false; E: true
// delta       delta
// ├──┤  A     ├──┤
// ┌──────────────┐ ┬
// │ B            │ │ delta
// │   ┌─node─┐   │ ┴
// │   │  C   │   │   D
// │   └──────┘   │ ┬
// │              │ │ delta
// └───────────E──┘ ┴
func ( *Node) ( *geo.Point,  float64) bool {
	return .TopLeft.X- <= .X &&
		.TopLeft.X+.Width+ >= .X &&
		.TopLeft.Y- <= .Y &&
		.TopLeft.Y+.Height+ >= .Y
}

// return true if the line overlaps the node bounding box
func ( *Node) (,  *geo.Point,  float64) bool {
	if .containsPoint(, ) || .containsPoint(, ) {
		return true
	}

	 := .TopLeft.X - 
	 := .TopLeft.X + .Width + 
	 := .TopLeft.Y - 
	 := .TopLeft.Y + .Height + 

	 := geo.NewPoint(, )
	 := geo.NewPoint(, )
	 := geo.NewPoint(, )
	 := geo.NewPoint(, )

	return intersects(, , , ) ||
		intersects(, , , ) ||
		intersects(, , , ) ||
		intersects(, , , )
}

func ( *Node) ( *Node,  float64) bool {
	if  == nil {
		return true
	}
	return .TopLeft.X+ < .TopLeft.X &&
		.TopLeft.X+.Width- > .TopLeft.X+.Width &&
		.TopLeft.Y+ < .TopLeft.Y &&
		.TopLeft.Y+.Height- > .TopLeft.Y+.Height
}

// orientation returns the orientation of node relative to otherNode.
// E.g. node ---> otherNode, here, node is to the left of otherNode, so Left would be returned
func ( *Node) ( *Node) geo.Orientation {
	if .TopLeft == nil || .TopLeft == nil {
		return geo.NONE
	}
	if (.TopLeft.Y + .Height) < .TopLeft.Y {
		if (.TopLeft.X + .Width) < .TopLeft.X {
			return geo.TopLeft
		}
		if (.TopLeft.X + .Width) < .TopLeft.X {
			return geo.TopRight
		}
		return geo.Top
	}

	if (.TopLeft.Y + .Height) < .TopLeft.Y {
		if (.TopLeft.X + .Width) < .TopLeft.X {
			return geo.BottomLeft
		}
		if (.TopLeft.X + .Width) < .TopLeft.X {
			return geo.BottomRight
		}
		return geo.Bottom
	}

	if (.TopLeft.X + .Width) < .TopLeft.X {
		return geo.Right
	}

	if (.TopLeft.X + .Width) < .TopLeft.X {
		return geo.Left
	}

	return geo.NONE
}

func ( *Node) ( *Node,  *geo.Point) geo.Orientation {
	// This is an optimized version that doesn't temporarily modify node's position
	if  == nil || .TopLeft == nil {
		return geo.NONE
	}

	// Simulate node being at point instead of its actual position
	// Same logic as orientation but with point coordinates instead of node.TopLeft
	if (.Y + .Height) < .TopLeft.Y {
		if (.X + .Width) < .TopLeft.X {
			return geo.TopLeft
		}
		if (.TopLeft.X + .Width) < .X {
			return geo.TopRight
		}
		return geo.Top
	}

	if (.TopLeft.Y + .Height) < .Y {
		if (.X + .Width) < .TopLeft.X {
			return geo.BottomLeft
		}
		if (.TopLeft.X + .Width) < .X {
			return geo.BottomRight
		}
		return geo.Bottom
	}

	if (.TopLeft.X + .Width) < .X {
		return geo.Right
	}

	if (.X + .Width) < .TopLeft.X {
		return geo.Left
	}

	return geo.NONE
}

// allReachableNodesGuarded returns all connected nodes in BFS order
// This includes itself at index 0
func ( *Node) (
	, ,  bool,
	 map[*Node]struct{},
	 workStepper,
) ([]*Node, error) {
	return .reachableNodesGuarded(
		func( *Node) bool { return true },
		,
		,
		,
		,
		,
	)
}

// reachabilityIsDescendantOf preserves isDescendantOf's ancestry precedence
// while charging every parent hop. Container reachability compares many node
// pairs, so charging only the pair and not these walks leaves a deep hierarchy
// able to bypass the operation's aggregate budget.
func reachabilityIsDescendantOf(
	,  *Node,
	 workStepper,
) (bool, error) {
	if  == nil {
		return false, fmt.Errorf("TALA reachability ancestry requires a work guard")
	}
	for  := ; ;  = ancestryParent() {
		if  := .Step();  != nil {
			return false, 
		}
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
	}
}

func ( *Node) (
	 func(*Node) bool,
	, ,  bool,
	 map[*Node]struct{},
	 workStepper,
) ([]*Node, error) {
	 := make([]*Node, 0)
	 := []*Node{}

	 := map[*Node]struct{}{
		: {},
	}

	 := func( *Node) {
		if ,  := [];  {
			return
		}
		if ,  := [];  {
			return
		}
		if !() {
			return
		}
		[] = struct{}{}
		 = append(, )
	}

	for len() > 0 {
		if  := .Step();  != nil {
			return nil, 
		}
		 := [0]
		 = [1:]
		 := true
		if  {
			if ,  := .Graph.NodeToTree[];  {
				 = false
			}
		}
		if  {
			 = append(, )
		}
		[] = struct{}{}

		for ,  := range .Edges {
			if  := .Step();  != nil {
				return nil, 
			}
			 := .adjacent()
			()
		}

		if  {
			if ,  := .Graph.Trees[];  {
				for ,  := range  {
					if  := .Step();  != nil {
						return nil, 
					}
					(.Node)
				}
			} else if ,  := .Graph.NodeToTree[];  {
				if .Parent != nil {
					(.Parent.Node)
				} else {
					(.sentinelNode())
				}
				for ,  := range .Children {
					if  := .Step();  != nil {
						return nil, 
					}
					(.Node)
				}
			}
		}
		if  {
			 := .orderedNears()
			if .isClusterVessel {
				for ,  := range .Graph.Clusters[].Nodes {
					 = append(, .orderedNears()...)
				}
			}
			for ,  := range  {
				if  := .Step();  != nil {
					return nil, 
				}
				if .Cluster.isActive() {
					 = .Cluster.Vessel
				} else if .Sequence.isActive() {
					 = .Sequence.Vessel
				}
				if .Container != .Container {
					continue
				}
				()
			}
		}

		if  {
			if .Sequence != nil {
				for ,  := range .Sequence.Nodes {
					if  := .Step();  != nil {
						return nil, 
					}
					()
				}
			}
			if .isClusterVessel {
				for ,  := range .Graph.Clusters[].Nodes {
					if  := .Step();  != nil {
						return nil, 
					}
					()
				}
			}

			for ,  := range .Graph.Nodes {
				if  := .Step();  != nil {
					return nil, 
				}
				if ,  := [];  {
					continue
				}
				,  := reachabilityIsDescendantOf(, , )
				if  != nil {
					return nil, 
				}
				if ! {
					,  = reachabilityIsDescendantOf(, , )
					if  != nil {
						return nil, 
					}
				}
				if  {
					()
				}
			}
		}
	}
	return , nil
}

func ( *Node) ( *Node) *Edge {
	for ,  := range .Edges {
		if .adjacent() ==  {
			return 
		}
	}
	return nil
}

// spillsOutOfNode detects whether the node has both
// a corner inside the container and a corner outside the container node
func ( *Node) ( *Node) bool {
	 := []*geo.Point{
		.TopLeft,
		geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y),
		geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y+.Height),
		geo.NewPoint(.TopLeft.X, .TopLeft.Y+.Height),
	}

	 := false
	 := false

	for ,  := range  {
		if .isPointOnNode() {
			 = true
		} else {
			 = true
		}
	}

	return  && 
}

// connectedNodes returns all nodes (including this one) that should move with it.
// This includes nodes with a path to it, nodes in the same container
// TODO for some reason e.From.Graph isn't populated with containers, so we pass mainGraph instead
func ( *Node) ( []*Node,  *Graph) []*Node {
	 := make([]*Node, 0)
	 := []*Node{}
	 := map[*Node]bool{: true}

	 := make(map[*Node]bool)
	for ,  := range  {
		[] = true
	}

	 := func( *Node) {
		if ,  := []; ! {
			 = append(, )
			[] = true
		}
	}

	for len() > 0 {
		 := [0]
		 = [1:]
		 := false
		for ,  := range  {
			if .isDescendantOf() {
				 = true
				break
			}
			if .isDescendantOf() && !.isDescendantOf() {
				 = true
				break
			}
		}
		if  {
			continue
		}
		 = append(, )
		for ,  := range .Edges {
			 := .adjacent()
			if ,  := [];  {
				continue
			}
			()
		}

		// If the current is a cluster vessel, a cluster node may be a container, which we should include the children of
		if .isClusterVessel {
			for ,  := range .Clusters[].Nodes {
				if .isContainer {
					for ,  := range .Containers[] {
						()
					}
				}
			}
		}

		// If the current is a child of a cluster node container, we should include that cluster vessel
		for ,  := range .Clusters {
			for ,  := range .Nodes {
				if .isContainer {
					 := false
					 := false
					for ,  := range .Containers[] {
						if  ==  {
							 = true
						}
						if ,  := [];  {
							 = true
							break
						}
					}
					if  {
						continue
					}
					if  {
						()
					}
				}
			}
		}

		for  := range .Containers {
			if  == nil {
				continue
			}
			if ,  := [];  {
				continue
			}

			// If the node is part a container, include the container (which will include all children downstream) ...
			 := false
			 := false

			for ,  := range .Containers[] {
				if  ==  {
					 = true
				}
				if ,  := [];  {
					 = true
					break
				}
			}
			// ... unless an excluded node is also within that container
			if  {
				continue
			}
			if  {
				()
			}

			// If the node is a container, everything within it is included
			if  ==  {
				for ,  := range .Containers[] {
					()
				}
			}
		}
	}

	return 
}

func ( *Node) () float64 {
	return .Width * .Height
}

// LabelTopLeft returns the top-left point for a label of the given size and
// position relative to node.
func ( *Node) ( label.Position, ,  float64) *geo.Point {
	var  *geo.Box
	if .IsOutside() {
		 = .GetBox()
	} else {
		 = .InnerBox()
	}

	return .GetPointOnBox(, label.PADDING, , )
}

// NodeOverlapCount reports how many nodes overlap node within delta.
func ( *Node) ( Nodes,  float64) int {
	 := 0
	for ,  := range  {
		if .doesOverlapCalc(, ) {
			++
		}
	}
	return 
}

func ( Node) () []geo.Point {
	 := make([]geo.Point, 0, 12)
	for ,  := range .SnapPointPercentages() {
		for ,  := range  {
			 = append(, *geo.NewPoint(.TopLeft.X+math.Round(.Width*.XPercentage), .TopLeft.Y+math.Round(.Height*.YPercentage)))
		}
	}
	return 
}

func ( Node) ( int) (geo.Point, bool) {
	 := 0
	for ,  := range .SnapPointPercentages() {
		for ,  := range  {
			if  ==  {
				return geo.Point{
					X: .TopLeft.X + math.Round(.Width*.XPercentage),
					Y: .TopLeft.Y + math.Round(.Height*.YPercentage),
				}, true
			}
			++
		}
	}
	return geo.Point{}, false
}

func ( Node) ( int) *geo.Point {
	,  := .nthPortValue()
	if ! {
		return nil
	}
	return &
}

func ( Node) ( *geo.Point) geo.Orientation {
	for ,  := range []geo.Orientation{geo.Top, geo.Right, geo.Left, geo.Bottom} {
		 := .PortIndices()
		for ,  := range  {
			 := .nthPort()
			if .Equals() {
				return 
			}
		}
	}
	return geo.NONE
}

func ( Node) ( geo.Orientation,  int) (geo.Point, bool) {
	 := .PortIndices()
	return .nthPortValue([])
}

func ( Node) ( geo.Orientation,  int) (geo.Point, bool) {
	if ,  := nodeshape.TableColumnPortValue(.Shape, , );  {
		return , true
	}
	return .nthPortOnSideValue(, )
}

func ( Node) () []geo.Point {
	 := .ports()
	 := .CenterPortIndices()

	 := make([]geo.Point, 0, len())
	for ,  := range  {
		 = append(, [])
	}
	return 
}

func ( Node) ( geo.Orientation) []geo.Point {
	 := .ports()
	 := .PortIndices()

	 := make([]geo.Point, 0, len())
	for ,  := range  {
		 = append(, [])
	}
	return 
}

func ( Node) () map[geo.Point]geo.Point {
	 := .ports()

	 := make(map[geo.Point]geo.Point)
	for ,  := range .MirroredPortIndices() {
		[[]] = []
	}
	return 
}

func ( *Node) (,  bool) {
	// When mirroring, we need to consider the loop offsets
	// otherwise, the node bounding box can change can end up in the wrong position.
	// In the example below, note how before mirroring, both nodes have their bounding boxes aligned at the same Y coodinate.
	// After mirroring, the node with a loop offset got a different Y coodinate misaligning the nodes.
	// In order to get the right bounding box after mirroring, it needs to account for the given offset
	// y = node.TopLeft.Y
	// h = node.Height
	// after mirror
	//         ┌────────┐
	//         │        │
	//     ┬   │   ┌────┴───────┐      ┌────────────────┐
	//     |   │   │            │      │                │
	//  -h |   └───►            │      │                │
	//     |       │            │      │                │
	//     ┴      -y────────────┘      │                │
	//                                 │                │
	//                                 └────────────────┘
	// ───────────────────────────────────────────────────────────── mirror axis
	// before mirror
	//         ┌────────┐              ┌────────────────┐
	//         │        │              │                │
	//     ┬   │   y────┴───────┐      │                │
	//     |   │   │            │      │                │
	//   h |   └───►            │      │                │
	//     |       │            │      │                │
	//     ┴       └────────────┘      └────────────────┘
	// the same applies when mirroring over the X axis
	var , , ,  float64
	if len(.LoopOffsets) > 0 {
		 = .LoopOffsets[geo.Top]
		 = .LoopOffsets[geo.Left]
		 = .LoopOffsets[geo.Right]
		 = .LoopOffsets[geo.Bottom]
	}
	if  {
		.TopLeft.X = -.TopLeft.X - .Width +  - 
	}
	if  {
		.TopLeft.Y = -.TopLeft.Y - .Height +  - 
	}
}

func ( *Node) (,  float64) {
	if .TopLeft != nil && .TopLeft.X ==  && .TopLeft.Y ==  {
		return
	}
	.moveNodeWithChildren(-.TopLeft.X, -.TopLeft.Y)
}

func ( *Node) (,  float64) {
	if  == 0 &&  == 0 {
		return
	}
	.translate(, )
	for ,  := range .Graph.allDescendantNodes(, true) {
		.translate(, )
	}
}

func ( *Node) (,  float64) {
	.TopLeft.X += 
	.TopLeft.Y += 
}

func ( *Node) ( bool) {
	var  Nodes
	if !.isContainer {
		return
	}
	 = .Graph.Containers[]
	var  Spacing
	if  {
		 = .Graph.containerPadding(, false)
	}
	,  := .fixedBounds()
	.expandForLabels(, )
	 := .InsidePlacement(.X-.X, .Y-.Y, )
	 := .X - .X
	 := .Y - .Y
	for ,  := range  {
		.moveNodeWithChildren(, )
	}
}

func ( Node) () bool {
	return .shapeType != imageType &&
		.shapeType != codeType &&
		.shapeType != tableType &&
		.shapeType != classType &&
		.shapeType != textType
}

// Make enough room for label to be center positioned
// Even though labels are placed at the last step, the most common is for long labels to be outside centered top or bottom.
// So we pre-emptively make enough room for it.
func ( *Node) (,  *geo.Point) {
	 := .Graph.Containers[]

	for ,  := range  {
		if .Label != nil && (.TopLeft.X == .X || .TopLeft.X+.Width == .X) {
			if .Label.Width > .Width {
				.X = math.Min(.X, math.Floor(.TopLeft.X+(.Width/2.-.Label.Width/2.)))
				.X = math.Max(.X, math.Ceil(.TopLeft.X+.Width-(.Width/2.-.Label.Width/2.)))
			}
		}
	}
}

func ( *Node) () {
	var  Nodes
	if !.isContainer {
		return
	}
	 = .Graph.Containers[]
	 := .Graph.containerPadding(, false)
	,  := .fixedBounds()
	.expandForLabels(, )
	.fitToBoundingBox(, , )
	 := .InsidePlacement(.X-.X, .Y-.Y, )
	.translate(.X-.X, .Y-.Y)
}

// InsidePlacement returns the top-left point at which content of the given
// size and padding fits inside n.
func ( *Node) (,  float64,  Spacing) geo.Point {
	 := .left + .right
	 := .top + .bottom
	// TODO update d2's GetInsidePlacement to take Spacing
	 := .Shape.GetInsidePlacement(, , , )

	if .Shape.GetType() == shape.CIRCLE_TYPE {
		 :=  + 
		 :=  + 

		 := .Shape.GetInnerBox()
		if .Width >  {
			.X += (.Width - ) / 2.
		}
		if .Height >  {
			.Y += (.Height - ) / 2.
		}
	}

	// always round the results from shape
	.X = math.Round(.X)
	.Y = math.Round(.Y)
	.X -= math.Round(/2) - .left
	.Y -= math.Round(/2) - .top
	return 
}

// InnerBox returns n's rounded content box.
func ( *Node) () *geo.Box {
	// always round the results from shape
	 := .Shape.GetInnerBox()
	return &geo.Box{
		TopLeft: &geo.Point{
			X: math.Round(.TopLeft.X),
			Y: math.Round(.TopLeft.Y),
		},
		Width:  math.Round(.Width),
		Height: math.Round(.Height),
	}
}

func ( *Node) () bool {
	var  int
	for ,  := range .Edges {
		if .isDirected() {
			if .isTargetedTo() {
				++
			} else {
				--
			}
		}
	}
	return  > 0
}

// IconSize returns the icon size appropriate for iconPosition on n.
func ( *Node) ( label.Position) float64 {
	 := math.Min(.Width, .Height)
	var  float64
	if  == label.InsideMiddleCenter {
		 = 0.5 * 
	} else {
		 = math.Min(, math.Max(defaultIconSize, 0.5*))
	}
	 = math.Min(, MaxIconSize)

	if !.IsOutside() {
		 := .InnerBox()
		 = math.Min(math.Max(0, .Width-2*label.PADDING), )
		 = math.Min(math.Max(0, .Height-2*label.PADDING), )
	}
	return 
}

func ( *Node) () []*Node {
	var  []*Node
	for  := range .Nears {
		 = append(, )
	}
	sortNodesByID()
	return 
}

func ( *Node) ( func(*Node) ( bool)) bool {
	if () {
		// stop early if apply returns true
		return true
	}

	if .isContainer {
		for ,  := range .Graph.Containers[] {
			if .() {
				return true
			}
		}
	}

	if .isClusterVessel {
		for ,  := range .Graph.Clusters[].Nodes {
			if .() {
				return true
			}
		}
	} else if ,  := .Graph.Sequences[];  {
		for ,  := range .Nodes {
			if .() {
				return true
			}
		}
	}
	return false
}

func ( *Node) ( func(*Node)) {
	if .isContainer {
		for ,  := range .Graph.Containers[] {
			.()
		}
	}

	if .isClusterVessel {
		for ,  := range .Graph.Clusters[].Nodes {
			.()
		}
	} else if ,  := .Graph.Sequences[];  {
		for ,  := range .Nodes {
			.()
		}
	}

	()
}

func ( *Node) () *Node {
	if .Cluster.isActive() {
		return .Cluster.Vessel.Container
	} else if .Sequence.isActive() {
		return .Sequence.Vessel.Container
	} else {
		return .Container
	}
}

func ( *Node) () int {
	 := 0
	for  := ;  != nil;  = .container() {
		++
	}
	return 
}

// returns the most nested container that is an ancestor of both n and otherNode
// In this example X.nearestSharedAncestor(Y) returns B.
// C, D, and E are nearer to the nodes X and Y, but are not a shared ancestor.
// A and nil are shared ancestors, but are further than B.
// ┌A───────────────────────────────────────────┐
// │  ┌B─────────────────────────────────────┐  │
// │  │                ┌D─────────────────┐  │  │
// │  │  ┌C─────────┐  │                  │  │  │
// │  │  │          │  │  ┌E───────────┐  │  │  │
// │  │  │  ┌────┐  │  │  │  ┌──────┐  │  │  │  │
// │  │  │  │ X  │  │  │  │  │ Y    │  │  │  │  │
// │  │  │  │    │  │  │  │  │      │  │  │  │  │
// │  │  │  └────┘  │  │  │  └──────┘  │  │  │  │
// │  │  │          │  │  └────────────┘  │  │  │
// │  │  └──────────┘  │                  │  │  │
// │  │                └──────────────────┘  │  │
// │  └──────────────────────────────────────┘  │
// └────────────────────────────────────────────┘
func ( *Node) ( *Node) *Node {
	 := .container()
	 := .container()
	if  == nil ||  == nil {
		return nil
	}
	 := .containerLevel()
	 := .containerLevel()

	for  !=  {
		if  ==  {
			 = .container()
			--
			 = .container()
			--
		} else if  >  {
			 = .container()
			--
		} else {
			 = .container()
			--
		}
		if  == nil ||  == nil {
			return nil
		}
	}
	return 
}

func ( *Node) () {
	.Width, .Height = .Height, .Width
	.TopLeft.Transpose()
	.padding.left, .padding.top = .padding.top, .padding.left
	.padding.right, .padding.bottom = .padding.bottom, .padding.right
	.margin.left, .margin.top = .margin.top, .margin.left
	.margin.right, .margin.bottom = .margin.bottom, .margin.right
}

// ContainerDirection reports the layout direction of n's owning container.
func ( *Node) () geo.Orientation {
	return .Graph.Direction(.container())
}

func ( *Node) ( int) {
	 := float64()
	.translate(-, -)
	.Width += 2 * 
	.Height += 2 * 
}

func ( *Node) () (,  float64) {
	if .Is3D {
		if .shapeType == hexagonType {
			 = threeDOffset / 2
		} else {
			 = threeDOffset
		}
		 = threeDOffset
	} else if .IsMultiple {
		 = multipleOffset
		 = multipleOffset
	}
	return , 
}