let duplicate (b: BlockReference) =
b.Name,
b.OwnerId,
b.Position,
b.Layer,
Math.Round(b.Rotation, 6),
b.ScaleFactors
let deleteDuplicatedBlockRef() =
let db = HostApplicationServices.WorkingDatabase
use tr = db.TransactionManager.StartTransaction()
let getRefs btrId =
let btr = tr.GetObject(btrId, OpenMode.ForRead) :?> BlockTableRecord
btr.GetBlockReferenceIds(true, false)
|> Seq.cast<_>
let openRefs brefId =
tr.GetObject(brefId, OpenMode.ForRead) :?> BlockReference
let skipFirst = function
| LazyList.Nil -> Seq.empty
| LazyList.Cons(_, xs) -> LazyList.toSeq xs
let groupRefsAndDelete =
Seq.cast<_>
>> Seq.collect getRefs
>> Seq.map openRefs
>> Seq.groupBy duplicate
>> Seq.map (snd >> LazyList.ofSeq)
>> Seq.collect skipFirst
>> Seq.fold
(fun cnt bref ->
bref.UpgradeOpen()
bref.Erase()
cnt + 1 ) 0
let cnt =
tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
|> groupRefsAndDelete
tr.Commit()
cnt
let duplicate (b: BlockReference) =
b.Name,
b.OwnerId,
Math.Round(b.Position.X, 6),
Math.Round(b.Position.Y, 6),
Math.Round(b.Position.Z, 6),
b.Layer,
Math.Round(b.Rotation, 6),
Math.Round(b.ScaleFactors.X, 6),
Math.Round(b.ScaleFactors.Y, 6),
Math.Round(b.ScaleFactors.Z, 6)
let deleteDuplicatedBlockRef() =
let db = HostApplicationServices.WorkingDatabase
use tr = db.TransactionManager.StartTransaction()
let getRefs btrId =
let btr = tr.GetObject(btrId, OpenMode.ForRead) :?> BlockTableRecord
btr.GetBlockReferenceIds(true, false)
|> Seq.cast<_>
let openRefs brefId =
tr.GetObject(brefId, OpenMode.ForRead) :?> BlockReference
let cnt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
|> Seq.cast<_>
|> Seq.collect getRefs
|> Seq.map openRefs
|> Seq.groupBy duplicate
|> Seq.collect (fun x -> snd x |> Seq.skip 1)
|> Seq.fold (fun cnt bref ->
bref.UpgradeOpen()
bref.Erase()
cnt + 1 ) 0
tr.Commit()
cnt
Try to set up a algorithm to only have loop through each set of blockreferences once
Something like create a dictionary<point3d , point3d>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
EqualsWillUseReferece classVariable1 = new EqualsWillUseReferece();
classVariable1.int1 = 15;
classVariable1.str1 = "string";
EqualsWillUseReferece classVariable2 = new EqualsWillUseReferece();
classVariable2.int1 = 15;
classVariable2.str1 = "string";
EqulsWillUseValues stuctVariable1 = new EqulsWillUseValues();
stuctVariable1.int1 = 15;
stuctVariable1.str1 = "string";
EqulsWillUseValues stuctVariable2 = new EqulsWillUseValues();
stuctVariable2.int1 = 15;
stuctVariable2.str1 = "string";
if (classVariable1.Equals(classVariable2))
{
Console.WriteLine("Class variables are Equal");
}
else
{
Console.WriteLine("Class variables are Not Equal");
}
if (stuctVariable1.Equals(stuctVariable2))
{
Console.WriteLine("Struc variables are Equal");
}
else
{
Console.WriteLine("Struc variables are Not Equal");
}
Console.ReadLine();
}
}
public class EqualsWillUseReferece
{
public int int1;
public string str1;
}
public struct EqulsWillUseValues
{
public int int1;
public string str1;
}
}
Try to set up a algorithm to only have loop through each set of blockreferences once
Something like create a dictionary<point3d , point3d>
Hi Jeff F,
I tried to implement that kind of solution, you can have a look at the code in this post http://www.acadnetwork.com/boardseen,/topic-51.msg79.html#new (http://www.acadnetwork.com/boardseen,/topic-51.msg79.html#new).
I used a structure for the key of my dictionary and i've implemented the 'equals' function to make the test as i wanted to do. But i don't really understand how to use the GetHashCode function and if i need tu use it.
Thanks.
(Edit: I think the post of Gile in the topic of AcadNetWork answers to my question)
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace DuplicateTest
{
public class Commands
{
struct DuplicatePattern
{
public string Name;
public string Layer;
public ObjectId OwnerId;
public double PositionX;
public double PositionY;
public double PositionZ;
public double Rotation;
public double ScaleX;
public double ScaleY;
public double ScaleZ;
}
private int DeleteDuplicatedBlockRef()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
int result = 0;
SelectionFilter filter = new SelectionFilter(new TypedValue[1] { new TypedValue(0, "INSERT") });
PromptSelectionResult psr = ed.SelectAll(filter);
if (psr.Status != PromptStatus.OK)
return 0;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
List<DuplicatePattern> Patterns = new List<DuplicatePattern>();
foreach (ObjectId id in psr.Value.GetObjectIds())
{
BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead, false);
DuplicatePattern dp = new DuplicatePattern();
dp.OwnerId = br.OwnerId;
dp.Name = br.Name;
dp.Layer = br.Layer;
dp.PositionX = Math.Round(br.Position.X, 6);
dp.PositionY = Math.Round(br.Position.Y, 6);
dp.PositionZ = Math.Round(br.Position.Z, 6);
dp.Rotation = Math.Round(br.Rotation, 6);
dp.ScaleX = Math.Round(br.ScaleFactors.X, 6);
dp.ScaleY = Math.Round(br.ScaleFactors.Y, 6);
dp.ScaleZ = Math.Round(br.ScaleFactors.Z, 6);
if (Patterns.Contains(dp))
{
br.UpgradeOpen();
br.Erase();
result++;
}
else
Patterns.Add(dp);
}
tr.Commit();
}
return result;
}
[CommandMethod("Cs_gile")]
public void DelDupBlkRef()
{
DateTime t0 = DateTime.Now;
int del = DeleteDuplicatedBlockRef();
DateTime t1 = DateTime.Now;
TimeSpan ts = t1 - t0;
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
"{0} duplicated block(s) have been erased in {1} milliseconds",
del, ts.TotalMilliseconds);
}
}
}
module DupBlks
open System
open System.Collections.Generic
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime
let duplicate (b: BlockReference) =
b.Name,
b.OwnerId,
Math.Round(b.Position.X, 6),
Math.Round(b.Position.Y, 6),
Math.Round(b.Position.Z, 6),
b.Layer,
Math.Round(b.Rotation, 6),
Math.Round(b.ScaleFactors.X, 6),
Math.Round(b.ScaleFactors.Y, 6),
Math.Round(b.ScaleFactors.Z, 6)
let deleteDuplicatedBlockRef() =
let db = HostApplicationServices.WorkingDatabase
use tr = db.TransactionManager.StartTransaction()
let getRefs btrId =
let btr = tr.GetObject(btrId, OpenMode.ForRead) :?> BlockTableRecord
btr.GetBlockReferenceIds(true, false)
|> Seq.cast<_>
let openRefs brefId =
tr.GetObject(brefId, OpenMode.ForRead) :?> BlockReference
let cnt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
|> Seq.cast<_>
|> Seq.collect getRefs
|> Seq.map openRefs
|> Seq.groupBy duplicate
|> Seq.collect (fun x -> snd x |> Seq.skip 1)
|> Seq.fold (fun cnt bref ->
bref.UpgradeOpen()
bref.Erase()
cnt + 1 ) 0
tr.Commit()
cnt
[<CommandMethod("Fs_gile")>]
let Test() =
let t0 = DateTime.Now
let del = deleteDuplicatedBlockRef()
let t1 = DateTime.Now
let ts = t1 - t0
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
"{0} duplicated block(s) have been erased in {1} milliseconds",
del, ts.TotalMilliseconds)
Commande: FS_GILE
10134 duplicated block(s) have been erased in 221.0126 milliseconds
Commande: CS_GILE2
10134 duplicated block(s) have been erased in 1372.8024 milliseconds
;;;---------------------------------------------------------------------------;
;;;
;;; DEL_BLK.LSP
;;;
;;; (C) Copyright 1999 by Autodesk, Inc.
;;;
;;; Permission to use, copy, modify, and distribute this software
;;; for any purpose and without fee is hereby granted, provided
;;; that the above copyright notice appears in all copies and
;;; that both that copyright notice and the limited warranty and
;;; restricted rights notice below appear in all supporting
;;; documentation.
;;;
;;; AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
;;; AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
;;; MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
;;; DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
;;; UNINTERRUPTED OR ERROR FREE.
;;;
;;; Use, duplication, or disclosure by the U.S. Government is subject to
;;; restrictions set forth in FAR 52.227-19 (Commercial Computer
;;; Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
;;; (Rights in Technical Data and Computer Software), as applicable.
;;;
;;; July 1996
;;;
;;;---------------------------------------------------------------------------;
;;;
;;; DESCRIPTION
;;;
;;; This function deletes duplicate block objects.
;;; A duplicate object is defined as
;;; -the same location
;;; -the same layer
;;; -the same block name
;;; -the same rotation angle
;;; -the same x scale
;;; -the same y scale
;;; -the same z scale
;;;---------------------------------------------------------------------------;
;;;****************************************************************************
;;;
;;; Code modified:
;;; - add a tolerance with position, rotation and scales
;;; - add a chrono
;;; - all blocks selected
(defun c:deldup_blk( / ss ssdup ct len e eb
pt lay bname ang sclx scly sclz obj obj_list)
;;(princ "\nSelect block objects.") ;Select objects and filter all but block insert objects.
(setq ss (ssget "_X" (list (cons 0 "INSERT"))))
(if ss ;If any valid objects were selected.
(progn
(princ "\nBuilding list of objects.")
(setq t0 (get-utime))
(setq ssdup (ssadd)) ;Initialize new selection set to hold objects to delete
(setq len (sslength ss)) ;Find out how many objects were selected.
(setq ct 0)
(while (< ct len) ;Loop through selected objects
(setq e (ssname ss ct)) ;Get an object name
(setq eb (entget e)) ;Get the entity list from the object name
(setq ct (+ ct 1)) ;Increment index into selection set
(setq pt (mapcar ;Access object's coordinate
'(lambda (x) (round x 0.000001))
(cdr (assoc 10 eb))
)
)
(setq lay (cdr (assoc 8 eb))) ;Access object's layer
(setq bname (cdr (assoc 2 eb))) ;Access object's block name
(setq ang (round (cdr (assoc 50 eb))0.000001)) ;Access object's rotation angle
(setq sclx (round (cdr (assoc 41 eb))0.000001)) ;Access object's x scale
(setq scly (round (cdr (assoc 42 eb))0.000001)) ;Access object's y scale
(setq sclz (round (cdr (assoc 43 eb))0.000001)) ;Access object's z scale
;Make list of object properties
(setq obj (list pt lay bname ang sclx scly sclz))
(if (not (member obj obj_list)) ;If these properties are not already in list
(setq obj_list (cons obj obj_list)) ;Add them to the list
(ssadd e ssdup) ;Else add object to selection set to delete
) ;End if
) ;End of while loop
(if (> (sslength ssdup) 0) ;If there are any objects in the selection set to delete
(progn
(princ "\nDeleting duplicate objects.")
(setq len (sslength ssdup)) ;Find out how many many objects to delete.
(setq ct 0)
(while (< ct len) ;Loop through objects and delete.
(setq e (ssname ssdup ct)) ;Get object name
(setq ct (+ ct 1)) ;Increment index into selection set
(entdel e) ;Delete duplicate object
) ;End of while loop
(setq t1 (get-utime))
(princ ;Print the number of objects deleted to command line
(strcat "\nDeleted "
(itoa len)
" duplicated block(s) have been erased in "
(rtos (- t1 t0))
" millseconds"
))
) ;End progn
(princ "\nNo duplicates found.") ;Else no there were no duplicates to delete.
) ;End if
) ;End progn
(princ "\nNo block objects selected.") ;Else there were no valid objects selected
) ;End if
(princ)
)
(defun round (num prec)
(if (zerop (setq prec (abs prec)))
num
(if (minusp num)
(* prec (fix (- (/ num prec) 0.5)))
(* prec (fix (+ (/ num prec) 0.5)))
)
)
)
(defun get-utime ()
(* 86400000. (getvar "tdusrtimer"))
)
Commande: DELDUP_BLK
Building list of objects.
Deleting duplicate objects.
Deleted 10134 duplicated blocks have been erased in 1359 millseconds
The upper C# code is certainly not very good: it seems to run a little slower than the old Autodesk del-blk.lsp (http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=2525595&linkID=9240858)
...
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++)
{
object obj3 = ((RtFieldInfo) fields[i]).InternalGetValue(a, false);
object obj4 = ((RtFieldInfo) fields[i]).InternalGetValue(obj, false);
...
Commande: DELDUP_BLK
Building list of objects.
Deleting duplicate objects.
Deleted 10134 duplicated blocks have been erased in 1359 millseconds
F# | Seq.groupBy | 450 ms |
F# | Map<duplicate,unit> | 500 ms |
C# | LINQ .groupBy | 510 ms |
C# | Dictionary<DuplicatePattern,int> | 530 ms |
C# | List<DuplicatePattern> | 2,100 ms |
Lisp | C:DELDUP_BLK | 5,800 ms |
struct DuplicatePattern
{
public string Layer;
public double PositionX;
public double PositionY;
public double PositionZ;
public double Rotation;
public double ScaleX;
public double ScaleY;
public double ScaleZ;
public DuplicatePattern(BlockReference bref)
{
Layer = bref.Layer;
PositionX = Math.Round(bref.Position.X, 6);
PositionY = Math.Round(bref.Position.Y, 6);
PositionZ = Math.Round(bref.Position.Z, 6);
Rotation = Math.Round(bref.Rotation, 6);
ScaleX = Math.Round(bref.ScaleFactors.X, 6);
ScaleY = Math.Round(bref.ScaleFactors.Y, 6);
ScaleZ = Math.Round(bref.ScaleFactors.Z, 6);
}
}
[CommandMethod("tt8")]
public static void test28()
{
DateTime t0 = DateTime.Now;
int count = 0;
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
var brefids =
from ObjectId id in (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead)
let btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead)
select btr.GetBlockReferenceIds(true, false);
foreach (var idcol in brefids)
{
var brefdict =
idcol.Cast<ObjectId>()
.Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
.GroupBy(bref => new DuplicatePattern(bref));
foreach (var brefs in brefdict)
{
foreach (var bref in brefs.Skip(1))
{
bref.UpgradeOpen();
bref.Erase();
count++;
}
}
}
tr.Commit();
}
TimeSpan ts = DateTime.Now - t0;
ed.WriteMessage(
"{0} duplicated block(s) have been erased in {1} milliseconds",
count, ts.TotalMilliseconds);
}
Commande: DELDUP_BLK
Building list of objects.
Deleting duplicate objects.
10134 duplicated block(s) have been erased in 1224 millseconds
Commande: TT8
10134 duplicated block(s) have been erased in 233.0134 milliseconds
Commande: CS_GILE
10134 duplicated block(s) have been erased in 275.0157 milliseconds
Commande: FS_GILE
10134 duplicated block(s) have been erased in 210.012 milliseconds
(defun delDups (/ n ss blk elst data orglst duplst)
(if (setq n -1
ss (ssget "_X" '((0 . "INSERT")))
)
(while (setq blk (ssname ss (setq n (1+ n))))
(setq elst (entget blk)
data (list
(cdr (assoc 330 elst))
(cdr (assoc 2 elst))
(mapcar '(lambda (x) (round x 0.000001)) (cdr (assoc 10 elst)))
(cdr (assoc 8 elst))
(round (cdr (assoc 50 elst)) 0.000001)
(round (cdr (assoc 41 elst)) 0.000001)
(round (cdr (assoc 42 elst)) 0.000001)
(round (cdr (assoc 43 elst)) 0.000001)
)
)
(if (member data orglst)
(setq duplst (cons blk duplst))
(setq orglst (cons data orglst))
)
)
)
(length (mapcar 'entdel duplst))
)
(defun round (num prec)
(if (zerop (setq prec (abs prec)))
num
(if (minusp num)
(* prec (fix (- (/ num prec) 0.5)))
(* prec (fix (+ (/ num prec) 0.5)))
)
)
)
(defun c:lsp_gile (/ t0 t1 cnt)
(vl-load-com)
(setq t0 (* 86400000. (getvar "tdusrtimer")))
(vla-startUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq cnt (delDups))
(vla-endUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq t1 (* 86400000. (getvar "tdusrtimer")))
(princ (strcat
"\n "
(itoa cnt)
" duplicated block(s) have been erased in "
(rtos (- t1 t0))
" millseconds"
)
)
(princ)
)
Commande: LSP_GILE
10134 duplicated block(s) have been erased in 624 millseconds
var brefsToDelete =
((BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead))
.Cast<ObjectId>()
.Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead))
.SelectMany(btr => btr.GetBlockReferenceIds(true, false).Cast<ObjectId>())
.Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
.GroupBy(bref => new DuplicatePattern(bref))
.SelectMany(brefs => brefs.Skip(1));
var brefsToDelete =
from ObjectId id in (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead)
let btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead)
select btr.GetBlockReferenceIds(true, false) into brefids
from ObjectId id in brefids
let bref = (BlockReference)tr.GetObject(id, OpenMode.ForRead)
group bref by new DuplicatePattern(bref) into brefDict
from brefs in brefDict.Skip(1)
select brefs;
struct DuplicatePattern
{
public ObjectId LayerId;
public Point3d Posision;
public double Rotation;
public Scale3d Scale;
}
... //command helper
static Acad::ErrorStatus getRefIds(AcDbObjectIdArray &blockRefIds)
{
AcDbObjectId blockTableRecordId;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcDbBlockTablePointer pBlockTable(pDb->blockTableId(),AcDb::kForRead);
AcDbBlockTableIterator *pIter;
pBlockTable->newIterator(pIter);
for(pIter->start();!pIter->done();pIter->step())
{
pIter->getRecordId(blockTableRecordId);
AcDbBlockTableRecordPointer pBlockTableRecord(blockTableRecordId,AcDb::kForRead);
pBlockTableRecord->getBlockReferenceIds(blockRefIds);
}
delete pIter;
return eOk;
}
//command
static void NukeDupRefs_nukeit(void)
{
LARGE_INTEGER freq,start,end;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
AcDbObjectIdArray blockRefIds;
getRefIds(blockRefIds);
std::vector<BlockData> vec;
vec.reserve(blockRefIds.length());
size_t cnt = 0;
for(size_t idx = 0; idx < blockRefIds.length(); idx++)
{
AcDbBlockReference *pRef = NULL;
if(acdbOpenAcDbEntity((AcDbEntity*&)pRef,blockRefIds[idx],AcDb::kForWrite) == Acad::eOk)
{
BlockData data(pRef);
if(std::find(vec.begin(),vec.end(),data) == vec.end())
{
vec.push_back(data);
}
else
{
pRef->erase();
cnt++;
}
pRef->close();
}
}
QueryPerformanceCounter(&end);
acutPrintf(_T("\nNuked %ld blocks in %f seconds: "),cnt,
(double)(end.QuadPart-start.QuadPart)/freq.QuadPart );
}
class BlockData
{
private:
AcDbObjectId m_layerId;
AcGePoint3d m_position;
double m_rotation;
AcGeScale3d m_scale;
public:
BlockData(const AcDbBlockReference *pReference);
bool operator==(const BlockData& rhs) const;
};
inline BlockData::BlockData(const AcDbBlockReference *pReference )
{
if(pReference)
{
m_layerId = pReference->layerId();
m_position = pReference->position();
m_rotation = pReference->rotation();
m_scale = pReference->scaleFactors();
}
}
inline bool BlockData::operator==( const BlockData& rhs )const
{
return m_layerId == rhs.m_layerId &&
m_position.isEqualTo(rhs.m_position) &&
m_rotation == rhs.m_rotation &&
m_scale.isEqualTo(rhs.m_scale);
}
C++ is a tad faster it seems
QuoteC++ is a tad faster it seems
Certainly, but looks like chinese to my eyes... :oops:
public class Commands
{
struct DuplicatePattern
{
public string Name;
public string Layer;
public ObjectId OwnerId;
public double PositionX;
public double PositionY;
public double PositionZ;
public double Rotation;
public double ScaleX;
public double ScaleY;
public double ScaleZ;
}
static Predicate<DuplicatePattern> Eq(DuplicatePattern b)
{
return delegate(DuplicatePattern a)
{
return
a.Name.Equals(b.Name) &&
a.Layer.Equals(b.Layer) &&
a.OwnerId.Equals(b.OwnerId) &&
a.PositionX.Equals(b.PositionX) &&
a.PositionY.Equals(b.PositionY) &&
a.PositionZ.Equals(b.PositionZ) &&
a.Rotation.Equals(b.Rotation) &&
a.ScaleX.Equals(b.ScaleX) &&
a.ScaleY.Equals(b.ScaleY) &&
a.ScaleZ.Equals(b.ScaleZ);
};
}
private int DeleteDuplicatedBlockRef()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
int result = 0;
SelectionFilter filter = new SelectionFilter(new TypedValue[1] { new TypedValue(0, "INSERT") });
PromptSelectionResult psr = ed.SelectAll(filter);
if (psr.Status != PromptStatus.OK)
return 0;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
List<DuplicatePattern> Patterns = new List<DuplicatePattern>();
foreach (ObjectId id in psr.Value.GetObjectIds())
{
BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite, false);
DuplicatePattern dp = new DuplicatePattern();
dp.OwnerId = br.OwnerId;
dp.Name = br.Name;
dp.Layer = br.Layer;
dp.PositionX = Math.Round(br.Position.X, 6);
dp.PositionY = Math.Round(br.Position.Y, 6);
dp.PositionZ = Math.Round(br.Position.Z, 6);
dp.Rotation = Math.Round(br.Rotation, 6);
dp.ScaleX = Math.Round(br.ScaleFactors.X, 6);
dp.ScaleY = Math.Round(br.ScaleFactors.Y, 6);
dp.ScaleZ = Math.Round(br.ScaleFactors.Z, 6);
if (Patterns.FindIndex(Eq(dp)) > -1)
{
br.Erase();
result++;
}
else
{
Patterns.Add(dp);
}
}
tr.Commit();
}
return result;
}
[CommandMethod("Cs_gile")]
public void DelDupBlkRef()
{
DateTime t0 = DateTime.Now;
int del = DeleteDuplicatedBlockRef();
DateTime t1 = DateTime.Now;
TimeSpan ts = t1 - t0;
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
"{0} duplicated block(s) have been erased in {1} milliseconds",
del, ts.TotalMilliseconds);
}
}
F# looks like Martian to me :laugh:
Code: [Select]...
static Predicate<DuplicatePattern> Eq(DuplicatePattern b)
{
return delegate(DuplicatePattern a)
{
return
a.Name.Equals(b.Name) &&
a.Layer.Equals(b.Layer) &&
a.OwnerId.Equals(b.OwnerId) &&
a.PositionX.Equals(b.PositionX) &&
a.PositionY.Equals(b.PositionY) &&
a.PositionZ.Equals(b.PositionZ) &&
a.Rotation.Equals(b.Rotation) &&
a.ScaleX.Equals(b.ScaleX) &&
a.ScaleY.Equals(b.ScaleY) &&
a.ScaleZ.Equals(b.ScaleZ);
};
}
...
if (Patterns.FindIndex(Eq(dp)) > -1)
{ ...
...
if (Patterns.Exists(b =>
dp.Name.Equals(b.Name) &&
dp.Layer.Equals(b.Layer) &&
dp.OwnerId.Equals(b.OwnerId) &&
dp.PositionX.Equals(b.PositionX) &&
dp.PositionY.Equals(b.PositionY) &&
dp.PositionZ.Equals(b.PositionZ) &&
dp.Rotation.Equals(b.Rotation) &&
dp.ScaleFactorsX.Equals(b.ScaleFactorsX) &&
dp.ScaleFactorsY.Equals(b.ScaleFactorsY) &&
dp.ScaleFactorsZ.Equals(b.ScaleFactorsZ)))
{ ...
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Func<BlockTableRecord, IEnumerable<BlockReference>> depfunc =
btr =>
btr.GetBlockReferenceIds(true, false).Cast<ObjectId>()
.Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
.GroupBy(bref => new { bref.Layer, bref.Position, bref.Rotation, bref.ScaleFactors })
.SelectMany(brefgroup => brefgroup.Skip(1));
var brefs =
((BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead)).Cast<ObjectId>()
.Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead))
.SelectMany(depfunc);
foreach (var bref in brefs)
{
bref.UpgradeOpen();
bref.Erase();
count++;
}
tr.Commit();
}
F# looks like Martian to me :laugh:
++
.........
Very minor optimization potential detected, if only for readability. May shave yet another few milliseconds off.
.........
..Or does the lambda look like Greek for anybody?
F# looks like Martian to me laughI discovered Martian two weeks ago, and I think I enjoy it.
HashSet<DuplicatePattern> Patterns = new HashSet<DuplicatePattern>();
...
if (Patterns.Contains(dp))
{
Well better get back to my C++ corner