mirror of https://github.com/statping/statping
json http handler - improved sample chart data
parent
2548606224
commit
a03498e035
|
@ -19,10 +19,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"math/rand"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sampleStart = time.Now().Add((-24 * 7) * time.Hour).UTC()
|
||||||
|
sampleHits = 9900.
|
||||||
|
)
|
||||||
|
|
||||||
// InsertSampleData will create the example/dummy services for a brand new Statping installation
|
// InsertSampleData will create the example/dummy services for a brand new Statping installation
|
||||||
func InsertSampleData() error {
|
func InsertSampleData() error {
|
||||||
utils.Log(1, "Inserting Sample Data...")
|
utils.Log(1, "Inserting Sample Data...")
|
||||||
|
@ -163,26 +167,31 @@ func insertSampleCheckins() error {
|
||||||
|
|
||||||
// InsertSampleHits will create a couple new hits for the sample services
|
// InsertSampleHits will create a couple new hits for the sample services
|
||||||
func InsertSampleHits() error {
|
func InsertSampleHits() error {
|
||||||
since := time.Now().Add((-24 * 7) * time.Hour).UTC()
|
|
||||||
for i := int64(1); i <= 5; i++ {
|
|
||||||
service := SelectService(i)
|
|
||||||
utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", 360, service.Name))
|
|
||||||
createdAt := since
|
|
||||||
alpha := float64(1.05)
|
|
||||||
|
|
||||||
for hi := int64(1); hi <= 168; hi++ {
|
for i := int64(1); i <= 5; i++ {
|
||||||
alpha += 0.01
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
service := SelectService(i)
|
||||||
latency := rand.Float64() * alpha
|
seed := time.Now().UnixNano()
|
||||||
createdAt = createdAt.Add(1 * time.Hour)
|
|
||||||
|
utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", sampleHits, service.Name))
|
||||||
|
createdAt := sampleStart
|
||||||
|
|
||||||
|
p := utils.NewPerlin(2., 2., 10, seed)
|
||||||
|
|
||||||
|
for hi := 0.; hi <= float64(sampleHits); hi++ {
|
||||||
|
|
||||||
|
latency := p.Noise1D(hi / 500)
|
||||||
|
createdAt = createdAt.Add(60 * time.Second)
|
||||||
hit := &types.Hit{
|
hit := &types.Hit{
|
||||||
Service: service.Id,
|
Service: service.Id,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
Latency: latency,
|
Latency: latency,
|
||||||
}
|
}
|
||||||
service.CreateHit(hit)
|
service.CreateHit(hit)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +406,7 @@ func InsertLargeSampleData() error {
|
||||||
|
|
||||||
var dayAgo = time.Now().Add((-24 * 90) * time.Hour)
|
var dayAgo = time.Now().Add((-24 * 90) * time.Hour)
|
||||||
|
|
||||||
insertHitRecords(dayAgo, 1450)
|
insertHitRecords(dayAgo, 5450)
|
||||||
|
|
||||||
insertFailureRecords(dayAgo, 730)
|
insertFailureRecords(dayAgo, 730)
|
||||||
|
|
||||||
|
@ -432,9 +441,16 @@ func insertHitRecords(since time.Time, amount int64) {
|
||||||
utils.Log(1, fmt.Sprintf("Adding %v hit records to service %v", amount, service.Name))
|
utils.Log(1, fmt.Sprintf("Adding %v hit records to service %v", amount, service.Name))
|
||||||
createdAt := since
|
createdAt := since
|
||||||
|
|
||||||
|
p := utils.NewPerlin(2, 2, 5, time.Now().UnixNano())
|
||||||
|
|
||||||
|
utils.Log(1, fmt.Sprint(p))
|
||||||
|
|
||||||
for hi := int64(1); hi <= amount; hi++ {
|
for hi := int64(1); hi <= amount; hi++ {
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
latency := rand.Float64()
|
latency := p.Noise1D(float64(hi / 10))
|
||||||
|
|
||||||
|
fmt.Printf("%0.0f\t%0.4f\n", hi, latency)
|
||||||
|
|
||||||
createdAt = createdAt.Add(1 * time.Minute)
|
createdAt = createdAt.Add(1 * time.Minute)
|
||||||
hit := &types.Hit{
|
hit := &types.Hit{
|
||||||
Service: service.Id,
|
Service: service.Id,
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
|
@ -42,8 +41,7 @@ func apiIndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
coreClone := *core.CoreApp
|
coreClone := *core.CoreApp
|
||||||
coreClone.Started = utils.Timezoner(core.CoreApp.Started, core.CoreApp.Timezone)
|
coreClone.Started = utils.Timezoner(core.CoreApp.Started, core.CoreApp.Timezone)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(coreClone, w, r)
|
||||||
json.NewEncoder(w).Encode(coreClone)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -77,8 +75,7 @@ func sendErrorJson(err error, w http.ResponseWriter, r *http.Request) {
|
||||||
Status: "error",
|
Status: "error",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(output, w, r)
|
||||||
json.NewEncoder(w).Encode(output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) {
|
func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -132,8 +129,7 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht
|
||||||
Output: obj,
|
Output: obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(output, w, r)
|
||||||
json.NewEncoder(w).Encode(output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
|
func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -141,7 +137,6 @@ func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
|
||||||
Status: "error",
|
Status: "error",
|
||||||
Error: errors.New("not authorized").Error(),
|
Error: errors.New("not authorized").Error(),
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
json.NewEncoder(w).Encode(output)
|
returnJson(output, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,7 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
c.Hits = c.AllHits()
|
c.Hits = c.AllHits()
|
||||||
c.Failures = c.LimitedFailures(64)
|
c.Failures = c.LimitedFailures(64)
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(checkins, w, r)
|
||||||
json.NewEncoder(w).Encode(checkins)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -54,8 +53,7 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
checkin.Hits = checkin.LimitedHits(32)
|
checkin.Hits = checkin.LimitedHits(32)
|
||||||
checkin.Failures = checkin.LimitedFailures(32)
|
checkin.Failures = checkin.LimitedFailures(32)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(checkin, w, r)
|
||||||
json.NewEncoder(w).Encode(checkin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
|
func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -32,8 +32,7 @@ func apiAllGroupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
auth := IsUser(r)
|
auth := IsUser(r)
|
||||||
groups := core.SelectGroups(false, auth)
|
groups := core.SelectGroups(false, auth)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(groups, w, r)
|
||||||
json.NewEncoder(w).Encode(groups)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiGroupHandler will show a single group
|
// apiGroupHandler will show a single group
|
||||||
|
@ -48,8 +47,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("group not found"), w, r)
|
sendErrorJson(errors.New("group not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(group, w, r)
|
||||||
json.NewEncoder(w).Encode(group)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiCreateGroupHandler accepts a POST method to create new groups
|
// apiCreateGroupHandler accepts a POST method to create new groups
|
||||||
|
@ -112,6 +110,5 @@ func apiGroupReorderHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
group.Order = g.Order
|
group.Order = g.Order
|
||||||
group.Update()
|
group.Update()
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(newOrder, w, r)
|
||||||
json.NewEncoder(w).Encode(newOrder)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
|
@ -256,6 +257,12 @@ func executeJSResponse(w http.ResponseWriter, r *http.Request, file string, data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
json.NewEncoder(w).Encode(d)
|
||||||
|
}
|
||||||
|
|
||||||
// error404Handler is a HTTP handler for 404 error pages
|
// error404Handler is a HTTP handler for 404 error pages
|
||||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
if usingSSL {
|
if usingSSL {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -30,10 +29,9 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
health := map[string]interface{}{
|
health := map[string]interface{}{
|
||||||
"services": len(core.Services()),
|
"services": len(core.Services()),
|
||||||
"online": core.Configs != nil,
|
"online": core.Configs != nil,
|
||||||
}
|
}
|
||||||
json.NewEncoder(w).Encode(health)
|
returnJson(health, w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,7 @@ func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(messages, w, r)
|
||||||
json.NewEncoder(w).Encode(messages)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
|
func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -95,8 +94,7 @@ func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(message, w, r)
|
||||||
json.NewEncoder(w).Encode(message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -36,8 +36,7 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
notif := n.(notifier.Notifier)
|
notif := n.(notifier.Notifier)
|
||||||
notifiers = append(notifiers, notif.Select())
|
notifiers = append(notifiers, notif.Select())
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(notifiers, w, r)
|
||||||
json.NewEncoder(w).Encode(notifiers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -51,8 +50,7 @@ func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(notifierObj, w, r)
|
||||||
json.NewEncoder(w).Encode(notifierObj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -78,8 +78,7 @@ func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
service.Order = s.Order
|
service.Order = s.Order
|
||||||
service.Update(false)
|
service.Update(false)
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(newOrder, w, r)
|
||||||
json.NewEncoder(w).Encode(newOrder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -141,8 +140,7 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("service not found"), w, r)
|
sendErrorJson(errors.New("service not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(servicer, w, r)
|
||||||
json.NewEncoder(w).Encode(servicer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -207,8 +205,7 @@ func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
end := time.Unix(endField, 0)
|
end := time.Unix(endField, 0)
|
||||||
|
|
||||||
obj := core.GraphDataRaw(service, start, end, grouping, "latency")
|
obj := core.GraphDataRaw(service, start, end, grouping, "latency")
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(obj, w, r)
|
||||||
json.NewEncoder(w).Encode(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -227,9 +224,7 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
end := time.Unix(endField, 0)
|
end := time.Unix(endField, 0)
|
||||||
|
|
||||||
obj := core.GraphDataRaw(service, start, end, grouping, "ping_time")
|
obj := core.GraphDataRaw(service, start, end, grouping, "ping_time")
|
||||||
|
returnJson(obj, w, r)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type dataXy struct {
|
type dataXy struct {
|
||||||
|
@ -285,9 +280,7 @@ func apiServiceHeatmapHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
month = 1
|
month = 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
returnJson(monthOutput, w, r)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(monthOutput)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -315,8 +308,7 @@ func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
services := core.Services()
|
services := core.Services()
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(services, w, r)
|
||||||
json.NewEncoder(w).Encode(services)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -345,8 +337,7 @@ func apiServiceFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("service not found"), w, r)
|
sendErrorJson(errors.New("service not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(servicer.AllFailures(), w, r)
|
||||||
json.NewEncoder(w).Encode(servicer.AllFailures())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiServiceHitsHandler(w http.ResponseWriter, r *http.Request) {
|
func apiServiceHitsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -367,6 +358,5 @@ func apiServiceHitsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(hits, w, r)
|
||||||
json.NewEncoder(w).Encode(hits)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,7 @@ func apiUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.Password = ""
|
user.Password = ""
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(user, w, r)
|
||||||
json.NewEncoder(w).Encode(user)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -121,8 +120,7 @@ func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
returnJson(users, w, r)
|
||||||
json.NewEncoder(w).Encode(users)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
|
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
114
utils/utils.go
114
utils/utils.go
|
@ -22,6 +22,8 @@ import (
|
||||||
"github.com/ararog/timeago"
|
"github.com/ararog/timeago"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -288,3 +290,115 @@ func HttpRequest(url, method string, content interface{}, headers []string, body
|
||||||
contents, err := ioutil.ReadAll(resp.Body)
|
contents, err := ioutil.ReadAll(resp.Body)
|
||||||
return contents, resp, err
|
return contents, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
B = 0x100
|
||||||
|
N = 0x1000
|
||||||
|
BM = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPerlin(alpha, beta float64, n int, seed int64) *Perlin {
|
||||||
|
return NewPerlinRandSource(alpha, beta, n, rand.NewSource(seed))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perlin is the noise generator
|
||||||
|
type Perlin struct {
|
||||||
|
alpha float64
|
||||||
|
beta float64
|
||||||
|
n int
|
||||||
|
|
||||||
|
p [B + B + 2]int
|
||||||
|
g3 [B + B + 2][3]float64
|
||||||
|
g2 [B + B + 2][2]float64
|
||||||
|
g1 [B + B + 2]float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPerlinRandSource(alpha, beta float64, n int, source rand.Source) *Perlin {
|
||||||
|
var p Perlin
|
||||||
|
var i int
|
||||||
|
|
||||||
|
p.alpha = alpha
|
||||||
|
p.beta = beta
|
||||||
|
p.n = n
|
||||||
|
|
||||||
|
r := rand.New(source)
|
||||||
|
|
||||||
|
for i = 0; i < B; i++ {
|
||||||
|
p.p[i] = i
|
||||||
|
p.g1[i] = float64((r.Int()%(B+B))-B) / B
|
||||||
|
|
||||||
|
for j := 0; j < 2; j++ {
|
||||||
|
p.g2[i][j] = float64((r.Int()%(B+B))-B) / B
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize2(&p.g2[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; i > 0; i-- {
|
||||||
|
k := p.p[i]
|
||||||
|
j := r.Int() % B
|
||||||
|
p.p[i] = p.p[j]
|
||||||
|
p.p[j] = k
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < B+2; i++ {
|
||||||
|
p.p[B+i] = p.p[i]
|
||||||
|
p.g1[B+i] = p.g1[i]
|
||||||
|
for j := 0; j < 2; j++ {
|
||||||
|
p.g2[B+i][j] = p.g2[i][j]
|
||||||
|
}
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
p.g3[B+i][j] = p.g3[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalize2(v *[2]float64) {
|
||||||
|
s := math.Sqrt(v[0]*v[0] + v[1]*v[1])
|
||||||
|
v[0] = v[0] / s
|
||||||
|
v[1] = v[1] / s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Perlin) Noise1D(x float64) float64 {
|
||||||
|
var scale float64 = 1
|
||||||
|
var sum float64
|
||||||
|
px := x
|
||||||
|
|
||||||
|
for i := 0; i < p.n; i++ {
|
||||||
|
val := p.noise1(px)
|
||||||
|
sum += val / scale
|
||||||
|
scale *= p.alpha
|
||||||
|
px *= p.beta
|
||||||
|
}
|
||||||
|
if sum < 0 {
|
||||||
|
sum = sum * -1
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Perlin) noise1(arg float64) float64 {
|
||||||
|
var vec [1]float64
|
||||||
|
vec[0] = arg
|
||||||
|
|
||||||
|
t := vec[0] + N
|
||||||
|
bx0 := int(t) & BM
|
||||||
|
bx1 := (bx0 + 1) & BM
|
||||||
|
rx0 := t - float64(int(t))
|
||||||
|
rx1 := rx0 - 1.
|
||||||
|
|
||||||
|
sx := sCurve(rx0)
|
||||||
|
u := rx0 * p.g1[p.p[bx0]]
|
||||||
|
v := rx1 * p.g1[p.p[bx1]]
|
||||||
|
|
||||||
|
return lerp(sx, u, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sCurve(t float64) float64 {
|
||||||
|
return t * t * (3. - 2.*t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lerp(t, a, b float64) float64 {
|
||||||
|
return a + t*(b-a)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue