Skip to content

Instantly share code, notes, and snippets.

@influx6
Created August 9, 2017 17:43
Show Gist options
  • Save influx6/8d90e5ed72e6eaedd1c09aee0a3f5a9e to your computer and use it in GitHub Desktop.
Save influx6/8d90e5ed72e6eaedd1c09aee0a3f5a9e to your computer and use it in GitHub Desktop.
Simple Constraint
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