Merge pull request #790 from gavin-ts/fix-shape-get-inside-placement

fix shape get inside placement
This commit is contained in:
gavin-ts 2023-02-10 16:40:21 -08:00 committed by GitHub
commit 088ba0f4a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 117 additions and 41 deletions

View file

@ -863,6 +863,11 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
}
}
// to examine GetInsidePlacement
// padX, padY := s.GetDefaultPadding()
// innerTL := s.GetInsidePlacement(s.GetInnerBox().Width, s.GetInnerBox().Height, padX, padY)
// fmt.Fprint(writer, renderOval(&innerTL, 5, 5, "fill:red;"))
// Closes the class=shape
fmt.Fprint(writer, `</g>`)

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
const (
@ -46,7 +47,7 @@ type Shape interface {
GetInnerBox() *geo.Box
// placing a rectangle of the given size and padding inside the shape, return the position relative to the shape's TopLeft
GetInsidePlacement(width, height, padding float64) geo.Point
GetInsidePlacement(width, height, paddingX, paddingY float64) geo.Point
GetDimensionsToFit(width, height, paddingX, paddingY float64) (float64, float64)
GetDefaultPadding() (paddingX, paddingY float64)
@ -58,8 +59,9 @@ type Shape interface {
}
type baseShape struct {
Type string
Box *geo.Box
Type string
Box *geo.Box
FullShape *Shape
}
func (s baseShape) Is(shapeType string) bool {
@ -86,8 +88,9 @@ func (s baseShape) GetInnerBox() *geo.Box {
return s.Box
}
func (s baseShape) GetInsidePlacement(_, _, padding float64) geo.Point {
return *geo.NewPoint(s.Box.TopLeft.X+padding, s.Box.TopLeft.Y+padding)
func (s baseShape) GetInsidePlacement(_, _, paddingX, paddingY float64) geo.Point {
innerTL := (*s.FullShape).GetInnerBox().TopLeft
return *geo.NewPoint(innerTL.X+paddingX/2, innerTL.Y+paddingY/2)
}
// return the minimum shape dimensions needed to fit content (width x height)
@ -156,12 +159,14 @@ func NewShape(shapeType string, box *geo.Box) Shape {
return NewText(box)
default:
return shapeSquare{
shape := shapeSquare{
baseShape: &baseShape{
Type: shapeType,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
}

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeCallout struct {
@ -17,12 +18,14 @@ const (
)
func NewCallout(box *geo.Box) Shape {
return shapeCallout{
shape := shapeCallout{
baseShape: &baseShape{
Type: CALLOUT_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func getTipWidth(box *geo.Box) float64 {

View file

@ -4,6 +4,7 @@ import (
"math"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeCircle struct {
@ -11,18 +12,20 @@ type shapeCircle struct {
}
func NewCircle(box *geo.Box) Shape {
return shapeCircle{
shape := shapeCircle{
baseShape: &baseShape{
Type: CIRCLE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeCircle) GetInnerBox() *geo.Box {
width := s.Box.Width
height := s.Box.Height
insideTL := s.GetInsidePlacement(width, height, 0)
insideTL := s.GetInsidePlacement(width, height, 0, 0)
tl := s.Box.TopLeft.Copy()
width -= 2 * (insideTL.X - tl.X)
height -= 2 * (insideTL.Y - tl.Y)
@ -38,7 +41,7 @@ func (s shapeCircle) GetDimensionsToFit(width, height, paddingX, paddingY float6
return diameter, diameter
}
func (s shapeCircle) GetInsidePlacement(width, height, padding float64) geo.Point {
func (s shapeCircle) GetInsidePlacement(width, height, paddingX, paddingY float64) geo.Point {
return *geo.NewPoint(s.Box.TopLeft.X+math.Ceil(s.Box.Width/2-width/2), s.Box.TopLeft.Y+math.Ceil(s.Box.Height/2-height/2))
}

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
// Class is basically a rectangle
@ -10,7 +11,7 @@ type shapeClass struct {
}
func NewClass(box *geo.Box) Shape {
return shapeClass{
shape := shapeClass{
shapeSquare{
baseShape: &baseShape{
Type: CLASS_TYPE,
@ -18,6 +19,8 @@ func NewClass(box *geo.Box) Shape {
},
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeClass) GetDefaultPadding() (paddingX, paddingY float64) {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
// The percentage values of the cloud's wide inner box
@ -32,18 +33,20 @@ type shapeCloud struct {
}
func NewCloud(box *geo.Box) Shape {
return shapeCloud{
shape := shapeCloud{
baseShape: &baseShape{
Type: CLOUD_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeCloud) GetInnerBox() *geo.Box {
width := s.Box.Width
height := s.Box.Height
insideTL := s.GetInsidePlacement(width, height, 0)
insideTL := s.GetInsidePlacement(width, height, 0, 0)
aspectRatio := width / height
if aspectRatio > CLOUD_WIDE_ASPECT_BOUNDARY {
width *= CLOUD_WIDE_INNER_WIDTH
@ -72,17 +75,17 @@ func (s shapeCloud) GetDimensionsToFit(width, height, paddingX, paddingY float64
}
}
func (s shapeCloud) GetInsidePlacement(width, height, padding float64) geo.Point {
func (s shapeCloud) GetInsidePlacement(width, height, paddingX, paddingY float64) geo.Point {
r := s.Box
width += padding
height += padding
width += paddingX
height += paddingY
aspectRatio := width / height
if aspectRatio > CLOUD_WIDE_ASPECT_BOUNDARY {
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_WIDE_INNER_X+padding/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_WIDE_INNER_Y+padding/2))
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_WIDE_INNER_X+paddingX/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_WIDE_INNER_Y+paddingY/2))
} else if aspectRatio < CLOUD_TALL_ASPECT_BOUNDARY {
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_TALL_INNER_X+padding/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_TALL_INNER_Y+padding/2))
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_TALL_INNER_X+paddingX/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_TALL_INNER_Y+paddingY/2))
} else {
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_SQUARE_INNER_X+padding/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_SQUARE_INNER_Y+padding/2))
return *geo.NewPoint(r.TopLeft.X+math.Ceil(r.Width*CLOUD_SQUARE_INNER_X+paddingX/2), r.TopLeft.Y+math.Ceil(r.Height*CLOUD_SQUARE_INNER_Y+paddingY/2))
}
}

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeCode struct {
@ -9,7 +10,7 @@ type shapeCode struct {
}
func NewCode(box *geo.Box) Shape {
return shapeCode{
shape := shapeCode{
shapeSquare: shapeSquare{
baseShape: &baseShape{
Type: CODE_TYPE,
@ -17,6 +18,8 @@ func NewCode(box *geo.Box) Shape {
},
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeCode) GetDefaultPadding() (paddingX, paddingY float64) {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeCylinder struct {
@ -16,12 +17,14 @@ const (
)
func NewCylinder(box *geo.Box) Shape {
return shapeCylinder{
shape := shapeCylinder{
baseShape: &baseShape{
Type: CYLINDER_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func getArcHeight(box *geo.Box) float64 {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeDiamond struct {
@ -12,12 +13,14 @@ type shapeDiamond struct {
}
func NewDiamond(box *geo.Box) Shape {
return shapeDiamond{
shape := shapeDiamond{
baseShape: &baseShape{
Type: DIAMOND_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeDiamond) GetInnerBox() *geo.Box {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeDocument struct {
@ -19,12 +20,14 @@ const (
)
func NewDocument(box *geo.Box) Shape {
return shapeDocument{
shape := shapeDocument{
baseShape: &baseShape{
Type: DOCUMENT_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeDocument) GetInnerBox() *geo.Box {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeHexagon struct {
@ -12,12 +13,14 @@ type shapeHexagon struct {
}
func NewHexagon(box *geo.Box) Shape {
return shapeHexagon{
shape := shapeHexagon{
baseShape: &baseShape{
Type: HEXAGON_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeHexagon) GetInnerBox() *geo.Box {

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeImage struct {
@ -9,12 +10,14 @@ type shapeImage struct {
}
func NewImage(box *geo.Box) Shape {
return shapeImage{
shape := shapeImage{
baseShape: &baseShape{
Type: IMAGE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeImage) IsRectangular() bool {

View file

@ -4,6 +4,7 @@ import (
"math"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeOval struct {
@ -11,18 +12,20 @@ type shapeOval struct {
}
func NewOval(box *geo.Box) Shape {
return shapeOval{
shape := shapeOval{
baseShape: &baseShape{
Type: OVAL_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeOval) GetInnerBox() *geo.Box {
width := s.Box.Width
height := s.Box.Height
insideTL := s.GetInsidePlacement(width, height, 0)
insideTL := s.GetInsidePlacement(width, height, 0, 0)
tl := s.Box.TopLeft.Copy()
width -= 2 * (insideTL.X - tl.X)
height -= 2 * (insideTL.Y - tl.Y)
@ -38,7 +41,7 @@ func (s shapeOval) GetDimensionsToFit(width, height, paddingX, paddingY float64)
return math.Ceil(math.Sqrt2 * paddedWidth), math.Ceil(math.Sqrt2 * paddedHeight)
}
func (s shapeOval) GetInsidePlacement(width, height, padding float64) geo.Point {
func (s shapeOval) GetInsidePlacement(width, height, paddingX, paddingY float64) geo.Point {
// showing the top left arc of the ellipse (drawn with '*')
// ┌──────────────────* ┬
// │ * │ │ry
@ -56,8 +59,8 @@ func (s shapeOval) GetInsidePlacement(width, height, padding float64) geo.Point
// r is the ellipse radius on the line between node.TopLeft and the ellipse center
// see https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo
r := rx * ry / math.Sqrt(math.Pow(rx*sin, 2)+math.Pow(ry*cos, 2))
// we want to offset r-padding away from the center
return *geo.NewPoint(s.Box.TopLeft.X+math.Ceil(rx-cos*(r-padding)), s.Box.TopLeft.Y+math.Ceil(ry-sin*(r-padding)))
// we want to offset r-padding/2 away from the center
return *geo.NewPoint(s.Box.TopLeft.X+math.Ceil(rx-cos*(r-paddingX/2)), s.Box.TopLeft.Y+math.Ceil(ry-sin*(r-paddingY/2)))
}
func (s shapeOval) Perimeter() []geo.Intersectable {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapePackage struct {
@ -21,12 +22,14 @@ const (
)
func NewPackage(box *geo.Box) Shape {
return shapePackage{
shape := shapePackage{
baseShape: &baseShape{
Type: PACKAGE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapePackage) GetInnerBox() *geo.Box {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapePage struct {
@ -18,12 +19,14 @@ const (
)
func NewPage(box *geo.Box) Shape {
return shapePage{
shape := shapePage{
baseShape: &baseShape{
Type: PAGE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapePage) GetInnerBox() *geo.Box {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeParallelogram struct {
@ -14,12 +15,14 @@ type shapeParallelogram struct {
const parallelWedgeWidth = 26.
func NewParallelogram(box *geo.Box) Shape {
return shapeParallelogram{
shape := shapeParallelogram{
baseShape: &baseShape{
Type: PARALLELOGRAM_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeParallelogram) GetInnerBox() *geo.Box {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapePerson struct {
@ -12,12 +13,14 @@ type shapePerson struct {
}
func NewPerson(box *geo.Box) Shape {
return shapePerson{
shape := shapePerson{
baseShape: &baseShape{
Type: PERSON_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
const (

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeQueue struct {
@ -12,12 +13,14 @@ type shapeQueue struct {
}
func NewQueue(box *geo.Box) Shape {
return shapeQueue{
shape := shapeQueue{
baseShape: &baseShape{
Type: QUEUE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func getArcWidth(box *geo.Box) float64 {

View file

@ -4,6 +4,7 @@ import (
"math"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeRealSquare struct {
@ -11,12 +12,14 @@ type shapeRealSquare struct {
}
func NewRealSquare(box *geo.Box) Shape {
return shapeRealSquare{
shape := shapeRealSquare{
baseShape: &baseShape{
Type: REAL_SQUARE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeRealSquare) AspectRatio1() bool {

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
type shapeSquare struct {
@ -9,12 +10,14 @@ type shapeSquare struct {
}
func NewSquare(box *geo.Box) Shape {
return shapeSquare{
shape := shapeSquare{
baseShape: &baseShape{
Type: SQUARE_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeSquare) IsRectangular() bool {

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeStep struct {
@ -12,12 +13,14 @@ type shapeStep struct {
}
func NewStep(box *geo.Box) Shape {
return shapeStep{
shape := shapeStep{
baseShape: &baseShape{
Type: STEP_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
const STEP_WEDGE_WIDTH = 35.0

View file

@ -5,6 +5,7 @@ import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
type shapeStoredData struct {
@ -14,12 +15,14 @@ type shapeStoredData struct {
const storedDataWedgeWidth = 15.
func NewStoredData(box *geo.Box) Shape {
return shapeStoredData{
shape := shapeStoredData{
baseShape: &baseShape{
Type: STORED_DATA_TYPE,
Box: box,
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeStoredData) GetInnerBox() *geo.Box {

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
// Table is basically a rectangle
@ -10,7 +11,7 @@ type shapeTable struct {
}
func NewTable(box *geo.Box) Shape {
return shapeTable{
shape := shapeTable{
shapeSquare{
baseShape: &baseShape{
Type: TABLE_TYPE,
@ -18,6 +19,8 @@ func NewTable(box *geo.Box) Shape {
},
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeTable) GetDefaultPadding() (paddingX, paddingY float64) {

View file

@ -2,6 +2,7 @@ package shape
import (
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/util-go/go2"
)
// Text is basically a rectangle
@ -10,7 +11,7 @@ type shapeText struct {
}
func NewText(box *geo.Box) Shape {
return shapeText{
shape := shapeText{
shapeSquare: shapeSquare{
baseShape: &baseShape{
Type: TEXT_TYPE,
@ -18,6 +19,8 @@ func NewText(box *geo.Box) Shape {
},
},
}
shape.FullShape = go2.Pointer(Shape(shape))
return shape
}
func (s shapeText) GetDefaultPadding() (paddingX, paddingY float64) {