AutoCad - Obtener puntos en orden

 
Vista:
Imágen de perfil de hernan

Obtener puntos en orden

Publicado por hernan (8 intervenciones) el 29/10/2016 06:37:45
Hola a todos, soy nuevo usando autolisp pero estoy aprendiendo rapio. Mi consulta es la siguiente: Estoy haciendo un programa que me calcula la distancia entre los puntos que selecciono en pantalla, la dificultad esta en que cuando voy seleccionando uno por uno los puntos el me arroja la distancia bien pero cuando hago una ventana de seleccion en ocasiones me arroja la distancia bien y en otras no, esto por la secuencia que toma los puntos. Como puedo hacer para que me corregir esto.
Este es el código, lo estoy terminando aun, pero funciona. En la imagen adjunta me arroja dos distancias diferentes de acuerdo como lo selecciones (Punto por punto - ventana de selección )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
(defun c:colin ()
(initget 7)
(setq m " m")
(setq n (getint "Numero de Colindantes: "))
  (setq i 0)
  (while (< i n)
	(setq inftexto (entget (car (entsel "Seleccione un texto:"))))
	(setq texto (cdr (assoc 1 inftexto)))
	(setq h (cdr (assoc 40 inftexto)))
	(setq h (* h 0.8))
	(setq puntos (ssget (list (cons 0 "POINT")))) ; Selecciona solo Puntos
	(setq cant (sslength puntos)); cantidad de puntos seleccionados
	;(entget (ssname puntos i)) ;Obtiene los atribulos de cada elemente
	(setq j 0)
	(setq dist 0) ; Inicializar distacia entre puntos
	(repeat (- cant 1)
	(setq p1 (cdr (assoc 10(entget (ssname puntos j))))) ; Obtiene las coordenadas primer punto
	(setq p2 (cdr (assoc 10(entget (ssname puntos (+ j 1)))))) ; Obtiene las coordenadas segundo punto
	(setq dist (+ dist (distance p1 p2))) ; Voy sumando las distancias entre puntos
	(setq j (+ j 1))
	)
	(setq dist (rtos dist 2 2)) ; Convierte la distancia a texto con 2 decimales como precision
	(setq punto (getpoint "\nIngrese punto de insercion: "))
	(setq texto2 (strcat dist m))
	(entmake(list
      (cons 0   "TEXT")
      (cons 100 "AcDbEntity")
      (cons 100 "AcDbMText")
      (cons 10 punto)
      (cons 1 texto2)
	  (cons 40 h)))
	(setq i (+ i 1))
 
)
(prin1)
)
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 1.285
Oro
Ha mantenido su posición en AutoCad (en relación al último mes)
Gráfica de AutoCad

Obtener puntos en orden

Publicado por Gerardo (989 intervenciones) el 29/10/2016 08:12:08
No veo la imagen adjunta, pero en todo caso la respuesta es que una vez que has seleccionado los puntos debes ordenarlos antes de calcular las distancias. El criterio de ordenamiento depende de lo que se trate el programa.

Intenta ordenarlos y si no va pues sube un ejemplo para entender el criterio de ordenamiento y poder ayudarte
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de hernan

Obtener puntos en orden

Publicado por hernan (8 intervenciones) el 29/10/2016 14:34:40
Captura2

Hola Gerardo, esta es la imagen, la idea es sacar la longitud por ejemplo de esos tres puntos, si te das cuenta debajo del nombre hay dos distancias, cuando selecciono punto por punto me da la distancia correcta pero cuando haga una ventana de selección para seleccionar todos los puntos me da otra distancia. Como puedo hacer para ordenar los puntos.
Siempre importo estos puntos desde un archivo, con el nombre del punto, coordenadas X y las Y. En la imagen solo hice puntos manual mente para probar el programa.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 1.285
Oro
Ha mantenido su posición en AutoCad (en relación al último mes)
Gráfica de AutoCad

Obtener puntos en orden

Publicado por Gerardo (989 intervenciones) el 30/10/2016 05:34:38
Bien.

Cuando tu seleccionas los puntos de uno en uno AutoCAD los va agregando en ese orden al conjunto de selección.

Cuando lo haces con un metodo masivo, como una ventana, lo que hace el CAD es recorrer la base de datos (que es ordenada) e ir agregando a la selección los que cumplan con el criterio solicitado (por ejemplo que sean puntos y estén dentro de la ventana). Eso significa que serán agregados en el orden de la BD que es el orden en que fueron creados los puntos.

El problema de ordenar con la rutina es que esta no tiene el sentido común que tu tienes para definir el orden, entonces debemos generar un proceso matemático de ordenamiento. Este podría ser por ejemplo tomar siempre el punto más cercano al punto elegido y que no sea el anterior seleccionado. Esto funcionaría con secuencias de puntos más regulares pero no en algunos casos en que el siguiente punto puede estar más lejos que uno que no sea el siguiente. Por ejemplo una doble fila que representa un camino, y donde el siguiente punto de uno de los lados del camino está más lejano que el punto "de en frente".

Luego hay otra desición difícil: cual elegir como primer punto?

Al final, para cada pregunta hay que decidir que calcular automáticamente y que dejarle al usuario. Podrías terminar calculandolo todo. Preguntandole al usuario el punto inicial y tu ordenando los puntos o mejor pidiendole al usuario que seleccione en orden y no calcular nada de esto. Porque el algoritmo de ordenamiento podría ser muy fácil, muy difícil o irresolvible.

Un par de ejemplos de posibles soluciones que talves y solo talves funcionen:

1-Si las secuencias de puntos siempre representan poligonos cerrados podrías definir un centroide como promedio de todos los puntos o como promedio de las coordenadas máximas y mínimas y hacer un barrido angular ordenando los puntos segun el angulo desde ese centroide. En este caso el punto inicial puede ser cualquiera.

2-Si las secuencias siempre representan caminos no ciclicos (abiertas), podrias tomar los dos puntos más lejanos entre si, y trazar una linea imaginaria entre ellos, y desde cada punto sacar un vector tambien imaginario perpendicular a esa línea, y ordenarlos segun su posición en esa línea. Luego, uno de los dos extremos iniciales terminará siendo el punto inicial del cálculo.

Te pregunto de nuevo: cual es el criterio de ordenamiento geométrico que te sirve para todos los casos posibles?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de hernan

Obtener puntos en orden

Publicado por hernan (8 intervenciones) el 30/10/2016 23:41:16
Hola Gerardo, gracias por tu información me ha despejado algunas dudas el ejemplo 1 seria lo mas acorde a lo que quiero hacer pues quiero sacar la longitud alrededor de un perímetro de un plano topográfico.
Gracias por tu ayuda te agradezco que te tomes el tiempo de explicarme.
Una pregunta si no es mucha molestia, como harías el centroide promedio, con que función lo haces?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 1.285
Oro
Ha mantenido su posición en AutoCad (en relación al último mes)
Gráfica de AutoCad

Obtener puntos en orden

Publicado por Gerardo (989 intervenciones) el 31/10/2016 03:51:52
Bien. Un centroide como "Centro de masa" creo que no sirve porque puede quedar fuera del poligono, y localizar un punto central que este dentro del poligono es un problema complejo. Creo que lo podríamos resolver con una serie de triangulaciones mínimas entre puntos, pero no debe ser tan simple

Por ahora te doy una forma fácil de obtener el punto promedio de todos los puntos para que empieces a experimentar. En ambos casos se requiere una lista, por lo que debes recorrer el conjunto de seleccion en un bucle y para cada punto tomar sus coordenadas e irlas agregando a una lista

1
2
3
4
5
6
7
8
9
10
11
;Sea LPuntos una lista de puntos (X Y) o (X Y Z)
 
(setq LstXs (mapcar 'car LPuntos) ;Lista de valores de todas las X
	LstYs (mapcar 'cadr LPuntos) ;Lista de valores de todas las Y
	Xsuma (apply '+ LstXs) ;suma de todas las X
	Ysuma (apply '+ LstYs) ;suma de todas las Y
	cant (length LPuntos) ;Cantidad de valores
	promX (/ XSuma cant) ;Promedio en X
	promY (/ YSuma cant) ;promedio en Y
	PUNTO (list promX promY 0.0) ;Punto promedio calculado
)

Fijate que ese codigo obtiene un promedio, quiere decir que si hay mayor cantidad de puntos hacia algún extremo el punto central se halará hacia ese extremo. En el siguiente código eso no pasa, porque voy a calcular el promedio solo de las coordenadas extremas, aunque tambien en este caso es un poco más probable que el punto quede fuera del poligono, por ejemplo si este tuviera forma de "boomerang".


1
2
3
4
5
6
7
8
9
10
(setq LstXs (mapcar 'car LPuntos) ;Lista de valores de todas las X
	LstYs (mapcar 'cadr LPuntos) ;Lista de valores de todas las Y
	Xmax (apply 'max LstXs) ;valor máximo de X
	Xmin (apply 'min LstXs) ;valor mínimo de X
	Ymax (apply 'max LstYs) ;valor máximo de Y
	Ymin (apply 'min LstYs) ;valor mínimo de Y
	promX (/ (+ Xmax Xmin) 2.0) ;Promedio en X
	promY (/ (+ Ymax Ymin) 2.0) ;promedio en Y
	PUNTO (list promX promY 0.0) ;Punto promedio calculado
)


Debes saber que el análisis geométrico es uno de los temas más difíciles en la programación.

Voy a insistir en la complejidad del analisis geométrico que quieres hacer y te muestro un ejemplo.
En la imagen adjunta hay un grupo de puntos y dos posibles poligonos que salen de ellos. Si me muestras esos puntos yo no sabria cual de los dos poligonos es la forma verdadera del predio, ambos parecen válidos. Y si yo no lo sé con claridad, como podría establecerle un criterio a la rutina?
Para establecer un criterio claro posiblemente tendrías que poner reglas que no se ajustan a las reglas de la vida real. Por ejemplo: si se pueden calcular varios polígonos, que siempre se tome el de mayor area como el verdadero. Así la rutina en un caso como el de la imagen determinaría cual de los dos poligonos calcula.

Fijate si es complejo que la las aplicaciones de topografía comerciales te generan puntos y le dejan al usuario la tarea de unirlos como este lo desee.
Untitled
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
Imágen de perfil de hernan

Obtener puntos en orden

Publicado por hernan (8 intervenciones) el 31/10/2016 21:02:19
Una vez mas gracias por tu explicacion, tomare en cuenta tus ejemplos y tratare de generar una rutina que compartiré cuando la termine. Gracias por sacar tiempo para explicar. (y)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Obtener puntos en orden

Publicado por Enrique Calderon (3 intervenciones) el 11/08/2017 05:54:22
Buen dia, no se si resolviste tu problema, yo tengo el mismo en una rutina que hice para hacer un resumen de ares de poligonos dentro de un dibujo, y enviar la informacion a un archivo en excel.
Tal ves entendi mal, pero tenia la creencia de que utilizando la funcion ssget, esta se llevaria a cabo en el orden en que fueron generados en el dibujo,
Ya que es poco menos que imposible, generar poligonos en un orden perfecto, como podria ser por ejemplo en el plano de un centro comercial donde podriamos tener por ejemplo 100 locales repartidos en 5 zonas,
La intencion de mi rutina es seleccionar cada uno de los poligonos que representan cada local asi como el nombre del local, y el resultado que arroje es una volumetria de las caracterisitcas del local, como podria ser, el area, el perimetro, y cualquier dato que se pudiera requerir, y enviar el resultado a un archivo en excel.

Al utilizar la rutina por primera vez selecciono un poligono y un texto (nombre del area) en el orden que quiero que aparesca en el archivo, y funciona perfectamente, pero esto esto puede ser muy tedioso, por ejemplo en el caso tuyo si tienes 500 puntos, pues es una proeza seleccionar uno por uno,

Lo que hice fue, que el programa eliminara cada uno de los elementos seleccionados y los generara nuevamente en el orden en que fueron seleccionados, asi quedan todos en un orden de acuerdo a la seleccion.

Esto con la intencion de que si haces modificaciones a cualquier poligono, puedas utilizar nuevamente la rutina, haciendo una seleccion mediante una ventana que contenga todos los elementos desead, asuminendo que ssget, recuperara queda elemento en el orden en que fueron creados.

Por ejemplo si el trazo de tus puntos es modificado , solo vuelves a seleccionarlos en tu rutina y presenta las nuevas mediciones de manera efectiva.
En ocaciones me funciona de esta manera la rutina y el resultado es el deseado. pero en otras ocaciones la seleccion es totalmente aleatoria, y me revuelve la informacion, con lo que el archivo generado ya no muestra los resultados de forma ordenada.
O tal ves haya alguna variable del sistema que regule la seleccion de la funcion ssget
Por lo pronto si no hay nadie que tenga la solucion a esto, lo que voy a hacer es que mi seleccion se ordene en base al codigo 5 de las entidades, que segun entiendo, este codigo en numero hexadecimal, representa el orden en que se genero en el dibuo.
Por ejemplo si tu generas tus circulos que representan tus puntos, en un orden especifico, al seleccionarlos con este sistema siempre te funcionara.

Aunque para tu caso, creo que seria mas funcional representar cada uno de tus puntos medianta la trayectoria de una polilinea, en la que cada vertice representa tus puntos, hay muchas rutinas que puedes encontrar en la red que filtran los codigos de las entridades, con lo que al mover cualquier vertice de tu polilinea, y ejecutar tu rutina, obtendras los resultados deseados de manera muy efectiva

1
2
3
4
5
6
(defun filtro_codigo_entidad (cod_filt nombre_entidad)
  (setq lista_nombre_entidad (entget nombre_entidad))
       		(setq codigo (vl-remove-if-not '(lambda(x)(member(car x) (list cod_filt))) lista_nombre_entidad))
	(setq nombre_codigo (cdar codigo)) (print "nombre_codigo  ")(princ nombre_codigo)
  (princ)
 )
Esta la llamas mediante la siguiente funcion

(filtro_codigo_entidad 0 nombre-de-la-entidad) te da el tipo de entidad por ejemplo "LWPOLYLINE" o "circle" o "text" etc.....
(filtro_codigo_entidad 5 nombre-de-la-entidad) te da el codigo denominado handle, y es un numero en hexadecimal que es de manera consecutiva el orden en que fue generado en el dibujo

Espero haber sido claro
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Obtener puntos en orden

Publicado por Enrique Calderon (3 intervenciones) el 11/08/2017 05:58:08
Te adjunto una funcion que al seleccionar entidades en el dibujo te arroja los codigos en un archivo de texto
Esta la encontre en la red, ya no recuerdo donde, y tiene algunas modificaciones que son inutiles en la rutina y solo las hice cuando esta aprendiendo a programar, y las hice tratando de entender el funcionamiento de la misma.
Debo agradecer al que la coloco en la red, y lamento no recordar el origen de la misma a fin de darle el credito que se merece.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(defun c:listx ( / n_e lis_e ctrl cont) (setvar "cmdecho" 0)
 
  (if (setq s_set (ssget))
      (progn (princ "ya se selecciono el objeto")
         (opn_l)(setq s_c 0)
         (repeat (sslength s_set)
            (if (setq n_e (ssname s_set s_c))(setq lis_e (entget n_e (list "*"))))
            (setq cont 0)
	    (print  if_w)
            (prn_l lis_e)
            (if (or (= (cdr (assoc 0 lis_e)) "POLYLINE") (= (cdr (assoc 0 lis_e)) "INSERT") )
               (progn  (setq ctrl t)
	                  (while (and ctrl (setq n_e (entnext n_e))) (print "Nombre de entidad ")(princ n_e)
				(setq cont 0)
				(if (= (cdr (assoc 0 (setq lis_e (entget n_e (list "*"))))) "SEQEND")
                        	(progn (setq ctrl nil)(prn_l lis_e))
                        		(progn (print "ESTA ES UNA cuando no hay or" if_w) (prn_l lis_e))
                     		)
                  	);final while
               ); final progn
            )
            (setq s_c (1+ s_c))
         )
         (close if_w)
      )))
(defun prn_l (lis_e / )
   (repeat (length lis_e)
      (print (nth cont lis_e) if_w)
      (setq cont (1+ cont))
   )
)
(defun opn_l ()
   (if (null nomls)(setq nomls ""))
   (if (setq nomls (getfiled "Lista de Entidad:" nomls "txt" 5))
      (if (wcmatch nomls "*`.*")
         (setq if_w (open nomls "w"))
         (setq if_w (open (strcat nomls ".txt") "w")
         )
      )
   )
)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Obtener puntos en orden

Publicado por Enrique (3 intervenciones) el 11/08/2017 06:26:57
Te adjunto una rutina denominada lispx, que debo agradecer al autor de la misma, aunque lamentablemente no recuerdo de donde la obtuve, tiene algunas modificaciones que son innecesarias a la misma, pero fueron con la intencion de ayudarme a entender el funcionamiento de la misma, cuando estaba aprendiendo a programar en auto lisp, pero de cualquier manera funciona

(defun c:listx ( / n_e lis_e ctrl cont) (setvar "cmdecho" 0)

(if (setq s_set (ssget))
(progn (princ "ya se selecciono el objeto")
(opn_l)(setq s_c 0)
(repeat (sslength s_set)
(if (setq n_e (ssname s_set s_c))(setq lis_e (entget n_e (list "*"))))
(setq cont 0)
(print if_w)
(prn_l lis_e)
(if (or (= (cdr (assoc 0 lis_e)) "POLYLINE") (= (cdr (assoc 0 lis_e)) "INSERT") )
(progn (setq ctrl t)
(while (and ctrl (setq n_e (entnext n_e))) (print "Nombre de entidad ")(princ n_e)
(setq cont 0)
(if (= (cdr (assoc 0 (setq lis_e (entget n_e (list "*"))))) "SEQEND")
(progn (setq ctrl nil)(prn_l lis_e))
(progn (print "ESTA ES UNA cuando no hay or" if_w) (prn_l lis_e))
)
);final while
); final progn
)
(setq s_c (1+ s_c))
)
(close if_w)
)))
(defun prn_l (lis_e / )
(repeat (length lis_e)
(print (nth cont lis_e) if_w)
(setq cont (1+ cont))
)
)
(defun opn_l ()
(if (null nomls)(setq nomls ""))
(if (setq nomls (getfiled "Lista de Entidad:" nomls "txt" 5))
(if (wcmatch nomls "*`.*")
(setq if_w (open nomls "w"))
(setq if_w (open (strcat nomls ".txt") "w")
)
)
)
)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar