| Правила | Регистрация | Пользователи | Поиск | Сообщения за день | Все разделы прочитаны |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > Готовые программы > JavaScript. nanoCAD 5. Округление координат объектов с учетом ПСК

JavaScript. nanoCAD 5. Округление координат объектов с учетом ПСК

Ответ
Поиск в этой теме
Непрочитано 27.04.2019, 08:36 #1
JavaScript. nanoCAD 5. Округление координат объектов с учетом ПСК
Нубий-IV
 
Инженер-философ
 
Хабаровск
Регистрация: 24.04.2019
Сообщений: 1,867

Использую для обработки подложки, полученной от архитекторов, перед передачей в расчетную программу.
Работа в активной ПСК позволяет обрабатывать повернутые секции зданий - координаты будут округлены именно в осях секции.
Лиспы с форума либо не работают в nanoCAD, либо не учитывают ПСК, аналогичный скрипт с сайта fordewind тоже работает только в МСК.

По замечаниям поста #2 исправлена ошибка округления полилинии при работе в наклонных ПСК.

Код:
[Выделить все]
// Округление координат объектов в активной ПСК
// Для линий, полилиний, кругов, точек, 3d-граней, блоков

/** 
 * Округляет число
 * 
 * @param {number} number число
 * @param {number} precision точность округления
 * @return {number}
 */
function RoundNumber(number, precision)
{
	return Math.round(number / precision) * precision
}

/** 
 * Округляет массив чисел
 * 
 * @param {array} array массив
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundArray(array, precision)
{
	for(var i = 0; i < array.length; i++)
		array[i] = RoundNumber(array[i], precision)
}

/** 
 * Округляет точку, хранящуюся в мировой системе координат (вершина линии, 3Dграни; точка; вставка блока; центр круга) 
 * 
 * @param {point} point точка
 * @param {number} precision точность округления
 * @return {point}
 */
function RoundPointWCS(point, precision)
{
	var pointUCS = Utility.TranslateCoordinates(point, acWorld, acUCS, false)
	pointUCS = Utility.CreateSafeArrayFromVector(pointUCS).toArray()
	
	RoundArray(pointUCS, precision)
	
	pointUCS = Utility.CreateTypedArrayFromJSArray(5, pointUCS)
	return Utility.TranslateCoordinates(pointUCS, acUCS, acWorld, false)
}

/**
 * Преобразует 2D-точку в 3D-точку, добавляя координату z.
 * 
 * @param {point} point точка
 * @param {number} z координата z
 * @return {point}
 */
function Point2Dto3D(point, z)
{
	var point2D = Utility.CreateSafeArrayFromVector(point).toArray()
	var point3D = new Array(point2D[0], point2D[1], z)
	return Utility.CreateTypedArrayFromJSArray(5, point3D)
}

/**
 * Преобразует 3D-точку в 2D-точку, удаляя координату z.
 * 
 * @param {point} point точка
 * @return {point}
 */
function Point3Dto2D(point)
{
	var point3D = Utility.CreateSafeArrayFromVector(point).toArray()
	var point2D = new Array(point3D[0], point3D[1])
	return Utility.CreateTypedArrayFromJSArray(5, point2D)
}

/** 
 * Округляет точку, хранящуюся в объектной системе координат (вершина полилинии) 
 * 
 * @param {point} point точка
 * @param {number} precision точность округления
 * @param {vector} ocsNormal вектор нормали OCS
 * @param {number} elevation уровень OCS
 * @return {point}
 */
function RoundPointOCS(point, precision, ocsNormal, elevation)
{
	var pointOCS = Point2Dto3D(point, elevation)
	pointOCS = Utility.TranslateCoordinates(pointOCS, acOCS, acUCS, false, ocsNormal)
	pointOCS = Utility.CreateSafeArrayFromVector(pointOCS).toArray()

	RoundArray(pointOCS, precision)
	
	pointOCS = Utility.CreateTypedArrayFromJSArray(5, pointOCS)
	pointOCS = Utility.TranslateCoordinates(pointOCS, acUCS, acOCS, false, ocsNormal)
	return Point3Dto2D(pointOCS)
}

/** 
 * Округляет отрезок. Округляются начало и конец.
 * 
 * @param {AcDbLine} line отрезок
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbLine(line, precision)
{
	line.StartPoint = RoundPointWCS(line.StartPoint, precision)
	line.EndPoint   = RoundPointWCS(line.EndPoint,   precision)
}

/** 
 * Округляет полилинию. Округляются все вершины.
 * 
 * @param {AcDbPolyline} polyline полилиния
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbPolyline(polyline, precision)
{
	polyline.Elevation = RoundNumber(polyline.Elevation, precision)

	var nVerts = (Utility.CreateSafeArrayFromVector(polyline.Coordinates).ubound() + 1) / 2

	for(var i = 0; i < nVerts; i++)
		polyline.Coordinate(i) = RoundPointOCS(polyline.Coordinate(i), precision, polyline.Normal, polyline.Elevation)
}

/** 
 * Округляет круг. Округляются центр и радиус.
 * 
 * @param {AcDbCircle} circle круг
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbCircle(circle, precision)
{
	circle.Center = RoundPointWCS(circle.Center, precision)
	circle.Radius = RoundNumber(circle.Radius, precision)
}

/** 
 * Округляет точку
 * 
 * @param {AcDbPoint} point точка
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbPoint(point, precision)
{
	point.Coordinates = RoundPointWCS(point.Coordinates, precision)
}

/** 
 * Округляет 3d-грань. Округляются все вершины.
 * 
 * @param {AcDbFace} face 3d-грань
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbFace(face, precision)
{
	var nVerts = (Utility.CreateSafeArrayFromVector(face.Coordinates).ubound() + 1) / 3
	
	for(var i = 0; i < nVerts; i++)
		face.Coordinate(i) = RoundPointWCS(face.Coordinate(i), precision)
}

/** 
 * Округляет вставку блока.Округляются только вставка, объекты внутри блока не меняются.
 * 
 * @param {AcDbBlockReference} blockReference вставленный блок
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundAcDbBlockReference(blockReference, precision)
{
	blockReference.InsertionPoint = RoundPointWCS(blockReference.InsertionPoint, precision)
}

/** 
 * Округляет объект чертежа
 * 
 * @param {Entity} entity объект
 * @param {number} precision точность округления
 * @return {void}
 */
function RoundEntity(entity, precision)
{
	switch(entity.ObjectName) {
	case "AcDbLine":
		RoundAcDbLine(entity, precision)
		break
	case "AcDbPolyline":
		RoundAcDbPolyline(entity, precision)
		break
	case "AcDbCircle":
		RoundAcDbCircle(entity, precision)
		break
	case "AcDbPoint":
		RoundAcDbPoint(entity, precision)
		break
	case "AcDbFace":
		RoundAcDbFace(entity, precision)
		break
	case "AcDbBlockReference":
		RoundAcDbBlockReference(entity, precision)
		break
	}
}

// Фильтр выбора объектов
var FilterType = [0]
var FilterData = ["LINE,LWPOLYLINE,CIRCLE,POINT,3DFACE,INSERT"]

FilterType = Utility.CreateTypedArrayFromJSArray(2, FilterType)
FilterData = Utility.CreateTypedArrayFromJSArray(8, FilterData)

// Выбор объектов
Utility.Prompt("Округление координат объектов")
ActiveSelectionSet.SelectOnScreen(FilterType, FilterData)

// Запрос точности округления
var precision = Utility.GetReal("Задайте точность округления")

// Округление выбранных объектов
for(var i = 0; i < ActiveSelectionSet.Count; i++)
{
	RoundEntity(ActiveSelectionSet.Item(i), precision)
}

// Сброс выделения
ActiveSelectionSet.Clear()

Последний раз редактировалось Нубий-IV, 05.05.2019 в 14:33. Причина: Исправление ошибок по замечаниям
Просмотров: 4382
 
Непрочитано 27.04.2019, 10:27
1 | #2
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Вопрос в том, в какой системе координат ты получаешь точки. Для отрезка / сплайна / точки / 3d-полилинии они (если не ошибаюсь) - в мировой. Для других типов объектов - в ОСК.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 28.04.2019, 22:25
1 | #3
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Посмотрел код по диагонали. Очень рекомендую автору внимательно ознакомиться с методом Math.Round и его перегрузками, там есть на что посмотреть. Потом, порекомендую вспомнить про ограничения двоичной систем счисления по отношению к числам с плавающей точкой и округлять координаты отрезков не бездумно, а как минимум с сохранением вектора прямой.
Boxa вне форума  
 
Автор темы   Непрочитано 29.04.2019, 14:51
#4
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,867


Цитата:
Сообщение от Boxa Посмотреть сообщение
ознакомиться с методом Math.Round и его перегрузками
Перегруженный округлятор в .NET есть, а в JavaScript он просто к ближайшему целому округляет, или я что-то путаю? В гугле все примеры с округлением на скриптах именно через умножить/поделить.

Цитата:
Сообщение от Boxa Посмотреть сообщение
округлять координаты отрезков не бездумно, а как минимум с сохранением вектора прямой.
Опасно сохранять векторы направления для отрезков в архитектурных чертежах. Если прямоугольный контур начерчен отрезками с привязкой "ближайшая", он может оказаться не прямоугольным,и в расчетной программе на таких стенах потом портится сетка. А если округлить к ближайшим сантиметрам - слегка повернутые отрезки выравниваются как надо. Т.е. "бездумное округление" наносит квадратную сетку, к вершинам которой притягиваются все объекты, и все становится "параллельно и перепендикулярно". А небольшое искажение геометрии не опасно для расчета, в отличие мелких наложений вершин и малозаметных щелей.

А разве можно округлить обе вершины отрезка в общем случае так, чтобы направление сохранилось?
Миниатюры
Нажмите на изображение для увеличения
Название: Отрезок.png
Просмотров: 40
Размер:	5.2 Кб
ID:	213697  
Нубий-IV вне форума  
 
Непрочитано 29.04.2019, 15:09
1 | #5
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Нубий-IV, Часто в чертежах, при пороговых значениях происходит округление координат вершин в разные стороны

(Зеленая - исходная, красная - результат) и отследить это сложно, а если речь идет о строительных чертежах, то при округлении координат нужно учитывать сетку и вектора осей. =(

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

Последний раз редактировалось Boxa, 29.04.2019 в 15:15.
Boxa вне форума  
 
Автор темы   Непрочитано 29.04.2019, 15:20
#6
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,867


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Вопрос в том, в какой системе координат ты получаешь точки
Ничего себе, вопрос на засыпку ! Обрабатывать объекты с разной системой координат одной функцией действительно был умный ход с моей стороны .
Фокус в том, что скрипт все равно работает, и именно так, как надо - и в МСК координаты становятся круглыми, и в ПСК, для всех видов объектов, независимо от их способа хранения координат.
Поразбираюсь в ближайшее время, почему это мне так повезло.

upd
Проверил - точно, есть ошибка.
Раньше работал только на планах. Когда ось Z у ПСК вертикальна, ошибка не проявлялась, а в наклонных ПСК полилинии округлялись неправильно.
Ошибку исправил, программу обновил.

Последний раз редактировалось Нубий-IV, 05.05.2019 в 14:30.
Нубий-IV вне форума  
 
Автор темы   Непрочитано 04.05.2019, 10:04
#7
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,867


Цитата:
Сообщение от Boxa Посмотреть сообщение
Часто в чертежах, при пороговых значениях происходит округление координат вершин в разные стороны
Шутку оценил, смешно. Случай нечастый, в реальных чертежах при тестировании то ли не сталкивался, то ли не обратил внимание. А вот если специально поднатужиться, можно получить интересный эффект.

Сваял наскоро тестовый чертеж, проверил свой скрипт и несколько лиспов с форума. Результаты - на картинке, чертеж - во вложении (кому интересно - округлять до целых). Танцуют все! Хотя, конечно, на конкурсе "округлятор хренов" я занял почетное первое место.

По-хорошему, надо отслеживать:
- изменение угла поворота, в том числе для линий, не параллельных осям
- касание вершинами
- касание вершиной к другим линиям (в том числе к кругам, эллипсам и сплайнам)
- для трехмерных схем (планы зданий на разных этажах) еще и совпадение с вершинами и линиями на других этажах

Получается, округлять объекты поодиночке не выйдет, это может нарушить связи между ними. Напрашивается решение в три прохода:
  1. Сверить каждый объект с каждым в поисках предполагаемых зависимостей.
  2. Для каждой вершины выбрать возможные варианты округления к ближайшим координатам в пределах допуска
  3. Выполнить полный перебор для всех вершин и вариантов округления, выбрать наименее нарушающий зависимости.
Похоже, я собираюсь вырастить дракона .

Где-нибудь можно подсмотреть готовое решение, чтобы не терять время, или эту задачу полностью еще никому не удалось решить?
Миниатюры
Нажмите на изображение для увеличения
Название: Округление.png
Просмотров: 50
Размер:	37.3 Кб
ID:	213810  
Вложения
Тип файла: dwg Округление.dwg (12.2 Кб, 13 просмотров)
Нубий-IV вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > Готовые программы > JavaScript. nanoCAD 5. Округление координат объектов с учетом ПСК

Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
При завершении копирования (copy) нескольких выделенных объектов, исходный остается активным. AutoCAD 2017. OlegPVQ AutoCAD 13 15.11.2018 01:59
Округление координат, полилиний, центров окружностей, блоков MA2 Программирование 44 15.01.2015 15:19
Кривая работа аннотативных объектов, созданных в пространстве модели. hwd AutoCAD 16 23.08.2013 18:16
Возможно ли извлекь данные точек на плоскости с учетом ПСК Alexg-12 AutoCAD 2 24.10.2012 14:54
управление системой координат Автокад из Делфей Владимир В Программирование 12 27.04.2005 09:54