// Moves element position as well as relationships. func (elems *Elements) move(from, to dvid.Point3d, deleteElement bool) (moved *Element, changed bool) { for i, elem := range *elems { if from.Equals(elem.Pos) { changed = true (*elems)[i].Pos = to moved = (*elems)[i].Copy() if deleteElement { (*elems)[i] = (*elems)[len(*elems)-1] // Delete without preserving order. *elems = (*elems)[:len(*elems)-1] break } } } // Check relationships for any moved points. for i, elem := range *elems { // Move any relationship with given pt. for j, r := range elem.Rels { if from.Equals(r.To) { r.To = to (*elems)[i].Rels[j] = r changed = true } } } return }
// GetGoogleSpec returns a google-specific tile spec, which includes how the tile is positioned relative to // scaled volume boundaries. Not that the size parameter is the desired size and not what is required to fit // within a scaled volume. func (d *Data) GetGoogleSpec(scaling Scaling, plane dvid.DataShape, offset dvid.Point3d, size dvid.Point2d) (*GoogleTileSpec, error) { tile := new(GoogleTileSpec) tile.offset = offset // Convert combination of plane and size into 3d size. sizeWant, err := dvid.GetPoint3dFrom2d(plane, size, 1) if err != nil { return nil, err } tile.sizeWant = sizeWant // Determine which geometry is appropriate given the scaling and the shape/orientation tileSpec, err := GetTileSpec(scaling, plane) if err != nil { return nil, err } geomIndex, found := d.TileMap[*tileSpec] if !found { return nil, fmt.Errorf("Could not find scaled volume in %q for %s with scaling %d", d.DataName(), plane, scaling) } geom := d.Scales[geomIndex] tile.gi = geomIndex tile.channelCount = geom.ChannelCount tile.channelType = geom.ChannelType // Get the # bytes for each pixel switch geom.ChannelType { case "uint8": tile.bytesPerVoxel = 1 case "float": tile.bytesPerVoxel = 4 case "uint64": tile.bytesPerVoxel = 8 default: return nil, fmt.Errorf("Unknown volume channel type in %s: %s", d.DataName(), geom.ChannelType) } // Check if the tile is completely outside the volume. volumeSize := geom.VolumeSize if offset[0] >= volumeSize[0] || offset[1] >= volumeSize[1] || offset[2] >= volumeSize[2] { tile.outside = true return tile, nil } // Check if the tile is on the edge and adjust size. var adjSize dvid.Point3d = sizeWant maxpt, err := offset.Expand2d(plane, size) for i := 0; i < 3; i++ { if maxpt[i] > volumeSize[i] { tile.edge = true adjSize[i] = volumeSize[i] - offset[i] } } tile.size = adjSize return tile, nil }
func (d *Data) DeleteElement(ctx *datastore.VersionedCtx, pt dvid.Point3d) error { // Get from block key blockSize := d.blockSize() blockCoord := pt.Chunk(blockSize).(dvid.ChunkPoint3d) tk := NewBlockTKey(blockCoord) d.Lock() defer d.Unlock() elems, err := getElements(ctx, tk) if err != nil { return err } // Delete the given element deleted, _ := elems.delete(pt) if deleted == nil { return fmt.Errorf("Did not find element %s in datastore", pt) } // Put block key version without given element if err := putElements(ctx, tk, elems); err != nil { return err } // Alter all stored versions of this annotation using a batch. store, err := d.BackendStore() if err != nil { return err } batcher, ok := store.(storage.KeyValueBatcher) if !ok { return fmt.Errorf("Data type annotation requires batch-enabled store, which %q is not\n", store) } batch := batcher.NewBatch(ctx) // Delete in label key if err := d.deleteElementInLabel(ctx, batch, deleted.Pos); err != nil { return err } // Delete element in any tags if err := d.deleteElementInTags(ctx, batch, deleted.Pos, deleted.Tags); err != nil { return err } // Modify any reference in relationships if err := d.deleteElementInRelationships(ctx, batch, deleted.Pos, deleted.Rels); err != nil { return err } return batch.Commit() }
func newFloatVolume(t *testing.T, offset, size dvid.Point3d) *testVolume { var buf bytes.Buffer for i := int64(0); i < size.Prod(); i++ { if err := binary.Write(&buf, binary.LittleEndian, float32(i)); err != nil { t.Fatalf("couldn't write to float volume: %v\n", err) } } return &testVolume{ data: buf.Bytes(), offset: offset, size: size, } }
func (d *Data) deleteElementInLabel(ctx *datastore.VersionedCtx, batch storage.Batch, pt dvid.Point3d) error { labelData := d.GetSyncedLabelblk() if labelData == nil { return nil // no synced labels } label, err := labelData.GetLabelAtPoint(ctx.VersionID(), pt) if err != nil { return err } tk := NewLabelTKey(label) elems, err := getElementsNR(ctx, tk) if err != nil { return fmt.Errorf("err getting elements for label %d: %v\n", label, err) } // Note all elements to be deleted. var delta DeltaModifyElements var toDel []int for i, elem := range elems { if pt.Equals(elem.Pos) { delta.Del = append(delta.Del, ElementPos{Label: label, Kind: elem.Kind, Pos: elem.Pos}) toDel = append(toDel, i) } } if len(toDel) == 0 { return nil } // Delete them from high index to low index due while reusing slice. for i := len(toDel) - 1; i >= 0; i-- { d := toDel[i] elems[d] = elems[len(elems)-1] elems[len(elems)-1] = ElementNR{} elems = elems[:len(elems)-1] } // Put the modified list of elements if err := putBatchElements(batch, tk, elems); err != nil { return err } // Notify any subscribers of label annotation changes. evt := datastore.SyncEvent{Data: d.DataUUID(), Event: ModifyElementsEvent} msg := datastore.SyncMessage{Event: ModifyElementsEvent, Version: ctx.VersionID(), Delta: delta} if err := datastore.NotifySubscribers(evt, msg); err != nil { return err } return nil }
// Moves element position as well as relationships. func (elems *ElementsNR) move(from, to dvid.Point3d, deleteElement bool) (moved *ElementNR, changed bool) { for i, elem := range *elems { if from.Equals(elem.Pos) { changed = true (*elems)[i].Pos = to moved = (*elems)[i].Copy() if deleteElement { (*elems)[i] = (*elems)[len(*elems)-1] // Delete without preserving order. *elems = (*elems)[:len(*elems)-1] break } } } return }
func (elems *Elements) deleteRel(pt dvid.Point3d) (changed bool) { for i, elem := range *elems { // Remove any relationship with given pt. var todel []int for j, r := range elem.Rels { if pt.Equals(r.To) { todel = append(todel, j) } } if len(todel) > 0 { (*elems)[i].Rels = elem.Rels.delete(todel) changed = true } } return }
// Deletes element position as well as relationships that reference that element. func (elems *ElementsNR) delete(pt dvid.Point3d) (deleted *ElementNR, changed bool) { // Delete any elements at point. var cut = -1 for i, elem := range *elems { if pt.Equals(elem.Pos) { cut = i break } } if cut >= 0 { deleted = (*elems)[cut].Copy() changed = true (*elems)[cut] = (*elems)[len(*elems)-1] // Delete without preserving order. *elems = (*elems)[:len(*elems)-1] } return }
// Deletes element position as well as relationships that reference that element. func (elems *Elements) delete(pt dvid.Point3d) (deleted *Element, changed bool) { // Delete any elements at point. var cut = -1 for i, elem := range *elems { if pt.Equals(elem.Pos) { cut = i break } } if cut >= 0 { deleted = (*elems)[cut].Copy() changed = true (*elems)[cut] = (*elems)[len(*elems)-1] // Delete without preserving order. *elems = (*elems)[:len(*elems)-1] } // Delete any relationships with the point. if elems.deleteRel(pt) { changed = true } return }
// move all reference to given element point in the related points in different blocks. // This is private method and assumes outer locking as well as current "from" block already being modified, // including relationships. func (d *Data) moveElementInRelationships(ctx *datastore.VersionedCtx, batch storage.Batch, from, to dvid.Point3d, rels []Relationship) error { blockSize := d.blockSize() fromBlockCoord := from.Chunk(blockSize).(dvid.ChunkPoint3d) // Get list of blocks with related points. relBlocks := make(map[dvid.IZYXString]struct{}) for _, rel := range rels { blockCoord := rel.To.Chunk(blockSize).(dvid.ChunkPoint3d) if blockCoord.Equals(fromBlockCoord) { continue // relationships are almoved in from block } relBlocks[blockCoord.ToIZYXString()] = struct{}{} } // Alter the moved points in those related blocks. for izyxstr := range relBlocks { blockCoord, err := izyxstr.ToChunkPoint3d() if err != nil { return err } tk := NewBlockTKey(blockCoord) elems, err := getElements(ctx, tk) if err != nil { return err } // Move element in related element. if _, changed := elems.move(from, to, false); !changed { dvid.Errorf("Unable to find moved element %s in related element @ block %s:\n%v\n", from, blockCoord, elems) continue } // Save the block elements. if err := putBatchElements(batch, tk, elems); err != nil { return err } } return nil }
// delete all reference to given element point in the slice of tags. // This is private method and assumes outer locking. func (d *Data) deleteElementInTags(ctx *datastore.VersionedCtx, batch storage.Batch, pt dvid.Point3d, tags []Tag) error { for _, tag := range tags { // Get the elements in tag. tk, err := NewTagTKey(tag) if err != nil { return err } elems, err := getElementsNR(ctx, tk) if err != nil { return err } // Note all elements to be deleted. var toDel []int for i, elem := range elems { if pt.Equals(elem.Pos) { toDel = append(toDel, i) } } if len(toDel) == 0 { continue } // Delete them from high index to low index due while reusing slice. for i := len(toDel) - 1; i >= 0; i-- { d := toDel[i] elems[d] = elems[len(elems)-1] elems[len(elems)-1] = ElementNR{} elems = elems[:len(elems)-1] } // Save the tag. if err := putBatchElements(batch, tk, elems); err != nil { return err } } return nil }
// blockSize is either defined by any synced labelblk or by the default block size. // Also checks to make sure that synced data is consistent. func (d *Data) blockSize() dvid.Point3d { if d.cachedBlockSize != nil { return *d.cachedBlockSize } var bsize dvid.Point3d d.cachedBlockSize = &bsize if lb := d.GetSyncedLabelblk(); lb != nil { bsize = lb.BlockSize().(dvid.Point3d) return bsize } if lv := d.GetSyncedLabelvol(); lv != nil { if len(bsize) != 0 && !bsize.Equals(lv.BlockSize) { dvid.Errorf("annotations %q is synced to labelblk and labelvol with different block sizes!\n", d.DataName()) } else { bsize = lv.BlockSize return bsize } } if len(bsize) != 0 { bsize = dvid.Point3d{DefaultBlockSize, DefaultBlockSize, DefaultBlockSize} } return bsize }
func TestSetMetadata(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid, _ := initTestRepo() server.CreateTestInstance(t, uuid, "imagetile", "tiles", dvid.Config{}) // Store Metadata url := fmt.Sprintf("%snode/%s/tiles/metadata", server.WebAPIPath, uuid) server.TestHTTP(t, "POST", url, bytes.NewBufferString(testMetadata)) // Check instance really has it set. var metadata metadataJSON respStr := server.TestHTTP(t, "GET", url, nil) if err := json.Unmarshal(respStr, &metadata); err != nil { t.Fatalf("Couldn't parse JSON response to metadata request (%v):\n%s\n", err, respStr) } expectMin := dvid.Point3d{0, 0, 0} expectMax := dvid.Point3d{5, 5, 4} if !expectMin.Equals(metadata.MinTileCoord) { t.Errorf("Expected min tile coord %s, got %s\n", expectMin, metadata.MinTileCoord) } if !expectMax.Equals(metadata.MaxTileCoord) { t.Errorf("Expected max tile coord %s, got %s\n", expectMax, metadata.MaxTileCoord) } tileSpec, err := parseTileSpec(metadata.Levels) if err != nil { t.Errorf("Error parsing returned tile level spec:\n%v\n", metadata.Levels) } if len(tileSpec) != 4 { t.Errorf("Bad tile spec load: only %d elements != 4\n", len(tileSpec)) } if tileSpec[2].Resolution.GetMax() != 40.0 { t.Errorf("Bad tile spec at level 2: %v\n", tileSpec[2]) } if tileSpec[3].TileSize.Value(2) != 512 { t.Errorf("Bad tile spec at level 3: %v\n", tileSpec[3]) } }
// GetGoogleSubvolGeom returns a google-specific voxel spec, which includes how the data is positioned relative to // scaled volume boundaries. Not that the size parameter is the desired size and not what is required to fit // within a scaled volume. func (d *Data) GetGoogleSubvolGeom(scaling Scaling, shape dvid.DataShape, offset dvid.Point3d, size dvid.Point) (*GoogleSubvolGeom, error) { gsg := new(GoogleSubvolGeom) if err := gsg.shape.FromShape(shape); err != nil { return nil, err } gsg.offset = offset // If 2d plane, convert combination of plane and size into 3d size. if size.NumDims() == 2 { size2d := size.(dvid.Point2d) sizeWant, err := dvid.GetPoint3dFrom2d(shape, size2d, 1) if err != nil { return nil, err } gsg.sizeWant = sizeWant } else { var ok bool gsg.sizeWant, ok = size.(dvid.Point3d) if !ok { return nil, fmt.Errorf("Can't convert %v to dvid.Point3d", size) } } // Determine which geometry is appropriate given the scaling and the shape/orientation tileSpec, err := GetGSpec(scaling, shape) if err != nil { return nil, err } geomIndex, found := d.GeomMap[*tileSpec] if !found { return nil, fmt.Errorf("Could not find scaled volume in %q for %s with scaling %d", d.DataName(), shape, scaling) } geom := d.Scales[geomIndex] gsg.gi = geomIndex gsg.channelCount = geom.ChannelCount gsg.channelType = geom.ChannelType // Get the # bytes for each pixel switch geom.ChannelType { case "UINT8": gsg.bytesPerVoxel = 1 case "FLOAT": gsg.bytesPerVoxel = 4 case "UINT64": gsg.bytesPerVoxel = 8 default: return nil, fmt.Errorf("Unknown volume channel type in %s: %s", d.DataName(), geom.ChannelType) } // Check if the requested area is completely outside the volume. volumeSize := geom.VolumeSize if offset[0] >= volumeSize[0] || offset[1] >= volumeSize[1] || offset[2] >= volumeSize[2] { gsg.outside = true return gsg, nil } // Check if the requested shape is on the edge and adjust size. adjSize := gsg.sizeWant maxpt := offset.Add(adjSize) for i := uint8(0); i < 3; i++ { if maxpt.Value(i) > volumeSize[i] { gsg.edge = true adjSize[i] = volumeSize[i] - offset[i] } } gsg.size = adjSize return gsg, nil }
func (d *Data) ConstructTiles(uuidStr string, tileSpec TileSpec, request datastore.Request) error { config := request.Settings() uuid, versionID, err := datastore.MatchingUUID(uuidStr) if err != nil { return err } if err = datastore.AddToNodeLog(uuid, []string{request.Command.String()}); err != nil { return err } source, err := datastore.GetDataByUUID(uuid, d.Source) if err != nil { return err } src, ok := source.(*imageblk.Data) if !ok { return fmt.Errorf("Cannot construct imagetile for non-voxels data: %s", d.Source) } // Save the current tile specification d.Levels = tileSpec if err := datastore.SaveDataByUUID(uuid, d); err != nil { return err } // Get size of tile at lowest resolution. lastLevel := Scaling(len(tileSpec) - 1) loresSpec, found := tileSpec[lastLevel] if !found { return fmt.Errorf("Illegal tile spec. Should have levels 0 to absent %d.", lastLevel) } var loresSize [3]float64 for i := 0; i < 3; i++ { loresSize[i] = float64(loresSpec.Resolution[i]) * float64(DefaultTileSize[i]) } loresMag := dvid.Point3d{1, 1, 1} for i := Scaling(0); i < lastLevel; i++ { levelMag := tileSpec[i].levelMag loresMag[0] *= levelMag[0] loresMag[1] *= levelMag[1] loresMag[2] *= levelMag[2] } // Get min and max points in terms of distance. var minPtDist, maxPtDist [3]float64 for i := uint8(0); i < 3; i++ { minPtDist[i] = float64(src.MinPoint.Value(i)) * float64(src.VoxelSize[i]) maxPtDist[i] = float64(src.MaxPoint.Value(i)) * float64(src.VoxelSize[i]) } // Adjust min and max points for the tileable surface at lowest resolution. var minTiledPt, maxTiledPt dvid.Point3d for i := 0; i < 3; i++ { minInt, _ := math.Modf(minPtDist[i] / loresSize[i]) maxInt, _ := math.Modf(maxPtDist[i] / loresSize[i]) minTileCoord := int32(minInt) maxTileCoord := int32(maxInt) minTiledPt[i] = minTileCoord * DefaultTileSize[i] * loresMag[i] maxTiledPt[i] = (maxTileCoord+1)*DefaultTileSize[i]*loresMag[i] - 1 } sizeVolume := maxTiledPt.Sub(minTiledPt).AddScalar(1) // Setup swappable ExtData buffers (the stitched slices) so we can be generating tiles // at same time we are reading and stitching them. var bufferLock [2]sync.Mutex var sliceBuffers [2]*imageblk.Voxels var bufferNum int // Get the planes we should tile. planes, err := config.GetShapes("planes", ";") if planes == nil { // If no planes are specified, construct imagetile for 3 orthogonal planes. planes = []dvid.DataShape{dvid.XY, dvid.XZ, dvid.YZ} } outF, err := d.putTileFunc(versionID) // sort the tile spec keys to iterate from highest to lowest resolution var sortedKeys []int for scaling, _ := range tileSpec { sortedKeys = append(sortedKeys, int(scaling)) } sort.Ints(sortedKeys) for _, plane := range planes { timedLog := dvid.NewTimeLog() offset := minTiledPt.Duplicate() switch { case plane.Equals(dvid.XY): width, height, err := plane.GetSize2D(sizeVolume) if err != nil { return err } dvid.Debugf("Tiling XY image %d x %d pixels\n", width, height) for z := src.MinPoint.Value(2); z <= src.MaxPoint.Value(2); z++ { server.BlockOnInteractiveRequests("imagetile.ConstructTiles [xy]") sliceLog := dvid.NewTimeLog() offset = offset.Modify(map[uint8]int32{2: z}) slice, err := dvid.NewOrthogSlice(dvid.XY, offset, dvid.Point2d{width, height}) if err != nil { return err } bufferLock[bufferNum].Lock() sliceBuffers[bufferNum], err = src.NewVoxels(slice, nil) if err != nil { return err } if err = src.GetVoxels(versionID, sliceBuffers[bufferNum], nil); err != nil { return err } // Iterate through the different scales, extracting tiles at each resolution. go func(bufferNum int, offset dvid.Point) { defer bufferLock[bufferNum].Unlock() timedLog := dvid.NewTimeLog() for _, key := range sortedKeys { scaling := Scaling(key) levelSpec := tileSpec[scaling] if err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if err := d.extractTiles(sliceBuffers[bufferNum], offset, scaling, outF); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if int(scaling) < len(tileSpec)-1 { if err := sliceBuffers[bufferNum].DownRes(levelSpec.levelMag); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } } } timedLog.Debugf("Tiled XY Tile using buffer %d", bufferNum) }(bufferNum, offset) sliceLog.Infof("Read XY Tile @ Z = %d, now tiling...", z) bufferNum = (bufferNum + 1) % 2 } timedLog.Infof("Total time to generate XY Tiles") case plane.Equals(dvid.XZ): width, height, err := plane.GetSize2D(sizeVolume) if err != nil { return err } dvid.Debugf("Tiling XZ image %d x %d pixels\n", width, height) for y := src.MinPoint.Value(1); y <= src.MaxPoint.Value(1); y++ { server.BlockOnInteractiveRequests("imagetile.ConstructTiles [xz]") sliceLog := dvid.NewTimeLog() offset = offset.Modify(map[uint8]int32{1: y}) slice, err := dvid.NewOrthogSlice(dvid.XZ, offset, dvid.Point2d{width, height}) if err != nil { return err } bufferLock[bufferNum].Lock() sliceBuffers[bufferNum], err = src.NewVoxels(slice, nil) if err != nil { return err } if err = src.GetVoxels(versionID, sliceBuffers[bufferNum], nil); err != nil { return err } // Iterate through the different scales, extracting tiles at each resolution. go func(bufferNum int, offset dvid.Point) { defer bufferLock[bufferNum].Unlock() timedLog := dvid.NewTimeLog() for _, key := range sortedKeys { scaling := Scaling(key) levelSpec := tileSpec[scaling] if err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if err := d.extractTiles(sliceBuffers[bufferNum], offset, scaling, outF); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if int(scaling) < len(tileSpec)-1 { if err := sliceBuffers[bufferNum].DownRes(levelSpec.levelMag); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } } } timedLog.Debugf("Tiled XZ Tile using buffer %d", bufferNum) }(bufferNum, offset) sliceLog.Infof("Read XZ Tile @ Y = %d, now tiling...", y) bufferNum = (bufferNum + 1) % 2 } timedLog.Infof("Total time to generate XZ Tiles") case plane.Equals(dvid.YZ): width, height, err := plane.GetSize2D(sizeVolume) if err != nil { return err } dvid.Debugf("Tiling YZ image %d x %d pixels\n", width, height) for x := src.MinPoint.Value(0); x <= src.MaxPoint.Value(0); x++ { server.BlockOnInteractiveRequests("imagetile.ConstructTiles [yz]") sliceLog := dvid.NewTimeLog() offset = offset.Modify(map[uint8]int32{0: x}) slice, err := dvid.NewOrthogSlice(dvid.YZ, offset, dvid.Point2d{width, height}) if err != nil { return err } bufferLock[bufferNum].Lock() sliceBuffers[bufferNum], err = src.NewVoxels(slice, nil) if err != nil { return err } if err = src.GetVoxels(versionID, sliceBuffers[bufferNum], nil); err != nil { return err } // Iterate through the different scales, extracting tiles at each resolution. go func(bufferNum int, offset dvid.Point) { defer bufferLock[bufferNum].Unlock() timedLog := dvid.NewTimeLog() for _, key := range sortedKeys { scaling := Scaling(key) levelSpec := tileSpec[scaling] outF, err := d.putTileFunc(versionID) if err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if err := d.extractTiles(sliceBuffers[bufferNum], offset, scaling, outF); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } if int(scaling) < len(tileSpec)-1 { if err := sliceBuffers[bufferNum].DownRes(levelSpec.levelMag); err != nil { dvid.Errorf("Error in tiling: %v\n", err) return } } } timedLog.Debugf("Tiled YZ Tile using buffer %d", bufferNum) }(bufferNum, offset) sliceLog.Debugf("Read YZ Tile @ X = %d, now tiling...", x) bufferNum = (bufferNum + 1) % 2 } timedLog.Infof("Total time to generate YZ Tiles") default: dvid.Infof("Skipping request to tile '%s'. Unsupported.", plane) } } return nil }
func (d *Data) MoveElement(ctx *datastore.VersionedCtx, from, to dvid.Point3d) error { // Calc block keys blockSize := d.blockSize() fromCoord := from.Chunk(blockSize).(dvid.ChunkPoint3d) fromTk := NewBlockTKey(fromCoord) toCoord := to.Chunk(blockSize).(dvid.ChunkPoint3d) toTk := NewBlockTKey(toCoord) d.Lock() defer d.Unlock() // Alter all stored versions of this annotation using a batch. store, err := d.BackendStore() if err != nil { return err } batcher, ok := store.(storage.KeyValueBatcher) if !ok { return fmt.Errorf("Data type annotation requires batch-enabled store, which %q is not\n", store) } batch := batcher.NewBatch(ctx) // Handle from block fromElems, err := getElements(ctx, fromTk) if err != nil { return err } deleteElement := (bytes.Compare(fromTk, toTk) != 0) moved, _ := fromElems.move(from, to, deleteElement) if moved == nil { return fmt.Errorf("Did not find moved element %s in datastore", from) } dvid.Infof("moved element %v from %s -> %s\n", *moved, fromCoord, toCoord) if err := putBatchElements(batch, fromTk, fromElems); err != nil { return err } // If we've moved blocks, add the element in new place. if deleteElement { toElems, err := getElements(ctx, toTk) if err != nil { return err } toElems.add(Elements{*moved}) dvid.Infof("new %s value: %v\n", toCoord, toElems) if err := putBatchElements(batch, toTk, toElems); err != nil { return err } } if err := batch.Commit(); err != nil { return err } batch = batcher.NewBatch(ctx) // Move in label key if err := d.moveElementInLabels(ctx, batch, from, to, moved.ElementNR); err != nil { return err } // Move element in any tags if err := d.moveElementInTags(ctx, batch, from, to, moved.Tags); err != nil { return err } // Move any reference in relationships if err := d.moveElementInRelationships(ctx, batch, from, to, moved.Rels); err != nil { return err } return batch.Commit() }
func (i Immutable) VoxelWithin(p dvid.Point3d) bool { izyx := p.ToBlockIZYXString(i.blockSize) _, found := i.blocks[izyx] return found }