Created
August 9, 2017 17:43
-
-
Save influx6/8d90e5ed72e6eaedd1c09aee0a3f5a9e to your computer and use it in GitHub Desktop.
Simple Constraint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type _range struct { | |
min float64 | |
max float64 | |
} | |
func (r _range) intersectMin(v float64) _range { | |
r.min = math.Max(r.min, v) | |
return r | |
} | |
func (r _range) intersectMax(v float64) _range { | |
r.max = math.Min(r.max, v) | |
return r | |
} | |
func (r _range) intersect(r2 _range) _range { | |
return _range{min: math.Max(r.min, r2.min), max: math.Min(r.max, r2.max)} | |
} | |
func (r _range) isValid() bool { | |
if r.max < r.min { | |
fmt.Println("invalid2", r.max-r.min) | |
} | |
return r.max >= r.min | |
} | |
func (r _range) nearest(v float64) float64 { | |
// return a sane value even if range is invalid | |
if r.max < r.min { | |
r.max, r.min = r.min, r.max | |
} | |
switch { | |
case r.min == r.max: | |
return r.min | |
case r.min >= v: | |
return r.min | |
case r.max <= v: | |
return r.max | |
default: | |
return v | |
} | |
} | |
type constrainedRect struct { | |
left, right, top, bottom, width, height, centerX, centerY _range | |
} | |
func newConstrainedRect() constrainedRect { | |
all := _range{min: math.Inf(-1), max: math.Inf(1)} | |
pos := _range{min: 0, max: math.Inf(1)} | |
return constrainedRect{ | |
left: all, right: all, top: all, bottom: all, width: pos, height: pos, centerX: all, centerY: all, | |
} | |
} | |
func (cr constrainedRect) isValid() bool { | |
_, r1 := cr.solveWidth(0) | |
_, r2 := cr.solveHeight(0) | |
_, r3 := cr.solveCenterX(0) | |
_, r4 := cr.solveCenterY(0) | |
return r1.width.isValid() && r2.height.isValid() && r3.centerX.isValid() && r4.centerY.isValid() | |
} | |
func (r constrainedRect) solveWidth(b float64) (float64, constrainedRect) { | |
centerXMax, centerXMin := r.centerX.max, r.centerX.min | |
rightMax, rightMin := r.right.max, r.right.min | |
leftMax, leftMin := r.left.max, r.left.min | |
// Width = (Right - CenterX) * 2 | |
if !math.IsInf(centerXMin, 0) && !math.IsInf(rightMax, 0) { | |
r.width = r.width.intersectMax((rightMax - centerXMin) * 2) | |
} | |
if !math.IsInf(centerXMax, 0) && !math.IsInf(rightMin, 0) { | |
r.width = r.width.intersectMin((rightMin - centerXMax) * 2) | |
} | |
// Width = Right - Left | |
if !math.IsInf(rightMax, 0) && !math.IsInf(leftMin, 0) { | |
r.width = r.width.intersectMax(rightMax - leftMin) | |
} | |
if !math.IsInf(rightMin, 0) && !math.IsInf(leftMax, 0) { | |
r.width = r.width.intersectMin(rightMin - leftMax) | |
} | |
// Width = (CenterX - Left) * 2 | |
if !math.IsInf(centerXMax, 0) && !math.IsInf(leftMin, 0) { | |
r.width = r.width.intersectMax((centerXMax - leftMin) * 2) | |
} | |
if !math.IsInf(centerXMin, 0) && !math.IsInf(leftMax, 0) { | |
r.width = r.width.intersectMin((centerXMin - leftMax) * 2) | |
} | |
return r.width.nearest(b), r | |
} | |
func (r constrainedRect) solveCenterX(b float64) (float64, constrainedRect) { | |
rightMax, rightMin := r.right.max, r.right.min | |
leftMax, leftMin := r.left.max, r.left.min | |
widthMax, widthMin := r.width.max, r.width.min | |
// CenterX = (Right + Left)/2 | |
if !math.IsInf(rightMax, 0) && !math.IsInf(leftMax, 0) { | |
r.centerX = r.centerX.intersectMax((rightMax + leftMax) / 2) | |
} | |
if !math.IsInf(rightMin, 0) && !math.IsInf(leftMin, 0) { | |
r.centerX = r.centerX.intersectMin((rightMin + leftMin) / 2) | |
} | |
// CenterX = Right - Width / 2 | |
if !math.IsInf(rightMax, 0) && !math.IsInf(widthMin, 0) { | |
r.centerX = r.centerX.intersectMax(rightMax - widthMin/2) | |
} | |
if !math.IsInf(rightMin, 0) && !math.IsInf(widthMax, 0) { | |
r.centerX = r.centerX.intersectMin(rightMin - widthMax/2) | |
} | |
// CenterX = Left + Width / 2 | |
if !math.IsInf(leftMax, 0) && !math.IsInf(widthMax, 0) { | |
r.centerX = r.centerX.intersectMax(leftMax + widthMax/2) | |
} | |
if !math.IsInf(leftMin, 0) && !math.IsInf(widthMin, 0) { | |
r.centerX = r.centerX.intersectMin(leftMin + widthMin/2) | |
} | |
return r.centerX.nearest(b), r | |
} | |
func (r constrainedRect) solveHeight(b float64) (float64, constrainedRect) { | |
centerYMax, centerYMin := r.centerY.max, r.centerY.min | |
bottomMax, bottomMin := r.bottom.max, r.bottom.min | |
topMax, topMin := r.top.max, r.top.min | |
// height = (bottom - centerY) * 2 | |
if !math.IsInf(centerYMin, 0) && !math.IsInf(bottomMax, 0) { | |
r.height = r.height.intersectMax((bottomMax - centerYMin) * 2) | |
} | |
if !math.IsInf(centerYMax, 0) && !math.IsInf(bottomMin, 0) { | |
r.height = r.height.intersectMin((bottomMin - centerYMax) * 2) | |
} | |
// height = bottom - top | |
if !math.IsInf(bottomMax, 0) && !math.IsInf(topMin, 0) { | |
r.height = r.height.intersectMax(bottomMax - topMin) | |
} | |
if !math.IsInf(bottomMin, 0) && !math.IsInf(topMax, 0) { | |
r.height = r.height.intersectMin(bottomMin - topMax) | |
} | |
// height = (centerY - top) * 2 | |
if !math.IsInf(centerYMax, 0) && !math.IsInf(topMin, 0) { | |
r.height = r.height.intersectMax((centerYMax - topMin) * 2) | |
} | |
if !math.IsInf(centerYMin, 0) && !math.IsInf(topMax, 0) { | |
r.height = r.height.intersectMin((centerYMin - topMax) * 2) | |
} | |
return r.height.nearest(b), r | |
} | |
func (r constrainedRect) solveCenterY(b float64) (float64, constrainedRect) { | |
bottomMax, bottomMin := r.bottom.max, r.bottom.min | |
topMax, topMin := r.top.max, r.top.min | |
heightMax, heightMin := r.height.max, r.height.min | |
// centerY = (bottom + top)/2 | |
if !math.IsInf(bottomMax, 0) && !math.IsInf(topMax, 0) { | |
r.centerY = r.centerY.intersectMax((bottomMax + topMax) / 2) | |
} | |
if !math.IsInf(bottomMin, 0) && !math.IsInf(topMin, 0) { | |
r.centerY = r.centerY.intersectMin((bottomMin + topMin) / 2) | |
} | |
// centerY = bottom - height / 2 | |
if !math.IsInf(bottomMax, 0) && !math.IsInf(heightMin, 0) { | |
r.centerY = r.centerY.intersectMax(bottomMax - heightMin/2) | |
} | |
if !math.IsInf(bottomMin, 0) && !math.IsInf(heightMax, 0) { | |
r.centerY = r.centerY.intersectMin(bottomMin - heightMax/2) | |
} | |
// centerY = top + height / 2 | |
if !math.IsInf(topMax, 0) && !math.IsInf(heightMax, 0) { | |
r.centerY = r.centerY.intersectMax(topMax + heightMax/2) | |
} | |
if !math.IsInf(topMin, 0) && !math.IsInf(heightMin, 0) { | |
r.centerY = r.centerY.intersectMin(topMin + heightMin/2) | |
} | |
return r.centerY.nearest(b), r | |
} | |
func (r constrainedRect) String() string { | |
return fmt.Sprintf("{left:%v, right:%v, top:%v, bottom:%v, width:%v, height:%v, centerX:%v, centerY:%v}", r.left, r.right, r.top, r.bottom, r.width, r.height, r.centerX, r.centerY) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment