Skip to content

Commit

Permalink
exposed ply comments
Browse files Browse the repository at this point in the history
  • Loading branch information
EliCDavis committed Jun 9, 2024
1 parent 11fe5fe commit 4a76029
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 93 deletions.
17 changes: 8 additions & 9 deletions examples/ply-utils/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,21 @@ import (
)

func writeHeaderAsPlaintext(header ply.Header, out io.Writer) error {
fmt.Fprintf(out, "%-14s %s\n", "Format:", header.Format.String())
fmt.Fprintf(out, "Format: %s\n", header.Format.String())

texFile := "(none)"
if header.TextureFile != nil {
texFile = *header.TextureFile
textures := header.TextureFiles()
fmt.Fprintf(out, "Texture Files: %d\n", len(textures))
for _, tex := range textures {
fmt.Fprintf(out, "%20s\n", tex)
}
fmt.Fprintf(out, "%-14s %s\n", "Texture File:", texFile)

// fmt.Fprintln(out, "Elements")
for _, ele := range header.Elements {
fmt.Fprintf(out, "%-14s %d entries\n", ele.Name+":", ele.Count)
fmt.Fprintf(out, "%s %d entries\n", ele.Name+":", ele.Count)
for _, prop := range ele.Properties {
if scalar, ok := prop.(ply.ScalarProperty); ok {
fmt.Fprintf(out, "%20s (%s)\n", prop.Name(), scalar.Type)
fmt.Fprintf(out, "\t%-14s (%s)\n", prop.Name(), scalar.Type)
} else if arr, ok := prop.(ply.ListProperty); ok {
fmt.Fprintf(out, "\t\t%s (count type: %s, list type: %s)\n", prop.Name(), arr.CountType, arr.ListType)
fmt.Fprintf(out, "\t%-14s (count type: %s, list type: %s)\n", prop.Name(), arr.CountType, arr.ListType)
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions examples/potree-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Potree Utils

## Hierarchy

### Summarize

```console
foo@bar:~$ potree-utils hierarchy summarize --metadata heidentor/metadata.json
| Level | Nodes | Average | Min | Max | Total | Volume | Spacing |
|--------|----------|----------|----------|----------|--------------|-----------------|--------------|
| 0 | 1 | 20640 | 20640 | 20640 | 20640 | 3765.8351 | 0.1215469 |
| 1 | 8 | 7888 | 1610 | 18043 | 63104 | 470.7294 | 0.0607734 |
| 2 | 42 | 6117 | 251 | 18823 | 256932 | 58.8412 | 0.0303867 |
| 3 | 164 | 6162 | 3 | 14552 | 1010691 | 7.3551 | 0.0151934 |
| 4 | 626 | 6098 | 2 | 19973 | 3817612 | 0.9194 | 0.0075967 |
| 5 | 2265 | 4623 | 1 | 12535 | 10471591 | 0.1149 | 0.0037983 |
| 6 | 5769 | 1767 | 1 | 5405 | 10194083 | 0.0144 | 0.0018992 |
| 7 | 7 | 252 | 1 | 486 | 1764 | 0.0018 | 0.0009496 |
```
45 changes: 37 additions & 8 deletions formats/ply/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import (
"encoding/binary"
"fmt"
"io"
"strings"
)

type Header struct {
Format Format `json:"format"`
Elements []Element `json:"elements"`
TextureFile *string `json:"texture,omitempty"`
Format Format `json:"format"`
Elements []Element `json:"elements"`
Comments []string `json:"comments"`
// TextureFile *string `json:"texture,omitempty"`

// Object information (arbitrary text)
ObjInfo []string `json:"objInfo"`
}

func (h Header) Bytes() []byte {
Expand All @@ -20,6 +25,31 @@ func (h Header) Bytes() []byte {
return buf.Bytes()
}

func (h Header) TextureFiles() []string {
textures := make([]string, 0)
for _, c := range h.Comments {
contents := strings.Fields(c)
if len(contents) == 0 {
continue
}

if len(contents) < 2 {
continue
}

if strings.ToLower(contents[0]) != "texturefile" {
continue
}

start := strings.Index(strings.ToLower(c), "texturefile")

// len("texturefile") == 11

textures = append(textures, strings.TrimSpace(c[start+11:]))
}
return textures
}

func (h Header) Write(out io.Writer) (err error) {
switch h.Format {
case ASCII:
Expand All @@ -36,16 +66,15 @@ func (h Header) Write(out io.Writer) (err error) {
return
}

if h.TextureFile != nil {
_, err = fmt.Fprintf(out, "comment TextureFile %s\n", *h.TextureFile)
for _, info := range h.Comments {
_, err = fmt.Fprintf(out, "comment %s\n", info)
if err != nil {
return
}
}

_, err = out.Write([]byte("comment Created with github.com/EliCDavis/polyform\n"))
if err != nil {
return
for _, info := range h.ObjInfo {
fmt.Fprintf(out, "obj_info %s\n", info)
}

for _, element := range h.Elements {
Expand Down
167 changes: 167 additions & 0 deletions formats/ply/header_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package ply_test

import (
"bytes"
"testing"

"github.com/EliCDavis/polyform/formats/ply"
"github.com/stretchr/testify/assert"
)

func TestHeaderTextureFiles(t *testing.T) {
tests := map[string]struct {
input ply.Header
want []string
}{
"no textures": {
input: ply.Header{
Comments: []string{
"test",
},
},
want: []string{},
},
"single tex": {
input: ply.Header{
Comments: []string{
"texturefile a.png",
},
},
want: []string{
"a.png",
},
},
"multiple textures": {
input: ply.Header{
Comments: []string{
"something",
"texturefile a.png",
"other something",
"TEXTUREFILE b.png",
"TextureFile with a space.jpg",
},
},
want: []string{
"a.png",
"b.png",
"with a space.jpg",
},
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
assert.Equal(t, tc.want, tc.input.TextureFiles())
})
}
}

func TestHeaderWrite(t *testing.T) {
tests := map[string]struct {
input ply.Header
want string
}{
"empty ascii": {
input: ply.Header{
Format: ply.ASCII,
},
want: `ply
format ascii 1.0
end_header
`,
},
"empty little endian": {
input: ply.Header{
Format: ply.BinaryLittleEndian,
},
want: `ply
format binary_little_endian 1.0
end_header
`,
},
"empty big endian": {
input: ply.Header{
Format: ply.BinaryBigEndian,
},
want: `ply
format binary_big_endian 1.0
end_header
`,
},
"obj_info": {
input: ply.Header{
Format: ply.ASCII,
ObjInfo: []string{
"test one two",
"test three four",
},
},
want: `ply
format ascii 1.0
obj_info test one two
obj_info test three four
end_header
`,
},
"comments": {
input: ply.Header{
Format: ply.ASCII,
Comments: []string{
"test one two",
"test three four",
},
},
want: `ply
format ascii 1.0
comment test one two
comment test three four
end_header
`,
},
"single element": {
input: ply.Header{
Format: ply.ASCII,
Comments: []string{
"Test Comment",
},
ObjInfo: []string{
"Test OBJ",
},
Elements: []ply.Element{
{
Name: "test",
Count: 12345678,
Properties: []ply.Property{
ply.ScalarProperty{
PropertyName: "foo",
Type: ply.UChar,
},
ply.ScalarProperty{
PropertyName: "Bar",
Type: ply.Double,
},
},
},
},
},
want: `ply
format ascii 1.0
comment Test Comment
obj_info Test OBJ
element test 12345678
property uchar foo
property double Bar
end_header
`,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
buf := &bytes.Buffer{}
assert.NoError(t, tc.input.Write(buf))
assert.Equal(t, tc.want, buf.String())
assert.Equal(t, tc.want, string(tc.input.Bytes()))
})
}
}
1 change: 1 addition & 0 deletions formats/ply/ply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func TestToMeshASCII(t *testing.T) {
format ascii 1.0
comment made by anonymous
comment this file is a cube
obj_info bs stuff
element vertex 8
property float32 x
property float32 y
Expand Down
16 changes: 9 additions & 7 deletions formats/ply/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func readPlyProperty(contents []string) (Property, error) {
func ReadHeader(in io.Reader) (Header, error) {
header := Header{
Elements: make([]Element, 0),
Comments: make([]string, 0),
}

magicNumber, err := readLine(in)
Expand Down Expand Up @@ -192,10 +193,8 @@ func ReadHeader(in io.Reader) (Header, error) {

contents := strings.Fields(line)
if contents[0] == "comment" {
if strings.ToLower(contents[1]) == "texturefile" {
name := contents[2]
header.TextureFile = &name
}
start := strings.Index(line, "comment")
header.Comments = append(header.Comments, strings.TrimSpace(line[7+start:]))
continue
}

Expand Down Expand Up @@ -237,13 +236,16 @@ func buildReader(in io.Reader) (BodyReader, *modeling.Material, error) {
}

var mat *modeling.Material = nil
if header.TextureFile != nil {
textures := header.TextureFiles()
if len(textures) > 0 {
tex := textures[0]
mat = &modeling.Material{
Name: *header.TextureFile,
Name: tex,
DiffuseColor: color.White,
ColorTextureURI: header.TextureFile,
ColorTextureURI: &tex,
}
}

return header.BuildReader(in), mat, nil
}

Expand Down
5 changes: 4 additions & 1 deletion formats/ply/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@ func BuildHeaderFromModel(model modeling.Mesh, format Format) Header {
Elements: []Element{
buildVertexElements(model.Float3Attributes(), int64(model.AttributeLength())),
},
Comments: []string{},
}

// Pull a texture file if relevant.
if len(model.Materials()) > 0 && model.Materials()[0].Material != nil {
mat := model.Materials()[0].Material
if mat.ColorTextureURI != nil {
header.TextureFile = mat.ColorTextureURI
header.Comments = append(header.Comments, fmt.Sprintf("TextureFile %s", *mat.ColorTextureURI))
}
}

header.Comments = append(header.Comments, "Created with github.com/EliCDavis/polyform")

// Optionally build face element
if model.Topology() == modeling.TriangleTopology {
faceProperties := []Property{
Expand Down
Loading

0 comments on commit 4a76029

Please sign in to comment.