Exemple #1
0
// DrawLine only writes to the slot label.
// The pointer to the amorph remains unchanged
// Empty() still reports true for the slot
func (m *TransposableMatrix) DrawLine(line []Point, suffix string, pivotPointsOnly bool) {
	for i := 0; i < len(line); i++ {
		s := spf("%v%v", i%10, suffix)
		if suffix == "" {
			s = ""
		}
		if pivotPointsOnly || i == len(line)-1 {
			m.SetLabel(line[i].x, line[i].y, Slot{Label: s})
		} else {
			x := util.Min(line[i+1].x, line[i].x)
			y := util.Min(line[i+1].y, line[i].y)
			dx := util.Abs(line[i+1].x - line[i].x)
			dy := util.Abs(line[i+1].y - line[i].y)
			// pf("sect :%v %v %v %v \n", x, x+dx, y, y+dy)
			for j := x; j <= x+dx; j++ {
				for k := y; k <= y+dy; k++ {
					m.SetLabel(j, k, Slot{Label: s})
				}
			}
		}
	}
}
Exemple #2
0
//
// exactStairyEdge returns amorphs
// with exactly the desired edges.
// The edge is also attached to the amorph.
// Param limit restricts the amount of amorphs returned.
func (ar *Reservoir) exactStairyEdge(x1, y, x2 int, limit int) (amorphs []Amorph) {

	enc := Enc(x1, y, x2)
	if _, ok := ar.Edge3[enc]; ok {
		mp := ar.Edge3[enc]

		for amIdx, _ := range mp {

			// pf("found idx %v of %v \n", amIdx, len(ar.Amorphs))

			lp := ar.Amorphs[amIdx] // effects a copying of the amorph
			lp.Cols = x1 + x2
			lp.Rows, lp.Slack = OtherSide(lp.NElements, lp.Cols)

			// Increase rows,
			// if the requested edge is a superedge.
			cntr := 0
			for lp.Rows <= util.Abs(y) || lp.Slack < util.Abs(x2*y) {
				lp.Rows++
				lp.Slack = (lp.Cols * lp.Rows) - lp.NElements
				if cntr++; cntr > 100 {
					panic("superedge blowup logic faulty")
				}
			}

			// Attach the edge
			lp.Edge = []int{x1, y, x2}

			amorphs = append(amorphs, lp)

			if len(amorphs) >= limit {
				return
			}

		}
	}
	return
}
Exemple #3
0
// returns a format string with as few as needed
//   post-decimal digits ;  1000 => 1000 , but 0.0400 => 0.04
func practicalFormat(mv float64) (floatFormat string, exponent int) {

	//Log x    =    Ln x / Ln 10
	fExponent := math.Log(mv) / math.Log(10)
	//exponent  = int(fExponent)
	exponent = util.Round(fExponent)

	sExponent := fmt.Sprint(util.Abs(exponent) + 2)
	floatFormat = "%12.0f"
	if mv < 10 {
		floatFormat = "%12.1f"
	}
	if mv < 1 {
		floatFormat = "%12." + sExponent + "f"
	}

	return
}
func (m *TransposableMatrix) renderHeaderTB(xscale, yscale int) {

	xo1 := RectOutp2.X1
	xo2 := RectOutp2.X2
	yo1 := RectOutp2.Y1
	yo2 := RectOutp2.Y2

	xoo := xo1 + margL
	yoo := yo1 + margT

	// row1
	tboxc.PriLineAt(xo1, yo1+0, "  x|")
	tboxc.PriLineAt(xo1, yo1+1, "   |")

	for x := xoo; x <= xo2-2; x += 2 {
		if xscale%10 == 0 {
			colHead1 := spf("%2d", (xscale-xscale%10)/10)
			tboxc.PriLineAt(x, yo1+0, colHead1)
		} else {
			tboxc.PriLineAt(x, yo1+0, "  ")
		}
		colHead2 := spf("%2d", util.Abs(xscale%10))
		tboxc.PriLineAt(x, yo1+1, colHead2)
		xscale += 1
	}

	// row3
	tboxc.PriLineAt(xo1, yo1+2, "  y|")
	tboxc.PriLineAt(xoo, yo1+2, spf(strings.Repeat("=", xo2-xo1-margL+1)))

	for y := yoo; y <= yo2; y++ {
		tboxc.PriLineAt(xo1, y, spf("%3d|", yscale))
		yscale++
	}

}
Exemple #5
0
// Distance returns levenshtein edit distance for the two slices of tokens of m.
func (m *Matrix) Distance() (int, float64) {

	dist := m.mx[len(m.mx)-1][len(m.mx[0])-1]

	relDist := 0.0

	ls1, ls2 := len(m.mx), len(m.mx[0])

	// First relDist computation:
	// 		1.) compensated for the size
	// 		2.) related to the smaller slice
	// Can lead to Zero, when diff == dist
	diff := util.Abs(ls1 - ls2)
	if ls1 >= ls2 { // row > col
		relDist = float64(dist-diff) / float64(ls2)
	} else {
		relDist = float64(dist-diff) / float64(ls1)
	}

	// Second relDist: Simply related to the larger slice.
	// Also account for ls1 and ls2 being one larger than the practical number of tokens.
	divisor := float64(ls1)
	if ls2 > ls1 { // row > col
		divisor = float64(ls2)
	}
	divisor--
	if divisor == 0.0 {
		divisor = 1.0
	}
	relDist = float64(dist) / divisor
	if relDist == 0.25 {
		fmt.Printf("dist %v - ls1 %v - relDist %5.2v\n", dist, divisor, relDist)
	}

	return dist, relDist
}
Exemple #6
0
// https://courses.engr.illinois.edu/ece390/archive/archive-f2000/mp/mp4/anti.html
func FuncDrawLiner(lCol color.RGBA, img *image.RGBA) func(P_next image.Point, lCol color.RGBA, img *image.RGBA) {

	var P_last image.Point = image.Point{-1111, -1111}

	r := img.Rect
	p0 := r.Min
	p1 := r.Max
	imgWidth := p1.X - p0.X

	return func(P_next image.Point, lCol color.RGBA, img *image.RGBA) {

		var P0, P1 image.Point

		if P_last.X == -1111 && P_last.Y == -1111 {
			P_last = P_next
			return
		} else {
			P0 = P_last
			P1 = P_next
			P_last = P_next
		}

		log.Printf("draw_line_start---------------------------------")

		x0, y0 := P0.X, P0.Y
		x1, y1 := P1.X, P1.Y

		bpp := 4 // bytes per pixel

		addr := (y0*imgWidth + x0) * bpp
		dx := x1 - x0
		dy := y1 - y0

		var du, dv, u, v int
		var uincr int = bpp
		var vincr int = imgWidth * bpp

		// switching to (u,v) to combine all eight octants
		if util.Abs(dx) > util.Abs(dy) {
			du = util.Abs(dx)
			dv = util.Abs(dy)
			u = x1
			v = y1
			uincr = bpp
			vincr = imgWidth * bpp
			if dx < 0 {
				uincr = -uincr
			}
			if dy < 0 {
				vincr = -vincr
			}
		} else {
			du = util.Abs(dy)
			dv = util.Abs(dx)
			u = y1
			v = x1
			uincr = imgWidth * bpp
			vincr = bpp
			if dy < 0 {
				uincr = -uincr
			}
			if dx < 0 {
				vincr = -vincr
			}
		}
		log.Printf("draw_line\tu %v - v %v - du %v - dv %v - uinc %v - vinc %v ", u, v, du, dv, uincr, vincr)

		// uend	  :=  u + 2 * du
		// d	     := (2 * dv) - du		// Initial value as in Bresenham's
		// incrS   :=  2 *  dv				// Δd for straight increments
		// incrD   :=  2 * (dv - du)	   // Δd for diagonal increments
		// twovdu  :=  0						// Numerator of distance starts at 0

		// I have NO idea why - but unless I use -1-
		//   instead of the orginal -2- as factor,
		//   all lines are drawn DOUBLE the intended size
		//   THIS is how it works for me:
		uend := u + 1*du
		d := (1 * dv) - du     // Initial value as in Bresenham's
		incrS := 1 * dv        // Δd for straight increments
		incrD := 1 * (dv - du) // Δd for diagonal increments
		twovdu := 0            // Numerator of distance starts at 0

		log.Printf("draw_line\tuend %v - d %v - incrS %v - incrD %v - twovdu %v", uend, d, incrS, incrD, twovdu)

		tmp := float64(du*du + dv*dv)
		invD := 1.0 / (2.0 * math.Sqrt(tmp))  /* Precomputed inverse denominator */
		invD2du := 2.0 * (float64(du) * invD) /* Precomputed constant */

		log.Printf("draw_line\tinvD %v - invD2du %v", invD, invD2du)

		cntr := -1

		setPix := funcSetPixler(lCol, img)

		for {
			cntr++
			//log.Printf("==lp%v ", cntr )

			// Ensure that addr is valid
			ftwovdu := float64(twovdu)
			setPix(addr-vincr, invD2du+ftwovdu*invD)
			setPix(addr, ftwovdu*invD)
			setPix(addr+vincr, invD2du-ftwovdu*invD)

			if d < 0 {
				/* choose straight (u direction) */
				twovdu = d + du
				d = d + incrS
			} else {
				/* choose diagonal (u+v direction) */
				twovdu = d - du
				d = d + incrD
				v = v + 1
				addr = addr + vincr
			}
			u = u + 1
			addr = addr + uincr

			if u > uend {
				break
			}
		}

		log.Printf("draw_line_end---------------------------------")

	}
}
// FuseTwoSections takes an outline with all concavest lowest narrowest sections,
// and one or two designated section indize out of clns.
// So far mostly *one* section is given, while the second is the
// computed right neighbor. Rightmost sect is complemented by the left neighbor.
// Those designated sections are fused.
// Param l    => outline
// Param clns => concavest, lowest, narrowest sections
// sct1       => index to clns for which to find a pair
// Returns: Fusion
func (ar *Reservoir) FuseTwoSections(l []Point, clns [][]int, sct1 []int) (Fusion, error) {

	fs := NewFusion()
	var err error

	// find the two sections - westward or eastward
	west, east := findYourNeighbor(clns, sct1)
	var sct2 []int
	if sct1[1] == 0 {
		// only fuse eastw possible
		if east < 0 {
			err = epf("NO EASTW NEIGHBOR 1 to %v", sct1)
			return fs, err
		}
		sct2 = clns[east]
	} else if sct1[1] == len(l)-1 {
		// only fuse westw possible
		if west < 0 {
			err = epf("NO WESTW NEIGHBOR 1 to %v", sct1)
			return fs, err
		}
		sct2 = sct1
		sct1 = clns[west]
	} else {
		if util.Abs(sct1[3]) > 0 &&
			util.Abs(sct1[3]) < util.Abs(sct1[6]) {
			// east flank higher than west flank?
			// => fuse westwards
			sct2 = sct1
			if west < 0 {
				err = epf("NO WESTW NEIGHBOR 2 to %v", sct1)
				return fs, err
			}
			sct1 = clns[west]
		} else {
			// fuse eastwards
			if east < 0 {
				err = epf("NO EASTW NEIGHBOR 2 to %v", sct1)
				return fs, err
			}
			sct2 = clns[east]
		}
	}
	// PrintSectOfCLNS(sct1)
	// PrintSectOfCLNS(sct2)

	fs.idxL = append(fs.idxL, sct1[0], sct1[1], sct2[0], sct2[1])
	fs.xyx = append(fs.xyx, sct1[2], sct1[6], sct2[2])
	fs.w = append(fs.w, sct1[3], sct1[4], sct1[5])
	fs.e = append(fs.e, sct2[6], sct2[7], sct2[8])

	sdgN := ar.SmallestDesirableHeight
	sdgWE := ar.SmallestDesirableWidth

	pW, pE, pN := Permissiveness(sdgN, sdgWE, fs.xyx, fs.w, fs.e)
	fs.pm = []int{pW, pE, pN}

	//
	// base point
	// always bottom left
	fs.base.x = l[sct1[0]].x             // x-coord taken from beginning
	baseY1 := l[sct1[0]].y               // y-coord taken either from beginning
	baseY2 := l[sct2[1]].y               //      or taken from end
	fs.base.y = util.Max(baseY1, baseY2) // take lowest y - meaning Max(), not Min()
	dyw := sct1[3]                       // correction for concave angles
	if dyw > 0 {
		fs.base.x++
	}

	switch {
	case fs.pm[0] < 0 && fs.pm[1] < 0: // eastw, westw blocked, concave
		fs.curveDesc = cncave
		fs.dirIdx, fs.maxOffs = -1, 0
	case fs.pm[0] > 0 && fs.pm[1] < 0: //  westwards
		fs.curveDesc = stairW
		fs.dirIdx, fs.maxOffs = 0, fs.pm[0]
	case fs.pm[0] < 0 && fs.pm[1] > 0: //  eastwards
		fs.curveDesc = stairE
		fs.dirIdx, fs.maxOffs = 1, fs.pm[1]
	case fs.pm[0] > 0 && fs.pm[1] > 0: // utterly convex
		fs.curveDesc = convex
		fs.dirIdx, fs.maxOffs = 1, fs.pm[1] // wanton choice: grow east
	}

	lowerX := 0
	if fs.xyx[1] < 0 {
		lowerX = 1
	}
	if lowerX == 0 && fs.w[0] > 0 {
		fs.concaveCore = true
	}
	if lowerX == 1 && fs.e[0] > 0 {
		fs.concaveCore = true
	}

	return fs, nil
}
Exemple #8
0
// abundantHeightMatch should replace mostAbundant()
// for the selection of the most appropriate amorph.
// It returns at least an amorph, complying to max height.
// If there are *several* amorphs close to the optimal height,
// then we return one of the most abundant in the interval plus-minus 2
func (dummy MostAbundantInProximity) Filter(amorphBlocks [][]Amorph, fs Fusion) (chosen *Amorph) {

	pfTmp := intermedPf(pf)
	defer func() { pf = pfTmp }()
	pf = pfDevNull

	heightLim := fs.pm[2]
	heightOpt := fs.FillHeightFloor()

	pf("lim%v,opt%v ", heightLim, heightOpt)

	// plus minus 2
	// -2=>0  , -1=>1  , 0=>2  , 1=>3 , 2=>4
	closest := [][]Amorph{
		[]Amorph{}, []Amorph{}, []Amorph{}, []Amorph{}, []Amorph{},
	}

	for i := 0; i < len(amorphBlocks); i++ {

		amorphs := amorphBlocks[i]

		// Scan all blocks of amorphs.
		// Extract one, which is closest to desired height.
		// Also create a histogram of amorphs,
		// which have a height of plus-minus 2
		for j := 0; j < len(amorphs); j++ {

			var lastDist, lpDist int

			lp := amorphs[j]

			if lp.Rows > heightLim {
				continue
			}

			if chosen == nil {
				chosen = &lp
			}
			lastDist = chosen.Rows - heightOpt
			lpDist = lp.Rows - heightOpt
			if util.Abs(lpDist) < util.Abs(lastDist) {
				chosen = &lp
			}

			if util.Abs(lpDist) <= 2 {
				closest[lpDist+2] = append(closest[lpDist+2], lp)
			}

		}
	}

	// Debug output
	if false {
		pf("\n")
		for i := 0; i < len(closest); i++ {
			sa := closest[i]
			pf("h%v fnd%v:  ", heightOpt+i-2, len(sa))
			for j := 0; j < len(sa); j++ {
				pf("%2v %vx%v=%2v | ", sa[j].IdxArticle, sa[j].Rows, sa[j].Cols, sa[j].NElements)
			}
			pf("\n")
		}
	}

	// How many amorphs were close to desired height
	maxBatch := 0
	for i := 0; i < len(closest); i++ {
		if len(closest[i]) > maxBatch {
			maxBatch = len(closest[i])
		}
	}

	// Return one abundant amorph
	// from the range +/- 2
	if maxBatch > 0 {
		for {
			if len(closest[2]) == maxBatch {
				chosen = &closest[2][0]
				break
			}
			if len(closest[1]) == maxBatch {
				chosen = &closest[1][0]
				break
			}
			if len(closest[3]) == maxBatch {
				chosen = &closest[3][0]
				break
			}
			if len(closest[0]) == maxBatch {
				chosen = &closest[0][0]
				break
			}
			if len(closest[4]) == maxBatch {
				chosen = &closest[4][0]
				break
			}
			break
		}
	}

	return
}