...

Source file src/oss.terrastruct.com/d2/lib/shape/shape_cylinder.go

Documentation: oss.terrastruct.com/d2/lib/shape

     1  package shape
     2  
     3  import (
     4  	"math"
     5  
     6  	"oss.terrastruct.com/d2/lib/geo"
     7  	"oss.terrastruct.com/d2/lib/svg"
     8  	"oss.terrastruct.com/util-go/go2"
     9  )
    10  
    11  type shapeCylinder struct {
    12  	*baseShape
    13  }
    14  
    15  const (
    16  	defaultArcDepth = 24.
    17  )
    18  
    19  func NewCylinder(box *geo.Box) Shape {
    20  	shape := shapeCylinder{
    21  		baseShape: &baseShape{
    22  			Type: CYLINDER_TYPE,
    23  			Box:  box,
    24  		},
    25  	}
    26  	shape.FullShape = go2.Pointer(Shape(shape))
    27  	return shape
    28  }
    29  
    30  func getArcHeight(box *geo.Box) float64 {
    31  	arcHeight := defaultArcDepth
    32  	// Note: box height should always be larger than 3*default
    33  	// this just handles after collapsing into an oval
    34  	if box.Height < arcHeight*2 {
    35  		arcHeight = box.Height / 2.0
    36  	}
    37  	return arcHeight
    38  }
    39  
    40  func (s shapeCylinder) GetInnerBox() *geo.Box {
    41  	height := s.Box.Height
    42  	tl := s.Box.TopLeft.Copy()
    43  	arc := getArcHeight(s.Box)
    44  	height -= 3 * arc
    45  	tl.Y += 2 * arc
    46  	return geo.NewBox(tl, s.Box.Width, height)
    47  }
    48  
    49  func cylinderOuterPath(box *geo.Box) *svg.SvgPathContext {
    50  	arcHeight := getArcHeight(box)
    51  	multiplier := 0.45
    52  	pc := svg.NewSVGPathContext(box.TopLeft, 1, 1)
    53  	pc.StartAt(pc.Absolute(0, arcHeight))
    54  	pc.C(false, 0, 0, box.Width*multiplier, 0, box.Width/2, 0)
    55  	pc.C(false, box.Width-box.Width*multiplier, 0, box.Width, 0, box.Width, arcHeight)
    56  	pc.V(true, box.Height-arcHeight*2)
    57  	pc.C(false, box.Width, box.Height, box.Width-box.Width*multiplier, box.Height, box.Width/2, box.Height)
    58  	pc.C(false, box.Width*multiplier, box.Height, 0, box.Height, 0, box.Height-arcHeight)
    59  	pc.V(true, -(box.Height - arcHeight*2))
    60  	pc.Z()
    61  	return pc
    62  }
    63  
    64  func cylinderInnerPath(box *geo.Box) *svg.SvgPathContext {
    65  	arcHeight := getArcHeight(box)
    66  	multiplier := 0.45
    67  	pc := svg.NewSVGPathContext(box.TopLeft, 1, 1)
    68  	pc.StartAt(pc.Absolute(0, arcHeight))
    69  	pc.C(false, 0, arcHeight*2, box.Width*multiplier, arcHeight*2, box.Width/2, arcHeight*2)
    70  	pc.C(false, box.Width-box.Width*multiplier, arcHeight*2, box.Width, arcHeight*2, box.Width, arcHeight)
    71  	return pc
    72  }
    73  
    74  func (s shapeCylinder) Perimeter() []geo.Intersectable {
    75  	return cylinderOuterPath(s.Box).Path
    76  }
    77  
    78  func (s shapeCylinder) GetSVGPathData() []string {
    79  	return []string{
    80  		cylinderOuterPath(s.Box).PathData(),
    81  		cylinderInnerPath(s.Box).PathData(),
    82  	}
    83  }
    84  
    85  func (s shapeCylinder) GetDimensionsToFit(width, height, paddingX, paddingY float64) (float64, float64) {
    86  	// 2 arcs top, height + padding, 1 arc bottom
    87  	totalHeight := height + paddingY + 3*defaultArcDepth
    88  	return math.Ceil(width + paddingX), math.Ceil(totalHeight)
    89  }
    90  
    91  func (s shapeCylinder) GetDefaultPadding() (paddingX, paddingY float64) {
    92  	return defaultPadding, defaultPadding / 2
    93  }
    94  

View as plain text