iteration 3
This commit is contained in:
parent
05a8e93379
commit
495bac61ff
5 changed files with 1625 additions and 1631 deletions
|
|
@ -255,7 +255,7 @@ import (
|
|||
const (
|
||||
MIN_RADIUS = 200
|
||||
PADDING = 20
|
||||
ARC_STEPS = 60 // High resolution for perfect circles
|
||||
ARC_STEPS = 60
|
||||
)
|
||||
|
||||
func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error {
|
||||
|
|
@ -268,17 +268,19 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) e
|
|||
positionLabelsIcons(obj)
|
||||
}
|
||||
|
||||
baseRadius := calculateBaseRadius(objects)
|
||||
// Calculate layout parameters
|
||||
baseRadius, maxNodeSize := calculateLayoutParams(objects)
|
||||
positionObjects(objects, baseRadius)
|
||||
|
||||
// Create edges with boundary-perfect arcs
|
||||
for _, edge := range g.Edges {
|
||||
createPerfectArc(edge, baseRadius)
|
||||
createBoundaryArc(edge, baseRadius, maxNodeSize)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateBaseRadius(objects []*d2graph.Object) float64 {
|
||||
func calculateLayoutParams(objects []*d2graph.Object) (float64, float64) {
|
||||
numNodes := float64(len(objects))
|
||||
maxSize := 0.0
|
||||
for _, obj := range objects {
|
||||
|
|
@ -286,7 +288,7 @@ func calculateBaseRadius(objects []*d2graph.Object) float64 {
|
|||
maxSize = math.Max(maxSize, size)
|
||||
}
|
||||
minRadius := (maxSize/2 + PADDING) / math.Sin(math.Pi/numNodes)
|
||||
return math.Max(minRadius, MIN_RADIUS)
|
||||
return math.Max(minRadius, MIN_RADIUS), maxSize
|
||||
}
|
||||
|
||||
func positionObjects(objects []*d2graph.Object, radius float64) {
|
||||
|
|
@ -298,6 +300,7 @@ func positionObjects(objects []*d2graph.Object, radius float64) {
|
|||
x := radius * math.Cos(angle)
|
||||
y := radius * math.Sin(angle)
|
||||
|
||||
// Center object at calculated position
|
||||
obj.TopLeft = geo.NewPoint(
|
||||
x-obj.Width/2,
|
||||
y-obj.Height/2,
|
||||
|
|
@ -305,21 +308,24 @@ func positionObjects(objects []*d2graph.Object, radius float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func createPerfectArc(edge *d2graph.Edge, baseRadius float64) {
|
||||
func createBoundaryArc(edge *d2graph.Edge, baseRadius, maxNodeSize float64) {
|
||||
if edge.Src == nil || edge.Dst == nil || edge.Src == edge.Dst {
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate arc radius outside node boundaries
|
||||
arcRadius := baseRadius + maxNodeSize/2 + PADDING
|
||||
|
||||
srcCenter := edge.Src.Center()
|
||||
dstCenter := edge.Dst.Center()
|
||||
layoutCenter := geo.NewPoint(0, 0)
|
||||
|
||||
// Calculate angles with proper wrapping
|
||||
// Calculate angles with shortest path
|
||||
startAngle := math.Atan2(srcCenter.Y-layoutCenter.Y, srcCenter.X-layoutCenter.X)
|
||||
endAngle := math.Atan2(dstCenter.Y-layoutCenter.Y, dstCenter.X-layoutCenter.X)
|
||||
|
||||
// Calculate angular distance taking shortest path
|
||||
angleDiff := endAngle - startAngle
|
||||
|
||||
// Normalize angle difference
|
||||
if angleDiff < 0 {
|
||||
angleDiff += 2 * math.Pi
|
||||
}
|
||||
|
|
@ -327,24 +333,23 @@ func createPerfectArc(edge *d2graph.Edge, baseRadius float64) {
|
|||
angleDiff -= 2 * math.Pi
|
||||
}
|
||||
|
||||
// Generate perfect circular arc
|
||||
// Generate arc points
|
||||
path := make([]*geo.Point, 0, ARC_STEPS+1)
|
||||
for i := 0; i <= ARC_STEPS; i++ {
|
||||
t := float64(i) / ARC_STEPS
|
||||
currentAngle := startAngle + t*angleDiff
|
||||
x := layoutCenter.X + baseRadius*math.Cos(currentAngle)
|
||||
y := layoutCenter.Y + baseRadius*math.Sin(currentAngle)
|
||||
angle := startAngle + t*angleDiff
|
||||
x := layoutCenter.X + arcRadius*math.Cos(angle)
|
||||
y := layoutCenter.Y + arcRadius*math.Sin(angle)
|
||||
path = append(path, geo.NewPoint(x, y))
|
||||
}
|
||||
|
||||
// Clip to shape boundaries while preserving arc properties
|
||||
// Clip to actual node boundaries
|
||||
edge.Route = path
|
||||
startIdx, endIdx := edge.TraceToShape(edge.Route, 0, len(edge.Route)-1)
|
||||
|
||||
// Maintain smooth arc after clipping
|
||||
if startIdx < endIdx {
|
||||
edge.Route = edge.Route[startIdx : endIdx+1]
|
||||
|
||||
// Ensure minimal points for smooth rendering
|
||||
if len(edge.Route) < 3 {
|
||||
edge.Route = []*geo.Point{path[0], path[len(path)-1]}
|
||||
|
|
@ -354,28 +359,6 @@ func createPerfectArc(edge *d2graph.Edge, baseRadius float64) {
|
|||
edge.IsCurve = true
|
||||
}
|
||||
|
||||
// Keep existing helper functions (positionLabelsIcons, boxContains, boxIntersections)
|
||||
// Helper if your geo.Box doesn’t implement Contains()
|
||||
func boxContains(b *geo.Box, p *geo.Point) bool {
|
||||
// typical bounding-box check
|
||||
return p.X >= b.TopLeft.X &&
|
||||
p.X <= b.TopLeft.X+b.Width &&
|
||||
p.Y >= b.TopLeft.Y &&
|
||||
p.Y <= b.TopLeft.Y+b.Height
|
||||
}
|
||||
|
||||
// Helper if your geo.Box doesn’t implement Intersections(geo.Segment) yet
|
||||
func boxIntersections(b *geo.Box, seg geo.Segment) []*geo.Point {
|
||||
// We'll assume d2's standard geo.Box has a built-in Intersections(*Segment) method.
|
||||
// If not, implement manually. For example, checking each of the 4 edges:
|
||||
// left, right, top, bottom
|
||||
// For simplicity, if you do have b.Intersections(...) you can just do:
|
||||
// return b.Intersections(seg)
|
||||
return b.Intersections(seg)
|
||||
// If you don't have that, you'd code the line-rect intersection yourself.
|
||||
}
|
||||
|
||||
// positionLabelsIcons is basically your logic that sets default label/icon positions if needed
|
||||
func positionLabelsIcons(obj *d2graph.Object) {
|
||||
// If there's an icon but no icon position, give it a default
|
||||
if obj.Icon != nil && obj.IconPosition == nil {
|
||||
|
|
@ -415,6 +398,17 @@ func positionLabelsIcons(obj *d2graph.Object) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func boxContains(b *geo.Box, p *geo.Point) bool {
|
||||
return p.X >= b.TopLeft.X &&
|
||||
p.X <= b.TopLeft.X+b.Width &&
|
||||
p.Y >= b.TopLeft.Y &&
|
||||
p.Y <= b.TopLeft.Y+b.Height
|
||||
}
|
||||
|
||||
func boxIntersections(b *geo.Box, seg geo.Segment) []*geo.Point {
|
||||
return b.Intersections(seg)
|
||||
}
|
||||
// package d2cycle
|
||||
|
||||
// import (
|
||||
|
|
|
|||
1440
e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json
generated
vendored
1440
e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json
generated
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
1440
e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json
generated
vendored
1440
e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json
generated
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Loading…
Reference in a new issue