Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,18 +324,13 @@ func passThroughImpl(pp *pc.PointCloud, core func(_, _ *pc.PointCloud) int) (*pc
}

func (e *editor) merge(pp *pc.PointCloud) {
pcNew := &pc.PointCloud{
PointCloudHeader: e.pp.PointCloudHeader.Clone(),
Points: e.pp.Points + pp.Points,
Data: append(e.pp.Data[:e.pp.Stride()*e.pp.Points], pp.Data...),
}
pcNew.Width = pcNew.Points
pcNew.Height = 1

e.push(&replacePatch{
header: e.pp.PointCloudHeader.Clone(),
data: e.pp.Data,
e.push(&appendPatch{
oldPoints: e.pp.Points,
oldWidth: e.pp.Width,
oldHeight: e.pp.Height,
})
e.pp = pcNew
n := e.pp.Points + pp.Points
data := append(e.pp.Data[:e.pp.Stride()*e.pp.Points], pp.Data...)
e.pp = newCloudView(e.pp, n, n, 1, data)
runtime.GC()
}
47 changes: 47 additions & 0 deletions patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ var (
errNoLabelField = errors.New("point cloud has no label field")
)

// pcgol caches an unsafe float32 alias of Data keyed only by its base pointer,
// so a change of the Data length must be delivered in a fresh PointCloud.
func newCloudView(pp *pc.PointCloud, points, width, height int, data []byte) *pc.PointCloud {
out := &pc.PointCloud{
PointCloudHeader: pp.PointCloudHeader.Clone(),
Points: points,
Data: data,
}
out.Width = width
out.Height = height
return out
}

func fieldByteOffset(h *pc.PointCloudHeader, name string) (int, bool) {
offset := 0
for i, fn := range h.Fields {
Expand Down Expand Up @@ -76,6 +89,30 @@ func (p *labelPatch) payload() []byte {
return nil
}

type appendPatch struct {
oldPoints, oldWidth, oldHeight int
}

func (p *appendPatch) revert(pp *pc.PointCloud) (*pc.PointCloud, error) {
stride := pp.Stride()
if stride <= 0 || p.oldPoints < 0 || p.oldWidth < 0 || p.oldHeight < 0 ||
p.oldPoints > pp.Points || p.oldPoints > len(pp.Data)/stride {
return nil, errBrokenPatch
}
return newCloudView(pp, p.oldPoints, p.oldWidth, p.oldHeight, pp.Data[:p.oldPoints*stride]), nil
}

func (p *appendPatch) encodeHead(buf *bytes.Buffer) {
buf.WriteByte(patchTypeAppend)
writeUint32(buf, uint32(p.oldPoints))
writeUint32(buf, uint32(p.oldWidth))
writeUint32(buf, uint32(p.oldHeight))
}

func (p *appendPatch) payload() []byte {
return nil
}

type replacePatch struct {
header pc.PointCloudHeader
data []byte
Expand Down Expand Up @@ -150,6 +187,16 @@ func decodePatch(b []byte) (patch, []byte, error) {
return nil, nil, r.err
}
return p, r.b, nil
case patchTypeAppend:
p := &appendPatch{
oldPoints: int(r.uint32()),
oldWidth: int(r.uint32()),
oldHeight: int(r.uint32()),
}
if r.err != nil {
return nil, nil, r.err
}
return p, r.b, nil
case patchTypeReplace:
p := &replacePatch{}
p.header.Version = math.Float32frombits(r.uint32())
Expand Down
19 changes: 19 additions & 0 deletions patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ func TestLabelPatchRevert(t *testing.T) {
assertCloudEqual(t, orig, out)
}

func TestAppendPatchRevert(t *testing.T) {
orig := makeTestCloud(t, 100, 10, 10)
pp := cloneCloud(orig)

p := &appendPatch{oldPoints: pp.Points, oldWidth: pp.Width, oldHeight: pp.Height}
added := makeTestCloud(t, 10, 10, 1)
pp.Data = append(pp.Data, added.Data...)
pp.Points += added.Points
pp.Width = pp.Points
pp.Height = 1

out, err := p.revert(pp)
if err != nil {
t.Fatal(err)
}
assertCloudEqual(t, orig, out)
}

func TestReplacePatchRevert(t *testing.T) {
orig := makeTestCloud(t, 100, 10, 10)
orig.Viewpoint = []float32{0, 0, 0, 1, 0, 0, 0}
Expand All @@ -97,6 +115,7 @@ func TestPatchEncodeDecodeRoundTrip(t *testing.T) {
orig.Viewpoint = []float32{1, 2, 3, 1, 0, 0, 0}
patches := []patch{
&labelPatch{indices: []uint32{1, 2, 42}, oldLabels: []uint32{7, 8, 9}},
&appendPatch{oldPoints: 90, oldWidth: 9, oldHeight: 10},
&replacePatch{header: orig.PointCloudHeader.Clone(), data: orig.Data},
}

Expand Down
Loading