Список форумов www.integro.ru www.integro.ru
ЦСИ ИНТЕГРО
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 

Поиск будликатов

 
Начать новую тему   Ответить на тему    Список форумов www.integro.ru -> Вопросы разработчиков
Предыдущая тема :: Следующая тема  
Автор Сообщение
Кузнецов Андрей



Зарегистрирован: 22.04.2005
Сообщения: 28
Откуда: Магнитогорск

СообщениеДобавлено: Пн 17 Апр 2006 12:24    Заголовок сообщения: Поиск будликатов Ответить с цитатой

Кто-нибудь задавлся задачей поиска дубликатов?
Хотя бы упрощенный вариант - абсалютный будль по геометрии (не включая семантику).
На скриптах сделал тест, но он очень медленный получился, поэтому работоспособным считать его не могу. Пока нет времени изобретать что-то более "хитрое". Если кто-то делал и есть желание обсудить, буду рад.
А вот обственно то, что сделал (сравниваются два слоя):
Код:

Dim aDupsForm
Dim ftIsProgress
' Вспомогательные функции
'===============================================
function CreateNewHTMLForm(aCaption, aInnerHTML)
  Dim aForm
  set aForm = Application.OpenHTMLWindow(ContextCard)
  aForm.Caption = aCaption
  with aForm.Browser
    .Navigate "about:blank"
    do while not (.ReadyState = 4 or .ReadyState = 3)
      Application.ProcessMessages
    loop
  end with
  set aForm.External = Disp
  aForm.Browser.Document.Body.innerHTML = aInnerHTML
  Set CreateNewHTMLForm = aForm
end function
Function ContourPartsIsEqual(P1, P2)
  Dim i, X1, Y1, C1, X2, Y2, C2
  ContourPartsIsEqual = False
  if P1.VertexCount <> P2.VertexCount then Exit Function
  For i = 0 to P1.VertexCount - 1
    P1.sGetVertex i, X1, Y1, C1
    P2.sGetVertex i, X2, Y2, C2
    if (X1 <> X2) or (Y1 <> Y2) or (C1 <> C2) then
      Exit Function
    end if
  Next
  ContourPartsIsEqual = True
End Function
Function ContoursIsEqual(C1, C2)
  Dim i
  ContoursIsEqual = False
  if C1.Count <> C2.Count then Exit Function
  For i = 0 to C1.Count - 1
    if not ContourPartsIsEqual(C1.Item(i), C2.Item(i)) then
      Exit Function
    end if
  Next
  ContoursIsEqual = True
End Function
Function GeometryIsEqual(MO1, MO2)
  Dim i
  GeometryIsEqual = False
  if MO1.Shapes.Count <> MO2.Shapes.Count then Exit Function
  For i = 0 to MO1.Shapes.Count - 1
    if not ContoursIsEqual(MO1.Shapes.Item(i).Contour, MO2.Shapes.Item(i).Contour) then
      Exit Function
    end if
  Next
  GeometryIsEqual = True
End Function
Function GeometryIsEqualByID(MOS, ID1, ID2)
  GeometryIsEqualByID = GeometryIsEqual(MOS.GetObject(ID1), MOS.GetObject(ID2))
End Function
Function CompareLayers(MOS, LayerID1, LayerID2)
  Dim MOQ1, MOQ2, i, aCount, aDups
  Set MOQ1 = MOS.QueryByLayers(LayerID1)
  Set MOQ2 = MOS.QueryByLayers(LayerID2)
  CompareLayers = 0
  aDups = 0
  aDupsForm.Browser.Document.all.Div0.InnerHTML = Application.ActiveDB.LayerFromID(LayerID1).Name
  aCount = 0
  Do While not MOQ1.EOF
    aCount = aCount + 1
    MOQ1.MoveNext
  loop
  MOQ1.Reset
  i = 0
  Do While not MOQ1.EOF
    MOQ2.Reset
    Do While not MOQ2.EOF
      Application.ProcessMessages
      if not ftIsProgress then Exit Function
      if GeometryIsEqualByID(MOS, MOQ1.ObjectID, MOQ2.ObjectID) then
        aDups = aDups + 1
        ' можно, например выделять дубли в одном слое...
        Application.Selection.Select MOQ1.ObjectID, 0
      end if
      MOQ2.MoveNext
    loop
    MOQ1.MoveNext
    i = i + 1
    aDupsForm.Browser.Document.all.Div1.InnerHTML = "Обработано <b>" & i & "</b> из <b>" & aCount & "</b><br>" &_
      "Дубликатов: <b>" & aDups & "</b>"
  loop
  CompareLayers = aDups
End Function
sub OnButtonStopClick
  ftIsProgress = False
End Sub
Sub OnFindDupsButtonClick
  Dim MOS, aDups
  if ftIsProgress then Exit Sub
  ftIsProgress = True
  Application.Selection.deselectAll
  Set MOS = Application.ActiveDB.MapObjects
  aDups = CompareLayers MOS, "000B00000410", "000800000413"
  ftIsProgress = False
End Sub
Sub StartFindDups
  Dim aHTML
  if not IsObject(Application.ActiveDB) then
    MsgBox "База данных не открыта"
    Exit sub
  end if
  ftIsProgress = False
  aHTML = "<b>Поиск дубликатов</b><hr>" & _
  "<input type=button value=Начать name=StartButton language=vbscript " &_
  "onclick='window.external.OnFindDupsButtonClick'>&nbsp" &_
  "<input type=button value=Остановить name=StopButton language=vbscript " &_
  "onclick='window.external.OnButtonStopClick'><br><br>" &_
  "<div name=Div0 id=Div0 Width=100% style='border: 1 solid #C0C0C0'>...</div>" &_
  "<div name=Div1 id=Div1 Width=100% style='border: 1 solid #C0C0C0'>...</div>"
  Set aDupsForm = CreateNewHTMLForm("Поиск дубликатов", aHTML)
  aDupsForm.Visible = True
end sub
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Кузнецов Андрей



Зарегистрирован: 22.04.2005
Сообщения: 28
Откуда: Магнитогорск

СообщениеДобавлено: Пн 17 Апр 2006 12:32    Заголовок сообщения: Ответить с цитатой

Прошу прощения за опечатку в названии темы
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Марина



Зарегистрирован: 18.07.2005
Сообщения: 8
Откуда: Самарский центр недвижимости

СообщениеДобавлено: Пн 17 Апр 2006 13:40    Заголовок сообщения: Re: Поиск дубликатов Ответить с цитатой

У нас такой вопрос тоже стоял, но до реализации дело пока не дошло.
Но первое, что приходит на ум: для убыстрения процесса надо с объектом из одного слоя сравнивать только те объекты из другого слоя, которые попадают в квадрат границ объекта.
Возможность реализовать запрос с использованием геометрии по-моему есть:
Код:
MapObjects.QueryByRect
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
andreichernov



Зарегистрирован: 14.02.2005
Сообщения: 209
Откуда: Самара

СообщениеДобавлено: Вт 18 Апр 2006 09:25    Заголовок сообщения: Ответить с цитатой

Я делал скрипт поиска двойных объектов. Могу прислать.
Относительно твоего кода - проще сделать через
QueryByContour
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Кузнецов Андрей



Зарегистрирован: 22.04.2005
Сообщения: 28
Откуда: Магнитогорск

СообщениеДобавлено: Вт 18 Апр 2006 10:28    Заголовок сообщения: Ответить с цитатой

Марина и Андрей, спасибо за отклики.
Андрей, QueryByContour, полагаю будет эффективен, если объекты состоят из одной формы. Здесь я думаю предложение Марины использовать MapObjects.QueryByRect будет корректнее. Как найду время попробую реализовать и оценить скорость работы.
А на счет "скрипта поиска двойных объектов" - вышлите, обязательно посмотрю, адрес: Andrew-G-K@yandex.ru.
Вообще задача эта всплывала давно, но без острой необходимости.
Сейчас обострилась в связи с такой ситуацией: есть две базы одна из другой сделанные путем простого копирования файлов (т.е. некорректно). Теперь их нужно объеденить. Но каждая из них уже поросла глюками и экспорт из них не проходит. Делаю переидентификацию этих баз (пространства идентификаторов, ситсемные объекты, геометрию), потом проверяю целостность. После этого объединяю. Все проходит нормально, но как следствие получаю дубли карт, слоев и объектов. Ладно с системными объектами - их не много и имена совпадают, а вот с пространственными объектами гораздо хуже. Мысли пока такие: вычислить объекты у котрых полностью совпадает геометрия (количество форм, координаты контуров), а затем сравнить семантику. Т.к. типы полей в таблицах "простые" (число или строка) и структара таблиц одинаковая, то думаю это реализовать тоже можно. Как вы уже знаете первое с чего начал - это геометрия.
Если инструмент получится, то думаю его можно будет применять и в других случаях.
А может есть решения моей задачи другими методами? Буду рад подсказкам.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
andreichernov



Зарегистрирован: 14.02.2005
Сообщения: 209
Откуда: Самара

СообщениеДобавлено: Вт 18 Апр 2006 11:11    Заголовок сообщения: Ответить с цитатой

Зря так сделаешь.
Умрешь.
Мы для устранения подобной фигни написали импорт и экспорт через собственный XML-файл.
При импорте проверяется, объект с таким ID в этом слое или нет,
если нет (то есть это дубликат), создается с новым идентификатором.
Ну то четь производится слияние двух некорректных баз через специальную процедуру импорта.
Вроде работает. [/i]
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Кузнецов Андрей



Зарегистрирован: 22.04.2005
Сообщения: 28
Откуда: Магнитогорск

СообщениеДобавлено: Вт 18 Апр 2006 13:19    Заголовок сообщения: Ответить с цитатой

Писать такую глобальную вещь я один не в силах. Попытался изменить начатый мною код.
Переписал функцию "CompareLayers" и пример отработал примерно в 150 раз быстрее (спасибо Марине).
Вот код:
Код:

Function CompareLayers(MOS, LayerID1, LayerID2)
  Dim MOQ1, MOQ2, i, aCount, aDups, MO, X1, X2, Y1, Y2
  Set MOQ1 = MOS.QueryByLayers(LayerID1)
  CompareLayers = 0
  aDups = 0
  aDupsForm.Browser.Document.all.Div0.InnerHTML = Application.ActiveDB.LayerFromID(LayerID1).Name
  aCount = 0
  Do While not MOQ1.EOF
    aCount = aCount + 1
    MOQ1.MoveNext
  loop
  MOQ1.Reset
  i = 0
  Do While not MOQ1.EOF
    ' возьмем область немного пошире
    Set MO = MOS.GetObject(MOQ1.ObjectID)
    X1 = MO.X1 - 1
    X2 = MO.X2 + 1
    Y1 = MO.Y1 - 1
    Y2 = MO.Y2 + 1
    Set MO = Nothing
    Set MOQ2 = MOS.QueryByRect(LayerID2, X1, Y1, X2, Y2, True)
       
    Do While not MOQ2.EOF
      Application.ProcessMessages
      if not ftIsProgress then Exit Function
      if GeometryIsEqualByID(MOS, MOQ1.ObjectID, MOQ2.ObjectID) then
        if not Application.Selection.IsSelected(MOQ1.ObjectID) then
          aDups = aDups + 1
          Application.Selection.Select MOQ1.ObjectID, 0
        end if 
      end if
      MOQ2.MoveNext
    loop
    MOQ1.MoveNext
    i = i + 1
    aDupsForm.Browser.Document.all.Div1.InnerHTML = "Обработано <b>" & i & "</b> из <b>" & aCount & "</b><br>" &_
      "Дубликатов: <b>" & aDups & "</b>"
  loop
  CompareLayers = aDups
End Function
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Начать новую тему   Ответить на тему    Список форумов www.integro.ru -> Вопросы разработчиков Часовой пояс: GMT + 5
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете добавлять приложения в этом форуме
Вы можете скачивать файлы в этом форуме


© phpBB Group
Русская поддержка phpBB